00001 #include "taskmanagerdata.h"
00002 
00003 #include "dependentdataexception.h"
00004 #include "reservation.h"
00005 #include "user.h"
00006 #include "resource.h"
00007 #include "project.h"
00008 #include "tasktype.h"
00009 #include "usertype.h"
00010 #include "resourcetype.h"
00011 #include "invitation.h"
00012 #include "clock.h"
00013 
00014 #include <QList>
00015 #include <QDebug>
00016 #include <tools/invaliddataexception.h>
00017 
00018 #include <typeinfo>
00019 
00020 namespace domain
00021 {
00022 
00023 struct TaskManagerDataPrivate
00024 {
00025     Clock systemClock;
00026     QList<StorableData*> data;
00027     QMap<QString, Type*> types;
00028     AdminUser* admin;
00029 
00030     template<typename T>
00031     T* nonConstPointer(const T* pointer)
00032     {
00033         if (pointer == (const T*)admin)
00034             return (T*)admin;
00035 
00036         T* ret = const_cast<T*>(pointer);
00037 
00038         if (ret == 0 || !data.contains(ret))
00039             return 0;
00040 
00041         return ret;
00042     }
00043 
00044     template<typename T>
00045     QList<T> dataByType()
00046     {
00047         QList<T> ret;
00048         Q_FOREACH(StorableData* item, data)
00049         {
00050             T casted = qobject_cast<T>(item);
00051             if (casted != 0)
00052                 ret << casted;
00053         }
00054 
00055         return ret;
00056     }
00057 
00058     template<typename T>
00059     QList<T> typeByType()
00060     {
00061         QList<T> ret;
00062         Q_FOREACH(Type* item, types)
00063         {
00064             T casted = qobject_cast<T>(item);
00065             if (casted != 0)
00066                 ret << casted;
00067         }
00068 
00069         return ret;
00070     }
00071 };
00072 
00073 TaskManagerData::TaskManagerData() : d(new TaskManagerDataPrivate())
00074 {
00075     d->admin = new AdminUser();
00076 
00077     connect(&d->systemClock, SIGNAL(timeChanged(QDateTime)),
00078             this, SIGNAL(timeChanged(QDateTime)));
00079 
00080     connect(this, SIGNAL(tasksChanged()), this, SIGNAL(dataChanged()));
00081     connect(this, SIGNAL(usersChanged()), this, SIGNAL(dataChanged()));
00082     connect(this, SIGNAL(reservationsChanged()), this, SIGNAL(dataChanged()));
00083     connect(this, SIGNAL(resourcesChanged()), this, SIGNAL(dataChanged()));
00084     connect(this, SIGNAL(projectsChanged()), this, SIGNAL(dataChanged()));
00085     connect(this, SIGNAL(invitationsChanged()), this, SIGNAL(dataChanged()));
00086 }
00087 
00088 TaskManagerData::~TaskManagerData()
00089 {
00090     clear();
00091     clearTheme();
00092     delete d->admin;
00093     delete d;
00094 }
00095 
00096 TaskManagerData* TaskManagerData::instance()
00097 {
00098     static TaskManagerData ret;
00099     return &ret;
00100 }
00101 
00102 void TaskManagerData::clear()
00103 {
00104     bool deletedSomething = true;
00105 
00106     while (!d->data.isEmpty() && deletedSomething)
00107     {
00108         deletedSomething = false;
00109 
00110         Q_FOREACH (StorableData* data, d->data)
00111         {
00112             try
00113             {
00114                 removeData(data);
00115                 deletedSomething = true;
00116                 break;
00117             }
00118             catch (DependentDataException&)
00119             {
00120                 continue;
00121             }
00122             catch (tools::StringException& e)
00123             {
00124                 qFatal("Caught exception: %s", qPrintable(e.message()));
00125             }
00126         }
00127     }
00128 
00129     if (!d->data.isEmpty())
00130     {
00131         qDebug() << "Unable to remove" << d->data;
00132         qFatal("Dependency loop detected.");
00133     }
00134 }
00135 
00136 void TaskManagerData::clearTheme()
00137 {
00138     clear();
00139 
00140     Q_FOREACH(Type* type, d->types)
00141     {
00142         delete type;
00143     }
00144 
00145     d->types.clear();
00146 }
00147 
00148 void TaskManagerData::addType(Type* type)
00149 {
00150     QString id = type->id();
00151 
00152     if (d->types.contains(id))
00153     {
00154         delete type;
00155         throw tools::InvalidDataException(QString("Multiple types with id %1").arg(id));
00156     }
00157 
00158     d->types[id] = type;
00159 }
00160 
00161 TaskType* TaskManagerData::createTaskType(QString id, QString name)
00162 {
00163     TaskType* ret = new TaskType(id, name);
00164     addType(ret);
00165     return ret;
00166 }
00167 
00168 UserType* TaskManagerData::createUserType(QString id, QString name)
00169 {
00170     UserType* ret = new UserType(id, name);
00171     addType(ret);
00172     return ret;
00173 }
00174 
00175 ResourceType* TaskManagerData::createResourceType(QString id, QString name)
00176 {
00177     ResourceType* ret = new ResourceType(id, name);
00178     addType(ret);
00179     return ret;
00180 }
00181 
00182 Clock* TaskManagerData::clock() const
00183 {
00184     return &d->systemClock;
00185 }
00186 
00187 QList<Task*> TaskManagerData::tasks() const
00188 {
00189     return d->dataByType<Task*>();
00190 }
00191 
00192 QList<Task*> TaskManagerData::tasksForUser(const User* user) const
00193 {
00194     QList<Task*> ret;
00195 
00196     Q_FOREACH(Task* task, tasks())
00197     {
00198         if (user == task->user())
00199             ret << task;
00200     }
00201 
00202     return ret;
00203 }
00204 
00205 QList<Reservation*> TaskManagerData::reservations() const
00206 {
00207     return d->dataByType<Reservation*>();
00208 }
00209 
00210 QList<User*> TaskManagerData::users() const
00211 {
00212     return d->dataByType<User*>();
00213 }
00214 
00215 QList<User*> TaskManagerData::allUsers() const
00216 {
00217     return users() << adminUser();
00218 }
00219 
00220 User* TaskManagerData::adminUser() const
00221 {
00222     return d->admin;
00223 }
00224 
00225 QList<Invitation*> TaskManagerData::invitations() const
00226 {
00227     return d->dataByType<Invitation*>();
00228 }
00229 
00230 QList<Resource*> TaskManagerData::resources() const
00231 {
00232     return d->dataByType<Resource*>();
00233 }
00234 
00235 QList<Project*> TaskManagerData::projects() const
00236 {
00237     return d->dataByType<Project*>();
00238 }
00239 
00240 Task* TaskManagerData::task(const Task* task) const
00241 {
00242     return d->nonConstPointer(task);
00243 }
00244 
00245 Resource* TaskManagerData::resource(const Resource* resource)
00246 {
00247     return d->nonConstPointer(resource);
00248 }
00249 
00250 Project* TaskManagerData::project(const Project* project)
00251 {
00252     return d->nonConstPointer(project);
00253 }
00254 
00255 User* TaskManagerData::user(const User* user)
00256 {
00257     if (user == d->admin)
00258         return d->admin;
00259 
00260     return d->nonConstPointer(user);
00261 }
00262 
00263 Invitation* TaskManagerData::invitation(const Invitation* invitation)
00264 {
00265     return d->nonConstPointer(invitation);
00266 }
00267 
00268 Task* TaskManagerData::createTask(TaskType* type, const User* user,
00269                                   const Schedule& schedule,
00270                                   TaskState::SettableState state,
00271                                   const QList<Task*>& subTasks,
00272                                   const QList<InvitationData>& invitations,
00273                                   const QList<ReservationData>& reservations)
00274 {
00275     if (!d->types.values().contains(type))
00276         throw tools::InvalidDataException("Type not valid");
00277 
00278     Task* task = new Task(type, d->nonConstPointer(user), schedule, state,
00279                           subTasks, invitations, reservations);
00280     connect(task, SIGNAL(dataChanged()), this, SIGNAL(tasksChanged()));
00281     d->data << task;
00282     emit tasksChanged();
00283     return task;
00284 }
00285 
00286 Project* TaskManagerData::createProject(const QString& description)
00287 {
00288     Project* project = new Project(description);
00289     connect(project, SIGNAL(dataChanged()), this, SIGNAL(projectsChanged()));
00290     d->data << project;
00291     emit projectsChanged();
00292     return project;
00293 }
00294 
00295 Invitation* TaskManagerData::createInvitation(const domain::Task* task,
00296                                               const domain::User* user)
00297 {
00298     Invitation* invitation = new Invitation(d->nonConstPointer(task),
00299                                             d->nonConstPointer(user));
00300     connect(invitation, SIGNAL(dataChanged()), this, SIGNAL(invitationsChanged()));
00301     d->data << invitation;
00302     emit invitationsChanged();
00303     return invitation;
00304 }
00305 
00306 Invitation* TaskManagerData::_createInvitation(Task* task, User* user)
00307 {
00308     Invitation* invitation = new Invitation(task, user);
00309     connect(invitation, SIGNAL(dataChanged()), this, SIGNAL(invitationsChanged()));
00310     d->data << invitation;
00311     emit invitationsChanged();
00312     return invitation;
00313 }
00314 
00315 Resource* TaskManagerData::createResource(const QString& description,
00316                                             ResourceType* type)
00317 {
00318     if (!d->types.values().contains(type))
00319         throw tools::InvalidDataException("Type not valid");
00320     
00321     Resource* resource = new Resource(type, description);
00322     connect(resource, SIGNAL(dataChanged()), this, SIGNAL(resourcesChanged()));
00323     d->data << resource;
00324     emit resourcesChanged();
00325     return resource;
00326 }
00327 
00328 Reservation* TaskManagerData::createReservation(
00329                         const Task* task, const Resource* resource,
00330                         const QDateTime& time, const Duration& duration)
00331 {
00332     Reservation* reservation = new Reservation(d->nonConstPointer(task),
00333                                                d->nonConstPointer(resource),
00334                                                time, duration);
00335 
00336     connect(reservation, SIGNAL(dataChanged()),
00337             this, SIGNAL(reservationsChanged()));
00338 
00339     d->data << reservation;
00340     emit reservationsChanged();
00341     return reservation;
00342 }
00343 
00344 Reservation* TaskManagerData::_createReservation(Task* task, Resource* resource,
00345                                                  const QDateTime& time,
00346                                                  const domain::Duration& duration)
00347 {
00348     Reservation* reservation = new Reservation(task, resource, time, duration);
00349 
00350     connect(reservation, SIGNAL(dataChanged()),
00351             this, SIGNAL(reservationsChanged()));
00352 
00353     d->data << reservation;
00354     emit reservationsChanged();
00355     return reservation;
00356 }
00357 
00358 User* TaskManagerData::createUser(UserType* type, const QString& name)
00359 {
00360     if (!d->types.values().contains(type))
00361         throw tools::InvalidDataException("Type not valid");
00362 
00363     Q_FOREACH(User* user, users())
00364     {
00365         if (user->name() == name)
00366             throw tools::InvalidDataException("There already is a user with the given name");
00367     }
00368 
00369     User* user = new User(type, name);
00370     connect(user, SIGNAL(dataChanged()), this, SIGNAL(usersChanged()));
00371     d->data << user;
00372     emit usersChanged();
00373     return user;
00374 }
00375 
00376 void TaskManagerData::removeData(const domain::StorableData* constData)
00377 {
00378     static QList<const StorableData*> dataToRemove;
00379 
00380     domain::StorableData* data = d->nonConstPointer(constData);
00381 
00382     if (data == 0)
00383         return;
00384 
00385     if (dataToRemove.contains(data))
00386     {
00387         qDebug() << "Unable to remove" << dataToRemove;
00388         qFatal("Dependency loop detected.");
00389     }
00390 
00391     dataToRemove << data;
00392 
00393     Q_FOREACH (StorableData* data, data->dependentData())
00394         removeData(data);
00395 
00396     try
00397     {
00398         delete data;
00399     }
00400     catch (tools::StringException& e)
00401     {
00402         qFatal("Caught exception: %s", qPrintable(e.message()));
00403     }
00404 
00405     d->data.removeAll(data);
00406     dataToRemove.removeAll(data);
00407 }
00408 
00409 QList<ResourceType*> TaskManagerData::resourceTypes() const
00410 {
00411     return d->typeByType<ResourceType*>();
00412 }
00413 
00414 QList<TaskType*> TaskManagerData::taskTypes() const
00415 {
00416     return d->typeByType<TaskType*>();
00417 }
00418 
00419 QList<UserType*> TaskManagerData::userTypes() const
00420 {
00421     return d->typeByType<UserType*>();
00422 }
00423 
00424 Type* TaskManagerData::typeById(const QString& id) const
00425 {
00426     if (d->types.contains(id))
00427         return d->types[id];
00428 
00429     return 0;
00430 }
00431 
00432 bool TaskManagerData::hasData() const
00433 {
00434     return !d->data.isEmpty();
00435 }
00436 
00437 bool TaskManagerData::hasTheme() const
00438 {
00439     return !d->types.isEmpty();
00440 }
00441 
00442 }