qtmeetings sources to Maemo garage
[qtmeetings] / src / BusinessLogic / Engine.cpp
1 #include "Engine.h"
2
3 #include <QTimer>
4 #include <QList>
5 #include "Room.h"
6 #include "Meeting.h"
7 #include "ConnectionSettings.h"
8 #include "Configuration.h"
9 #include "CommunicationManager.h"
10 #include "DeviceManager.h"
11 #include "Clock.h"
12 #include "ErrorMapper.h"
13
14 #include <QtDebug>
15
16 QTime Engine::endOfTheDay = QTime( 23, 59, 0, 0 ); // end of the day is 11:59pm
17
18 Engine::Engine() :
19                 iClock( 0 ), iConfiguration( Configuration::instance() ), iCommunication( 0 ), iCurrentRoom( 0 )
20 {
21         // if reading of configuration fails, signal that initialization failed
22         if ( iConfiguration == 0 )
23         {
24                 QTimer::singleShot( 0, this, SIGNAL( initializationFailed() ) );
25                 return;
26         }
27         // initialize communication
28         iCommunication = new CommunicationManager( *(iConfiguration->connectionSettings()) );
29         connect( iCommunication,
30                          SIGNAL( error( int, CommunicationManager::CommunicationType  ) ),
31                          this,
32                          SLOT( errorHandler( int ) ) );
33         connect( iCommunication,
34                          SIGNAL( meetingsFetched( const QList<Meeting*>& ) ),
35                          this,
36                          SLOT( meetingsFetched( const QList<Meeting*>& ) )
37                         );
38         connect( iCommunication,
39                          SIGNAL( meetingDetailsFetched( Meeting& ) ),
40                          this,
41                          SLOT( meetingDetailsFetched( Meeting& ) )
42                         );
43
44         // create application clock
45         iClock = new Clock;
46         connect( iClock, SIGNAL( tick( QDateTime ) ), this, SLOT( checkStatusOfAllRooms() ) );
47
48         iAutoRefresh = new QTimer;
49         iAutoRefresh->setInterval( iConfiguration->connectionSettings()->refreshInterval() * 1000 );
50         iAutoRefresh->start();
51         connect( iAutoRefresh, SIGNAL( timeout() ), iAutoRefresh, SLOT( start() ) );
52         connect( iAutoRefresh, SIGNAL( timeout() ), this, SLOT( fetchMeetings() ) );
53
54         iDevice = new DeviceManager( iConfiguration->startupSettings() );
55         connect( iDevice, SIGNAL( error( int, const QString& ) ), this, SLOT( errorHandler( int, const QString& ) ) );
56         iDevice->initDeviceManager();
57
58         QTimer::singleShot( 0, this, SLOT( fetchMeetings() ) );
59
60         // TODO: continue implementation
61 }
62
63 Engine::~Engine()
64 {
65         while ( !iMeetings.isEmpty() )
66                 delete iMeetings.takeFirst();
67 }
68
69 Room* Engine::defaultRoom()
70 {
71         return iConfiguration->defaultRoom();
72 }
73
74 Clock* Engine::clock()
75 {
76         return iClock;
77 }
78
79 Configuration* Engine::configuration()
80 {
81         return iConfiguration;
82 }
83
84 DeviceManager* Engine::deviceManager()
85 {
86         return iDevice;
87 }
88
89 void Engine::checkStatusOfAllRooms()
90 {
91         // iterate trough on the rooms
92         for ( int i = 0; i < iConfiguration->rooms().count(); i++ )
93         {
94                 // and check the status
95                 roomStatusInfoNeeded( iConfiguration->rooms().at( i ) );
96         }
97 }
98
99 int Engine::indexOfMeetingAt( Room *aRoom, QDateTime aAt )
100 {
101         for ( int i = 0; i < iMeetings.count(); i++ )
102         {
103                 // exchange server ensures that there is only one meeting in a room at a specified time
104                 if ( aRoom->equals( iMeetings.at( i )->room() )
105                           && iMeetings.at( i )->startsAt() <= aAt
106                           && iMeetings.at( i )->endsAt() >= aAt )
107                 {
108                         return i;
109                 }
110         }
111         return -1;
112 }
113
114 int Engine::indexOfMeetingAfter( Room *aRoom, QDateTime aAfter )
115 {
116         // seeks for the next meeting on the SAME DAY
117         int min = -1;
118         for ( int i = 0; i < iMeetings.count(); i++ )
119         {
120                 // if the meeting is in the same room, on the same day but after the specified time
121                 if ( aRoom->equals( iMeetings.at( i )->room() )
122                           && iMeetings.at( i )->startsAt().date() == aAfter.date()
123                           && iMeetings.at( i )->startsAt() > aAfter )
124                 {
125                         // if there was not any meeting find yet or the previously found is a later one then the (i)th
126                         if ( min == -1
127                                   || iMeetings.at( min )->startsAt() > iMeetings.at( i )->startsAt() )
128                         {
129                                 min = i;
130                         }
131                 }
132         }
133         return min;
134 }
135
136 void Engine::roomStatusInfoNeeded( Room *aRoom )
137 {
138         if ( aRoom == 0 )
139         {
140                 return;
141         }
142
143         int indexOfCurrentMeeting = indexOfMeetingAt( aRoom, iClock->datetime() );
144         int indexOfNextMeeting = indexOfMeetingAfter( aRoom, iClock->datetime() );
145
146 //      qDebug() << QString( "Engine::roomStatusInfoNeeded\troom:%1current:%2 next:%3" ).arg( aRoom->toString() ).arg( indexOfCurrentMeeting ).arg( indexOfNextMeeting );
147
148         // if there is no meeting, then status is Free; otherwise Busy
149         Room::Status status = ( indexOfCurrentMeeting == -1 ) ? Room::FreeStatus : Room::BusyStatus;
150         // if room is Busy, then check end time, otherwise...
151         QTime until = ( status == Room::BusyStatus ) ? iMeetings.at( indexOfCurrentMeeting )->endsAt().time() :
152                           // ...if there is meeting following on the same day then check end time, otherwise end is the of the working day
153                           (( indexOfNextMeeting != -1 ) ? iMeetings.at( indexOfNextMeeting )->startsAt().time() : Engine::endOfTheDay );
154
155         emit roomStatusChanged( aRoom, status, until );
156 }
157
158 void Engine::fetchMeetings()
159 {
160         // TODO : define interval correctly. at the moment it's +/- 14 days
161         Room *room = iCurrentRoom;
162         if ( room == 0 ) room = defaultRoom();
163         qDebug() << "Engine::fetchMeetings for " << room->name();
164         fetchMeetings( iClock->datetime().addDays( -14 ), iClock->datetime().addDays( 14 ), room );
165 }
166
167 void Engine::fetchMeetings( const QDateTime &aFrom, const QDateTime &aUntil, Room *aIn )
168 {
169         iCommunication->fetchMeetings( aFrom, aUntil, *aIn );
170 }
171
172 void Engine::fetchMeetingDetails( Meeting *aMeeting )
173 {
174         iCommunication->fetchMeetingDetails( *aMeeting );
175 }
176
177 bool Engine::isMeetingInList( const QList<Meeting*> &aList, const Meeting *aMeeting )
178 {
179         for ( int i = 0; i < aList.count(); i++ )
180         {
181                 if ( aMeeting->equals( *(aList.at( i )) ) )
182                 {
183                         return true;
184                 }
185         }
186         return false;
187 }
188
189 void Engine::meetingsFetched( const QList<Meeting*> &aMeetings )
190 {
191         // check if there is any new meeting in the list came from the server -> added
192         for ( int i = 0; i < aMeetings.count(); i++ )
193         {
194                 // if the (i)th meeting is not in the local meeting list
195                 if ( !isMeetingInList( iMeetings, aMeetings.at( i ) ) )
196                 {
197                         // add to the local database =)
198                         Meeting* m = new Meeting( *(aMeetings.at( i )) );
199                         iMeetings.append( m );
200                         // and signal the changes
201                         emit meetingAdded( m );
202                 }
203         }
204
205         // check if there is any meeting NOT in the list came from the server -> deleted
206         for ( int i = 0; i < iMeetings.count(); i++ )
207         {
208                 // if the (i)th meeting is in the local but NOT in the server's meeting list
209                 if ( !isMeetingInList( aMeetings, iMeetings.at( i ) ) )
210                 {
211                         Meeting* m = iMeetings.takeAt( i );
212                         // signal the changes
213                         emit meetingDeleted( m );
214                         // delete the meeting from the local list
215                         delete m;
216                 }
217         }
218
219         // refresh room status info
220         roomStatusInfoNeeded( defaultRoom() );
221 }
222
223 void Engine::meetingDetailsFetched( Meeting &aDetailedMeeting )
224 {
225         emit meetingDetailsFetched( &aDetailedMeeting );
226 }
227
228 void Engine::errorHandler( int aCode, const QString &aAddInfo )
229 {
230         qDebug() << "Engine::ErrorHandler, aCode: " << aCode;
231         // inform UI about the problem
232         if( aCode >= 100 && aCode <= 110 )
233                 qDebug() << "CommunicationManager signaled an error:" << aCode;
234         emit error( ErrorMapper::codeToString( aCode, aAddInfo ) );
235 }
236
237 void Engine::currentRoomChanged( Room *aCurrentRoom )
238 {
239         iCurrentRoom = aCurrentRoom;
240         qDebug() << "Engine::currentRoomChanged to " << iCurrentRoom->name();
241 }