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  doxygen