00001 #include "tasktype.h"
00002 
00003 #include "clock.h"
00004 #include "task.h"
00005 #include "invitation.h"
00006 #include "user.h"
00007 #include "usertype.h"
00008 #include "resourcetype.h"
00009 #include "reservation.h"
00010 
00011 #include <QVariant>
00012 #include "resource.h"
00013 #include <tools/invaliddataexception.h>
00014 
00015 namespace domain
00016 {
00017 
00018 struct TaskTypePrivate
00019 {
00020     QList<Field> fields;
00021     QList<Requirement*> requirements;
00022     QList<UserType*> potentialOwners;
00023     TaskType* q;
00024 
00025     TaskTypePrivate(TaskType* qq) : q(qq)
00026     {
00027     }
00028 
00029     ~TaskTypePrivate()
00030     {
00031         qDeleteAll(requirements);
00032     }
00033 
00034     template<typename T>
00035     QList<Requirement*> requirementByType()
00036     {
00037         QList<Requirement*> ret;
00038 
00039         Q_FOREACH (Requirement* req, requirements)
00040         {
00041             if (qobject_cast<T>(req->type) != 0)
00042                 ret << req;
00043         }
00044 
00045         return ret;
00046     }
00047 
00048     template<typename Req, typename Type>
00049     Req* addRequirement(Type* type, unsigned min, unsigned max)
00050     {
00051         if (max < min)
00052         {
00053             throw tools::InvalidDataException(QString("Invalid arguments for "
00054             "requirement of type %1. Maximum value (%2) is less than minimum "
00055             "value (%3)").arg(type->name()).arg(min).arg(max));
00056         }
00057 
00058         Q_FOREACH (Requirement* req, requirements)
00059         {
00060             if (req->type == type)
00061             {
00062                 throw tools::InvalidDataException(QString("Cannot have multiple "
00063                                 "requirements for type %1").arg(type->name()));
00064             }
00065         }
00066 
00067         Req* req = new Req(type);
00068         req->min = min;
00069         req->max = max;
00070         requirements << req;
00071 
00072         emit q->dataChanged();
00073 
00074         return req;
00075     }
00076 };
00077 
00078 TaskType::TaskType(const QString& id, const QString& name) : Type(id, name),
00079                                                     d(new TaskTypePrivate(this))
00080 {
00081 }
00082 
00083 TaskType::~TaskType()
00084 {
00085     delete d;
00086 }
00087 
00088 const QList<Field>& TaskType::fields() const
00089 {
00090     return d->fields;
00091 }
00092 
00093 const QList<Requirement*>& TaskType::requirements() const
00094 {
00095     return d->requirements;
00096 }
00097 
00098 QList<Requirement*> TaskType::resourceRequirements() const
00099 {
00100     return d->requirementByType<ResourceType*>();
00101 }
00102 
00103 QList<Requirement*> TaskType::userRequirements() const
00104 {
00105     return d->requirementByType<UserType*>();
00106 }
00107 
00108 bool TaskType::requirementsAreFulfilled(const Task* task) const
00109 {
00110     if (task->taskType() != this)
00111         return false;
00112 
00113     Q_FOREACH (Requirement* requirement, d->requirements)
00114     {
00115         if (!requirement->isFulfilled(task))
00116             return false;
00117     }
00118 
00119     return true;
00120 }
00121 
00122 bool TaskType::canBeSuccessful(const domain::Task* task) const
00123 {
00124     Q_FOREACH (Requirement* requirement, d->requirements)
00125     {
00126         if (!requirement->canBeSuccessful(task))
00127             return false;
00128     }
00129 
00130     return true;
00131 }
00132 
00133 const QList<UserType*>& TaskType::potentialOwners() const
00134 {
00135     return d->potentialOwners;
00136 }
00137 
00138 bool TaskType::userCanCreate (UserType* userType) const
00139 {
00140     return potentialOwners().contains(userType);
00141 }
00142 
00143 void TaskType::addField(const domain::Field& field)
00144 {
00145     if (!field.isValid())
00146     {
00147         throw tools::InvalidDataException(QString("Invalid field to add to "
00148         "tasktype %1: field insufficiently instantiated").arg(this->name()));
00149     }
00150     else if (!this->fieldById(field.id).isNull())
00151     {
00152         throw tools::InvalidDataException(QString("Invalid field to add to "
00153         "tasktype %1. Duplicate ID %2").arg(this->name()).arg(field.id));
00154     }
00155 
00156     d->fields << field;
00157     emit dataChanged();
00158 }
00159 
00160 UserRequirement* TaskType::addRequirement(
00161                             UserType* type, unsigned int min, unsigned int max)
00162 {
00163     return d->addRequirement<UserRequirement>(type, min, max);
00164 }
00165 
00166 ResourceRequirement* TaskType::addRequirement(
00167                         ResourceType* type, unsigned int min, unsigned int max)
00168 {
00169     return d->addRequirement<ResourceRequirement>(type, min, max);
00170 }
00171 void TaskType::addPotentialOwner(UserType* owner)
00172 {
00173     if (!potentialOwners().contains(owner))
00174     {
00175         d->potentialOwners << owner;
00176         emit dataChanged();
00177     }
00178 }
00179 
00180 Field TaskType::fieldById(const QString& id) const
00181 {
00182     Q_FOREACH (Field field, d->fields)
00183     {
00184         if (field.id == id)
00185             return field;
00186     }
00187 
00188     return Field();
00189 }
00190 
00191 Requirement* TaskType::requirementByType(Type* type) const
00192 {
00193     Q_FOREACH (Requirement* req, d->requirements)
00194     {
00195         if (req->type == type)
00196             return req;
00197     }
00198 
00199     return 0;
00200 }
00201 
00202 bool Field::isValid(const QVariant& val) const
00203 {
00204     QVariant value = val;
00205 
00206     if (value.toString().isEmpty())
00207         return false;
00208 
00209     if (nature == Textual)
00210         return value.convert(QVariant::String);
00211     else
00212         return value.convert(QVariant::Int);
00213 }
00214 
00215 bool Field::isNull() const
00216 {
00217     return id.isEmpty();
00218 }
00219 
00220 bool Field::isValid() const
00221 {
00222     return !(id.isEmpty() || name.isEmpty());
00223 }
00224 
00225 Requirement::Requirement(Type* type) : type(type)
00226 {
00227 }
00228 
00229 UserRequirement::UserRequirement(UserType* userType) : Requirement(userType)
00230 {
00231 }
00232 
00233 UserRequirement::~UserRequirement()
00234 {
00235 }
00236 
00237 bool UserRequirement::isFulfilled(const Task* task) const
00238 {
00239     unsigned count = 0;
00240 
00241     Q_FOREACH (const Invitation* invitation, task->invitations())
00242     {
00243         if (invitation->user()->userType() == type &&
00244             invitation->state() == Invitation::Accepted)
00245         {
00246             count++;
00247         }
00248     }
00249 
00250     return count >= min && count <= max;
00251 }
00252 
00253 bool UserRequirement::canBeSuccessful(const domain::Task* task) const
00254 {
00255     return isFulfilled(task);
00256 }
00257 
00258 ResourceRequirement::ResourceRequirement(ResourceType* resourceType) :
00259                                                        Requirement(resourceType)
00260 {
00261 }
00262 
00263 ResourceRequirement::~ResourceRequirement()
00264 {
00265 }
00266 
00267 bool ResourceRequirement::isFulfilled(const Task* task) const
00268 {
00269     unsigned count = 0;
00270 
00271     Q_FOREACH (const Reservation* reservation, task->reservations())
00272     {
00273         if (reservation->resource()->resourceType() == type &&
00274             reservation->isActive())
00275         {
00276             count++;
00277         }
00278     }
00279 
00280     return count >= min && count <= max;
00281 }
00282 
00283 bool ResourceRequirement::canBeSuccessful(const domain::Task* task) const
00284 {
00285     unsigned count = 0;
00286 
00287     Q_FOREACH (const Reservation* reservation, task->reservations())
00288     {
00289         if (reservation->resource()->resourceType() == type &&
00290             reservation->time() <= Clock::currentTime())
00291         {
00292             count++;
00293         }
00294     }
00295 
00296     return count >= min && count <= max;
00297 
00298 }
00299 
00300 }