Still working
[qtmeetings] / src / BusinessLogic / Engine.cpp
1 #include "Engine.h"
2 #include "Room.h"
3 #include "Meeting.h"
4 #include "ConnectionSettings.h"
5 #include "Configuration.h"
6 #include "DisplaySettings.h"
7 #include "CommunicationManager.h"
8 // #include "DeviceManager.h"
9 #include "Clock.h"
10 #include "ErrorMapper.h"
11 #include "UIManager.h"
12
13 #include <QApplication>
14 #include <QTimer>
15 #include <QList>
16 #include <QtDebug>
17
18 QTime Engine::endOfTheDay = QTime( 23, 59, 0, 0 ); // end of the day is 11:59pm
19 const int IDLE_TIME_MULTIPLIER = 60000; // Multiplies milliseconds to minutes
20
21 // Macro to help deleting objects. This could be global.
22 #define QT_DELETE(X) \
23         if ( X != 0 ) \
24         { \
25                 delete X; \
26                 X = 0; \
27         }
28
29
30 Engine::Engine() :
31                 iClock( 0 ), iConfiguration( 0 ), iCommunication( 0 )
32 {
33         qDebug() << "Engine::Engine()";
34         
35         initConfiguration();
36         initDevice();
37         initCommunication();
38         initUserInterface();
39         
40         //initialize idle time counter
41         iIdleTimeCounter = new QTimer();
42         iIdleTimeCounter->setSingleShot( true );
43         // iIdleTimeCounter->setInterval( IDLE_TIME_MULTIPLIER * iConfiguration->displaySettings()->screensaver() );
44         iIdleTimeCounter->setInterval( 10000 );
45         iIdleTimeCounter->start();
46
47         // create application clock
48         iClock = new Clock;
49         connect( iClock, SIGNAL( tick( QDateTime ) ), this, SLOT( checkStatusOfAllRooms() ) );
50         // connect( iClock, SIGNAL( tick( QDateTime ) ), iWindowManager, SLOT( distributeDateTimeInfo( QDateTime ) ) );
51
52         // Create auto refresh timer
53         iAutoRefresh = new QTimer;
54         iAutoRefresh->setInterval( iConfiguration->connectionSettings()->refreshInterval() * 1000 );
55         iAutoRefresh->start();
56         connect( iAutoRefresh, SIGNAL( timeout() ), iAutoRefresh, SLOT( start() ) );
57         connect( iAutoRefresh, SIGNAL( timeout() ), this, SLOT( fetchMeetings() ) );
58         
59         if( iDevice->currentOperationMode() == DeviceManager::KioskMode )
60         {
61                 iWindowManager->setFullscreen();
62         }
63
64         connectSignals();
65         
66         QTimer::singleShot( 0, this, SLOT( fetchMeetings() ) );
67
68         // TODO: continue implementation
69 }
70
71 Engine::~Engine()
72 {
73         qDebug() << "Engine::~Engine()";
74         while ( !iMeetings.isEmpty() )
75                 delete iMeetings.takeFirst();
76         
77         if ( iIdleTimeCounter != 0 )
78         {
79                 iIdleTimeCounter->stop();
80                 delete iIdleTimeCounter;
81                 iIdleTimeCounter = 0;
82         }
83         QT_DELETE( iClock );
84         QT_DELETE( iDevice );
85
86         QT_DELETE( iUIManager );
87         QT_DELETE( iWindowManager );
88 }
89
90 void Engine::closeApplication()
91 {
92         qDebug() << "Engine::closeApplication()";
93         // closes application after 1 second
94         QTimer::singleShot( 1000, QApplication::instance(), SLOT( quit() ) );
95 }
96
97 Room* Engine::defaultRoom()
98 {
99         qDebug() << "Engine::defaultRoom()";
100         return iConfiguration->defaultRoom();
101 }
102
103 void Engine::checkStatusOfAllRooms()
104 {
105 //      qDebug() << "Engine::checkStatusOfAllRooms()";
106         // iterate trough on the rooms
107         for ( int i = 0; i < iConfiguration->rooms().count(); i++ )
108         {
109                 // and check the status
110                 roomStatusInfoNeeded( iConfiguration->rooms().at( i ) );
111         }
112 }
113
114 int Engine::indexOfMeetingAt( Room *aRoom, QDateTime aAt )
115 {
116 //      qDebug() << "Engine::indexOfMeetingAt( Room *, QDateTime )";
117         for ( int i = 0; i < iMeetings.count(); i++ )
118         {
119                 // exchange server ensures that there is only one meeting in a room at a specified time
120                 if ( aRoom->equals( iMeetings.at( i )->room() )
121                           && iMeetings.at( i )->startsAt() <= aAt
122                           && iMeetings.at( i )->endsAt() >= aAt )
123                 {
124                         return i;
125                 }
126         }
127         return -1;
128 }
129
130 int Engine::indexOfMeetingAfter( Room *aRoom, QDateTime aAfter )
131 {
132 //      qDebug() << "Engine::indexOfMeetingAfter( Room *, QDateTime )";
133         // seeks for the next meeting on the SAME DAY
134         int min = -1;
135         for ( int i = 0; i < iMeetings.count(); i++ )
136         {
137                 // if the meeting is in the same room, on the same day but after the specified time
138                 if ( aRoom->equals( iMeetings.at( i )->room() )
139                           && iMeetings.at( i )->startsAt().date() == aAfter.date()
140                           && iMeetings.at( i )->startsAt() > aAfter )
141                 {
142                         // if there was not any meeting find yet or the previously found is a later one then the (i)th
143                         if ( min == -1
144                                   || iMeetings.at( min )->startsAt() > iMeetings.at( i )->startsAt() )
145                         {
146                                 min = i;
147                         }
148                 }
149         }
150         return min;
151 }
152
153 void Engine::roomStatusInfoNeeded( Room *aRoom )
154 {
155 //      qDebug() << "Engine::roomStatusInfoNeeded( Room * )";
156         if ( aRoom == 0 )
157         {
158                 return;
159         }
160
161         int indexOfCurrentMeeting = indexOfMeetingAt( aRoom, iClock->datetime() );
162         int indexOfNextMeeting = indexOfMeetingAfter( aRoom, iClock->datetime() );
163
164         // if there is no meeting, then status is Free; otherwise Busy
165         Room::Status status = ( indexOfCurrentMeeting == -1 ) ? Room::FreeStatus : Room::BusyStatus;
166         // if room is Busy, then check end time, otherwise...
167         QTime until = ( status == Room::BusyStatus ) ? iMeetings.at( indexOfCurrentMeeting )->endsAt().time() :
168                           // ...if there is meeting following on the same day then check end time, otherwise end is the of the working day
169                           (( indexOfNextMeeting != -1 ) ? iMeetings.at( indexOfNextMeeting )->startsAt().time() : Engine::endOfTheDay );
170
171         //currently works only for deafult room
172 //      if( aRoom->equals( *(defaultRoom() ) ) )
173 //              iWindowManager->roomStatusChanged( aRoom, status, until );
174 }
175
176 void Engine::fetchMeetings()
177 {
178         Room *room = defaultRoom();
179         qDebug() << "Engine::fetchMeetings for " << room->name();
180         fetchMeetings( iClock->datetime(), iClock->datetime().addDays( 7 ), room );
181 }
182
183 bool Engine::isMeetingInList( const QList<Meeting*> &aList, const Meeting *aMeeting )
184 {
185         qDebug() << "Engine::isMeetingInList( const QList<Meeting*> &, const Meeting * )";
186         for ( int i = 0; i < aList.count(); i++ )
187         {
188                 if ( aMeeting->equals( *(aList.at( i )) ) )
189                 {
190                         return true;
191                 }
192         }
193         return false;
194 }
195
196 void Engine::meetingsFetched( const QList<Meeting*> &aMeetings )
197 {
198         qDebug() << "Engine::meetingsFetched( const QList<Meeting*> & )";
199         // check if there is any new meeting in the list came from the server -> added
200         for ( int i = 0; i < aMeetings.count(); i++ )
201         {
202                 // if the (i)th meeting is not in the local meeting list
203                 if ( !isMeetingInList( iMeetings, aMeetings.at( i ) ) )
204                 {
205                         // add to the local database =)
206                         Meeting* m = new Meeting( *(aMeetings.at( i )) );
207                         iMeetings.append( m );
208                         // and signal the changes
209 //                      iWeeklyView->insertMeeting( m );
210                 }
211         }
212
213         // check if there is any meeting NOT in the list came from the server -> deleted
214         for ( int i = 0; i < iMeetings.count(); i++ )
215         {
216                 // if the (i)th meeting is in the local but NOT in the server's meeting list
217                 if ( !isMeetingInList( aMeetings, iMeetings.at( i ) ) )
218                 {
219                         Meeting* m = iMeetings.takeAt( i );
220                         // signal the changes
221 //                      iWeeklyView->deleteMeeting( m );
222                         // delete the meeting from the local list
223                         delete m;
224                 }
225         }
226
227         // refresh room status info
228         roomStatusInfoNeeded( defaultRoom() );
229 }
230
231 void Engine::errorHandler( int aCode, const QString &aAddInfo )
232 {
233         qDebug() << "Engine::ErrorHandler, aCode: " << aCode;
234         // inform UI about the problem
235         if( aCode >= 100 && aCode <= 150 ) { //communication errors
236                 //we don't want these to close operation changing
237                 qDebug() << "CommunicationManager signaled an error:" << aCode;
238         }
239         
240         iWindowManager->error( ErrorMapper::codeToString( aCode, aAddInfo ) );
241 }
242
243 void Engine::fetchMeetings( const QDateTime &aFrom, const QDateTime &aUntil, const Room *aIn )
244 {
245         qDebug() << "Engine::fetchMeetings( const QDateTime &, const QDateTime &, const Room * )";
246         iCommunication->fetchMeetings( aFrom, aUntil, *aIn );
247 }
248
249 void Engine::fetchMeetingDetails(Meeting *aMeeting)
250 {
251         qDebug() << "[Engine::fetchMeetingDetails] <TODO : METHOD NOT IMPLEMENTED>";
252 //      Meeting tempMeeting = aMeeting;
253 //      iCommunication->fetchMeetingDetails( tempMeeting );
254 }
255
256 void Engine::cancelFetchMeetingDetails()
257 {
258         iCommunication->cancelFetchMeetingDetails();
259 }
260
261 void Engine::shownWeekChanged( QDate aFrom )
262 {
263         qDebug() << "[Engine::shownWeekChanged] <Invoked>";
264         QDateTime from( aFrom );
265         QDateTime to( aFrom.addDays( 7 ), QTime( 23, 59 ) );
266         qDebug() << "[Engine::shownWeekChanged] <From " << aFrom.toString( "d.m. h:mm" ) << " to " << to.toString( "d.m. h:mm" ) << ">";
267         iCommunication->fetchMeetings( from, to, *defaultRoom() );
268 //      fetchMeetings( from, to, iWindowManager->weeklyView()->currentRoom() );
269 }
270
271 void Engine::changeDeviceMode( bool aChange )
272 {
273         if ( aChange )
274         {
275                 connect( iDevice, SIGNAL( changingModeFailed() ), this, SLOT( changeModeFailed() ) );
276                 iAutoRefresh->stop(); // Stop the meeting update
277         }
278         iDevice->changeMode( aChange );
279 }
280
281 void Engine::changeModeFailed()
282 {
283         qDebug() << "Engine::progressBarCancelled()";
284         iDevice->changeMode( false );
285         iAutoRefresh->start(); //we start the metting updating
286 }
287
288 void Engine::initUserInterface()
289 {
290         qDebug() << "[Engine::initUserInterface] <Invoked>";
291         
292         // Initialize the window manager and connect what ever signals can be connected
293         iWindowManager = new WindowManager;
294         // Create the UIManager which internally handles most of the UI actions
295         iUIManager = new UIManager( this, iWindowManager );
296         
297         connect( iWindowManager, SIGNAL( eventDetected() ), this, SLOT( handleViewEvent() ) );
298         connect( iWindowManager, SIGNAL( previousViewRestored() ), iUIManager, SLOT( previousViewRestored() ) );
299         connect( iWindowManager, SIGNAL( dialogActivated() ), this, SLOT( dialogActivated() ) );
300         connect( iWindowManager, SIGNAL( dialogDeactivated() ), this, SLOT( dialogDeactivated() ) );
301         
302         // Show the UI
303         iWindowManager->setWindowState( Qt::WindowMaximized );
304         iWindowManager->show();
305         iUIManager->showMainView();
306         
307         qDebug() << "[Engine::initUserInterface] <Finished>";
308 }
309
310 void Engine::handleViewEvent()
311 {
312         if ( iIdleTimeCounter != 0 )
313         {
314                 // Restart the idle time counter when view event is received
315                 iIdleTimeCounter->stop();
316                 iIdleTimeCounter->start();
317         }
318 }
319
320 void Engine::initConfiguration()
321 {
322         iConfiguration = Configuration::instance();
323         if ( iConfiguration == 0 )
324         {
325                 QTimer::singleShot( 0, this, SLOT( closeApplication() ) );
326         }
327 }
328
329 void Engine::connectSignals()
330 {
331         // Connect engine objects signals to UIManager
332         connect( iClock, SIGNAL( tick( QDateTime ) ), iUIManager, SLOT( updateTime( QDateTime ) ) );
333         connect( iIdleTimeCounter, SIGNAL( timeout() ) , iUIManager, SLOT( roomStatusIndicatorRequested() ) );
334         
335         iUIManager->connectDeviceManager( iDevice );
336         iUIManager->connectCommunicationManager( iCommunication );
337 }
338
339 void Engine::initCommunication()
340 {
341         // initialize communication
342         iCommunication = new CommunicationManager( *(iConfiguration->connectionSettings()) );
343         connect( iCommunication, SIGNAL( error( int, CommunicationManager::CommunicationType  ) ),
344                         this, SLOT( errorHandler( int ) ) );
345         connect( iCommunication, SIGNAL( meetingsFetched( const QList<Meeting*>& ) ),
346                         this, SLOT( meetingsFetched( const QList<Meeting*>& ) ) );
347 }
348
349 void Engine::initDevice()
350 {
351         // create device manager
352         iDevice = new DeviceManager( iConfiguration->startupSettings() );
353         connect( iDevice, SIGNAL( error( int, const QString& ) ), this, SLOT( errorHandler( int, const QString& ) ) );  
354         iDevice->initDeviceManager();
355 }
356
357 void Engine::dialogActivated()
358 {
359         if ( iIdleTimeCounter != 0 )
360         {
361                 iIdleTimeCounter->stop();
362         }
363 }
364
365 void Engine::dialogDeactivated()
366 {
367         if ( iIdleTimeCounter != 0 )
368         {
369                 iIdleTimeCounter->start();
370         }
371 }
372
373 void Engine::previousViewRestored()
374 {
375         if ( iIdleTimeCounter != 0 )
376         {
377                 iIdleTimeCounter->start();
378         }
379 }
380
381 void Engine::stopIdleTimeCounter()
382 {
383         if ( iIdleTimeCounter != 0 )
384         {
385                 iIdleTimeCounter->stop();
386         }
387 }
388
389 void Engine::startIdleTimeCounter()
390 {
391         if ( iIdleTimeCounter != 0 )
392         {
393                 iIdleTimeCounter->start();
394         }
395 }