calendar.cpp
Go to the documentation of this file.00001 /*************************************************************************** 00002 file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/src/model/calendar.cpp $ 00003 version : $LastChangedRevision: 746 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2008-04-19 11:23:51 +0200 (Sat, 19 Apr 2008) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007 by Johan De Taeye * 00010 * * 00011 * This library is free software; you can redistribute it and/or modify it * 00012 * under the terms of the GNU Lesser General Public License as published * 00013 * by the Free Software Foundation; either version 2.1 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 00019 * General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Lesser General Public * 00022 * License along with this library; if not, write to the Free Software * 00023 * Foundation Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * 00024 * * 00025 ***************************************************************************/ 00026 00027 #define FREPPLE_CORE 00028 #include "frepple/model.h" 00029 00030 namespace frepple 00031 { 00032 00033 template<class Calendar> DECLARE_EXPORT Tree HasName<Calendar>::st; 00034 00035 00036 DECLARE_EXPORT Calendar::~Calendar() 00037 { 00038 // De-allocate all the dynamic memory used for the bucket objects 00039 while (firstBucket) 00040 { 00041 Bucket* tmp = firstBucket; 00042 firstBucket = firstBucket->nextBucket; 00043 delete tmp; 00044 } 00045 } 00046 00047 00048 DECLARE_EXPORT CalendarDouble::~CalendarDouble() 00049 { 00050 // Remove all references from buffers 00051 for (Buffer::iterator b = Buffer::begin(); b != Buffer::end(); ++b) 00052 { 00053 if (b->getMinimum()==this) b->setMinimum(NULL); 00054 if (b->getMaximum()==this) b->setMaximum(NULL); 00055 } 00056 00057 // Remove all references from resources 00058 for (Resource::iterator r = Resource::begin(); r != Resource::end(); ++r) 00059 if (r->getMaximum()==this) r->setMaximum(NULL); 00060 } 00061 00062 00063 DECLARE_EXPORT CalendarBool::~CalendarBool() 00064 { 00065 // Remove all references from locations 00066 for (Location::iterator l = Location::begin(); l != Location::end(); ++l) 00067 { 00068 if (l->getAvailable() == this) 00069 l->setAvailable(NULL); 00070 } 00071 } 00072 00073 00074 DECLARE_EXPORT Calendar::Bucket* Calendar::addBucket 00075 (Date start, Date end, string name) 00076 { 00077 // Assure the start is before the end. 00078 if (start > end) 00079 { 00080 // Switch arguments 00081 Date tmp = end; 00082 end = start; 00083 start = end; 00084 } 00085 00086 // Create new bucket and insert in the list 00087 Bucket *next = firstBucket, *prev = NULL; 00088 while (next && next->startdate < start) 00089 { 00090 prev = next; 00091 next = next->nextBucket; 00092 } 00093 00094 // Create the new bucket 00095 Bucket *c = createNewBucket(start,end,name); 00096 c->nextBucket = next; 00097 c->prevBucket = prev; 00098 00099 // Maintain linked list 00100 if (prev) prev->nextBucket = c; 00101 else firstBucket = c; 00102 if (next) next->prevBucket = c; 00103 00104 // Return the new bucket 00105 return c; 00106 } 00107 00108 00109 DECLARE_EXPORT void Calendar::removeBucket(Calendar::Bucket* bkt) 00110 { 00111 // Verify the bucket is on this calendar indeed 00112 Bucket *b = firstBucket; 00113 while (b && b != bkt) b = b->nextBucket; 00114 00115 // Error 00116 if (!b) 00117 throw DataException("Trying to remove unavailable bucket from calendar '" 00118 + getName() + "'"); 00119 00120 // Update the list 00121 if (bkt->prevBucket) 00122 // Previous bucket links to a new next bucket 00123 bkt->prevBucket->nextBucket = bkt->nextBucket; 00124 else 00125 // New head for the bucket list 00126 firstBucket = bkt->nextBucket; 00127 if (bkt->nextBucket) 00128 // Update the reference prevBucket of the next bucket 00129 bkt->nextBucket->prevBucket = bkt->prevBucket; 00130 00131 // Delete the bucket 00132 delete bkt; 00133 } 00134 00135 00136 DECLARE_EXPORT Calendar::Bucket* Calendar::findBucket(Date d) const 00137 { 00138 Calendar::Bucket *curBucket = NULL; 00139 double curPriority = DBL_MAX; 00140 for (Bucket *b = firstBucket; b; b = b->nextBucket) 00141 { 00142 if (b->getStart() > d) 00143 // Buckets are sorted by the start date. Other entries definately 00144 // won't be effective 00145 break; 00146 else if (curPriority > b->getPriority() 00147 && d >= b->getStart() && d < b->getEnd() 00148 && b->checkValid(d) ) 00149 { 00150 // Bucket is effective and has lower priority than other effective ones. 00151 curPriority = b->getPriority(); 00152 curBucket = &*b; 00153 } 00154 } 00155 return curBucket; 00156 } 00157 00158 00159 DECLARE_EXPORT Calendar::Bucket* Calendar::findBucket(const string& d) const 00160 { 00161 for (Bucket *b = firstBucket; b; b = b->nextBucket) 00162 if (b->getName() == d) return b; 00163 return NULL; 00164 } 00165 00166 00167 DECLARE_EXPORT void Calendar::writeElement(XMLOutput *o, const Keyword& tag, mode m) const 00168 { 00169 // Writing a reference 00170 if (m == REFERENCE) 00171 { 00172 o->writeElement 00173 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type); 00174 return; 00175 } 00176 00177 // Write the complete object 00178 if (m != NOHEADER) o->BeginObject 00179 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type); 00180 00181 // Write all buckets 00182 o->BeginObject (Tags::tag_buckets); 00183 for (BucketIterator i = beginBuckets(); i != endBuckets(); ++i) 00184 // We use the FULL mode, to force the buckets being written regardless 00185 // of the depth in the XML tree. 00186 o->writeElement(Tags::tag_bucket, *i, FULL); 00187 o->EndObject(Tags::tag_buckets); 00188 00189 o->EndObject(tag); 00190 } 00191 00192 00193 DECLARE_EXPORT Calendar::Bucket* Calendar::createBucket(const AttributeList& atts) 00194 { 00195 // Pick up the start, end and name attributes 00196 Date startdate = atts.get(Tags::tag_start)->getDate(); 00197 const DataElement* d = atts.get(Tags::tag_end); 00198 Date enddate = *d ? d->getDate() : Date::infiniteFuture; 00199 string name = atts.get(Tags::tag_name)->getString(); 00200 00201 // Check for existence of the bucket: same name, start date and end date 00202 Calendar::Bucket* result = NULL; 00203 for (BucketIterator x = beginBuckets(); x!=endBuckets(); ++x) 00204 { 00205 if ((!name.empty() && x->nm==name) 00206 || (name.empty() && x->startdate==startdate && x->enddate==enddate)) 00207 { 00208 // Found! 00209 result = &*x; 00210 break; 00211 } 00212 } 00213 00214 // Pick up the action attribute and update the bucket accordingly 00215 switch (MetaClass::decodeAction(atts)) 00216 { 00217 case ADD: 00218 // Only additions are allowed 00219 if (result) 00220 throw("Bucket " + string(startdate) + " " + string(enddate) + " " + name 00221 + " already exists in calendar '" + getName() + "'"); 00222 result = addBucket(startdate, enddate, name); 00223 return result; 00224 case CHANGE: 00225 // Only changes are allowed 00226 if (!result) 00227 throw DataException("Bucket " + string(startdate) + " " + string(enddate) 00228 + " " + name + " doesn't exist in calendar '" + getName() + "'"); 00229 return result; 00230 case REMOVE: 00231 // Delete the entity 00232 if (!result) 00233 throw DataException("Bucket " + string(startdate) + " " + string(enddate) 00234 + " " + name + " doesn't exist in calendar '" + getName() + "'"); 00235 else 00236 { 00237 // Delete it 00238 removeBucket(result); 00239 return NULL; 00240 } 00241 case ADD_CHANGE: 00242 if (!result) 00243 // Adding a new bucket 00244 result = addBucket(startdate, enddate, name); 00245 return result; 00246 } 00247 00248 // This part of the code isn't expected not be reached 00249 throw LogicException("Unreachable code reached"); 00250 } 00251 00252 00253 DECLARE_EXPORT void Calendar::beginElement (XMLInput& pIn, const Attribute& pAttr) 00254 { 00255 if (pAttr.isA (Tags::tag_bucket) 00256 && pIn.getParentElement().first.isA(Tags::tag_buckets)) 00257 // A new bucket 00258 pIn.readto(createBucket(pIn.getAttributes())); 00259 } 00260 00261 00262 DECLARE_EXPORT void Calendar::Bucket::writeHeader(XMLOutput *o) const 00263 { 00264 // The header line has a variable number of attributes: start, end and/or name 00265 if (startdate != Date::infinitePast) 00266 { 00267 if (enddate != Date::infiniteFuture) 00268 { 00269 if (!nm.empty()) 00270 o->BeginObject(Tags::tag_bucket, Tags::tag_start, string(startdate), Tags::tag_end, string(enddate), Tags::tag_name, nm); 00271 else 00272 o->BeginObject(Tags::tag_bucket, Tags::tag_start, string(startdate), Tags::tag_end, string(enddate)); 00273 } 00274 else 00275 { 00276 if (!nm.empty()) 00277 o->BeginObject(Tags::tag_bucket, Tags::tag_start, string(startdate), Tags::tag_name, nm); 00278 else 00279 o->BeginObject(Tags::tag_bucket, Tags::tag_start, string(startdate)); 00280 } 00281 } 00282 else 00283 { 00284 if (enddate != Date::infiniteFuture) 00285 { 00286 if (!nm.empty()) 00287 o->BeginObject(Tags::tag_bucket, Tags::tag_end, string(enddate), Tags::tag_name, nm); 00288 else 00289 o->BeginObject(Tags::tag_bucket, Tags::tag_end, string(enddate)); 00290 } 00291 else 00292 { 00293 if (!nm.empty()) 00294 o->BeginObject(Tags::tag_bucket, Tags::tag_name, nm); 00295 else 00296 o->BeginObject(Tags::tag_bucket); 00297 } 00298 } 00299 } 00300 00301 00302 DECLARE_EXPORT void Calendar::Bucket::writeElement 00303 (XMLOutput *o, const Keyword& tag, mode m) const 00304 { 00305 assert(m == DEFAULT || m == FULL); 00306 writeHeader(o); 00307 if (priority) o->writeElement(Tags::tag_priority, priority); 00308 o->EndObject(tag); 00309 } 00310 00311 00312 DECLARE_EXPORT void Calendar::Bucket::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement) 00313 { 00314 if (pAttr.isA(Tags::tag_priority)) 00315 pElement >> priority; 00316 } 00317 00318 00319 DECLARE_EXPORT Calendar::EventIterator& Calendar::EventIterator::operator++() 00320 { 00321 // Go over all entries and ask them to update the iterator 00322 Date d = curDate; 00323 curDate = Date::infiniteFuture; // Cause end date is not included 00324 curBucket = NULL; 00325 curPriority = DBL_MAX; 00326 for (const Calendar::Bucket *b = theCalendar->firstBucket; b; b = b->nextBucket) 00327 b->nextEvent(this, d); 00328 return *this; 00329 } 00330 00331 00332 DECLARE_EXPORT Calendar::EventIterator& Calendar::EventIterator::operator--() 00333 { 00334 // Go over all entries and ask them to update the iterator 00335 Date d = curDate; 00336 curDate = Date::infinitePast; 00337 curBucket = NULL; 00338 curPriority = DBL_MAX; 00339 for (const Calendar::Bucket *b = theCalendar->firstBucket; b; b = b->nextBucket) 00340 b->prevEvent(this, d); 00341 return *this; 00342 } 00343 00344 00345 DECLARE_EXPORT void Calendar::Bucket::nextEvent(EventIterator* iter, Date refDate) const 00346 { 00347 if (iter->curPriority < priority) 00348 // Priority isn't low enough to overrule current date 00349 return; 00350 00351 if (refDate < startdate && startdate <= iter->curDate) 00352 { 00353 // Next event is the start date of the bucket 00354 iter->curDate = startdate; 00355 iter->curBucket = this; 00356 iter->curPriority = priority; 00357 return; 00358 } 00359 00360 if (refDate < enddate && enddate < iter->curDate) 00361 { 00362 // Next event is the end date of the bucket 00363 iter->curDate = enddate; 00364 iter->curBucket = iter->theCalendar->findBucket(enddate); 00365 iter->curPriority = priority; 00366 return; 00367 } 00368 } 00369 00370 00371 DECLARE_EXPORT void Calendar::Bucket::prevEvent(EventIterator* iter, Date refDate) const 00372 { 00373 if (iter->curPriority < priority) 00374 // Priority isn't low enough to overrule current date 00375 return; 00376 00377 if (refDate >= enddate && enddate > iter->curDate) 00378 { 00379 // Previous event is the end date of the bucket 00380 iter->curDate = enddate; 00381 iter->curBucket = iter->theCalendar->findBucket(enddate); 00382 iter->curPriority = priority; 00383 return; 00384 } 00385 00386 if (refDate >= startdate && startdate >= iter->curDate) 00387 { 00388 // Previous event is the start date of the bucket 00389 iter->curDate = startdate; 00390 iter->curBucket = this; 00391 iter->curPriority = priority; 00392 return; 00393 } 00394 } 00395 00396 00397 } // end namespace
Documentation generated by
