model.h

Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.8.0/include/frepple/model.h $
00003   version : $LastChangedRevision: 1190 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2010-02-22 19:14:53 +0100 (Mon, 22 Feb 2010) $
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 *
00024  * USA                                                                     *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 #ifndef MODEL_H
00029 #define MODEL_H
00030 
00031 /** @mainpage frePPLe Library API
00032   * The frePPLe class library provides a framework for modeling a
00033   * manufacturing environment.<br>
00034   * This document describes its C++ API.<P>
00035   *
00036   * @namespace frepple
00037   * @brief Core namespace
00038   */
00039 
00040 #include "frepple/utils.h"
00041 #include "frepple/timeline.h"
00042 using namespace frepple::utils;
00043 
00044 namespace frepple
00045 {
00046 
00047 class Flow;
00048 class FlowEnd;
00049 class FlowPlan;
00050 class LoadPlan;
00051 class Resource;
00052 class ResourceInfinite;
00053 class Problem;
00054 class Demand;
00055 class OperationPlan;
00056 class Item;
00057 class Operation;
00058 class OperationPlanState;
00059 class OperationFixedTime;
00060 class OperationTimePer;
00061 class OperationRouting;
00062 class OperationAlternate;
00063 class Buffer;
00064 class BufferInfinite;
00065 class BufferProcure;
00066 class Plan;
00067 class Plannable;
00068 class Calendar;
00069 class Load;
00070 class Location;
00071 class Customer;
00072 class HasProblems;
00073 class Solvable;
00074 class PeggingIterator;
00075 
00076 
00077 /** @brief This class is used for initialization. */
00078 class LibraryModel
00079 {
00080   public:
00081     static void initialize();
00082 };
00083 
00084 
00085 /** @brief This is the class used to represent variables that are
00086   * varying over time.
00087   *
00088   * Some example usages for calendars:
00089   *  - A calendar defining the available capacity of a resource
00090   *    week by week.
00091   *  - The minimum inventory desired in a buffer week by week.
00092   *  - The working hours and holidays at a certain location.
00093   */
00094 class Calendar : public HasName<Calendar>
00095 {
00096   public:
00097     class BucketIterator; // Forward declaration
00098     class EventIterator; // Forward declaration
00099 
00100     /** @brief This class represents a time bucket as a part of a calendar.
00101       *
00102       * Manipulation of instances of this class need to be handled with the
00103       * methods on the friend class Calendar.
00104       * @see Calendar
00105       */
00106     class Bucket : public Object, public NonCopyable
00107     {
00108         friend class Calendar;
00109         friend class BucketIterator;
00110         friend class EventIterator;
00111       private:
00112         /** Name of the bucket. */
00113         string nm;
00114 
00115         /** Start date of the bucket. */
00116         Date startdate;
00117 
00118         /** End Date of the bucket. */
00119         Date enddate;
00120 
00121         /** A pointer to the next bucket. */
00122         Bucket* nextBucket;
00123 
00124         /** A pointer to the previous bucket. */
00125         Bucket* prevBucket;
00126 
00127         /** Priority of this bucket, compared to other buckets effective
00128           * at a certain time.
00129           */
00130         int priority;
00131 
00132         /** A pointer to the owning calendar. */
00133         Calendar *cal;
00134 
00135         /** Increments an iterator to the next change event.<br>
00136           * A bucket will evaluate the current state of the iterator, and
00137           * update it if a valid next event can be generated.
00138           */
00139         DECLARE_EXPORT void nextEvent(EventIterator*, Date) const;
00140 
00141         /** Increments an iterator to the previous change event.<br>
00142           * A bucket will evaluate the current state of the iterator, and
00143           * update it if a valid previous event can be generated.
00144           */
00145         DECLARE_EXPORT void prevEvent(EventIterator*, Date) const;
00146 
00147       protected:
00148         /** Constructor. */
00149         Bucket(Calendar *c, Date start, Date end, string name) : nm(name),
00150           startdate(start), enddate(end), nextBucket(NULL), prevBucket(NULL),
00151           priority(0), cal(c) {initType(metadata);}
00152 
00153         /** Auxilary function to write out the start of the XML. */
00154         DECLARE_EXPORT void writeHeader(XMLOutput *, const Keyword&) const;
00155 
00156       public:
00157         /** Return the calendar to whom the bucket belongs. */
00158         Calendar* getCalendar() const {return cal;}
00159 
00160         /** This method is here only to keep the API of all calendar classes
00161           * consistent.<br>
00162           * Note that this isn't exactly a virtual method, since the return
00163           * value is different for different calendar types.
00164           */
00165         void getValue() const {}
00166 
00167         /** This method is here only to keep the API of all calendar classes
00168           * consistent.
00169           */
00170         void setValue() {}
00171 
00172         /** Returns the name of the bucket. If no name was ever explicitly
00173           * specified with the setName() method, a default name is generated
00174           * by converting the start date into a string.<br>
00175           * To reduce the memory needs, this default string is computed with
00176           * every call to the getName() method and never stored internally.
00177           * Only explicitly specified names are kept in memory.
00178           */
00179         string getName() const {return nm.empty() ? string(startdate) : nm;}
00180 
00181         /** Returns true if the name of the bucket has not been explicitly
00182           * specified. */
00183         bool useDefaultName() const {return nm.empty();}
00184 
00185         /** Updates the name of a bucket. */
00186         void setName(const string& s) {nm=s;}
00187 
00188         /** Returns the end date of the bucket. */
00189         Date getEnd() const {return enddate;}
00190 
00191         /** Updates the end date of the bucket. */
00192         void setEnd(const Date& d) {enddate = d;}
00193 
00194         /** Returns the start date of the bucket. */
00195         Date getStart() const {return startdate;}
00196 
00197         /** Updates the end date of the bucket. */
00198         void setStart(const Date& d) {startdate = d;}
00199 
00200         /** Returns the priority of this bucket, compared to other buckets
00201           * effective at a certain time.<br>
00202           * Lower numbers indicate a higher priority level.<br>
00203           * The default value is 0.
00204           */
00205         int getPriority() const {return priority;}
00206 
00207         /** Updates the priority of this bucket, compared to other buckets
00208           * effective at a certain time.<br>
00209           * Lower numbers indicate a higher priority level.<br>
00210           * The default value is 0.
00211           */
00212         void setPriority(int f) {priority = f;}
00213 
00214         /** Verifies whether this entry is effective on a given date. */
00215         bool checkValid(Date d) const
00216         {
00217           return true;
00218         }
00219 
00220         /** Convert the value of the bucket to a boolean value. */
00221         virtual bool getBool() const {return true;}
00222 
00223         virtual DECLARE_EXPORT void writeElement
00224           (XMLOutput*, const Keyword&, mode=DEFAULT) const;
00225 
00226         /** Reads the bucket information from the input. Only the fields "name"
00227           * and "start" are read in. Other fields as also written out but these
00228           * are information-only fields.
00229           */
00230         DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
00231 
00232         virtual const MetaClass& getType() const
00233           {return *metadata;}
00234         virtual size_t getSize() const
00235           {return sizeof(Bucket) + nm.size();}
00236         static DECLARE_EXPORT const MetaCategory* metadata;
00237         virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00238         virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00239         static int initialize();
00240     };
00241 
00242     /** Default constructor. */
00243     Calendar(const string& n) : HasName<Calendar>(n), firstBucket(NULL) {}
00244 
00245     /** Destructor, which cleans up the buckets too and all references to the
00246       * calendar from the core model.
00247       */
00248     DECLARE_EXPORT ~Calendar();
00249 
00250     /** Convert the value of the calendar to a boolean value. */
00251     virtual bool getBool() const {return false;}
00252 
00253     /** This is a factory method that creates a new bucket using the start
00254       * date as the key field. The fields are passed as an array of character
00255       * pointers.<br>
00256       * This method is intended to be used to create objects when reading
00257       * XML input data.
00258       */
00259     DECLARE_EXPORT Bucket* createBucket(const AttributeList&);
00260 
00261     /** Adds a new bucket to the list. */
00262     DECLARE_EXPORT Bucket* addBucket(Date, Date, string);
00263 
00264     /** Removes a bucket from the list. */
00265     DECLARE_EXPORT void removeBucket(Bucket* bkt);
00266 
00267     /** Returns the bucket where a certain date belongs to.
00268       * A bucket will always be returned, i.e. the data structure is such
00269       * that we all dates between infinitePast and infiniteFuture match
00270       * with one (and only one) bucket.
00271       */
00272     DECLARE_EXPORT Bucket* findBucket(Date d, bool fwd = true) const;
00273 
00274     /** Returns the bucket with a certain name.
00275       * A NULL pointer is returned in case no bucket can be found with the
00276       * given name.
00277       */
00278     DECLARE_EXPORT Bucket* findBucket(const string&) const;
00279 
00280     /** @brief An iterator class to go through all dates where the calendar
00281       * value changes.*/
00282     class EventIterator
00283     {
00284       friend class Calendar::Bucket;
00285       protected:
00286         const Calendar* theCalendar;
00287         const Bucket* curBucket;
00288         Date curDate;
00289         double curPriority;
00290       public:
00291         const Date& getDate() const {return curDate;}
00292         const Bucket* getBucket() const {return curBucket;}
00293         const Calendar* getCalendar() const {return theCalendar;}
00294         EventIterator(const Calendar* c, Date d = Date::infinitePast,
00295           bool forward = true) : theCalendar(c), curDate(d)
00296         {
00297           if (!c)
00298             throw LogicException("Creating iterator for NULL calendar");
00299           curBucket = c->findBucket(d,forward);
00300         };
00301         DECLARE_EXPORT EventIterator& operator++();
00302         DECLARE_EXPORT EventIterator& operator--();
00303         EventIterator operator++(int)
00304           {EventIterator tmp = *this; ++*this; return tmp;}
00305         EventIterator operator--(int)
00306           {EventIterator tmp = *this; --*this; return tmp;}
00307     };
00308 
00309     /** @brief An iterator class to go through all buckets of the calendar. */
00310     class BucketIterator
00311     {
00312       private:
00313         Bucket* curBucket;
00314       public:
00315         BucketIterator(Bucket* b = NULL) : curBucket(b) {}
00316         bool operator != (const BucketIterator &b) const
00317           {return b.curBucket != curBucket;}
00318         bool operator == (const BucketIterator &b) const
00319           {return b.curBucket == curBucket;}
00320         BucketIterator& operator++()
00321           {if (curBucket) curBucket = curBucket->nextBucket; return *this;}
00322         BucketIterator operator++(int)
00323           {BucketIterator tmp = *this; ++*this; return tmp;}
00324         BucketIterator& operator--()
00325           {if(curBucket) curBucket = curBucket->prevBucket; return *this;}
00326         BucketIterator operator--(int)
00327           {BucketIterator tmp = *this; --*this; return tmp;}
00328         Bucket* operator ->() const {return curBucket;}
00329         Bucket& operator *() const {return *curBucket;}
00330     };
00331 
00332     /** Returns an iterator to go through the list of buckets. */
00333     BucketIterator beginBuckets() const {return BucketIterator(firstBucket);}
00334 
00335     /** Returns an iterator to go through the list of buckets. */
00336     BucketIterator endBuckets() const {return BucketIterator(NULL);}
00337 
00338     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
00339     void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement) {}
00340     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
00341     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00342     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00343     static int initialize();
00344 
00345     static DECLARE_EXPORT PyObject* getEvents(PyObject*, PyObject*, PyObject*);
00346 
00347     virtual const MetaClass& getType() const {return *metadata;}
00348     static DECLARE_EXPORT const MetaCategory* metadata;
00349 
00350     virtual size_t getSize() const
00351     {
00352       size_t i = sizeof(Calendar) + getName().size();
00353       for (BucketIterator j = beginBuckets(); j!= endBuckets(); ++j)
00354         i += j->getSize();
00355       return i;
00356     }
00357 
00358   protected:
00359     /** Find the lowest priority of any bucket. */
00360     int lowestPriority() const
00361     {
00362       int min = 0;
00363       for (BucketIterator i = beginBuckets(); i != endBuckets(); ++i)
00364         if (i->getPriority() < min) min = i->getPriority();
00365       return min;
00366     }
00367 
00368   private:
00369     /** A pointer to the first bucket. The buckets are stored in a doubly
00370       * linked list. */
00371     Bucket* firstBucket;
00372 
00373     /** This is the factory method used to generate new buckets. Each subclass
00374       * should provide an override for this function. */
00375     virtual Bucket* createNewBucket(Date start, Date end, string name)
00376       {return new Bucket(this, start,end,name);}
00377 };
00378 
00379 
00380 /** @brief This calendar type is used to store values in its buckets.
00381   *
00382   * The template type must statisfy the following requirements:
00383   *   - XML import supported by the operator >> of the class DataElement.
00384   *   - XML export supported by the method writeElement of the class XMLOutput.
00385   * Subclasses will need to implement the getType() method.
00386   * @see CalendarPointer
00387   */
00388 template <typename T> class CalendarValue : public Calendar
00389 {
00390   public:
00391     /** @brief A special type of calendar bucket, designed to hold a
00392       * a value.
00393       * @see Calendar::Bucket
00394       */
00395     class BucketValue : public Calendar::Bucket
00396     {
00397         friend class CalendarValue<T>;
00398       private:
00399         /** This is the value stored in this bucket. */
00400         T val;
00401 
00402         /** Constructor. */
00403         BucketValue(CalendarValue<T> *c, Date start, Date end, string name)
00404           : Bucket(c,start,end,name), val(c->getDefault()) {}
00405 
00406       public:
00407         /** Returns the value of this bucket. */
00408         const T& getValue() const {return val;}
00409 
00410         /** Convert the value of the bucket to a boolean value. */
00411         bool getBool() const {return val != 0;}
00412 
00413         /** Updates the value of this bucket. */
00414         void setValue(const T& v) {val = v;}
00415 
00416         void writeElement
00417         (XMLOutput *o, const Keyword& tag, mode m = DEFAULT) const
00418         {
00419           assert(m == DEFAULT || m == FULL);
00420           writeHeader(o, tag);
00421           if (getPriority()) o->writeElement(Tags::tag_priority, getPriority());
00422           o->writeElement(Tags::tag_value, val);
00423           o->EndObject(tag);
00424         }
00425 
00426         void endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00427         {
00428           if (pAttr.isA(Tags::tag_value))
00429             pElement >> val;
00430           else
00431             Bucket::endElement(pIn, pAttr, pElement);
00432         }
00433 
00434         virtual const MetaClass& getType() const
00435           {return *Calendar::Bucket::metadata;}
00436 
00437         virtual size_t getSize() const
00438           {return sizeof(typename CalendarValue<T>::BucketValue) + getName().size();}
00439     };
00440 
00441     /** @brief A special event iterator, providing also access to the
00442       * current value. */
00443     class EventIterator : public Calendar::EventIterator
00444     {
00445       public:
00446         /** Constructor. */
00447         EventIterator(const Calendar* c, Date d = Date::infinitePast,
00448           bool f = true) : Calendar::EventIterator(c,d,f) {}
00449 
00450         /** Return the current value of the iterator at this date. */
00451         T getValue()
00452         {
00453           typedef CalendarValue<T> calendarvaluetype;
00454           typedef typename CalendarValue<T>::BucketValue bucketvaluetype;
00455           return curBucket ?
00456             static_cast<const bucketvaluetype*>(curBucket)->getValue() :
00457             static_cast<const calendarvaluetype*>(theCalendar)->getDefault();
00458         }
00459     };
00460 
00461     /** Default constructor. */
00462     CalendarValue(const string& n) : Calendar(n) {}
00463 
00464     /** Returns the value on the specified date. */
00465     const T& getValue(const Date d) const
00466     {
00467       BucketValue* x = static_cast<BucketValue*>(findBucket(d));
00468       return x ? x->getValue() : defaultValue;
00469     }
00470 
00471     /** Updates the value in a certain date range.<br>
00472       * This will create a new bucket if required. */
00473     void setValue(Date start, Date end, const T& v)
00474     {
00475       BucketValue* x = static_cast<BucketValue*>(findBucket(start));
00476       if (x && x->getStart() == start && x->getEnd() <= end)
00477         // We can update an existing bucket: it has the same start date
00478         // and ends before the new effective period ends.
00479         x->setEnd(end);
00480       else
00481         // Creating a new bucket
00482         x = static_cast<BucketValue*>(addBucket(start,end,""));
00483       x->setValue(v);
00484       x->setPriority(lowestPriority()-1);
00485     }
00486 
00487     virtual const MetaClass& getType() const = 0;
00488 
00489     const T& getValue(Calendar::BucketIterator& i) const
00490       {return reinterpret_cast<BucketValue&>(*i).getValue();}
00491 
00492     /** Returns the default calendar value when no entry is matching. */
00493     virtual T getDefault() const {return defaultValue;}
00494 
00495     /** Convert the value of the calendar to a boolean value. */
00496     virtual bool getBool() const {return defaultValue != 0;}
00497 
00498     /** Update the default calendar value when no entry is matching. */
00499     virtual void setDefault(const T v) {defaultValue = v;}
00500 
00501     void writeElement(XMLOutput *o, const Keyword& tag, mode m=DEFAULT) const
00502     {
00503       // Writing a reference
00504       if (m == REFERENCE)
00505       {
00506         o->writeElement
00507           (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00508         return;
00509       }
00510 
00511       // Write the complete object
00512       if (m != NOHEADER) o->BeginObject
00513         (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00514 
00515       // Write my own fields
00516       o->writeElement(Tags::tag_default, getDefault());
00517 
00518       // Write all buckets
00519       o->BeginObject (Tags::tag_buckets);
00520       for (BucketIterator i = beginBuckets(); i != endBuckets(); ++i)
00521         // We use the FULL mode, to force the buckets being written regardless
00522         // of the depth in the XML tree.
00523         o->writeElement(Tags::tag_bucket, *i, FULL);
00524       o->EndObject(Tags::tag_buckets);
00525 
00526       o->EndObject(tag);
00527     }
00528 
00529     void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00530     {
00531       if (pAttr.isA(Tags::tag_default))
00532         pElement >> defaultValue;
00533       else
00534         Calendar::endElement(pIn, pAttr, pElement);
00535     }
00536 
00537   private:
00538     /** Factory method to add new buckets to the calendar.
00539       * @see Calendar::addBucket()
00540       */
00541     Bucket* createNewBucket(Date start, Date end, string name)
00542       {return new BucketValue(this,start,end,name);}
00543 
00544     /** Value when no bucket is matching a certain date. */
00545     T defaultValue;
00546 };
00547 
00548 
00549 /* Declaration of specialized template functions. */
00550 template <> DECLARE_EXPORT bool CalendarValue<string>::getBool() const;
00551 template <> DECLARE_EXPORT bool CalendarValue<string>::BucketValue::getBool() const;
00552 
00553 
00554 /** @brief This calendar type is used to store object pointers in its buckets.
00555   *
00556   * The template type must statisfy the following requirements:
00557   *   - It must be a subclass of the Object class and implement the
00558   *     beginElement(), writeElement() and endElement() as appropriate.
00559   *   - Implement a metadata data element
00560   * Subclasses will need to implement the getType() method.
00561   * @see CalendarValue
00562   */
00563 template <typename T> class CalendarPointer : public Calendar
00564 {
00565   public:
00566     /** @brief A special type of calendar bucket, designed to hold a pointer
00567       * to an object.
00568       * @see Calendar::Bucket
00569       */
00570     class BucketPointer : public Calendar::Bucket
00571     {
00572         friend class CalendarPointer<T>;
00573       private:
00574         /** The object stored in this bucket. */
00575         T* val;
00576 
00577         /** Constructor. */
00578         BucketPointer(CalendarPointer<T> *c, Date start, Date end, string name)
00579           : Bucket(c,start,end,name), val(c->getDefault()) {};
00580 
00581       public:
00582         /** Returns the value stored in this bucket. */
00583         T* getValue() const {return val;}
00584 
00585         /** Convert the value of the bucket to a boolean value. */
00586         bool getBool() const {return val != NULL;}
00587 
00588         /** Updates the value of this bucket. */
00589         void setValue(T* v) {val = v;}
00590 
00591         void writeElement
00592         (XMLOutput *o, const Keyword& tag, mode m = DEFAULT) const
00593         {
00594           assert(m == DEFAULT || m == FULL);
00595           writeHeader(o, tag);
00596           if (getPriority()) o->writeElement(Tags::tag_priority, getPriority());
00597           if (val) o->writeElement(Tags::tag_value, val);
00598           o->EndObject(tag);
00599         }
00600 
00601         void beginElement(XMLInput& pIn, const Attribute& pAttr)
00602         {
00603           if (pAttr.isA(Tags::tag_value))
00604             pIn.readto(
00605               MetaCategory::ControllerDefault(T::metadata,pIn.getAttributes())
00606             );
00607           else
00608             Bucket::beginElement(pIn, pAttr);
00609         }
00610 
00611         void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00612         {
00613           if (pAttr.isA(Tags::tag_value))
00614           {
00615             T *o = dynamic_cast<T*>(pIn.getPreviousObject());
00616             if (!o)
00617               throw LogicException
00618               ("Incorrect object type during read operation");
00619             val = o;
00620           }
00621           else
00622             Bucket::endElement(pIn, pAttr, pElement);
00623         }
00624 
00625         virtual const MetaClass& getType() const
00626           {return *Calendar::Bucket::metadata;}
00627 
00628         virtual size_t getSize() const
00629           {return sizeof(typename CalendarPointer<T>::BucketPointer) + getName().size();}
00630     };
00631 
00632     /** @brief A special event iterator, providing also access to the
00633       * current value. */
00634     class EventIterator : public Calendar::EventIterator
00635     {
00636       public:
00637         /** Constructor. */
00638         EventIterator(const Calendar* c, Date d = Date::infinitePast,
00639           bool f = true) : Calendar::EventIterator(c,d,f) {}
00640 
00641         /** Return the current value of the iterator at this date. */
00642         const T* getValue()
00643         {
00644           typedef CalendarPointer<T> calendarpointertype;
00645           typedef typename CalendarPointer<T>::BucketPointer bucketpointertype;
00646           return curBucket ?
00647             static_cast<const bucketpointertype*>(curBucket)->getValue() :
00648             static_cast<const calendarpointertype*>(theCalendar)->getDefault();
00649         }
00650     };
00651 
00652     /** Default constructor. */
00653     CalendarPointer(const string& n) : Calendar(n), defaultValue(NULL) {}
00654 
00655     /** Returns the value on the specified date. */
00656     T* getValue(const Date d) const
00657     {
00658       BucketPointer* x = static_cast<BucketPointer*>(findBucket(d));
00659       return x ? x->getValue() : defaultValue;
00660     }
00661 
00662     /** Convert the value of the calendar to a boolean value. */
00663     virtual bool getBool() const {return defaultValue != NULL;}
00664 
00665     /** Updates the value in a certain date range.<br>
00666       * This will create a new bucket if required. */
00667     void setValue(Date start, Date end, T* v)
00668     {
00669       BucketPointer* x = static_cast<BucketPointer*>(findBucket(start));
00670       if (x && x->getStart() == start && x->getEnd() <= end)
00671         // We can update an existing bucket: it has the same start date
00672         // and ends before the new effective period ends.
00673         x->setEnd(end);
00674       else
00675         // Creating a new bucket
00676         x = static_cast<BucketPointer*>(addBucket(start,end,""));
00677       x->setValue(v);
00678       x->setPriority(lowestPriority()-1);
00679     }
00680 
00681     /** Returns the default calendar value when no entry is matching. */
00682     virtual T* getDefault() const {return defaultValue;}
00683 
00684     /** Update the default calendar value when no entry is matching. */
00685     virtual void setDefault(T* v) {defaultValue = v;}
00686 
00687     virtual const MetaClass& getType() const = 0;
00688 
00689     void writeElement(XMLOutput *o, const Keyword& tag, mode m=DEFAULT) const
00690     {
00691       // Writing a reference
00692       if (m == REFERENCE)
00693       {
00694         o->writeElement
00695           (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00696         return;
00697       }
00698 
00699       // Write the complete object
00700       if (m != NOHEADER) o->BeginObject
00701         (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00702 
00703       // Write my own fields
00704       if (defaultValue) o->writeElement(Tags::tag_default, defaultValue);
00705 
00706       // Write all buckets
00707       o->BeginObject (Tags::tag_buckets);
00708       for (BucketIterator i = beginBuckets(); i != endBuckets(); ++i)
00709         // We use the FULL mode, to force the buckets being written regardless
00710         // of the depth in the XML tree.
00711         o->writeElement(Tags::tag_bucket, *i, FULL);
00712       o->EndObject(Tags::tag_buckets);
00713 
00714       o->EndObject(tag);
00715     }
00716 
00717     void beginElement(XMLInput& pIn, const Attribute& pAttr)
00718     {
00719       if (pAttr.isA (Tags::tag_default))
00720         pIn.readto(T::reader(T::metadata,pIn.getAttributes()));
00721       else
00722         Calendar::beginElement(pIn, pAttr);
00723     }
00724 
00725     void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00726     {
00727       if (pAttr.isA(Tags::tag_default))
00728       {
00729         T *o = dynamic_cast<T*>(pIn.getPreviousObject());
00730         if (!o)
00731           throw LogicException("Incorrect object type during read operation");
00732         defaultValue = o;
00733       }
00734       else
00735         Calendar::endElement(pIn, pAttr, pElement);
00736     }
00737 
00738   private:
00739     /** Factory method to add new buckets to the calendar.
00740       * @see Calendar::addBucket()
00741       */
00742     Bucket* createNewBucket(Date start, Date end, string name)
00743       {return new BucketPointer(this,start,end,name);}
00744 
00745     /** Value when no bucket is matching a certain date. */
00746     T* defaultValue;
00747 };
00748 
00749 
00750 /** @brief A calendar only defining time buckets and not storing any data
00751   * fields. */
00752 class CalendarVoid : public Calendar
00753 {
00754   public:
00755     CalendarVoid(const string& n) : Calendar(n) {initType(metadata);}
00756     virtual const MetaClass& getType() const {return *metadata;}
00757     static DECLARE_EXPORT const MetaClass* metadata;
00758     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00759     static int initialize();
00760 };
00761 
00762 
00763 /** @brief A calendar storing double values in its buckets. */
00764 class CalendarDouble : public CalendarValue<double>
00765 {
00766   public:
00767     CalendarDouble(const string& n) : CalendarValue<double>(n)
00768       {setDefault(0.0); initType(metadata);}
00769     DECLARE_EXPORT ~CalendarDouble();
00770     virtual const MetaClass& getType() const {return *metadata;}
00771     static DECLARE_EXPORT const MetaClass* metadata;
00772     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00773     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00774     static int initialize();
00775 
00776     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00777 };
00778 
00779 
00780 /** @brief A calendar storing integer values in its buckets. */
00781 class CalendarInt : public CalendarValue<int>
00782 {
00783   public:
00784     CalendarInt(const string& n) : CalendarValue<int>(n)
00785       {setDefault(0); initType(metadata);}
00786     virtual const MetaClass& getType() const {return *metadata;}
00787     static DECLARE_EXPORT const MetaClass* metadata;
00788     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00789     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00790     static int initialize();
00791 
00792     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00793 };
00794 
00795 
00796 /** @brief A calendar storing boolean values in its buckets. */
00797 class CalendarBool : public CalendarValue<bool>
00798 {
00799   public:
00800     CalendarBool(const string& n) : CalendarValue<bool>(n)
00801       {setDefault(false); initType(metadata);}
00802     DECLARE_EXPORT ~CalendarBool();
00803     virtual const MetaClass& getType() const {return *metadata;}
00804     static DECLARE_EXPORT const MetaClass* metadata;
00805     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00806     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00807     static int initialize();
00808 
00809     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00810 };
00811 
00812 
00813 /** @brief A calendar storing strings in its buckets. */
00814 class CalendarString : public CalendarValue<string>
00815 {
00816   public:
00817     CalendarString(const string& n) : CalendarValue<string>(n) {initType(metadata);}
00818     virtual const MetaClass& getType() const {return *metadata;}
00819     bool getBool() const {return getDefault().empty();}
00820     static DECLARE_EXPORT const MetaClass* metadata;
00821     virtual size_t getSize() const
00822     {
00823       size_t i = sizeof(CalendarString);
00824       for (BucketIterator j = beginBuckets(); j!= endBuckets(); ++j)
00825         i += j->getSize()
00826             + static_cast<CalendarValue<string>::BucketValue&>(*j).getValue().size();
00827       return i;
00828     }
00829     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00830     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00831     static int initialize();
00832 
00833     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00834 };
00835 
00836 
00837 /** @brief A calendar storing pointers to operations in its buckets. */
00838 class CalendarOperation : public CalendarPointer<Operation>
00839 {
00840   public:
00841     CalendarOperation(const string& n) : CalendarPointer<Operation>(n)
00842       {initType(metadata);}
00843     virtual const MetaClass& getType() const {return *metadata;}
00844     static DECLARE_EXPORT const MetaClass* metadata;
00845     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
00846     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
00847     static int initialize();
00848 
00849     static DECLARE_EXPORT PyObject* setPythonValue(PyObject*, PyObject*, PyObject*);
00850 };
00851 
00852 
00853 /** @brief A problem represents infeasibilities, alerts and warnings in
00854   * the plan.
00855   *
00856   * Problems are maintained internally by the system. They are thus only
00857   * exported, meaning that you can't directly import or create problems.<br>
00858   * This class is the pure virtual base class for all problem types.<br>
00859   * The usage of the problem objects is based on the following principles:
00860   *  - Problems objects are passive. They don't actively change the model
00861   *    state.
00862   *  - Objects of the HasProblems class actively create and destroy Problem
00863   *    objects.
00864   *  - Problem objects are managed in a 'lazy' way, meaning they only are
00865   *    getting created when the list of problems is requested by the user.<br>
00866   *    During normal planning activities we merely mark the planning entities
00867   *    that have changed, so we can easily pick up which entities to recompute
00868   *    the problems for. In this way we can avoid the cpu and memory overhead
00869   *    of keeping the problem list up to date at all times, while still
00870   *    providing the user with the correct list of problems when required.
00871   *  - Given the above, Problems are lightweight objects that consume
00872   *    limited memory.
00873   */
00874 class Problem : public NonCopyable, public Object
00875 {
00876   public:
00877     class const_iterator;
00878     friend class const_iterator;
00879 
00880     /** Constructor.
00881       * Note that this method can't manipulate the problem container, since
00882       * the problem objects aren't fully constructed yet.
00883       * @see addProblem
00884       */
00885     explicit Problem(HasProblems *p) : owner(p)
00886     {
00887       if (!owner) throw LogicException("Invalid problem creation");
00888       initType(metadata);
00889     }
00890 
00891     /** Initialize the class. */
00892     static int initialize();
00893 
00894     /** Destructor.
00895       * @see removeProblem
00896       */
00897     virtual ~Problem() {}
00898 
00899     /** Returns the duration of this problem. */
00900     virtual const DateRange getDateRange() const = 0;
00901 
00902     /** Returns a text description of this problem. */
00903     virtual string getDescription() const = 0;
00904 
00905     /** Returns the object type having this problem. */
00906     virtual string getEntity() const = 0;
00907 
00908     /** Returns true if the plan remains feasible even if it contains this
00909       * problem, i.e. if the problems flags only a warning.
00910       * Returns false if a certain problem points at an infeasibility of the
00911       * plan.
00912       */
00913     virtual bool isFeasible() const = 0;
00914 
00915     /** Returns a double number reflecting the magnitude of the problem. This
00916       * allows us to focus on the significant problems and filter out the
00917       * small ones.
00918       */
00919     virtual double getWeight() const = 0;
00920 
00921     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
00922     void endElement(XMLInput&, const Attribute&, const DataElement&) {}
00923     static DECLARE_EXPORT void writer(const MetaCategory*, XMLOutput*);
00924 
00925     PyObject* getattro(const Attribute&);
00926 
00927     PyObject* str() const
00928     {
00929       return PythonObject(getDescription());
00930     }
00931 
00932     /** Returns an iterator to the very first problem. The iterator can be
00933       * incremented till it points past the very last problem. */
00934     static DECLARE_EXPORT const_iterator begin();
00935 
00936     /** Return an iterator to the first problem of this entity. The iterator
00937       * can be incremented till it points past the last problem of this
00938       * plannable entity.<br>
00939       * The boolean argument specifies whether the problems need to be
00940       * recomputed as part of this method.
00941       */
00942     static DECLARE_EXPORT const_iterator begin(HasProblems*, bool = true);
00943 
00944     /** Return an iterator pointing beyond the last problem. */
00945     static DECLARE_EXPORT const const_iterator end();
00946 
00947     /** Erases the list of all problems. This methods can be used reduce the
00948       * memory consumption at critical points. The list of problems will be
00949       * recreated when the problem detection is triggered again.
00950       */
00951     static DECLARE_EXPORT void clearProblems();
00952 
00953     /** Erases the list of problems linked with a certain plannable object.<br>
00954       * If the second parameter is set to true, the problems will be
00955       * recreated when the next problem detection round is triggered.
00956       */
00957     static DECLARE_EXPORT void clearProblems(HasProblems& p, bool setchanged = true);
00958 
00959     /** Returns a pointer to the object that owns this problem. */
00960     virtual Object* getOwner() const = 0;
00961 
00962     /** Return a reference to the metadata structure. */
00963     virtual const MetaClass& getType() const {return *metadata;}
00964 
00965     /** Storing metadata on this class. */
00966     static DECLARE_EXPORT const MetaCategory* metadata;
00967 
00968   protected:
00969     /** Each Problem object references a HasProblem object as its owner. */
00970     HasProblems *owner;
00971 
00972     /** Each Problem contains a pointer to the next pointer for the same
00973       * owner. This class implements thus an intrusive single linked list
00974       * of Problem objects. */
00975     Problem *nextProblem;
00976 
00977     /** Adds a newly created problem to the problem container.
00978       * This method needs to be called in the constructor of a problem
00979       * subclass. It can't be called from the constructor of the base
00980       * Problem class, since the object isn't fully created yet and thus
00981       * misses the proper information used by the compare method.
00982       * @see removeProblem
00983       */
00984     DECLARE_EXPORT void addProblem();
00985 
00986     /** Removes a problem from the problem container.
00987       * This method needs to be called from the destructor of a problem
00988       * subclass.<br>
00989       * Due to the single linked list data structure, this methods'
00990       * performance is linear with the number of problems of an entity.
00991       * This is acceptable since we don't expect entities with a huge amount
00992       * of problems.
00993       * @see addproblem
00994       */
00995     DECLARE_EXPORT void removeProblem();
00996 
00997     /** Comparison of 2 problems.<br>
00998       * To garantuee that the problems are sorted in a consistent and stable
00999       * way, the following sorting criteria are used (in order of priority):
01000       * <ol><li>Entity<br>
01001       *    This sort is to be ensured by the client. This method can't
01002       *    compare problems of different entities!</li>
01003       * <li>Type<br>
01004       *    Each problem type has a hashcode used for sorting.</li>
01005       * <li>Start date</li></ol>
01006       * The sorting is expected such that it can be used as a key, i.e. no
01007       * two problems of will ever evaluate to be identical.
01008       */
01009     DECLARE_EXPORT bool operator < (const Problem& a) const;
01010 };
01011 
01012 
01013 /** @brief Classes that keep track of problem conditions need to implement
01014   * this class.
01015   *
01016   * This class is closely related to the Problem class.
01017   * @see Problem
01018   */
01019 class HasProblems
01020 {
01021     friend class Problem::const_iterator;
01022     friend class Problem;
01023   public:
01024     class EntityIterator;
01025 
01026     /** Returns an iterator pointing to the first HasProblem object. */
01027     static DECLARE_EXPORT EntityIterator beginEntity();
01028 
01029     /** Returns an iterator pointing beyond the last HasProblem object. */
01030     static DECLARE_EXPORT EntityIterator endEntity();
01031 
01032     /** Constructor. */
01033     HasProblems() : firstProblem(NULL) {}
01034 
01035     /** Destructor. It needs to take care of making sure all problems objects
01036       * are being deleted as well. */
01037     virtual ~HasProblems() {Problem::clearProblems(*this, false);}
01038 
01039     /** Returns the plannable entity relating to this problem container. */
01040     virtual Plannable* getEntity() const = 0;
01041 
01042     /** Called to update the list of problems. The function will only be
01043       * called when:
01044       *  - the list of problems is being recomputed
01045       *  - AND, problem detection is enabled for this object
01046       *  - AND, the object has changed since the last problem computation
01047       */
01048     virtual void updateProblems() = 0;
01049 
01050   private:
01051     /** A pointer to the first problem of this object. Problems are maintained
01052       * in a single linked list. */
01053     Problem* firstProblem;
01054 };
01055 
01056 
01057 /** @brief This class is an implementation of the "visitor" design pattern.
01058   * It is intended as a basis for different algoritms processing the frePPLe
01059   * data.
01060   *
01061   * The goal is to decouple the solver/algorithms from the model/data
01062   * representation. Different solvers can be easily be plugged in to work on
01063   * the same data.
01064   */
01065 class Solver : public HasName<Solver>
01066 {
01067   public:
01068     explicit Solver(const string& n) : HasName<Solver>(n), loglevel(0) {}
01069     virtual ~Solver() {}
01070 
01071     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01072     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01073     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
01074     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
01075     static int initialize();
01076 
01077     static DECLARE_EXPORT PyObject* solve(PyObject*, PyObject*);
01078 
01079     virtual void solve(void* = NULL) = 0;
01080     virtual void solve(const Demand*,void* = NULL)
01081       {throw LogicException("Called undefined solve(Demand*) method");}
01082     virtual void solve(const Operation*,void* = NULL)
01083       {throw LogicException("Called undefined solve(Operation*) method");}
01084     virtual void solve(const OperationFixedTime* o, void* v = NULL)
01085       {solve(reinterpret_cast<const Operation*>(o),v);}
01086     virtual void solve(const OperationTimePer* o, void* v = NULL)
01087       {solve(reinterpret_cast<const Operation*>(o),v);}
01088     virtual void solve(const OperationRouting* o, void* v = NULL)
01089       {solve(reinterpret_cast<const Operation*>(o),v);}
01090     virtual void solve(const OperationAlternate* o, void* v = NULL)
01091       {solve(reinterpret_cast<const Operation*>(o),v);}
01092     virtual void solve(const Resource*,void* = NULL)
01093       {throw LogicException("Called undefined solve(Resource*) method");}
01094     virtual void solve(const ResourceInfinite* r, void* v = NULL)
01095       {solve(reinterpret_cast<const Resource*>(r),v);}
01096     virtual void solve(const Buffer*,void* = NULL)
01097       {throw LogicException("Called undefined solve(Buffer*) method");}
01098     virtual void solve(const BufferInfinite* b, void* v = NULL)
01099       {solve(reinterpret_cast<const Buffer*>(b),v);}
01100     virtual void solve(const BufferProcure* b, void* v = NULL)
01101       {solve(reinterpret_cast<const Buffer*>(b),v);}
01102     virtual void solve(const Load* b, void* v = NULL)
01103       {throw LogicException("Called undefined solve(Load*) method");}
01104     virtual void solve(const Flow* b, void* v = NULL)
01105       {throw LogicException("Called undefined solve(Flow*) method");}
01106     virtual void solve(const FlowEnd* b, void* v = NULL)
01107       {solve(reinterpret_cast<const Flow*>(b),v);}
01108     virtual void solve(const Solvable*,void* = NULL)
01109       {throw LogicException("Called undefined solve(Solvable*) method");}
01110 
01111     /** Returns how elaborate and verbose output is requested.<br>
01112       * As a guideline solvers should respect the following guidelines:
01113       * - 0:<br>
01114       *   Completely silent.<br>
01115       *   This is the default value.
01116       * - 1:<br>
01117       *   Minimal and high-level messages on the progress that are sufficient
01118       *   for logging normal operation.<br>
01119       * - 2:<br>
01120       *   Higher numbers are solver dependent. These levels are typically
01121       *   used for debugging and tracing, and provide more detail on the
01122       *   solver's progress.
01123       */
01124     unsigned short getLogLevel() const {return loglevel;}
01125 
01126     /** Controls whether verbose output will be generated. */
01127     void setLogLevel(unsigned short v) {loglevel = v;}
01128 
01129     virtual const MetaClass& getType() const {return *metadata;}
01130     static DECLARE_EXPORT const MetaCategory* metadata;
01131 
01132   private:
01133     /** Controls the amount of tracing and debugging messages. */
01134     unsigned short loglevel;
01135 };
01136 
01137 
01138 /** @brief This class needs to be implemented by all classes that implement
01139   * dynamic behavior, and which can be called by a solver.
01140   */
01141 class Solvable
01142 {
01143   public:
01144     /** This method is called by solver classes. The implementation of this
01145       * class simply calls the solve method on the solver class. Using the
01146       * polymorphism the solver can implement seperate methods for different
01147       * plannable subclasses.
01148       */
01149     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
01150 
01151     /** Destructor. */
01152     virtual ~Solvable() {}
01153 };
01154 
01155 
01156 /** @brief This class needs to be implemented by all classes that implement
01157   * dynamic behavior in the plan.
01158   *
01159   * The problem detection logic is implemented in the detectProblems() method.
01160   * For performance reasons, problem detection is "lazy", i.e. problems are
01161   * computed only when somebody really needs the access to the list of
01162   * problems.
01163   */
01164 class Plannable : public HasProblems, public Solvable
01165 {
01166   public:
01167     /** Constructor. */
01168     Plannable() : useProblemDetection(true), changed(true)
01169      {anyChange = true;}
01170 
01171     /** Specify whether this entity reports problems. */
01172     DECLARE_EXPORT void setDetectProblems(bool b);
01173 
01174     /** Returns whether or not this object needs to detect problems. */
01175     bool getDetectProblems() const {return useProblemDetection;}
01176 
01177     /** Loops through all plannable objects and updates their problems if
01178       * required. */
01179     static DECLARE_EXPORT void computeProblems();
01180 
01181     /** See if this entity has changed since the last problem
01182       * problem detection run. */
01183     bool getChanged() const {return changed;}
01184 
01185     /** Mark that this entity has been updated and that the problem
01186       * detection needs to be redone. */
01187     void setChanged(bool b = true) {changed=b; if (b) anyChange=true;}
01188 
01189     /** Implement the pure virtual function from the HasProblem class. */
01190     Plannable* getEntity() const {return const_cast<Plannable*>(this);}
01191 
01192     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01193     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01194 
01195   private:
01196     /** Stores whether this entity should be skip problem detection, or not. */
01197     bool useProblemDetection;
01198 
01199     /** Stores whether this entity has been updated since the last problem
01200       * detection run. */
01201     bool changed;
01202 
01203     /** Marks whether any entity at all has changed its status since the last
01204       * problem detection round.
01205       */
01206     static DECLARE_EXPORT bool anyChange;
01207 
01208     /** This flag is set to true during the problem recomputation. It is
01209       * required to garantuee safe access to the problems in a multi-threaded
01210       * environment.
01211       */
01212     static DECLARE_EXPORT bool computationBusy;
01213 };
01214 
01215 
01216 /** @brief The purpose of this class is to compute the levels of all buffers,
01217   * operations and resources in the model, and to categorize them in clusters.
01218   *
01219   * Resources and buffers linked to the delivery operations of
01220   * the demand are assigned level 1. buffers one level upstream have
01221   * level 2, and so on...
01222   *
01223   * A cluster is group of planning entities (buffers, resources and operations)
01224   * that are linked together using loads and/or flows. Each cluster can be seen
01225   * as a completely independent part of the model and the planning problem.
01226   * There is no interaction possible between clusters.
01227   * Clusters are helpful is multi-threading the planning problem, partial
01228   * replanning of the model, etc...
01229   */
01230 class HasLevel
01231 {
01232 
01233 #if defined(_MSC_VER) || defined(__BORLANDC__)
01234     // Visual C++ 6.0 and Borland C++ 5.5. seem to get confused. Static
01235     // functions can't access private members.
01236     friend class HasLevel;
01237 #endif
01238 
01239   private:
01240     /** Flags whether the current computation is still up to date or not.
01241       * The flag is set when new objects of this are created or updated.
01242       * Running the computeLevels function clears the flag.
01243       */
01244     static DECLARE_EXPORT bool recomputeLevels;
01245 
01246     /** This flag is set to true during the computation of the levels. It is
01247       * required to ensure safe access to the level information in a
01248       * multi-threaded environment.
01249       */
01250     static DECLARE_EXPORT bool computationBusy;
01251 
01252     /** Stores the total number of clusters in the model. */
01253     static DECLARE_EXPORT unsigned short numberOfClusters;
01254 
01255     /** Stores the total number of hanging clusters in the model. */
01256     static DECLARE_EXPORT unsigned short numberOfHangingClusters;
01257 
01258     /** Stores the level of this entity. Higher numbers indicate more
01259       * upstream entities.
01260       * A value of -1 indicates an unused entity.
01261       */
01262     short lvl;
01263 
01264     /** Stores the cluster number of the current entity. */
01265     unsigned short cluster;
01266 
01267   protected:
01268     /** Default constructor. The initial level is -1 and basically indicates
01269       * that this HasHierarchy (either Operation, Buffer or Resource) is not
01270       * being used at all...
01271       */
01272     HasLevel() : lvl(0), cluster(0) {}
01273 
01274     /** Copy constructor. Since the characterictics of the new object are the
01275       * same as the original, the level and cluster are also the same.
01276       * No recomputation is required.
01277       */
01278     HasLevel(const HasLevel& o) : lvl(o.lvl), cluster(o.cluster) {}
01279 
01280     /** Destructor. Deleting a HasLevel object triggers recomputation of the
01281       * level and cluster computation, since the network now has changed.
01282       */
01283     ~HasLevel() {recomputeLevels = true;}
01284 
01285     /** This function recomputes all levels in the model.
01286       * It is called automatically when the getLevel or getCluster() function
01287       * on a Buffer, Resource or Operation are called while the
01288       * "recomputeLevels" flag is set.
01289       * Right, this is an example of a 'lazy' algorithm: only compute the
01290       * information when it is required. Note however that the computation
01291       * is triggered over the complete model, not a subset...
01292       * The runtime of the algorithm is pretty much linear with the total
01293       * number of operations in the model. The cluster size also has some
01294       * (limited) impact on the performance: a network with larger cluster
01295       * size will take longer to analyze.
01296       * @exception LogicException Generated when there are too many clusters in
01297       *     your model. The maximum limit is USHRT_MAX, i.e. the greatest
01298       *     number that can be stored in a variable of type "unsigned short".
01299       *     The limit is platform dependent. On 32-bit platforms it will
01300       *     typically be 65535.
01301       */
01302     static DECLARE_EXPORT void computeLevels();
01303 
01304   public:
01305     /** Returns the total number of clusters.<br>
01306       * If not up to date the recomputation will be triggered.
01307       */
01308     static unsigned short getNumberOfClusters()
01309     {
01310       if (recomputeLevels || computationBusy) computeLevels();
01311       return numberOfClusters;
01312     }
01313 
01314     /** Returns the total number of hanging clusters. A hanging cluster
01315       * is a cluster that consists of a single entity that isn't connected
01316       * to any other entity.<br>
01317       * If not up to date the recomputation will be triggered.
01318       */
01319     static unsigned short getNumberOfHangingClusters()
01320     {
01321       if (recomputeLevels || computationBusy) computeLevels();
01322       return numberOfHangingClusters;
01323     }
01324 
01325     /** Return the level (and recompute first if required). */
01326     short getLevel() const
01327     {
01328       if (recomputeLevels || computationBusy) computeLevels();
01329       return lvl;
01330     }
01331 
01332     /** Return the cluster number (and recompute first if required). */
01333     unsigned short getCluster() const
01334     {
01335       if (recomputeLevels || computationBusy) computeLevels();
01336       return cluster;
01337     }
01338 
01339     /** This function should be called when something is changed in the network
01340       * structure. The notification sets a flag, but does not immediately
01341       * trigger the recomputation.
01342       * @see computeLevels
01343       */
01344     static void triggerLazyRecomputation() {recomputeLevels = true;}
01345 };
01346 
01347 
01348 /** @brief This abstract class is used to associate buffers and resources with
01349   * a physical or logical location.
01350   *
01351   * The 'available' calendar is used to model the working hours and holidays
01352   * of resources, buffers and operations.
01353   */
01354 class Location : public HasHierarchy<Location>, public HasDescription
01355 {
01356   public:
01357     /** Constructor. */
01358     explicit Location(const string& n) : HasHierarchy<Location>(n), available(NULL) {}
01359 
01360     /** Destructor. */
01361     virtual DECLARE_EXPORT ~Location();
01362 
01363     /** Returns the availability calendar of the location.<br>
01364       * The availability calendar models the working hours and holidays. It
01365       * applies to all operations, resources and buffers using this location.
01366       */
01367     CalendarBool *getAvailable() const {return available;}
01368 
01369     /** Updates the availability calend of the location. */
01370     void setAvailable(CalendarBool* b) {available = b;}
01371 
01372     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01373     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
01374     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01375     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
01376     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
01377     size_t extrasize() const
01378     {return getName().size() + HasDescription::extrasize();}
01379     virtual const MetaClass& getType() const {return *metadata;}
01380     static DECLARE_EXPORT const MetaCategory* metadata;
01381     static int initialize();
01382 
01383   private:
01384     /** The availability calendar models the working hours and holidays. It
01385       * applies to all operations, resources and buffers using this location.
01386       */
01387     CalendarBool* available;
01388 };
01389 
01390 
01391 /** @brief This class implements the abstract Location class. */
01392 class LocationDefault : public Location
01393 {
01394   public:
01395     explicit LocationDefault(const string& str) : Location(str) {initType(metadata);}
01396     virtual const MetaClass& getType() const {return *metadata;}
01397     static DECLARE_EXPORT const MetaClass* metadata;
01398     virtual size_t getSize() const
01399     {return sizeof(LocationDefault) + Location::extrasize();}
01400     static int initialize();
01401 };
01402 
01403 
01404 /** @brief This abstracts class represents customers.
01405   *
01406   * Demands can be associated with a customer, but there is no planning
01407   * behavior directly linked to customers.
01408   */
01409 class Customer : public HasHierarchy<Customer>, public HasDescription
01410 {
01411   public:
01412     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01413     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
01414     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01415     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
01416     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
01417     size_t extrasize() const
01418     {return getName().size() + HasDescription::extrasize();}
01419     Customer(const string& n) : HasHierarchy<Customer>(n) {}
01420     virtual DECLARE_EXPORT ~Customer();
01421     virtual const MetaClass& getType() const {return *metadata;}
01422     static DECLARE_EXPORT const MetaCategory* metadata;
01423     static int initialize();
01424 };
01425 
01426 
01427 /** @brief This class implements the abstract Customer class. */
01428 class CustomerDefault : public Customer
01429 {
01430   public:
01431     explicit CustomerDefault(const string& str) : Customer(str) {initType(metadata);}
01432     virtual const MetaClass& getType() const {return *metadata;}
01433     static DECLARE_EXPORT const MetaClass* metadata;
01434     virtual size_t getSize() const
01435     {return sizeof(CustomerDefault) + Customer::extrasize();}
01436     static int initialize();
01437 };
01438 
01439 
01440 /** @brief An operation represents an activity: these consume and produce material,
01441   * take time and also require capacity.
01442   *
01443   * An operation consumes and produces material, modeled through flows.<br>
01444   * An operation requires capacity, modeled through loads.
01445   *
01446   * This is an abstract base class for all different operation types.
01447   */
01448 class Operation : public HasName<Operation>,
01449       public HasLevel, public Plannable, public HasDescription
01450 {
01451     friend class Flow;
01452     friend class Load;
01453     friend class OperationPlan;
01454     friend class OperationRouting;   
01455     friend class OperationAlternate; 
01456 
01457   protected:
01458     /** Constructor. Don't use it directly. */
01459     explicit Operation(const string& str) : HasName<Operation>(str),
01460       loc(NULL), size_minimum(1.0), size_multiple(0.0), size_maximum(DBL_MAX),
01461       cost(0.0), hidden(false), first_opplan(NULL), last_opplan(NULL) {}
01462 
01463     /** Extra logic called when instantiating an operationplan.<br>
01464       * When the function returns false the creation of the operationplan
01465       * is denied and it is deleted.
01466       */
01467     virtual bool extraInstantiate(OperationPlan* o) {return true;}
01468 
01469   public:
01470     /** Destructor. */
01471     virtual DECLARE_EXPORT ~Operation();
01472 
01473     /** Returns a pointer to the operationplan being instantiated. */
01474     OperationPlan* getFirstOpPlan() const {return first_opplan;}
01475 
01476     /** Returns the delay before this operation.
01477       * @see setPreTime
01478       */
01479     TimePeriod getPreTime() const {return pre_time;}
01480 
01481     /** Updates the delay before this operation.<br>
01482       * This delay is a soft constraint. This means that solvers should try to
01483       * respect this waiting time but can choose to leave a shorter time delay
01484       * if required.<br>
01485       * @see setPostTime
01486       */
01487     void setPreTime(TimePeriod t)
01488     {
01489       if (t<TimePeriod(0L))
01490         throw DataException("No negative pre-operation time allowed");
01491       pre_time=t;
01492       setChanged();
01493     }
01494 
01495     /** Returns the delay after this operation.
01496       * @see setPostTime
01497       */
01498     TimePeriod getPostTime() const {return post_time;}
01499 
01500     /** Updates the delay after this operation.<br>
01501       * This delay is a soft constraint. This means that solvers should try to
01502       * respect this waiting time but can choose to leave a shorter time delay
01503       * if required.
01504       * @see setPreTime
01505       */
01506     void setPostTime(TimePeriod t)
01507     {
01508       if (t<TimePeriod(0L))
01509         throw DataException("No negative post-operation time allowed");
01510       post_time=t;
01511       setChanged();
01512     }
01513 
01514     /** Return the operation cost.<br>
01515       * The cost of executing this operation, per unit of the
01516       * operation_plan.<br>
01517       * The default value is 0.0.
01518       */
01519     double getCost() const {return cost;}
01520 
01521     /** Update the operation cost.<br>
01522       * The cost of executing this operation, per unit of the operation_plan.
01523       */
01524     void setCost(const double c)
01525     {
01526       if (c >= 0) cost = c;
01527       else throw DataException("Operation cost must be positive");
01528     }
01529 
01530     typedef Association<Operation,Buffer,Flow>::ListA flowlist;
01531     typedef Association<Operation,Resource,Load>::ListA  loadlist;
01532 
01533     /** This is the factory method which creates all operationplans of the
01534       * operation. */
01535     DECLARE_EXPORT OperationPlan* createOperationPlan(double, Date,
01536       Date, Demand* = NULL, OperationPlan* = NULL, unsigned long = 0,
01537       bool makeflowsloads=true) const;
01538 
01539     /** Calculates the daterange starting from (or ending at) a certain date
01540       * and using a certain amount of effective available time on the
01541       * operation.
01542       *
01543       * This calculation considers the availability calendars of:
01544       * - the availability calendar of the operation's location
01545       * - the availability calendar of all resources loaded by the operation @todo not implemented yet
01546       * - the availability calendar of the locations of all resources loaded @todo not implemented yet
01547       *   by the operation
01548       *
01549       * @param[in] thedate  The date from which to start searching.
01550       * @param[in] duration The amount of available time we are looking for.
01551       * @param[in] forward  The search direction
01552       * @param[out] actualduration This variable is updated with the actual
01553       *             amount of available time found.
01554       */
01555     DECLARE_EXPORT DateRange calculateOperationTime
01556       (Date thedate, TimePeriod duration, bool forward,
01557         TimePeriod* actualduration = NULL) const;
01558 
01559     /** Calculates the effective, available time between two dates.
01560       *
01561       * This calculation considers the availability calendars of:
01562       * - the availability calendar of the operation's location
01563       * - the availability calendar of all resources loaded by the operation @todo not implemented yet
01564       * - the availability calendar of the locations of all resources loaded @todo not implemented yet
01565       *   by the operation
01566       *
01567       * @param[in] start  The date from which to start searching.
01568       * @param[in] end    The date where to stop searching.
01569       * @param[out] actualduration This variable is updated with the actual
01570       *             amount of available time found.
01571       */
01572     DECLARE_EXPORT DateRange calculateOperationTime
01573       (Date start, Date end, TimePeriod* actualduration = NULL) const;
01574 
01575     /** This method stores ALL logic the operation needs to compute the
01576       * correct relationship between the quantity, startdate and enddate
01577       * of an operationplan.
01578       *
01579       * The parameters "startdate", "enddate" and "quantity" can be
01580       * conflicting if all are specified together.
01581       * Typically, one would use one of the following combinations:
01582       *  - specify quantity and start date, and let the operation compute the
01583       *    end date.
01584       *  - specify quantity and end date, and let the operation compute the
01585       *    start date.
01586       *  - specify both the start and end date, and let the operation compute
01587       *    the quantity.
01588       *  - specify quantity, start and end date. In this case, you need to
01589       *    be aware that the operationplan that is created can be different
01590       *    from the parameters you requested.
01591       *
01592       * The following priority rules apply upon conflicts.
01593       *  - respecting the end date has the first priority.
01594       *  - respecting the start date has second priority.
01595       *  - respecting the quantity should be done if the specified dates can
01596       *    be respected.
01597       *  - if the quantity is being computed to meet the specified dates, the
01598       *    quantity being passed as argument is to be treated as a maximum
01599       *    limit. The created operationplan can have a smaller quantity, but
01600       *    not bigger...
01601       *  - at all times, we expect to have an operationplan that is respecting
01602       *    the constraints set by the operation. If required, some of the
01603       *    specified parameters may need to be violated. In case of such a
01604       *    violation we expect the operationplan quantity to be 0.
01605       *
01606       * The pre- and post-operation times are NOT considered in this method.
01607       * This method only enforces "hard" constraints. "Soft" constraints are
01608       * considered as 'hints' by the solver.
01609       *
01610       * Subclasses need to override this method to implement the correct
01611       * logic.
01612       */
01613     virtual OperationPlanState setOperationPlanParameters
01614       (OperationPlan*, double, Date, Date, bool=true, bool=true) const = 0;
01615 
01616     /** Returns the location of the operation, which is used to model the
01617       * working hours and holidays. */
01618     Location* getLocation() const {return loc;}
01619 
01620     /** Updates the location of the operation, which is used to model the
01621       * working hours and holidays. */
01622     void setLocation(Location* l) {loc = l;}
01623 
01624     /** Returns an reference to the list of flows. */
01625     const flowlist& getFlows() const {return flowdata;}
01626 
01627     /** Returns an reference to the list of flows. */
01628     const loadlist& getLoads() const {return loaddata;}
01629 
01630     /** Return the flow that is associates a given buffer with this
01631       * operation. Returns NULL is no such flow exists. */
01632     Flow* findFlow(const Buffer* b, Date d) const
01633     {return flowdata.find(b,d);}
01634 
01635     /** Return the load that is associates a given resource with this
01636       * operation. Returns NULL is no such load exists. */
01637     Load* findLoad(const Resource* r, Date d) const
01638     {return loaddata.find(r,d);}
01639 
01640     /** Deletes all operationplans of this operation. The boolean parameter
01641       * controls whether we delete also locked operationplans or not.
01642       */
01643     DECLARE_EXPORT void deleteOperationPlans(bool deleteLockedOpplans = false);
01644 
01645     /** Sets the minimum size of operationplans.<br>
01646       * The default value is 1.0
01647       */
01648     void setSizeMinimum(double f)
01649     {
01650       if (f<0)
01651         throw DataException("Operation can't have a negative minimum size");
01652       size_minimum = f;
01653       setChanged();
01654     }
01655 
01656     /** Returns the minimum size for operationplans. */
01657     double getSizeMinimum() const {return size_minimum;}
01658 
01659     /** Sets the multiple size of operationplans. */
01660     void setSizeMultiple(double f)
01661     {
01662       if (f<0)
01663         throw DataException("Operation can't have a negative multiple size");
01664       size_multiple = f;
01665       setChanged();
01666     }
01667 
01668     /** Returns the mutiple size for operationplans. */
01669     double getSizeMultiple() const {return size_multiple;}
01670 
01671     /** Sets the maximum size of operationplans. */
01672     void setSizeMaximum(double f)
01673     {
01674       if (f < size_minimum)
01675         throw DataException("Operation maximum size must be higher than the minimum size");
01676       if (f <= 0)
01677         throw DataException("Operation maximum size must be greater than 0");
01678       size_maximum = f;
01679       setChanged();
01680     }
01681 
01682     /** Returns the maximum size for operationplans. */
01683     double getSizeMaximum() const {return size_maximum;}
01684 
01685     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
01686     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
01687     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
01688     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
01689     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
01690     static int initialize();
01691 
01692     size_t extrasize() const
01693     {return getName().size() + HasDescription::extrasize();}
01694 
01695     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
01696 
01697     typedef list<Operation*> Operationlist;
01698 
01699     /** Returns a reference to the list of sub operations of this operation. */
01700     virtual const Operationlist& getSubOperations() const {return nosubOperations;}
01701 
01702     /** Returns a reference to the list of super-operations, i.e. operations
01703       * using the current Operation as a sub-Operation.
01704       */
01705     const Operationlist& getSuperOperations() const {return superoplist;}
01706 
01707     /** Register a super-operation, i.e. an operation having this one as a
01708       * sub-operation. */
01709     void addSuperOperation(Operation * o) {superoplist.push_front(o);}
01710 
01711     /** Removes a sub-operation from the list. This method will need to be
01712       * overridden by all operation types that acts as a super-operation. */
01713     virtual void removeSubOperation(Operation *o) {}
01714 
01715     /** Removes a super-operation from the list. */
01716     void removeSuperOperation(Operation *o)
01717     {superoplist.remove(o); o->removeSubOperation(this);}
01718 
01719     /** Return the release fence of this operation. */
01720     TimePeriod getFence() const {return fence;}
01721 
01722     /** Update the release fence of this operation. */
01723     void setFence(TimePeriod t) {if (fence!=t) setChanged(); fence=t;}
01724 
01725     virtual DECLARE_EXPORT void updateProblems();
01726 
01727     void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
01728     bool getHidden() const {return hidden;}
01729 
01730     static DECLARE_EXPORT const MetaCategory* metadata;
01731 
01732   protected:
01733     DECLARE_EXPORT void initOperationPlan(OperationPlan*, double,
01734         const Date&, const Date&, Demand*, OperationPlan*, unsigned long,
01735         bool = true) const;
01736 
01737   private:
01738     /** List of operations using this operation as a sub-operation */
01739     Operationlist superoplist;
01740 
01741     /** Empty list of operations.<br>
01742       * For operation types which have no suboperations this list is 
01743       * used as the list of suboperations.
01744       */
01745     static DECLARE_EXPORT Operationlist nosubOperations;
01746 
01747     /** Location of the operation.<br>
01748       * The location is used to model the working hours and holidays.
01749       */
01750     Location* loc;
01751 
01752     /** Represents the time between this operation and a next one. */
01753     TimePeriod post_time;
01754 
01755     /** Represents the time between this operation and a previous one. */
01756     TimePeriod pre_time;
01757 
01758     /** Represents the release fence of this operation, i.e. a period of time
01759       * (relative to the current date of the plan) in which normally no
01760       * operationplan is allowed to be created.
01761       */
01762     TimePeriod fence;
01763 
01764     /** Singly linked list of all flows of this operation. */
01765     flowlist flowdata;
01766 
01767     /** Singly linked list of all resources Loaded by this operation. */
01768     loadlist loaddata;
01769 
01770     /** Minimum size for operationplans.<br>
01771       * The default value is 1.0
01772       */
01773     double size_minimum;
01774 
01775     /** Multiple size for operationplans. */
01776     double size_multiple;
01777 
01778     /** Maximum size for operationplans. */
01779     double size_maximum;
01780 
01781     /** Cost of the operation.<br>
01782       * The default value is 0.0.
01783       */
01784     double cost;
01785 
01786     /** Does the operation require serialization or not. */
01787     bool hidden;
01788 
01789     /** A pointer to the first operationplan of this operation.<br>
01790       * All operationplans of this operation are stored in a sorted
01791       * doubly linked list.
01792       */
01793     OperationPlan* first_opplan;
01794 
01795     /** A pointer to the last operationplan of this operation.<br>
01796       * All operationplans of this operation are stored in a sorted
01797       * doubly linked list.
01798       */
01799     OperationPlan* last_opplan;
01800 };
01801 
01802 
01803 /** @brief An operationplan is the key dynamic element of a plan. It
01804   * represents a certain quantity being planned along a certain operation
01805   * during a certain date range.
01806   *
01807   * From a coding perspective:
01808   *  - Operationplans are created by the factory method createOperationPlan()
01809   *    on the matching operation class.
01810   *  - The createLoadAndFlowplans() can optionally be called to also create
01811   *    the loadplans and flowplans, to take care of the material and
01812   *    capacity consumption.
01813   *  - Once you're sure about creating the operationplan, the instantiate()
01814   *    method should be called. It will assign the operationplan a unique
01815   *    numeric identifier, register the operationplan in a container owned
01816   *    by the operation instance, and also create loadplans and flowplans
01817   *    if this hasn't been done yet.<br>
01818   *  - Operationplans can be organized in hierarchical structure, matching
01819   *    the operation hierarchies they belong to.
01820   *
01821   * @TODO reading suboperationplans can be improved
01822   */
01823 class OperationPlan
01824       : public Object, public HasProblems, public NonCopyable
01825 {
01826     friend class FlowPlan;
01827     friend class LoadPlan;
01828     friend class Demand;
01829     friend class Operation;
01830     friend class OperationAlternate;
01831     friend class OperationRouting;
01832     friend class ProblemPrecedence;
01833 
01834   public:
01835     class FlowPlanIterator;
01836 
01837     /** Returns an iterator pointing to the first flowplan. */
01838     FlowPlanIterator beginFlowPlans() const;
01839 
01840     /** Returns an iterator pointing beyond the last flowplan. */
01841     FlowPlanIterator endFlowPlans() const;
01842 
01843     /** Returns how many flowplans are created on an operationplan. */
01844     int sizeFlowPlans() const;
01845 
01846     class LoadPlanIterator;
01847 
01848     /** Returns an iterator pointing to the first loadplan. */
01849     LoadPlanIterator beginLoadPlans() const;
01850 
01851     /** Returns an iterator pointing beyond the last loadplan. */
01852     LoadPlanIterator endLoadPlans() const;
01853 
01854     /** Returns how many loadplans are created on an operationplan. */
01855     int sizeLoadPlans() const;
01856 
01857     /** @brief This class models an STL-like iterator that allows us to iterate over
01858       * the operationplans in a simple and safe way.
01859       *
01860       * Objects of this class are created by the begin() and end() functions.
01861       */
01862     class iterator
01863     {
01864       public:
01865         /** Constructor. The iterator will loop only over the operationplans
01866           * of the operation passed. */
01867         iterator(const Operation* x) : op(Operation::end()), mode(1)
01868         {
01869           opplan = x ? x->getFirstOpPlan() : NULL;
01870         }
01871 
01872         /** Constructor. The iterator will loop only over the suboperationplans
01873           * of the operationplan passed. */
01874         iterator(const OperationPlan* x) : op(Operation::end()), mode(2)
01875         {
01876           opplan = x ? x->firstsubopplan : NULL;
01877         }
01878 
01879         /** Constructor. The iterator will loop over all operationplans. */
01880         iterator() : op(Operation::begin()), mode(3)
01881         {
01882           // The while loop is required since the first operation might not
01883           // have any operationplans at all
01884           while (op!=Operation::end() && !op->getFirstOpPlan()) ++op;
01885           if (op!=Operation::end())
01886             opplan = op->getFirstOpPlan();
01887           else
01888             opplan = NULL;
01889         }
01890 
01891         /** Copy constructor. */
01892         iterator(const iterator& it) : opplan(it.opplan), op(it.op), mode(it.mode) {}
01893 
01894         /** Return the content of the current node. */
01895         OperationPlan& operator*() const {return *opplan;}
01896 
01897         /** Return the content of the current node. */
01898         OperationPlan* operator->() const {return opplan;}
01899 
01900         /** Pre-increment operator which moves the pointer to the next
01901           * element. */
01902         iterator& operator++()
01903         {
01904           if (mode == 2)
01905             opplan = opplan->nextsubopplan;
01906           else
01907             opplan = opplan->next;
01908           // Move to a new operation
01909           if (!opplan && mode == 3)
01910           {
01911             do ++op;
01912             while (op!=Operation::end() && (!op->getFirstOpPlan() || op->getHidden()));
01913             if (op!=Operation::end())
01914               opplan = op->getFirstOpPlan();
01915             else
01916               opplan = NULL;
01917           }
01918           return *this;
01919         }
01920 
01921         /** Post-increment operator which moves the pointer to the next
01922           * element. */
01923         iterator operator++(int)
01924         {
01925           iterator tmp(*this);
01926           if (mode == 2)
01927             opplan = opplan->nextsubopplan;
01928           else
01929             opplan = opplan->next;
01930           // Move to a new operation
01931           if (!opplan && mode==3)
01932           {
01933             do ++op; while (op!=Operation::end() && !op->getFirstOpPlan());
01934             if (op!=Operation::end())
01935               opplan = op->getFirstOpPlan();
01936             else
01937               opplan = NULL;
01938           }
01939           return tmp;
01940         }
01941 
01942         /** Comparison operator. */
01943         bool operator==(const iterator& y) const {return opplan == y.opplan;}
01944 
01945         /** Inequality operator. */
01946         bool operator!=(const iterator& y) const {return opplan != y.opplan;}
01947 
01948       private:
01949         /** A pointer to current operationplan. */
01950         OperationPlan* opplan;
01951 
01952         /** An iterator over the operations. */
01953         Operation::iterator op;
01954 
01955         /** Describes the type of iterator.<br>
01956           * 1) iterate over operationplan instances of operation
01957           * 2) iterate over suboperationplans of an operationplan
01958           * 3) iterate over all operationplans
01959           */
01960         short mode;
01961     };
01962 
01963     friend class iterator;
01964 
01965     static iterator end() {return iterator(static_cast<Operation*>(NULL));}
01966 
01967     static iterator begin() {return iterator();}
01968 
01969     /** Returns true when not a single operationplan object exists. */
01970     static bool empty() {return begin()==end();}
01971 
01972     /** Returns the number of operationplans in the system. This method
01973       * is linear with the number of operationplans in the model, and should
01974       * therefore be used only with care.
01975       */
01976     static unsigned long size()
01977     {
01978       unsigned long cnt = 0;
01979       for (OperationPlan::iterator i = begin(); i != end(); ++i) ++cnt;
01980       return cnt;
01981     }
01982 
01983     /** This is a factory method that creates an operationplan pointer based
01984       * on the name and id, which are passed as an array of character pointers.
01985       * This method is intended to be used to create objects when reading
01986       * XML input data.
01987       */
01988     static DECLARE_EXPORT Object* createOperationPlan(const MetaClass*, const AttributeList&);
01989 
01990     /** Destructor. */
01991     virtual DECLARE_EXPORT ~OperationPlan();
01992 
01993     virtual DECLARE_EXPORT void setChanged(bool b = true);
01994 
01995     /** Returns the quantity. */
01996     double getQuantity() const {return quantity;}
01997 
01998     /** Updates the quantity.<br>
01999       * The operationplan quantity is subject to the following rules:
02000       *  - The quantity must be greater than or equal to the minimum size.<br>
02001       *    The value is rounded up to the smallest multiple above the minimum
02002       *    size if required, or rounded down to 0.
02003       *  - The quantity must be a multiple of the multiple_size field.<br>
02004       *    The value is rounded up or down to meet this constraint.
02005       *  - The quantity must be smaller than or equal to the maximum size.<br>
02006       *    The value is limited to the smallest multiple below this limit.
02007       *  - Setting the quantity of an operationplan to 0 is always possible,
02008       *    regardless of the minimum, multiple and maximum values.
02009       * This method can only be called on top operationplans. Sub operation
02010       * plans should pass on a call to the parent operationplan.
02011       */
02012     virtual DECLARE_EXPORT double setQuantity(double f,
02013       bool roundDown = false, bool update = true, bool execute = true);
02014 
02015     /** Returns a pointer to the demand for which this operation is a delivery.
02016       * If the operationplan isn't a delivery operation, this is a NULL pointer.
02017       */
02018     Demand* getDemand() const {return dmd;}
02019 
02020     /** Updates the demand to which this operationplan is a solution. */
02021     DECLARE_EXPORT void setDemand(Demand* l);
02022 
02023     /** Calculate the penalty of an operationplan. */
02024     DECLARE_EXPORT double getPenalty() const;
02025 
02026     /** Calculate the unavailable time during the operationplan. The regular 
02027       * duration is extended with this amount.
02028       */
02029     DECLARE_EXPORT TimePeriod getUnavailable() const;
02030 
02031     /** Returns whether the operationplan is locked. A locked operationplan
02032       * is never changed.
02033       */
02034     bool getLocked() const {return flags & IS_LOCKED;}
02035 
02036     /** Deletes all operationplans of a certain operation. A boolean flag
02037       * allows to specify whether locked operationplans are to be deleted too.
02038       */
02039     static DECLARE_EXPORT void deleteOperationPlans(Operation* o, bool deleteLocked=false);
02040 
02041     /** Locks/unlocks an operationplan. A locked operationplan is never
02042       * changed.
02043       */
02044     virtual DECLARE_EXPORT void setLocked(bool b = true);
02045 
02046     /** Returns a pointer to the operation being instantiated. */
02047     Operation* getOperation() const {return oper;}
02048 
02049     /** Fixes the start and end date of an operationplan. Note that this
02050       * overrules the standard duration given on the operation, i.e. no logic
02051       * kicks in to verify the data makes sense. This is up to the user to
02052       * take care of.<br>
02053       * The methods setStart(Date) and setEnd(Date) are therefore preferred
02054       * since they properly apply all appropriate logic.
02055       */
02056     void setStartAndEnd(Date st, Date nd)
02057     {
02058       dates.setStartAndEnd(st,nd);
02059       update();
02060     }
02061 
02062     /** A method to restore a previous state of an operationplan.<br>
02063       * NO validity checks are done on the parameters.
02064       */
02065     void restore(const OperationPlanState& x);
02066 
02067     /** Updates the operationplan owning this operationplan. In case of
02068       * a OperationRouting steps this will be the operationplan representing the
02069       * complete routing. */
02070     void DECLARE_EXPORT setOwner(OperationPlan* o);
02071 
02072     /** Returns a pointer to the operationplan for which this operationplan
02073       * a sub-operationplan.<br>
02074       * The method returns NULL if there is no owner defined.<br>
02075       * E.g. Sub-operationplans of a routing refer to the overall routing
02076       * operationplan.<br>
02077       * E.g. An alternate sub-operationplan refers to its parent.
02078       * @see getTopOwner
02079       */
02080     OperationPlan* getOwner() const {return owner;}
02081 
02082     /** Returns a pointer to the operationplan owning a set of
02083       * sub-operationplans. There can be multiple levels of suboperations.<br>
02084       * If no owner exists the method returns the current operationplan.
02085       * @see getOwner
02086       */
02087     const OperationPlan* getTopOwner() const
02088     {
02089       if (owner)
02090       {
02091         // There is an owner indeed
02092         OperationPlan* o(owner);
02093         while (o->owner) o = o->owner;
02094         return o;
02095       }
02096       else
02097         // This operationplan is itself the top of a hierarchy
02098         return this;
02099     }
02100 
02101     /** Returns the start and end date of this operationplan. */
02102     const DateRange & getDates() const {return dates;}
02103 
02104     /** Returns a unique identifier of the operationplan.<br>
02105       * The identifier can be specified in the data input (in which case
02106       * we check for the uniqueness during the read operation).<br>
02107       * For operationplans created during a solver run, the identifier is
02108       * assigned in the instantiate() function. The numbering starts with the
02109       * highest identifier read in from the input and is then incremented
02110       * for every operationplan that is registered.
02111       */
02112     unsigned long getIdentifier() const {return id;}
02113 
02114     /** Updates the end date of the operationplan and compute the start
02115       * date.<br>
02116       * Locked operationplans are not updated by this function.<br>
02117       * Slack can be introduced between sub operationaplans by this method,
02118       * i.e. the sub operationplans are only moved if required to meet the
02119       * end date.
02120       */
02121     virtual DECLARE_EXPORT void setEnd(Date);
02122 
02123     /** Updates the start date of the operationplan and compute the end
02124       * date.<br>
02125       * Locked operation_plans are not updated by this function.<br>
02126       * Slack can be introduced between sub operationaplans by this method,
02127       * i.e. the sub operationplans are only moved if required to meet the
02128       * start date.
02129       */
02130     virtual DECLARE_EXPORT void setStart(Date);
02131 
02132     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02133     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02134     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02135     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02136     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02137     static int initialize();
02138 
02139     PyObject* str() const
02140     {          
02141       ostringstream ch;
02142       ch << id;
02143       return PythonObject(ch.str());
02144     }
02145 
02146     static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
02147 
02148     /** Initialize the operationplan. The initialization function should be
02149       * called when the operationplan is ready to be 'officially' added. The
02150       * initialization performs the following actions:
02151       * <ol>
02152       * <li> assign an identifier</li>
02153       * <li> create the flow and loadplans if these hadn't been created
02154       * before</li>
02155       * <li> add the operationplan to the global list of operationplans</li>
02156       * <li> create a link with a demand object if this is a delivery
02157       * operationplan</li>
02158       * </ol>
02159       * Every operationplan subclass that has sub-operations will normally
02160       * need to create an override of this function.<br>
02161       *
02162       * The return value indicates whether the initialization was successfull.
02163       * If the operationplan is invalid, it will be DELETED and the return value
02164       * is 'false'.
02165       */
02166     virtual DECLARE_EXPORT bool instantiate();
02167 
02168     /** This method links the operationplan in the list of all operationplans
02169       * maintained on the operation.<br>
02170       * In most cases calling this method is not required since it included
02171       * in the instantiate method. In exceptional cases the solver already
02172       * needs to see uncommitted operationplans in the list - eg for the
02173       * procurement buffer.
02174       * @see instantiate
02175       */
02176     DECLARE_EXPORT void insertInOperationplanList();
02177 
02178     /** Add a sub-operationplan to the list. */
02179     virtual DECLARE_EXPORT void addSubOperationPlan(OperationPlan*);
02180 
02181     /** Remove a sub-operation_plan from the list. */
02182     virtual DECLARE_EXPORT void eraseSubOperationPlan(OperationPlan*);
02183 
02184     /** This function is used to create the proper loadplan and flowplan
02185       * objects associated with the operation. */
02186     DECLARE_EXPORT void createFlowLoads();
02187 
02188     bool getHidden() const {return getOperation()->getHidden();}
02189 
02190     /** Searches for an OperationPlan with a given identifier.<br>
02191       * Returns a NULL pointer if no such OperationPlan can be found.<br>
02192       * The method is of complexity O(n), i.e. involves a LINEAR search through
02193       * the existing operationplans, and can thus be quite slow in big models.<br>
02194       * The method is O(1), i.e. constant time regardless of the model size,
02195       * when the parameter passed is bigger than the operationplan counter.
02196       */
02197     static DECLARE_EXPORT OperationPlan* findId(unsigned long l);
02198 
02199     /** Problem detection is actually done by the Operation class. That class
02200       * actually "delegates" the responsability to this class, for efficiency.
02201       */
02202     virtual void updateProblems();
02203 
02204     /** Implement the pure virtual function from the HasProblem class. */
02205     Plannable* getEntity() const {return oper;}
02206 
02207     /** Return the metadata. We return the metadata of the operation class,
02208       * not the one of the operationplan class!
02209       */
02210     const MetaClass& getType() const {return *metadata;}
02211 
02212     static DECLARE_EXPORT const MetaClass* metadata;
02213 
02214     static DECLARE_EXPORT const MetaCategory* metacategory;
02215 
02216     virtual size_t getSize() const
02217       {return sizeof(OperationPlan);}
02218 
02219     /** Handles the persistence of operationplan objects. */
02220     static DECLARE_EXPORT void writer(const MetaCategory*, XMLOutput*);
02221 
02222     /** Comparison of 2 OperationPlans.
02223       * To garantuee that the problems are sorted in a consistent and stable
02224       * way, the following sorting criteria are used (in order of priority):
02225       * <ol><li>Operation</li>
02226       * <li>Start date (earliest dates first)</li>
02227       * <li>Quantity (biggest quantities first)</li></ol>
02228       * Multiple operationplans for the same values of the above keys can exist.
02229       */
02230     DECLARE_EXPORT bool operator < (const OperationPlan& a) const;
02231 
02232   private:
02233     /** Updates the operationplan based on the latest information of quantity,
02234       * date and locked flag.<br>
02235       * This method will also update parent and child operationplans.
02236       * @see resizeFlowLoadPlans
02237       */
02238     virtual DECLARE_EXPORT void update();
02239 
02240     /** Update the loadplans and flowplans of the operationplan based on the 
02241       * latest information of quantity, date and locked flag.<br>
02242       * This method will NOT update parent or child operationplans. 
02243       * @see update
02244       */
02245     DECLARE_EXPORT void resizeFlowLoadPlans();
02246 
02247     /** Pointer to a higher level OperationPlan. */
02248     OperationPlan *owner;
02249 
02250     /** Quantity. */
02251     double quantity;
02252 
02253     /** Default constructor.<br>
02254       * This way of creating operationplan objects is not intended for use by
02255       * any client applications. Client applications should use the factory
02256       * method on the operation class instead.<br>
02257       * Subclasses of the Operation class may use this constructor in their
02258       * own override of the createOperationPlan method.
02259       * @see Operation::createOperationPlan
02260       */
02261     OperationPlan() : owner(NULL), quantity(0.0), flags(0), dmd(NULL),
02262       id(0), oper(NULL), firstflowplan(NULL), firstloadplan(NULL),
02263       prev(NULL), next(NULL), firstsubopplan(NULL), lastsubopplan(NULL),
02264       nextsubopplan(NULL), prevsubopplan(NULL)
02265         {initType(metadata);}
02266 
02267   private:
02268     static const short IS_LOCKED = 1;
02269     static const short IS_SETUP = 2;
02270     static const short HAS_SETUP = 4;
02271 
02272     /** Is this operationplan locked? A locked operationplan doesn't accept
02273       * any changes. This field is only relevant for top-operationplans. */
02274     short flags;
02275 
02276     /** Counter of OperationPlans, which is used to automatically assign a
02277       * unique identifier for each operationplan.<br>
02278       * The value of the counter is the first available identifier value that
02279       * can be used for a new operationplan.
02280       * @see getIdentifier()
02281       */
02282     static DECLARE_EXPORT unsigned long counter;
02283 
02284     /** Pointer to the demand.<br>
02285       * Only delivery operationplans have this field set. The field is NULL 
02286       * for all other operationplans. 
02287       */
02288     Demand *dmd;
02289 
02290     /** Unique identifier.<br>
02291       * The field is 0 while the operationplan is not fully registered yet.
02292       */
02293     unsigned long id;
02294 
02295     /** Start and end date. */
02296     DateRange dates;
02297 
02298     /** Pointer to the operation. */
02299     Operation *oper;
02300 
02301     /** Root of a single linked list of flowplans. */
02302     FlowPlan* firstflowplan;
02303 
02304     /** Single linked list of loadplans. */
02305     LoadPlan* firstloadplan;
02306 
02307     /** Pointer to the previous operationplan.<br>
02308       * Operationplans are chained in a doubly linked list for each operation.
02309       * @see next
02310       */
02311     OperationPlan* prev;
02312 
02313     /** Pointer to the next operationplan.<br>
02314       * Operationplans are chained in a doubly linked list for each operation.
02315       * @see prev
02316       */
02317     OperationPlan* next;
02318 
02319     /** Pointer to the first suboperationplan of this operationplan. */
02320     OperationPlan* firstsubopplan;
02321 
02322     /** Pointer to the last suboperationplan of this operationplan. */
02323     OperationPlan* lastsubopplan;
02324 
02325     /** Pointer to the next suboperationplan of the parent operationplan. */
02326     OperationPlan* nextsubopplan;
02327 
02328     /** Pointer to the previous suboperationplan of the parent operationplan. */
02329     OperationPlan* prevsubopplan;
02330 };
02331 
02332 
02333 /** @brief A simple class to easily remember the date and quantity of
02334   * an operationplan. */
02335 class OperationPlanState  // @todo should also restore suboperationplans!!!  replace by move command???
02336 {
02337   public:
02338     Date start;
02339     Date end;
02340     double quantity;
02341 
02342     /** Default constructor. */
02343     OperationPlanState() : quantity(0.0) {}
02344 
02345     /** Constructor. */
02346     OperationPlanState(const OperationPlan* x)
02347     {
02348       if (!x) 
02349       {
02350         quantity = 0.0;
02351         return;
02352       }
02353       else
02354       {
02355         start = x->getDates().getStart();
02356         end = x->getDates().getEnd();
02357         quantity = x->getQuantity();
02358       }
02359     }
02360 
02361     /** Constructor. */
02362     OperationPlanState(const Date x, const Date y, double q) 
02363       : start(x), end(y), quantity(q) {}
02364 
02365     /** Constructor. */
02366     OperationPlanState(const DateRange& x, double q) 
02367       : start(x.getStart()), end(x.getEnd()), quantity(q) {}
02368 };
02369 
02370 
02371 /** @brief Models an operation that takes a fixed amount of time, independent
02372   * of the quantity. */
02373 class OperationFixedTime : public Operation
02374 {
02375   public:
02376     /** Constructor. */
02377     explicit OperationFixedTime(const string& s) : Operation(s) {initType(metadata);}
02378 
02379     /** Returns the length of the operation. */
02380     const TimePeriod getDuration() const {return duration;}
02381 
02382     /** Updates the duration of the operation. Existing operation plans of this
02383       * operation are not automatically refreshed to reflect the change. */
02384     void setDuration(TimePeriod t)
02385     {
02386       if (t<0L)
02387         throw DataException("FixedTime operation can't have a negative duration");
02388       duration = t;
02389     }
02390 
02391     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02392     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02393     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02394     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02395     static int initialize();
02396 
02397     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02398 
02399     virtual const MetaClass& getType() const {return *metadata;}
02400     static DECLARE_EXPORT const MetaClass* metadata;
02401     virtual size_t getSize() const
02402     {return sizeof(OperationFixedTime) + Operation::extrasize();}
02403 
02404     /** A operation of this type enforces the following rules on its
02405       * operationplans:
02406       *  - The duration is always constant.
02407       *  - If the end date is specified, we use that and ignore the start
02408       *    date that could have been passed.
02409       *  - If no end date but only a start date are specified, we'll use
02410       *    that date.
02411       *  - If no dates are specified, we don't update the dates of the
02412       *    operationplan.
02413       *  - The quantity can be any positive number.
02414       *  - Locked operationplans can't be updated.
02415       * @see Operation::setOperationPlanParameters
02416       */
02417     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02418       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02419   
02420   protected:
02421     DECLARE_EXPORT virtual bool extraInstantiate(OperationPlan* o);
02422 
02423   private:
02424     /** Stores the lengh of the Operation. */
02425     TimePeriod duration;
02426 };
02427 
02428 
02429 /** @brief Models an operation to convert a setup on a resource. */
02430 class OperationSetup : public Operation
02431 {
02432   friend class CommandErase;
02433   public:
02434     /** Constructor. */
02435     explicit OperationSetup(const string& s) : Operation(s) {initType(metadata);}
02436 
02437     // Never write the setup operation
02438     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const {}
02439     static int initialize();
02440 
02441     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02442 
02443     virtual const MetaClass& getType() const {return *metadata;}
02444     static DECLARE_EXPORT const MetaClass* metadata;
02445     virtual size_t getSize() const
02446     {return sizeof(OperationSetup) + Operation::extrasize();}
02447 
02448     /** A operation of this type enforces the following rules on its
02449       * operationplans:
02450       *  - The duration is calculated based on the conversion type.
02451       */
02452     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02453       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02454 
02455     /** A pointer to the operation that is instantiated for all conversions. */
02456     static DECLARE_EXPORT const Operation* setupoperation;
02457 };
02458 
02459 
02460 /** @brief Models an operation whose duration is the sum of a constant time,
02461   * plus a cetain time per unit.
02462   */
02463 class OperationTimePer : public Operation
02464 {
02465   public:
02466     /** Constructor. */
02467     explicit OperationTimePer(const string& s) : Operation(s) {initType(metadata);}
02468 
02469     /** Returns the constant part of the operation time. */
02470     TimePeriod getDuration() const {return duration;}
02471 
02472     /** Sets the constant part of the operation time. */
02473     void setDuration(TimePeriod t)
02474     {
02475       if(t<0L)
02476         throw DataException("TimePer operation can't have a negative duration");
02477       duration = t;
02478     }
02479 
02480     /** Returns the time per unit of the operation time. */
02481     TimePeriod getDurationPer() const {return duration_per;}
02482 
02483     /** Sets the time per unit of the operation time. */
02484     void setDurationPer(TimePeriod t)
02485     {
02486       if(t<0L)
02487         throw DataException("TimePer operation can't have a negative duration-per");
02488       duration_per = t;
02489     }
02490 
02491     /** A operation of this type enforces the following rules on its
02492       * operationplans:
02493       *   - If both the start and end date are specified, the quantity is
02494       *     computed to match these dates.
02495       *     If the time difference between the start and end date is too
02496       *     small to fit the fixed duration, the quantity is set to 0.
02497       *   - If only an end date is specified, it will be respected and we
02498       *     compute a start date based on the quantity.
02499       *   - If only a start date is specified, it will be respected and we
02500       *     compute an end date based on the quantity.
02501       *   - If no date is specified, we respect the quantity and the end
02502       *     date of the operation. A new start date is being computed.
02503       * @see Operation::setOperationPlanParameters
02504       */
02505     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02506       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02507 
02508     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02509     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02510     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02511     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02512     static int initialize();
02513 
02514     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02515 
02516     virtual const MetaClass& getType() const {return *metadata;}
02517     static DECLARE_EXPORT const MetaClass* metadata;
02518     virtual size_t getSize() const
02519     {return sizeof(OperationTimePer) + Operation::extrasize();}
02520 
02521   private:
02522     /** Constant part of the operation time. */
02523     TimePeriod duration;
02524 
02525     /** Variable part of the operation time. */
02526     TimePeriod duration_per;
02527 };
02528 
02529 
02530 /** @brief Represents a routing operation, i.e. an operation consisting of
02531   * multiple, sequential sub-operations.
02532   */
02533 class OperationRouting : public Operation
02534 {
02535   public:
02536     /** Constructor. */
02537     explicit OperationRouting(const string& c) : Operation(c) {initType(metadata);}
02538 
02539     /** Destructor. */
02540     DECLARE_EXPORT ~OperationRouting();
02541 
02542     /** Adds a new steps to routing at the start of the routing. */
02543     void addStepFront(Operation *o)
02544     {
02545       if (!o) throw DataException("Adding NULL operation to routing");
02546       steps.push_front(o);
02547       o->addSuperOperation(this);
02548     }
02549 
02550     /** Adds a new steps to routing at the end of the routing. */
02551     void addStepBack(Operation *o)
02552     {
02553       if (!o) throw DataException("Adding NULL operation to routing");
02554       steps.push_back(o);
02555       o->addSuperOperation(this);
02556     }
02557 
02558     /** Add one or more steps to a routing. */
02559     static DECLARE_EXPORT PyObject* addStep(PyObject*, PyObject*);
02560 
02561     /** Remove a step from a routing. */
02562     void removeSubOperation(Operation *o)
02563     {steps.remove(o); o->superoplist.remove(this);}
02564 
02565     /** A operation of this type enforces the following rules on its
02566       * operationplans:
02567       *  - If an end date is given, sequentially use this method on the
02568       *    different steps. The steps are stepped through starting from the
02569       *    last step, and each step will adjust to meet the requested end date.
02570       *    If there is slack between the routings' step operationplans, it can
02571       *    be used to "absorb" the change.
02572       *  - When a start date is given, the behavior is similar to the previous
02573       *    case, except that we step through the operationplans from the
02574       *    first step this time.
02575       *  - If both a start and an end date are given, we use only the end date.
02576       *  - If there are no sub operationplans yet, apply the requested changes
02577       *    blindly.
02578       * @see Operation::setOperationPlanParameters
02579       */
02580     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02581       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02582 
02583     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02584     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02585     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02586     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02587     static int initialize();
02588 
02589     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02590 
02591     /** Return a list of all sub-operationplans. */
02592     virtual const Operationlist& getSubOperations() const {return steps;}
02593 
02594     virtual const MetaClass& getType() const {return *metadata;}
02595     static DECLARE_EXPORT const MetaClass* metadata;
02596     virtual size_t getSize() const
02597     {
02598       return sizeof(OperationRouting) + Operation::extrasize()
02599         + steps.size() * 2 * sizeof(Operation*);
02600     }
02601 
02602   protected:
02603     /** Extra logic to be used when instantiating an operationplan. */
02604     virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o);
02605 
02606   private:
02607     /** Stores a double linked list of all step operations. */
02608     Operationlist steps;
02609 };
02610 
02611 
02612 inline void OperationPlan::restore(const OperationPlanState& x)
02613 {
02614   getOperation()->setOperationPlanParameters(this, x.quantity, x.start, x.end, true);
02615   assert(quantity == x.quantity);
02616   assert(dates.getStart() == x.start || x.start!=x.end);
02617   assert(dates.getEnd() == x.end || x.start!=x.end);
02618 }
02619 
02620 
02621 /** This type defines what mode used to search the alternates. */
02622 enum SearchMode
02623 {
02624   /** Select the alternate with the lowest priority number.<br>
02625     * This is the default.
02626     */
02627   PRIORITY = 0,
02628   /** Select the alternate which gives the lowest cost. */
02629   MINCOST = 1,
02630   /** Select the alternate which gives the lowest penalty. */
02631   MINPENALTY = 2,
02632   /** Select the alternate which gives the lowest sum of the cost and
02633     * penalty. */
02634   MINCOSTPENALTY = 3
02635 };
02636 
02637 
02638 /** Writes a search mode to an output stream. */
02639 inline ostream & operator << (ostream & os, const SearchMode & d)
02640 {
02641   switch (d)
02642   {
02643     case PRIORITY: os << "PRIORITY"; return os;
02644     case MINCOST: os << "MINCOST"; return os;
02645     case MINPENALTY: os << "MINPENALTY"; return os;
02646     case MINCOSTPENALTY: os << "MINCOSTPENALTY"; return os;
02647     default: assert(false); return os;
02648   }
02649 }
02650 
02651 
02652 /** Translate a string to a search mode value. */
02653 DECLARE_EXPORT SearchMode decodeSearchMode(const string& c);
02654 
02655 
02656 /** @brief This class represents a choice between multiple operations. The
02657   * alternates are sorted in order of priority.
02658   */
02659 class OperationAlternate : public Operation
02660 {
02661   public:
02662     typedef pair<int,DateRange> alternateProperty;
02663 
02664     /** Constructor. */
02665     explicit OperationAlternate(const string& c)
02666       : Operation(c), search(PRIORITY) {initType(metadata);}
02667 
02668     /** Destructor. */
02669     DECLARE_EXPORT ~OperationAlternate();
02670 
02671     /** Add a new alternate operation.<br>
02672       * The lower the priority value, the more important this alternate
02673       * operation is. */
02674     DECLARE_EXPORT void addAlternate
02675       (Operation*, int = 1, DateRange = DateRange());
02676 
02677     /** Removes an alternate from the list. */
02678     DECLARE_EXPORT void removeSubOperation(Operation *);
02679 
02680     /** Returns the properties of a certain suboperation.
02681       * @exception LogicException Generated when the argument operation is
02682       *     null or when it is not a sub-operation of this alternate.
02683       */
02684     DECLARE_EXPORT const alternateProperty& getProperties(Operation* o) const;
02685 
02686     /** Updates the priority of a certain suboperation.
02687       * @exception DataException Generated when the argument operation is
02688       *     not null and not a sub-operation of this alternate.
02689       */
02690     DECLARE_EXPORT void setPriority(Operation*, int);
02691 
02692     /** Updates the effective daterange of a certain suboperation.
02693       * @exception DataException Generated when the argument operation is
02694       *     not null and not a sub-operation of this alternate.
02695       */
02696     DECLARE_EXPORT void setEffective(Operation*, DateRange);
02697 
02698     /** Return the search mode. */
02699     SearchMode getSearch() const {return search;}
02700 
02701     /** Update the search mode. */
02702     void setSearch(const string a) {search = decodeSearchMode(a);}
02703 
02704     /** A operation of this type enforces the following rules on its
02705       * operationplans:
02706       *  - Very simple, call the method with the same name on the alternate
02707       *    suboperationplan.
02708       * @see Operation::setOperationPlanParameters
02709       */
02710     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02711       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02712 
02713     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02714     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02715     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02716     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02717     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02718     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02719     virtual const Operationlist& getSubOperations() const {return alternates;}
02720     static int initialize();
02721 
02722     /** Add an alternate to the operation.<br>
02723       * The keyword arguments are "operation", "priority", "effective_start"
02724       * and "effective_end"
02725       */
02726     static DECLARE_EXPORT PyObject* addAlternate(PyObject*, PyObject*, PyObject*);
02727 
02728     virtual const MetaClass& getType() const {return *metadata;}
02729     static DECLARE_EXPORT const MetaClass* metadata;
02730     virtual size_t getSize() const
02731     {
02732       return sizeof(OperationAlternate) + Operation::extrasize()
02733           + alternates.size() * (5*sizeof(Operation*)+sizeof(alternateProperty));
02734     }
02735 
02736   protected:
02737     /** Extra logic to be used when instantiating an operationplan. */
02738     virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o);
02739 
02740   private:
02741     typedef list<alternateProperty> alternatePropertyList;
02742 
02743     /** List of the priorities of the different alternate operations. The list
02744       * is maintained such that it is sorted in ascending order of priority. */
02745     alternatePropertyList alternateProperties;
02746 
02747     /** List of all alternate operations. The list is sorted with the operation
02748       * with the highest priority at the start of the list.<br>
02749       * Note that the list of operations and the list of priorities go hand in
02750       * hand: they have an equal number of elements and the order of the
02751       * elements is matching in both lists.
02752       */
02753     Operationlist alternates;
02754 
02755     /** Mode to select the preferred alternates. */
02756     SearchMode search;
02757 };
02758 
02759 
02760 /** @brief An item defines the products being planned, sold, stored and/or
02761   * manufactured. Buffers and demands have a reference an item.
02762   *
02763   * This is an abstract class.
02764   */
02765 class Item : public HasHierarchy<Item>, public HasDescription
02766 {
02767   public:
02768     /** Constructor. Don't use this directly! */
02769     explicit Item(const string& str) : HasHierarchy<Item>(str),
02770       deliveryOperation(NULL), price(0.0) {}
02771 
02772     /** Returns the delivery operation.<br>
02773       * This field is inherited from a parent item, if it hasn't been
02774       * specified.
02775       */
02776     Operation* getOperation() const
02777     {
02778       // Current item has a non-empty deliveryOperation field
02779       if (deliveryOperation) return deliveryOperation;
02780 
02781       // Look for a non-empty deliveryOperation field on owners
02782       for (Item* i = getOwner(); i; i=i->getOwner())
02783         if (i->deliveryOperation) return i->deliveryOperation;
02784 
02785       // The field is not specified on the item or any of its parents.
02786       return NULL;
02787     }
02788 
02789     /** Updates the delivery operation.<br>
02790       * If some demands have already been planned using the old delivery
02791       * operation they are left untouched and won't be replanned.
02792       */
02793     void setOperation(Operation* o) {deliveryOperation = o;}
02794 
02795     /** Return the selling price of the item.<br>
02796       * The default value is 0.0.
02797       */
02798     double getPrice() const {return price;}
02799 
02800     /** Update the selling price of the item. */
02801     void setPrice(const double c)
02802     {
02803       if (c >= 0) price = c;
02804       else throw DataException("Item price must be positive");
02805     }
02806 
02807     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02808     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02809     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02810     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02811     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02812     static int initialize();
02813 
02814     /** Destructor. */
02815     virtual DECLARE_EXPORT ~Item();
02816 
02817     virtual const MetaClass& getType() const {return *metadata;}
02818     static DECLARE_EXPORT const MetaCategory* metadata;
02819 
02820   private:
02821     /** This is the operation used to satisfy a demand for this item.
02822       * @see Demand
02823       */
02824     Operation* deliveryOperation;
02825 
02826     /** Selling price of the item. */
02827     double price;
02828 };
02829 
02830 
02831 /** @brief This class is the default implementation of the abstract Item
02832   * class. */
02833 class ItemDefault : public Item
02834 {
02835   public:
02836     explicit ItemDefault(const string& str) : Item(str) {initType(metadata);}
02837     virtual const MetaClass& getType() const {return *metadata;}
02838     static DECLARE_EXPORT const MetaClass* metadata;
02839     virtual size_t getSize() const
02840     {
02841       return sizeof(ItemDefault) + getName().size()
02842         + HasDescription::extrasize();
02843     }
02844     static int initialize();
02845 };
02846 
02847 
02848 /** @brief A buffer represents a combination of a item and location.<br>
02849   * It is the entity for keeping modeling inventory.
02850   */
02851 class Buffer : public HasHierarchy<Buffer>, public HasLevel,
02852       public Plannable, public HasDescription
02853 {
02854     friend class Flow;
02855     friend class FlowPlan;
02856 
02857   public:
02858     typedef TimeLine<FlowPlan> flowplanlist;
02859     typedef Association<Operation,Buffer,Flow>::ListB flowlist;
02860 
02861     /** Constructor. Implicit creation of instances is disallowed. */
02862     explicit Buffer(const string& str) : HasHierarchy<Buffer>(str),
02863         hidden(false), producing_operation(NULL), loc(NULL), it(NULL),
02864         min_cal(NULL), max_cal(NULL), carrying_cost(0.0) {}
02865 
02866     /** Returns the operation that is used to supply extra supply into this
02867       * buffer. */
02868     Operation* getProducingOperation() const {return producing_operation;}
02869 
02870     /** Updates the operation that is used to supply extra supply into this
02871       * buffer. */
02872     void setProducingOperation(Operation* o)
02873       {producing_operation = o; setChanged();}
02874 
02875     /** Returns the item stored in this buffer. */
02876     Item* getItem() const {return it;}
02877 
02878     /** Updates the Item stored in this buffer. */
02879     void setItem(Item* i) {it = i; setChanged();}
02880 
02881     /** Returns the Location of this buffer. */
02882     Location* getLocation() const {return loc;}
02883 
02884     /** Updates the location of this buffer. */
02885     void setLocation(Location* i) {loc = i;}
02886 
02887     /** Returns a pointer to a calendar for storing the minimum inventory
02888       * level. */
02889     CalendarDouble* getMinimum() const {return min_cal;}
02890 
02891     /** Returns a pointer to a calendar for storing the maximum inventory
02892       * level. */
02893     CalendarDouble* getMaximum() const {return max_cal;}
02894 
02895     /** Updates the minimum inventory target for the buffer. */
02896     DECLARE_EXPORT void setMinimum(CalendarDouble *);
02897 
02898     /** Updates the minimum inventory target for the buffer. */
02899     DECLARE_EXPORT void setMaximum(CalendarDouble *);
02900 
02901     /** Return the carrying cost.<br>
02902       * The cost of carrying inventory in this buffer. The value is a
02903       * percentage of the item sales price, per year and per unit.
02904       */
02905     double getCarryingCost() const {return carrying_cost;}
02906 
02907     /** Return the carrying cost.<br>
02908       * The cost of carrying inventory in this buffer. The value is a
02909       * percentage of the item sales price, per year and per unit.<br>
02910       * The default value is 0.0.
02911       */
02912     void setCarryingCost(const double c)
02913     {
02914       if (c >= 0) carrying_cost = c;
02915       else throw DataException("Buffer carrying_cost must be positive");
02916     }
02917 
02918     DECLARE_EXPORT virtual void beginElement(XMLInput&, const Attribute&);
02919     DECLARE_EXPORT virtual void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02920     DECLARE_EXPORT virtual void endElement(XMLInput&, const Attribute&, const DataElement&);
02921     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02922     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02923 
02924     size_t extrasize() const
02925     {return getName().size() + HasDescription::extrasize();}
02926 
02927     /** Initialize the class. */
02928     static int initialize();
02929 
02930     /** Destructor. */
02931     virtual DECLARE_EXPORT ~Buffer();
02932 
02933     /** Returns the available material on hand immediately after the
02934       * given date.
02935       */
02936     DECLARE_EXPORT double getOnHand(Date d = Date::infinitePast) const;
02937 
02938     /** Update the on-hand inventory at the start of the planning horizon. */
02939     DECLARE_EXPORT void setOnHand(double f);
02940 
02941     /** Returns minimum or maximum available material on hand in the given
02942       * daterange. The third parameter specifies whether we return the
02943       * minimum (which is the default) or the maximum value.
02944       * The computation is INclusive the start and end dates.
02945       */
02946     DECLARE_EXPORT double getOnHand(Date, Date, bool min = true) const;
02947 
02948     /** Returns a reference to the list of all flows of this buffer. */
02949     const flowlist& getFlows() const {return flows;}
02950 
02951     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02952 
02953     /** Returns a reference to the list of all flow plans of this buffer. */
02954     const flowplanlist& getFlowPlans() const {return flowplans;}
02955 
02956     /** Returns a reference to the list of all flow plans of this buffer. */
02957     flowplanlist& getFlowPlans() {return flowplans;}
02958 
02959     /** Return the flow that is associates a given operation with this
02960       * buffer.<br>Returns NULL is no such flow exists. */
02961     Flow* findFlow(const Operation* o, Date d) const
02962     {return flows.find(o,d);}
02963 
02964     /** Deletes all operationplans consuming from or producing from this
02965       * buffer. The boolean parameter controls whether we delete also locked
02966       * operationplans or not.
02967       */
02968     DECLARE_EXPORT void deleteOperationPlans(bool deleteLockedOpplans = false);
02969 
02970     virtual DECLARE_EXPORT void updateProblems();
02971 
02972     void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
02973     bool getHidden() const {return hidden;}
02974 
02975     virtual const MetaClass& getType() const {return *metadata;}
02976     static DECLARE_EXPORT const MetaCategory* metadata;
02977 
02978     /** This function matches producing and consuming operationplans
02979       * with each other, and updates the pegging iterator accordingly.
02980       */
02981     virtual DECLARE_EXPORT void followPegging
02982       (PeggingIterator&, FlowPlan*, short, double, double);
02983 
02984   private:
02985     /** This models the dynamic part of the plan, representing all planned
02986       * material flows on this buffer. */
02987     flowplanlist flowplans;
02988 
02989     /** This models the defined material flows on this buffer. */
02990     flowlist flows;
02991 
02992     /** Hide this entity from serialization or not. */
02993     bool hidden;
02994 
02995     /** This is the operation used to create extra material in this buffer. */
02996     Operation *producing_operation;
02997 
02998     /** Location of this buffer.<br>
02999       * This field is only used as information.<br>
03000       * The default is NULL.
03001       */
03002     Location* loc;
03003 
03004     /** Item being stored in this buffer.<br>
03005       * The default value is NULL.
03006       */
03007     Item* it;
03008 
03009     /** Points to a calendar to store the minimum inventory level.<br>
03010       * The default value is NULL, resulting in a constant minimum level
03011       * of 0.
03012       */
03013     CalendarDouble *min_cal;
03014 
03015     /** Points to a calendar to store the maximum inventory level.<br>
03016       * The default value is NULL, resulting in a buffer without excess
03017       * inventory problems.
03018       */
03019     CalendarDouble *max_cal;
03020 
03021     /** Carrying cost.<br>
03022       * The cost of carrying inventory in this buffer. The value is a
03023       * percentage of the item sales price, per year and per unit.
03024       */
03025     double carrying_cost;
03026 };
03027 
03028 
03029 
03030 /** @brief This class is the default implementation of the abstract Buffer class. */
03031 class BufferDefault : public Buffer
03032 {
03033   public:
03034     explicit BufferDefault(const string& str) : Buffer(str) {initType(metadata);}
03035     virtual const MetaClass& getType() const {return *metadata;}
03036     virtual size_t getSize() const
03037     {return sizeof(BufferDefault) + Buffer::extrasize();}
03038     static DECLARE_EXPORT const MetaClass* metadata;
03039     static int initialize();
03040 };
03041 
03042 
03043 /** @brief  This class represents a material buffer with an infinite supply of extra
03044   * material.
03045   *
03046   * In other words, it never constrains the plan and it doesn't propagate any
03047   * requirements upstream.
03048   */
03049 class BufferInfinite : public Buffer
03050 {
03051   public:
03052     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03053     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03054     virtual const MetaClass& getType() const {return *metadata;}
03055     virtual size_t getSize() const
03056       {return sizeof(BufferInfinite) + Buffer::extrasize();}
03057     explicit BufferInfinite(const string& c) : Buffer(c)
03058       {setDetectProblems(false); initType(metadata);}
03059     static DECLARE_EXPORT const MetaClass* metadata;
03060     static int initialize();
03061 };
03062 
03063 
03064 /** @brief This class models a buffer that is replenish by an external supplier
03065   * using a reorder-point policy.
03066   *
03067   * It represents a material buffer where a replenishment is triggered
03068   * whenever the inventory drops below the minimum level. The buffer is then
03069   * replenished to the maximum inventory level.<br>
03070   * A leadtime is taken into account for the replenishments.<br>
03071   * The following parameters control this replenishment:
03072   *  - <b>MinimumInventory</b>:<br>
03073   *    Inventory level triggering a new replenishment.<br>
03074   *    The actual inventory can drop below this value.
03075   *  - <b>MaximumInventory</b>:<br>
03076   *    Inventory level to which we try to replenish.<br>
03077   *    The actual inventory can exceed this value.
03078   *  - <b>Leadtime</b>:<br>
03079   *    Time taken between placing the purchase order with the supplier and the
03080   *    delivery of the material.
03081   *
03082   * Using the additional parameters described below the replenishments can be
03083   * controlled in more detail. The resulting inventory profile can end up
03084   * to be completely different from the classical saw-tooth pattern!
03085   *
03086   * The timing of the replenishments can be constrained by the following
03087   * parameters:
03088   *  - <b>MinimumInterval</b>:<br>
03089   *    Minimum time between replenishments.<br>
03090   *    The order quantity will be increased such that it covers at least
03091   *    the demand in the minimum interval period. The actual inventory can
03092   *    exceed the target set by the MinimumInventory parameter.
03093   *  - <b>MaximumInterval</b>:<br>
03094   *    Maximum time between replenishments.<br>
03095   *    The order quantity will replenish to an inventory value less than the
03096   *    maximum when this maximum interval is reached.
03097   * When the minimum and maximum interval are equal we basically define a fixed
03098   * schedule replenishment policy.
03099   *
03100   * The quantity of the replenishments can be constrained by the following
03101   * parameters:
03102   *  - <b>MinimumQuantity</b>:<br>
03103   *    Minimum quantity for a replenishment.<br>
03104   *    This parameter can cause the actual inventory to exceed the target set
03105   *    by the MinimumInventory parameter.
03106   *  - <b>MaximumQuantity</b>:<br>
03107   *    Maximum quantity for a replenishment.<br>
03108   *    This parameter can cause the maximum inventory target never to be
03109   *    reached.
03110   *  - <b>MultipleQuantity</b>:<br>
03111   *    All replenishments are rounded up to a multiple of this value.
03112   * When the minimum and maximum quantity are equal we basically define a fixed
03113   * quantity replenishment policy.
03114   */
03115 class BufferProcure : public Buffer
03116 {
03117   public:
03118     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03119     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03120     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03121     virtual const MetaClass& getType() const {return *metadata;}
03122     virtual size_t getSize() const
03123       {return sizeof(BufferProcure) + Buffer::extrasize();}
03124     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03125     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03126     static int initialize();
03127 
03128     /** Constructor. */
03129     explicit BufferProcure(const string& c) : Buffer(c), min_inventory(0),
03130       max_inventory(0), size_minimum(0), size_maximum(DBL_MAX), size_multiple(0),
03131       oper(NULL) {initType(metadata);}
03132     static DECLARE_EXPORT const MetaClass* metadata;
03133 
03134     /** Return the purchasing leadtime. */
03135     TimePeriod getLeadtime() const {return leadtime;}
03136 
03137     /** Update the procurement leadtime. */
03138     void setLeadtime(TimePeriod p)
03139     {
03140       if (p<0L)
03141         throw DataException("Procurement buffer can't have a negative lead time");
03142       leadtime = p;
03143     }
03144 
03145     /** Return the release time fence. */
03146     TimePeriod getFence() const {return fence;}
03147 
03148     /** Update the release time fence. */
03149     void setFence(TimePeriod p) {fence = p;}
03150 
03151     /** Return the inventory level that will trigger creation of a
03152       * purchasing.
03153       */
03154     double getMinimumInventory() const {return min_inventory;}
03155 
03156     /** Update the minimum inventory level to trigger replenishments. */
03157     void setMinimumInventory(double f)
03158     {
03159       if (f<0)
03160         throw DataException("Procurement buffer can't have a negative minimum inventory");
03161       min_inventory = f;
03162       // minimum is increased over the maximum: auto-increase the maximum
03163       if (max_inventory < min_inventory) max_inventory = min_inventory;
03164     }
03165 
03166     /** Return the maximum inventory level to which we wish to replenish. */
03167     double getMaximumInventory() const {return max_inventory;}
03168 
03169     /** Update the inventory level to replenish to. */
03170     void setMaximumInventory(double f)
03171     {
03172       if (f<0)
03173         throw DataException("Procurement buffer can't have a negative maximum inventory");
03174       max_inventory = f;
03175       // maximum is lowered below the minimum: auto-decrease the minimum
03176       if (max_inventory < min_inventory) min_inventory = max_inventory;
03177     }
03178 
03179     /** Return the minimum interval between purchasing operations.<br>
03180       * This parameter doesn't control the timing of the first purchasing
03181       * operation, but only to the subsequent ones.
03182       */
03183     TimePeriod getMinimumInterval() const {return min_interval;}
03184 
03185     /** Update the minimum time between replenishments. */
03186     void setMinimumInterval(TimePeriod p)
03187     {
03188       if (p<0L)
03189         throw DataException("Procurement buffer can't have a negative minimum interval");
03190       min_interval = p;
03191       // minimum is increased over the maximum: auto-increase the maximum
03192       if (max_interval < min_interval) max_interval = min_interval;
03193     }
03194 
03195     /** Return the maximum time interval between sytem-generated replenishment
03196       * operations.
03197       */
03198     TimePeriod getMaximumInterval() const {return max_interval;}
03199 
03200     /** Update the minimum time between replenishments. */
03201     void setMaximumInterval(TimePeriod p)
03202     {
03203       if (p<0L)
03204         throw DataException("Procurement buffer can't have a negative maximum interval");
03205       max_interval = p;
03206       // maximum is lowered below the minimum: auto-decrease the minimum
03207       if (max_interval < min_interval) min_interval = max_interval;
03208     }
03209 
03210     /** Return the minimum quantity of a purchasing operation. */
03211     double getSizeMinimum() const {return size_minimum;}
03212 
03213     /** Update the minimum replenishment quantity. */
03214     void setSizeMinimum(double f)
03215     {
03216       if (f<0)
03217         throw DataException("Procurement buffer can't have a negative minimum size");
03218       size_minimum = f;
03219       // minimum is increased over the maximum: auto-increase the maximum
03220       if (size_maximum < size_minimum) size_maximum = size_minimum;
03221    }
03222 
03223     /** Return the maximum quantity of a purchasing operation. */
03224     double getSizeMaximum() const {return size_maximum;}
03225 
03226     /** Update the maximum replenishment quantity. */
03227     void setSizeMaximum(double f)
03228     {
03229       if (f<0)
03230         throw DataException("Procurement buffer can't have a negative maximum size");
03231       size_maximum = f;
03232       // maximum is lowered below the minimum: auto-decrease the minimum
03233       if (size_maximum < size_minimum) size_minimum = size_maximum;
03234     }
03235 
03236     /** Return the multiple quantity of a purchasing operation. */
03237     double getSizeMultiple() const {return size_multiple;}
03238 
03239     /** Update the multiple quantity. */
03240     void setSizeMultiple(double f)
03241     {
03242       if (f<0)
03243         throw DataException("Procurement buffer can't have a negative multiple size");
03244       size_multiple = f;
03245     }
03246 
03247     /** Returns the operation that is automatically created to represent the
03248       * procurements.
03249       */
03250     DECLARE_EXPORT Operation* getOperation() const;
03251 
03252   private:
03253     /** Purchasing leadtime.<br>
03254       * Within this leadtime fence no additional purchase orders can be generated.
03255       */
03256     TimePeriod leadtime;
03257 
03258     /** Time window from the current date in which all procurements are expected
03259       * to be released.
03260       */
03261     TimePeriod fence;
03262 
03263     /** Inventory level that will trigger the creation of a replenishment.<br>
03264       * Because of the replenishment leadtime, the actual inventory will drop
03265       * below this value. It is up to the user to set an appropriate minimum
03266       * value.
03267       */
03268     double min_inventory;
03269 
03270     /** The maximum inventory level to which we plan to replenish.<br>
03271       * This is not a hard limit - other parameters can make that the actual
03272       * inventory either never reaches this value or always exceeds it.
03273       */
03274     double max_inventory;
03275 
03276     /** Minimum time interval between purchasing operations. */
03277     TimePeriod min_interval;
03278 
03279     /** Maximum time interval between purchasing operations. */
03280     TimePeriod max_interval;
03281 
03282     /** Minimum purchasing quantity.<br>
03283       * The default value is 0, meaning no minimum.
03284       */
03285     double size_minimum;
03286 
03287     /** Maximum purchasing quantity.<br>
03288       * The default value is 0, meaning no maximum limit.
03289       */
03290     double size_maximum;
03291 
03292     /** Purchases are always rounded up to a multiple of this quantity.<br>
03293       * The default value is 0, meaning no multiple needs to be applied.
03294       */
03295     double size_multiple;
03296 
03297     /** A pointer to the procurement operation. */
03298     Operation* oper;
03299 };
03300 
03301 
03302 /** @brief This class defines a material flow to/from a buffer, linked with an
03303   * operation. This default implementation plans the material flow at the
03304   * start of the operation.
03305   */
03306 class Flow : public Object, public Association<Operation,Buffer,Flow>::Node,
03307       public Solvable
03308 {
03309   public:
03310     /** Destructor. */
03311     virtual DECLARE_EXPORT ~Flow();
03312 
03313     /** Constructor. */
03314     explicit Flow(Operation* o, Buffer* b, double q)
03315       : quantity(q), priority(1), hasAlts(false), altFlow(NULL), search(PRIORITY)
03316     {
03317       setOperation(o);
03318       setBuffer(b);
03319       validate(ADD);
03320       initType(metadata);
03321     }
03322 
03323     /** Returns the operation. */
03324     Operation* getOperation() const {return getPtrA();}
03325 
03326     /** Updates the operation of this flow. This method can be called only ONCE
03327       * for each flow. In case that doesn't suit you, delete the existing flow
03328       * and create a new one.
03329       */
03330     void setOperation(Operation* o) {if (o) setPtrA(o,o->getFlows());}
03331 
03332     /** Returns true if this flow consumes material from the buffer. */
03333     bool isConsumer() const {return quantity < 0;}
03334 
03335     /** Returns true if this flow produces material into the buffer. */
03336     bool isProducer() const {return quantity >= 0;}
03337 
03338     /** Returns the material flow PER UNIT of the operationplan. */
03339     double getQuantity() const {return quantity;}
03340 
03341     /** Updates the material flow PER UNIT of the operationplan. Existing
03342       * flowplans are NOT updated to take the new quantity in effect. Only new
03343       * operationplans and updates to existing ones will use the new quantity
03344       * value.
03345       */
03346     void setQuantity(double f) {quantity = f;}
03347 
03348     /** Returns the buffer. */
03349     Buffer* getBuffer() const {return getPtrB();}
03350 
03351     /** Updates the buffer of this flow. This method can be called only ONCE
03352       * for each flow. In case that doesn't suit you, delete the existing flow
03353       * and create a new one.
03354       */
03355     void setBuffer(Buffer* b) {if (b) setPtrB(b,b->getFlows());}
03356 
03357     /** Update the priority of a flow. */
03358     void setPriority(int i) {priority = i;}
03359 
03360     /** Return the priority of a flow. */
03361     int getPriority() const {return priority;}
03362 
03363     /** Returns true if there are alternates for this flow. */
03364     bool hasAlternates() const {return hasAlts;}
03365 
03366     /** Returns the flow of which this one is an alternate.<br>
03367       * NULL is return where there is none.
03368       */
03369     Flow* getAlternate() const {return altFlow;}
03370 
03371     /** Define the flow of which this one is an alternate. */
03372     DECLARE_EXPORT void setAlternate(Flow *);
03373 
03374     /** Define the flow of which this one is an alternate. */
03375     DECLARE_EXPORT void setAlternate(const string& n);
03376 
03377     /** Return the search mode. */
03378     SearchMode getSearch() const {return search;}
03379 
03380     /** Update the search mode. */
03381     void setSearch(const string a) {search = decodeSearchMode(a);}
03382 
03383     /** A flow is considered hidden when either its buffer or operation
03384       * are hidden. */
03385     virtual bool getHidden() const
03386     {
03387       return (getBuffer() && getBuffer()->getHidden())
03388         || (getOperation() && getOperation()->getHidden());
03389     }
03390 
03391     /** This method holds the logic the compute the date of a flowplan. */
03392     virtual Date getFlowplanDate(const FlowPlan*) const;
03393 
03394     /** This method holds the logic the compute the quantity of a flowplan. */
03395     virtual double getFlowplanQuantity(const FlowPlan*) const;
03396 
03397     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03398     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
03399     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03400     static int initialize();
03401     static void writer(const MetaCategory*, XMLOutput*);
03402 
03403     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03404 
03405     virtual const MetaClass& getType() const {return *metadata;}
03406     static DECLARE_EXPORT const MetaCategory* metadata;
03407     virtual size_t getSize() const {return sizeof(Flow) + getName().size();}
03408 
03409   protected:
03410     /** Default constructor. */
03411     explicit Flow() : quantity(0.0), priority(1), hasAlts(false), 
03412       altFlow(NULL), search(PRIORITY) {initType(metadata);}
03413 
03414   private:
03415     /** Verifies whether a flow meets all requirements to be valid. */
03416     DECLARE_EXPORT void validate(Action action);
03417 
03418     /** Quantity of the flow. */
03419     double quantity;
03420 
03421     /** Priority of the flow - used in case of alternate flows. */
03422     int priority;
03423 
03424     /** Flag that is set to true when a flow has alternates. */
03425     bool hasAlts;
03426 
03427     /** A flow representing the main flow of a set of alternate flows. */
03428     Flow* altFlow;
03429 
03430     /** Mode to select the preferred alternates. */
03431     SearchMode search;
03432 
03433     static PyObject* create(PyTypeObject* pytype, PyObject* args, PyObject* kwds);
03434     DECLARE_EXPORT PyObject* getattro(const Attribute&);
03435     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03436 };
03437 
03438 
03439 /** @brief This class defines a material flow to/from a buffer, linked with an
03440   * operation. This subclass represents a flow that is at the start date of
03441   * the operation.
03442   */
03443 class FlowStart : public Flow
03444 {
03445   public:
03446     /** Constructor. */
03447     explicit FlowStart(Operation* o, Buffer* b, double q) : Flow(o,b,q) {}
03448 
03449     /** This constructor is called from the plan begin_element function. */
03450     explicit FlowStart() {}
03451 
03452     virtual const MetaClass& getType() const {return *metadata;}
03453     static DECLARE_EXPORT const MetaClass* metadata;
03454     virtual size_t getSize() const {return sizeof(FlowStart);}
03455     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03456 };
03457 
03458 
03459 /** @brief This class defines a material flow to/from a buffer, linked with an
03460   * operation. This subclass represents a flow that is at end date of the
03461   * operation.
03462   */
03463 class FlowEnd : public Flow
03464 {
03465   public:
03466     /** Constructor. */
03467     explicit FlowEnd(Operation* o, Buffer* b, double q) : Flow(o,b,q) {}
03468 
03469     /** This constructor is called from the plan begin_element function. */
03470     explicit FlowEnd() {}
03471 
03472     /** This method holds the logic the compute the date of a flowplan. */
03473     virtual Date getFlowplanDate(const FlowPlan* fl) const;
03474 
03475     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03476 
03477     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03478 
03479     virtual const MetaClass& getType() const {return *metadata;}
03480     static DECLARE_EXPORT const MetaClass* metadata;
03481     virtual size_t getSize() const {return sizeof(FlowEnd);}
03482 };
03483 
03484 
03485 /** @brief A flowplan represents a planned material flow in or out of a buffer.
03486   *
03487   * Flowplans are owned by operationplans, which manage a container to store
03488   * them.
03489   */
03490 class FlowPlan : public TimeLine<FlowPlan>::EventChangeOnhand, public PythonExtensionBase
03491 {
03492     friend class OperationPlan::FlowPlanIterator;
03493   private:
03494     /** Points to the flow instantiated by this flowplan. */
03495     const Flow *fl;
03496 
03497     /** Python interface method. */
03498     PyObject* getattro(const Attribute&);
03499 
03500     /** Points to the operationplan owning this flowplan. */
03501     OperationPlan *oper;
03502 
03503     /** Points to the next flowplan owned by the same operationplan. */
03504     FlowPlan *nextFlowPlan;
03505 
03506   public:
03507 
03508     static DECLARE_EXPORT const MetaCategory* metadata;
03509     static int initialize();
03510 
03511     /** Constructor. */
03512     explicit DECLARE_EXPORT FlowPlan(OperationPlan*, const Flow*);
03513 
03514     /** Returns the flow of which this is an plan instance. */
03515     const Flow* getFlow() const {return fl;}
03516 
03517     /** Returns the buffer. */
03518     const Buffer* getBuffer() const {return fl->getBuffer();}
03519 
03520     /** Update the flow of an already existing flowplan.<br>
03521       * The new flow must belong to the same operation.
03522       */
03523     DECLARE_EXPORT void setFlow(const Flow*);
03524 
03525     /** Returns the operationplan owning this flowplan. */
03526     OperationPlan* getOperationPlan() const {return oper;}
03527 
03528     /** Destructor. */
03529     virtual ~FlowPlan()
03530     {
03531       Buffer* b = getFlow()->getBuffer();
03532       b->setChanged();
03533       b->flowplans.erase(this);
03534     }
03535 
03536     /** Writing the element.
03537       * This method has the same prototype as a usual instance of the Object
03538       * class, but this is only superficial: FlowPlan isn't a subclass of
03539       * Object at all.
03540       */
03541     void DECLARE_EXPORT writeElement
03542       (XMLOutput*, const Keyword&, mode=DEFAULT) const;
03543 
03544     /** Updates the quantity of the flowplan by changing the quantity of the
03545       * operationplan owning this flowplan.<br>
03546       * The boolean parameter is used to control whether to round up (false)
03547       * or down (true) in case the operation quantity must be a multiple.
03548       */
03549     void setQuantity(double qty, bool b=false, bool u = true)
03550     {
03551       if (getFlow()->getEffective().within(getDate()))
03552         oper->setQuantity(qty / getFlow()->getQuantity(), b, u);
03553     }
03554 
03555     /** This function needs to be called whenever the flowplan date or
03556       * quantity are changed.
03557       */
03558     DECLARE_EXPORT void update();
03559 
03560     /** Return a pointer to the timeline data structure owning this flowplan. */
03561     TimeLine<FlowPlan>* getTimeLine() const
03562     {return &(getFlow()->getBuffer()->flowplans);}
03563 
03564     /** Returns true when the flowplan is hidden.<br>
03565       * This is determined by looking at whether the flow is hidden or not.
03566       */
03567     bool getHidden() const {return fl->getHidden();}
03568 };
03569 
03570 
03571 inline double Flow::getFlowplanQuantity(const FlowPlan* fl) const
03572 {
03573   return getEffective().within(fl->getDate()) ?
03574     fl->getOperationPlan()->getQuantity() * getQuantity() :
03575     0.0;
03576 }
03577 
03578 
03579 inline Date Flow::getFlowplanDate(const FlowPlan* fl) const
03580 {
03581   return fl->getOperationPlan()->getDates().getStart();
03582 }
03583 
03584 
03585 inline Date FlowEnd::getFlowplanDate(const FlowPlan* fl) const
03586 {
03587   return fl->getOperationPlan()->getDates().getEnd();
03588 }
03589 
03590 
03591 /** @brief This class is used to represent a matrix defining the changeover
03592   * times between setups.
03593   */
03594 class SetupMatrix : public HasName<SetupMatrix>
03595 {
03596   public:
03597     class RuleIterator; // Forward declaration
03598    /** @brief An specific changeover rule in a setup matrix. */
03599    class Rule : public Object
03600     {
03601       friend class RuleIterator;
03602       friend class SetupMatrix;
03603       public:
03604         /** Constructor. */
03605         DECLARE_EXPORT Rule(SetupMatrix *s, int p = 0);
03606 
03607         /** Destructor. */
03608         DECLARE_EXPORT ~Rule();
03609 
03610         virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03611         DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03612         virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03613         virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03614         static int initialize();
03615 
03616         virtual const MetaClass& getType() const {return *metadata;}
03617         static DECLARE_EXPORT const MetaCategory* metadata;
03618 
03619         size_t getSize() const
03620           {return sizeof(Rule) + from.size() + to.size();}
03621 
03622         /** Update the priority.<br>
03623           * The priority value is a key field. If multiple rules have the
03624           * same priority a data exception is thrown.
03625           */
03626         DECLARE_EXPORT void setPriority(const int);
03627 
03628         /** Return the priority. */
03629         double getPriority() const {return priority;}
03630 
03631         /** Update the from setup. */
03632         void setFromSetup(const string f) {from = f;}
03633 
03634         /** Return the from setup. */
03635         const string& getFromSetup() const {return from;}
03636 
03637         /** Update the from setup. */
03638         void setToSetup(const string f) {to = f;}
03639 
03640         /** Return the from setup. */
03641         const string& getToSetup() const {return to;}
03642 
03643         /** Update the conversion duration. */
03644         void setDuration(const TimePeriod p) {duration = p;}
03645 
03646         /** Return the conversion duration. */
03647         TimePeriod getDuration() const {return duration;}
03648 
03649         /** Update the conversion cost. */
03650         void setCost(const double p) {cost = p;}
03651 
03652         /** Return the conversion cost. */
03653         double getCost() const {return cost;}
03654 
03655       private:
03656         /** Original setup. */
03657         string from;
03658 
03659         /** New setup. */
03660         string to;
03661 
03662         /** Changeover time. */
03663         TimePeriod duration;
03664 
03665         /** Changeover cost. */
03666         double cost;
03667 
03668         /** Priority of the rule.<br>
03669           * This field is the key field, i.e. within a setup matrix all rules
03670           * need to have different priorities.
03671           */
03672         int priority;
03673 
03674         /** Pointer to the owning matrix. */
03675         SetupMatrix *matrix;
03676 
03677         /** Pointer to the next rule in this matrix. */
03678         Rule *nextRule;
03679 
03680         /** Pointer to the previous rule in this matrix. */
03681         Rule *prevRule;
03682     };
03683 
03684     /** @brief An iterator class to go through all rules of a setup matrix. */
03685     class RuleIterator
03686     {
03687       private:
03688         Rule* curRule;
03689       public:
03690         /** Constructor. */
03691         RuleIterator(Rule* c = NULL) : curRule(c) {}
03692         bool operator != (const RuleIterator &b) const
03693           {return b.curRule != curRule;}
03694         bool operator == (const RuleIterator &b) const
03695           {return b.curRule == curRule;}
03696         RuleIterator& operator++()
03697           {if (curRule) curRule = curRule->nextRule; return *this;}
03698         RuleIterator operator++(int)
03699           {RuleIterator tmp = *this; ++*this; return tmp;}
03700         RuleIterator& operator--()
03701           {if(curRule) curRule = curRule->prevRule; return *this;}
03702         RuleIterator operator--(int)
03703           {RuleIterator tmp = *this; --*this; return tmp;}
03704         Rule* operator ->() const {return curRule;}
03705         Rule& operator *() const {return *curRule;}
03706     };
03707 
03708   public:
03709     /** Default constructor. */
03710     SetupMatrix(const string& n) : HasName<SetupMatrix>(n), firstRule(NULL) {}
03711 
03712     /** Destructor. */
03713     DECLARE_EXPORT ~SetupMatrix();
03714 
03715     /** This is a factory method that creates a new rule<br>
03716       * This method is intended to be used to create objects when reading
03717       * XML input data.
03718       */
03719     DECLARE_EXPORT Rule* createRule(const AttributeList&);
03720 
03721     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03722     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
03723     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03724     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03725     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03726     static int initialize();
03727 
03728     virtual const MetaClass& getType() const {return *metadata;}
03729     static DECLARE_EXPORT const MetaCategory* metadata;
03730 
03731     virtual size_t getSize() const
03732     {
03733       size_t i = sizeof(SetupMatrix) + getName().size();
03734       for (RuleIterator j = beginRules(); j!= endRules(); ++j)
03735         i += j->getSize();
03736       return i;
03737     }
03738 
03739     size_t extrasize() const {return getName().size();}
03740 
03741     /** Returns an iterator to go through the list of buckets. */
03742     RuleIterator beginRules() const {return RuleIterator(firstRule);}
03743 
03744     /** Returns an iterator to go through the list of buckets. */
03745     RuleIterator endRules() const {return RuleIterator(NULL);}
03746 
03747     /** Python interface to add a new rule. */
03748     static DECLARE_EXPORT PyObject* addPythonRule(PyObject*, PyObject*, PyObject*);
03749 
03750     /** Computes the changeover time and cost between 2 setup values.
03751       *
03752       * To compute the time of a changeover the algorithm will evaluate all
03753       * rules in sequence (in order of priority).<br>
03754       * For a rule to match the changeover between the original setup X to
03755       * a new setup Y, two conditions need to be fulfilled:
03756       *  - The original setup X must match with the fromsetup of the rule.<br>
03757       *    If the fromsetup field is empty, it is considered a match.
03758       *  - The new setup Y must match with the tosetup of the rule.<br>
03759       *    If the tosetup field is empty, it is considered a match.
03760       * The wildcard characters * and ? can be used in the fromsetup and
03761       * tosetup fields.<br>
03762       * As soon as a matching rule is found, it is applied and subsequent
03763       * rules are not evaluated.<br>
03764       * If no matching rule is found, the changeover is not allowed: a NULL
03765       * pointer is returned.
03766       */
03767     DECLARE_EXPORT Rule* calculateSetup(const string, const string) const;
03768 
03769   private:
03770     /** Head of the list of rules. */
03771     Rule *firstRule;
03772 };
03773 
03774 
03775 /** @brief This class is the default implementation of the abstract
03776   * SetupMatrix class.
03777   */
03778 class SetupMatrixDefault : public SetupMatrix
03779 {
03780   public:
03781     explicit SetupMatrixDefault(const string& str) : SetupMatrix(str) {initType(metadata);}
03782     virtual const MetaClass& getType() const {return *metadata;}
03783     static DECLARE_EXPORT const MetaClass* metadata;
03784     virtual size_t getSize() const
03785     {return sizeof(SetupMatrixDefault) + SetupMatrix::extrasize();}
03786     static int initialize();
03787 };
03788 
03789 
03790 /** @brief This class represents a workcentre, a physical or logical
03791   * representation of capacity.
03792   */
03793 class Resource : public HasHierarchy<Resource>,
03794       public HasLevel, public Plannable, public HasDescription
03795 {
03796     friend class Load;
03797     friend class LoadPlan;
03798 
03799   public:
03800     /** The default time window before the ask date where we look for
03801       * available capacity. */
03802     static const long defaultMaxEarly = 100*86400L;
03803 
03804     /** Constructor. */
03805     explicit Resource(const string& str) : HasHierarchy<Resource>(str),
03806       max_cal(NULL), loc(NULL), cost(0.0), hidden(false), maxearly(defaultMaxEarly),
03807       setupmatrix(NULL) {};
03808 
03809     /** Destructor. */
03810     virtual DECLARE_EXPORT ~Resource();
03811 
03812     /** Updates the size of a resource. */
03813     DECLARE_EXPORT void setMaximum(CalendarDouble* c);
03814 
03815     /** Return a pointer to the maximum capacity profile. */
03816     CalendarDouble* getMaximum() const {return max_cal;}
03817 
03818     /** Returns the cost of using 1 unit of this resource for 1 hour.<br>
03819       * The default value is 0.0.
03820       */
03821     double getCost() const {return cost;}
03822 
03823     /** Update the cost of using 1 unit of this resource for 1 hour. */
03824     void setCost(const double c)
03825     {
03826       if (c >= 0) cost = c;
03827       else throw DataException("Resource cost must be positive");
03828     }
03829 
03830     typedef Association<Operation,Resource,Load>::ListB loadlist;
03831     typedef TimeLine<LoadPlan> loadplanlist;
03832 
03833     /** Returns a reference to the list of loadplans. */
03834     const loadplanlist& getLoadPlans() const {return loadplans;}
03835 
03836     /** Returns a reference to the list of loadplans. */
03837     loadplanlist& getLoadPlans() {return loadplans;}
03838 
03839     /** Returns a constant reference to the list of loads. It defines
03840       * which operations are using the resource.
03841       */
03842     const loadlist& getLoads() const {return loads;}
03843 
03844     /** Return the load that is associates a given operation with this
03845       * resource. Returns NULL is no such load exists. */
03846     Load* findLoad(const Operation* o, Date d) const
03847     {return loads.find(o,d);}
03848 
03849     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03850     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03851     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
03852     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03853     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03854 
03855     /** Initialize the class. */
03856     static int initialize();
03857 
03858     size_t extrasize() const
03859     {return getName().size() + HasDescription::extrasize() + setup.size();}
03860 
03861     /** Returns the location of this resource. */
03862     Location* getLocation() const {return loc;}
03863 
03864     /** Updates the location of this resource. */
03865     void setLocation(Location* i) {loc = i;}
03866 
03867     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03868 
03869     /** Deletes all operationplans loading this resource. The boolean parameter
03870       * controls whether we delete also locked operationplans or not.
03871       */
03872     DECLARE_EXPORT void deleteOperationPlans(bool = false);
03873 
03874     /** Recompute the problems of this resource. */
03875     virtual DECLARE_EXPORT void updateProblems();
03876 
03877     /** Scan the setups of this resource. */
03878     virtual DECLARE_EXPORT void updateSetups(const LoadPlan* = NULL);
03879 
03880     void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
03881     bool getHidden() const {return hidden;}
03882 
03883     virtual const MetaClass& getType() const {return *metadata;}
03884     static DECLARE_EXPORT const MetaCategory* metadata;
03885 
03886     /** Returns the maximum inventory buildup allowed in case of capacity
03887       * shortages. */
03888     TimePeriod getMaxEarly() const {return maxearly;}
03889 
03890     /** Updates the maximum inventory buildup allowed in case of capacity
03891       * shortages. */
03892     void setMaxEarly(TimePeriod c)
03893     {
03894       if (c >= 0L) maxearly = c;
03895       else throw DataException("MaxEarly must be positive");
03896     }
03897 
03898     /** Return a pointer to the setup matrix. */
03899     SetupMatrix* getSetupMatrix() const {return setupmatrix;}
03900 
03901     /** Update the reference to the setup matrix. */
03902     void setSetupMatrix(SetupMatrix *s) {setupmatrix = s;}
03903 
03904     /** Return the current setup. */
03905     const string& getSetup() const {return setup;}
03906 
03907     /** Update the current setup. */
03908     void setSetup(const string s) {setup = s;}
03909 
03910   private:
03911     /** This calendar is used to updates to the resource size. */
03912     CalendarDouble* max_cal;
03913 
03914     /** Stores the collection of all loadplans of this resource. */
03915     loadplanlist loadplans;
03916 
03917     /** This is a list of all load models that are linking this resource with
03918       * operations. */
03919     loadlist loads;
03920 
03921     /** A pointer to the location of the resource. */
03922     Location* loc;
03923 
03924     /** The cost of using 1 unit of this resource for 1 hour. */
03925     double cost;
03926 
03927     /** Specifies whether this resource is hidden for serialization. */
03928     bool hidden;
03929 
03930     /** Maximum inventory buildup allowed in case of capacity shortages. */
03931     TimePeriod maxearly;
03932 
03933     /** Reference to the setup matrix. */
03934     SetupMatrix *setupmatrix;
03935 
03936     /** Current setup. */
03937     string setup;
03938 };
03939 
03940 
03941 /** @brief This class is the default implementation of the abstract
03942   * Resource class.
03943   */
03944 class ResourceDefault : public Resource
03945 {
03946   public:
03947     explicit ResourceDefault(const string& str) : Resource(str) {initType(metadata);}
03948     virtual const MetaClass& getType() const {return *metadata;}
03949     static DECLARE_EXPORT const MetaClass* metadata;
03950     virtual size_t getSize() const
03951     {return sizeof(ResourceDefault) + Resource::extrasize();}
03952     static int initialize();
03953 };
03954 
03955 
03956 /** @brief This class represents a resource that'll never have any
03957   * capacity shortage. */
03958 class ResourceInfinite : public Resource
03959 {
03960   public:
03961     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03962     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03963     virtual const MetaClass& getType() const {return *metadata;}
03964     explicit ResourceInfinite(const string& c) : Resource(c)
03965       {setDetectProblems(false); initType(metadata);}
03966     static DECLARE_EXPORT const MetaClass* metadata;
03967     virtual size_t getSize() const
03968     {return sizeof(ResourceInfinite) + Resource::extrasize();}
03969     static int initialize();
03970 };
03971 
03972 
03973 /** @brief This class links a resource to a certain operation. */
03974 class Load
03975       : public Object, public Association<Operation,Resource,Load>::Node,
03976       public Solvable
03977 {
03978     friend class Resource;
03979     friend class Operation;
03980 
03981   public:
03982     /** Constructor. */
03983     explicit Load(Operation* o, Resource* r, double u)
03984       : priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY)
03985     {
03986       setOperation(o);
03987       setResource(r);
03988       setQuantity(u);
03989       validate(ADD);
03990       initType(metadata);
03991     }
03992 
03993     /** Destructor. */
03994     DECLARE_EXPORT ~Load();
03995 
03996     /** Returns the operation consuming the resource capacity. */
03997     Operation* getOperation() const {return getPtrA();}
03998 
03999     /** Updates the operation being loaded. This method can only be called
04000       * once for a load. */
04001     void setOperation(Operation* o) {if (o) setPtrA(o,o->getLoads());}
04002 
04003     /** Returns the capacity resource being consumed. */
04004     Resource* getResource() const {return getPtrB();}
04005 
04006     /** Updates the capacity being consumed. This method can only be called
04007       * once on a resource. */
04008     void setResource(Resource* r) {if (r) setPtrB(r,r->getLoads());}
04009 
04010     /** Returns how much capacity is consumed during the duration of the
04011       * operationplan. */
04012     double getQuantity() const {return qty;}
04013 
04014     /** Updates the quantity of the load.
04015       * @exception DataException When a negative number is passed.
04016       */
04017     void setQuantity(double f)
04018     {
04019       if (f < 0) throw DataException("Load quantity can't be negative");
04020       qty = f;
04021     }
04022 
04023     /** Update the priority of a load. */
04024     void setPriority(int i) {priority = i;}
04025 
04026     /** Return the priority of a load. */
04027     int getPriority() const {return priority;}
04028 
04029     /** Returns true if there are alternates for this load. */
04030     bool hasAlternates() const {return hasAlts;}
04031 
04032     /** Returns the load of which this one is an alternate.<br>
04033       * NULL is return where there is none.
04034       */
04035     Load* getAlternate() const {return altLoad;}
04036 
04037     /** Define the load of which this one is an alternate. */
04038     DECLARE_EXPORT void setAlternate(Load *);
04039 
04040     /** Define the load of which this one is an alternate. */
04041     DECLARE_EXPORT void setAlternate(const string& n);
04042 
04043     /** Update the required resource setup. */
04044     DECLARE_EXPORT void setSetup(const string);
04045 
04046     /** Return the required resource setup. */
04047     const string& getSetup() const {return setup;}
04048 
04049     /** This method holds the logic the compute the date of a loadplan. */
04050     virtual Date getLoadplanDate(const LoadPlan*) const;
04051 
04052     /** This method holds the logic the compute the quantity of a loadplan. */
04053     virtual double getLoadplanQuantity(const LoadPlan*) const;
04054 
04055     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04056     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04057     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04058     DECLARE_EXPORT PyObject* getattro(const Attribute&);
04059     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04060     static int initialize();
04061     static void writer(const MetaCategory*, XMLOutput*);
04062 
04063     bool getHidden() const
04064      {
04065       return (getResource() && getResource()->getHidden())
04066         || (getOperation() && getOperation()->getHidden());
04067     }
04068     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04069 
04070     virtual const MetaClass& getType() const {return *metadata;}
04071     static DECLARE_EXPORT const MetaCategory* metadata;
04072     virtual size_t getSize() const
04073       {return sizeof(Load) + getName().size() + getSetup().size();}
04074 
04075     /** Default constructor. */
04076     Load() : qty(1.0), priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY)
04077       {initType(metadata);}
04078 
04079     /** Return the search mode. */
04080     SearchMode getSearch() const {return search;}
04081 
04082     /** Update the search mode. */
04083     void setSearch(const string a) {search = decodeSearchMode(a);}
04084 
04085   private:
04086     /** This method is called to check the validity of the object. It will
04087       * delete the invalid loads: be careful with the 'this' pointer after
04088       * calling this method!
04089       */
04090     DECLARE_EXPORT void validate(Action action);
04091 
04092     /** Stores how much capacity is consumed during the duration of an
04093       * operationplan. */
04094     double qty;
04095 
04096     /** Priority of the load - used in case of alternate loads. */
04097     int priority;
04098 
04099     /** Flag that is set to true when a load has alternates. */
04100     bool hasAlts;
04101 
04102     /** A load representing the main load of a set of alternates. */
04103     Load* altLoad;
04104 
04105     /** Required setup. */
04106     string setup;
04107 
04108     /** Mode to select the preferred alternates. */
04109     SearchMode search;
04110 
04111     /** Factory method. */
04112     static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
04113 };
04114 
04115 
04116 
04117 /** @brief This is the (logical) top class of the complete model.
04118   *
04119   * This is a singleton class: only a single instance can be created.
04120   * The data model has other limitations that make it not obvious to support
04121   * building multiple models/plans in memory of the same application: e.g.
04122   * the operations, resources, problems, operationplans... etc are all
04123   * implemented in static, global lists. An entity can't be simply linked with
04124   * a particular plan if multiple ones would exist.
04125   */
04126 class Plan : public Plannable, public Object
04127 {
04128   private:
04129     /** Current Date of this plan. */
04130     Date cur_Date;
04131 
04132     /** A name for this plan. */
04133     string name;
04134 
04135     /** A getDescription of this plan. */
04136     string descr;
04137 
04138     /** Pointer to the singleton plan object. */
04139     static DECLARE_EXPORT Plan* thePlan;
04140 
04141     /** The only constructor of this class is made private. An object of this
04142       * class is created by the instance() member function.
04143       */
04144     Plan() : cur_Date(Date::now()) {initType(metadata);}
04145 
04146   public:
04147     /** Return a pointer to the singleton plan object.
04148       * The singleton object is created during the initialization of the
04149       * library.
04150       */
04151     static Plan& instance() {return *thePlan;}
04152 
04153     /** Destructor.
04154       * @warning In multi threaded applications, the destructor is never called
04155       * and the plan object leaks when we exit the application.
04156       * In single-threaded applications this function is called properly, when
04157       * the static plan variable is deleted.
04158       */
04159     DECLARE_EXPORT ~Plan();
04160 
04161     /** Returns the plan name. */
04162     const string& getName() const {return name;}
04163 
04164     /** Updates the plan name. */
04165     void setName(const string& s) {name = s;}
04166 
04167     /** Returns the current Date of the plan. */
04168     const Date & getCurrent() const {return cur_Date;}
04169 
04170     /** Updates the current date of the plan. This method can be relatively
04171       * heavy in a plan where operationplans already exist, since the
04172       * detection for BeforeCurrent problems needs to be rerun.
04173       */
04174     DECLARE_EXPORT void setCurrent(Date);
04175 
04176     /** Returns the description of the plan. */
04177     const string& getDescription() const {return descr;}
04178 
04179     /** Updates the description of the plan. */
04180     void setDescription(const string& str) {descr = str;}
04181 
04182     /** This method writes out the model information. Depending on a flag in
04183       * the XMLOutput object a complete model is written, or only the
04184       * dynamic plan information.
04185       * @see CommandSave, CommandSavePlan
04186       */
04187     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04188     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04189     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04190     DECLARE_EXPORT PyObject* getattro(const Attribute&);
04191     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04192 
04193     /** Initialize the class. */
04194     static int initialize();
04195 
04196     virtual void updateProblems() {};
04197 
04198     /** This method basically solves the whole planning problem. */
04199     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04200 
04201     const MetaClass& getType() const {return *metadata;}
04202     static DECLARE_EXPORT const MetaCategory* metadata;
04203     virtual size_t getSize() const
04204       {return sizeof(Plan) + name.size() + descr.size();}
04205 };
04206 
04207 
04208 /** @brief This command is used for reading XML input. The input comes either
04209   * from a flatfile, or from the standard input.
04210   *
04211   * The command is not thread-safe: multiple threads can simultaneously access
04212   * the same objects.
04213   */
04214 class CommandReadXMLFile : public Command
04215 {
04216   public:
04217     /** Constructor. If no file or directory name is passed or specified later
04218       * the standard input will be read during execution of the command. */
04219     CommandReadXMLFile(const char* s = NULL, bool v = true, bool o = false)
04220         : validate(v), validate_only(o) {if (s) filename = s;}
04221 
04222     /** Constructor. */
04223     CommandReadXMLFile(const string& s, bool v = true, bool o = false)
04224         : filename(s), validate(v), validate_only(o) {}
04225 
04226     /** Update the name of the input file. */
04227     void setFileName(const string& v) {filename = v;}
04228 
04229     /** Returns the name of the input file. */
04230     string getFileName() {return filename;}
04231 
04232     /** Enables or disables the validation. */
04233     void setValidate(bool b) {validate = b;}
04234 
04235     /** Returns true if the schema validation has been enabled. */
04236     bool getValidate() {return validate;}
04237 
04238     /** Only validate the input, do not really execute it. */
04239     void setValidateOnly(bool b) {validate_only = b;}
04240 
04241     /** Returns whether we only need to validate to data, or really execute
04242       * them too. */
04243     bool getValidateOnly() {return validate_only;}
04244 
04245     /** The commit action reads the input. If a filename is specified (either
04246       * in the constructor or with the setFileName function), a flat file is
04247       * read. Otherwise, the standard input is read. */
04248     DECLARE_EXPORT void execute();
04249 
04250     /** Python interface for this command. */
04251     static DECLARE_EXPORT PyObject* executePython(PyObject*, PyObject*);
04252 
04253   private:
04254     /** Name of the input to be read. An empty string means that we want to
04255       * read from standard input rather than a file. */
04256     string filename;
04257 
04258     /** Specifies whether or not the input file needs to be validated against
04259       * the schema definition. The validation is switched ON by default.
04260       * Switching it ON is recommended in situations where there is not
04261       * 100% garantuee on the validity of the input data.
04262       */
04263     bool validate;
04264 
04265     /** If set to true the input data are validated against the schema, but the
04266       * contents isn't executed. The default value is false. */
04267     bool validate_only;
04268 };
04269 
04270 
04271 /** @brief This command is used for reading XML input from a certain string.
04272   *
04273   * The command is not thread-safe: multiple threads can simultaneously access
04274   * the same objects.
04275   */
04276 class CommandReadXMLString : public Command
04277 {
04278   public:
04279     /** Constructor. */
04280     CommandReadXMLString(const string& s, const bool v=true, const bool o=false)
04281         : data(s), validate(v), validate_only(o) {};
04282 
04283     /** Default constructor. */
04284     CommandReadXMLString(const bool v=true, const bool o=false)
04285         : validate(v), validate_only(o) {};
04286 
04287     /** Updates the data string. */
04288     void setData(const string& v) {data = v;}
04289 
04290     /** Returns the data string. */
04291     string getData() {return data;}
04292 
04293     /** Enables or disables the validation. */
04294     void setValidate(bool b) {validate = b;}
04295 
04296     /** Returns true if the schema validation has been enabled. */
04297     bool getValidate() {return validate;}
04298 
04299     /** Only validate the input, do not really execute it. */
04300     void setValidateOnly(bool b) {validate_only = b;}
04301 
04302     /** Returns whether we only need to validate to data, or really execute
04303       * them too. */
04304     bool getValidateOnly() {return validate_only;}
04305 
04306     /** The commit action reads the input. */
04307     DECLARE_EXPORT void execute();
04308 
04309     /** Python interface for this command. */
04310     static DECLARE_EXPORT PyObject* executePython(PyObject *, PyObject *);
04311 
04312     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04313 
04314   private:
04315     /** Name of the input to be read. An empty string means that we want to
04316       * read from standard input rather than a file. */
04317     string data;
04318 
04319     /** Specifies whether or not the input file needs to be validated against
04320       * the schema definition. The validation is switched ON by default.
04321       * Switching it ON is recommended in situations where there is not
04322       * 100% garantuee on the validity of the input data.
04323       */
04324     bool validate;
04325 
04326     /** If set to true the input data are validated against the schema, but the
04327       * contents isn't executed. The default value is false. */
04328     bool validate_only;
04329 };
04330 
04331 
04332 /** @brief This command writes the complete model to an XML-file.
04333   *
04334   * Both the static model (i.e. items, locations, buffers, resources,
04335   * calendars, etc...) and the dynamic data (i.e. the actual plan including
04336   * the operationplans, demand, problems, etc...).<br>
04337   * The format is such that the output file can be re-read to restore the
04338   * very same model.<br>
04339   * The data is written by the execute() function.
04340   * @see CommandSavePlan
04341   */
04342 class CommandSave : public Command
04343 {
04344   public:
04345     /** Constructor. */
04346     CommandSave(const string& v = "plan.out")
04347         : filename(v), content(XMLOutput::STANDARD) {};
04348 
04349     /** Destructor. */
04350     virtual ~CommandSave() {};
04351 
04352     /** Return the name of the output file. */
04353     string getFileName() const {return filename;}
04354 
04355     /** Update the name of the output file. */
04356     void setFileName(const string& v) {filename = v;}
04357 
04358     /** Execute the command, ie write the data into XML format. */
04359     DECLARE_EXPORT void execute();
04360 
04361     /** Python interface to this command. */
04362     static DECLARE_EXPORT PyObject* executePython(PyObject*, PyObject*);
04363 
04364     /** Return the type of output. */
04365     XMLOutput::content_type getContent() const {return content;}
04366 
04367     /** Update the type of output.
04368       * @see XMLOutput::content_type
04369       */
04370     void setContent(XMLOutput::content_type t) {content = t;}
04371 
04372     /** Updates the string that is printed as the first line of each XML
04373       * document.<br>
04374       * The default value is:
04375       *   <?xml version="1.0" encoding="UTF-8"?>
04376       */
04377     void setHeaderStart(const string& s) {headerstart = s;}
04378 
04379     /** Returns the string that is printed as the first line of each XML
04380       * document. */
04381     string getHeaderStart() const {return headerstart;}
04382 
04383     /** Updates the attributes that are written for the root element of each
04384       * XML document.<br>
04385       * The default value is an empty string.
04386       */
04387     void setHeaderAtts(const string& s) {headeratts = s;}
04388 
04389     /** Returns the attributes that are written for the root element of each
04390       * XML document. */
04391     string getHeaderAtts() const {return headeratts;}
04392 
04393   private:
04394     string filename;
04395     string headerstart;
04396     string headeratts;
04397     XMLOutput::content_type content;
04398 };
04399 
04400 
04401 /** @brief This command writes the dynamic part of the plan to an  text file.
04402   *
04403   * This saved information covers the buffer flowplans, operationplans,
04404   * resource loading, demand, problems, etc...<br>
04405   * The main use of this function is in the test suite: a simple text file
04406   * comparison allows us to identify changes quickly. The output format is
04407   * only to be seen in this context of testing, and is not intended to be used
04408   * as an official method for publishing plans to other systems.<br>
04409   * The data file is written by the execute() function.
04410   * @see CommandSave
04411   */
04412 class CommandSavePlan : public Command
04413 {
04414   public:
04415     CommandSavePlan(const string& v = "plan.out") : filename(v) {};
04416     string getFileName() const {return filename;}
04417     void setFileName(const string& v) {filename = v;}
04418     DECLARE_EXPORT void execute();
04419 
04420     /** Python interface to this command. */
04421     static DECLARE_EXPORT PyObject* executePython(PyObject*, PyObject*);
04422 
04423     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04424   private:
04425     string filename;
04426 };
04427 
04428 
04429 /** @brief This command prints a summary of the dynamically allocated memory
04430   * to the standard output. This is useful for understanding better the size
04431   * of your model.
04432   *
04433   * The numbers reported by this function won't match the memory size as
04434   * reported by the operating system, since the dynamically allocated memory
04435   * is only a part of the total memory used by a program.
04436   */
04437 class CommandPlanSize : public Command
04438 {
04439   public:
04440     CommandPlanSize() {};
04441     DECLARE_EXPORT void execute();
04442     static PyObject* executePython(PyObject* self, PyObject* args)
04443       {CommandPlanSize x;x.execute(); return Py_BuildValue("");}
04444     void undo() {}
04445     bool undoable() const {return true;}
04446 };
04447 
04448 
04449 /** @brief This command deletes part of the model or the plan from memory.
04450   *
04451   * The class allows the following modes to control what to delete:
04452   *  - plan:<br>
04453   *    Deletes the dynamic modelling constructs, such as operationplans,
04454   *    loadplans and flowplans only. Locked operationplans are not
04455   *    deleted.<br>
04456   *    The static model is left intact.<br>
04457   *    This is the default mode.
04458   *  - model:<br>
04459   *    The dynamic as well as the static objects are removed. You'll end
04460   *    up with a completely empty model.
04461   *    Due to the logic required in the object destructors this mode doesn't
04462   *    scale linear with the model size.
04463   */
04464 class CommandErase : public Command
04465 {
04466   public:
04467     CommandErase(bool staticAlso = false) : deleteStaticModel(staticAlso) {};
04468 
04469     DECLARE_EXPORT void execute();
04470 
04471     /** Python interface to this command. */
04472     static DECLARE_EXPORT PyObject* executePython(PyObject*, PyObject*);
04473 
04474     bool getDeleteStaticModel() const {return deleteStaticModel;}
04475     void setDeleteStaticModel(bool b) {deleteStaticModel = b;}
04476   private:
04477     /** Flags whether to delete the complete static model or only the
04478       * dynamic plan information. */
04479     bool deleteStaticModel;
04480 };
04481 
04482 
04483 /** @brief Represents the (independent) demand in the system. It can represent a
04484   * customer order or a forecast.
04485   *
04486   * This is an abstract class.
04487   */
04488 class Demand
04489       : public HasHierarchy<Demand>, public Plannable, public HasDescription
04490 {
04491   public:
04492     typedef slist<OperationPlan*> OperationPlan_list;
04493 
04494     /** Constructor. */
04495     explicit Demand(const string& str) : HasHierarchy<Demand>(str),
04496       it(NULL), oper(NULL), cust(NULL), qty(0.0), prio(0),
04497       maxLateness(TimePeriod::MAX), minShipment(0), hidden(false) {}
04498 
04499     /** Destructor. Deleting the demand will also delete all delivery operation
04500       * plans */
04501     virtual ~Demand() {deleteOperationPlans(true);}
04502 
04503     /** Returns the quantity of the demand. */
04504     double getQuantity() const {return qty;}
04505 
04506     /** Updates the quantity of the demand. The quantity must be be greater
04507       * than or equal to 0. */
04508     virtual DECLARE_EXPORT void setQuantity(double);
04509 
04510     /** Returns the priority of the demand.<br>
04511       * Lower numbers indicate a higher priority level.
04512       */
04513     int getPriority() const {return prio;}
04514 
04515     /** Updates the due date of the demand.<br>
04516       * Lower numbers indicate a higher priority level.
04517       */
04518     virtual void setPriority(int i) {prio=i; setChanged();}
04519 
04520     /** Returns the item/product being requested. */
04521     Item* getItem() const {return it;}
04522 
04523     /** Updates the item/product being requested. */
04524     virtual void setItem(Item *i) {it=i; setChanged();}
04525 
04526     /** This fields points to an operation that is to be used to plan the
04527       * demand. By default, the field is left to NULL and the demand will then
04528       * be planned using the delivery operation of its item.
04529       * @see Item::getDelivery()
04530       */
04531     Operation* getOperation() const {return oper;}
04532 
04533     /** This function returns the operation that is to be used to satisfy this
04534       * demand. In sequence of priority this goes as follows:
04535       *   1) If the "operation" field on the demand is set, use it.
04536       *   2) Otherwise, use the "delivery" field of the requested item.
04537       *   3) Else, return NULL. This demand can't be satisfied!
04538       */
04539     DECLARE_EXPORT Operation* getDeliveryOperation() const;
04540 
04541     /** Returns the cluster which this demand belongs to. */
04542     int getCluster() const
04543     {
04544       Operation* o = getDeliveryOperation();
04545       return o ? o->getCluster() : 0;
04546     }
04547 
04548     /** Updates the operation being used to plan the demand. */
04549     virtual void setOperation(Operation* o) {oper=o; setChanged();}
04550 
04551     /** Returns the delivery operationplan list. */
04552     DECLARE_EXPORT const OperationPlan_list& getDelivery() const;
04553 
04554     /** Returns the latest delivery operationplan. */
04555     DECLARE_EXPORT OperationPlan* getLatestDelivery() const;
04556 
04557     /** Returns the earliest delivery operationplan. */
04558     DECLARE_EXPORT OperationPlan* getEarliestDelivery() const;
04559 
04560     /** Adds a delivery operationplan for this demand. */
04561     DECLARE_EXPORT void addDelivery(OperationPlan *o);
04562 
04563     /** Removes a delivery operationplan for this demand. */
04564     DECLARE_EXPORT void removeDelivery(OperationPlan *o);
04565 
04566     /** Deletes all delivery operationplans of this demand.<br>
04567       * The (optional) boolean parameter controls whether we delete also locked
04568       * operationplans or not.<br>
04569       * The second (optional) argument is a command list that can be used to
04570       * remove the operationplans in an undo-able way.
04571       */
04572     DECLARE_EXPORT void deleteOperationPlans
04573       (bool deleteLockedOpplans = false, CommandList* = NULL);
04574 
04575     /** Returns the due date of the demand. */
04576     const Date& getDue() const {return dueDate;}
04577 
04578     /** Updates the due date of the demand. */
04579     virtual void setDue(Date d) {dueDate = d; setChanged();}
04580 
04581     /** Returns the customer. */
04582     Customer* getCustomer() const {return cust;}
04583 
04584     /** Updates the customer. */
04585     virtual void setCustomer(Customer* c) {cust = c; setChanged();}
04586 
04587     /** Returns the total amount that has been planned. */
04588     DECLARE_EXPORT double getPlannedQuantity() const;
04589 
04590     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04591     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04592     virtual DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04593     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
04594     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04595     static int initialize();
04596 
04597     size_t extrasize() const
04598     {
04599       return getName().size() + HasDescription::extrasize()
04600         + sizeof(void*) * 2 * deli.size();
04601     }
04602 
04603     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04604 
04605     /** Return the maximum delay allowed in satisfying this demand.<br>
04606       * The default value is infinite.
04607       */
04608     TimePeriod getMaxLateness() const {return maxLateness;}
04609 
04610     /** Updates the maximum allowed lateness for this demand.<br>
04611       * The default value is infinite.<br>
04612       * The argument must be a positive time period.
04613       */
04614     virtual void setMaxLateness(TimePeriod m)
04615     {
04616       if (m < 0L)
04617         throw DataException("The maximum demand lateness must be positive");
04618       maxLateness = m;
04619     }
04620 
04621     /** Return the minimum shipment quantity allowed in satisfying this
04622       * demand.<br>
04623       * The default value is 0, which allows deliveries of any size.
04624       */
04625     double getMinShipment() const {return minShipment;}
04626 
04627     /** Updates the maximum allowed lateness for this demand.<br>
04628       * The default value is infinite.<br>
04629       * The argument must be a positive time period.
04630       */
04631     virtual void setMinShipment(double m)
04632     {
04633       if (m < 0.0)
04634         throw DataException("The minumum demand shipment quantity must be positive");
04635       minShipment = m;
04636     }
04637 
04638     /** Recompute the problems. */
04639     virtual DECLARE_EXPORT void updateProblems();
04640 
04641     /** Specifies whether of not this demand is to be hidden from
04642       * serialization. The default value is false. */
04643     void setHidden(bool b) {hidden = b;}
04644 
04645     /** Returns true if this demand is to be hidden from serialization. */
04646     bool getHidden() const {return hidden;}
04647 
04648     virtual const MetaClass& getType() const {return *metadata;}
04649     static DECLARE_EXPORT const MetaCategory* metadata;
04650 
04651   private:
04652     /** Requested item. */
04653     Item *it;
04654 
04655     /** Delivery Operation. Can be left NULL, in which case the delivery
04656       * operation can be specified on the requested item. */
04657     Operation *oper;
04658 
04659     /** Customer creating this demand. */
04660     Customer *cust;
04661 
04662     /** Requested quantity. Only positive numbers are allowed. */
04663     double qty;
04664 
04665     /** Priority. Lower numbers indicate a higher priority level.*/
04666     int prio;
04667 
04668     /** Due date. */
04669     Date dueDate;
04670 
04671     /** Maximum lateness allowed when planning this demand.<br>
04672       * The default value is TimePeriod::MAX.
04673       */
04674     TimePeriod maxLateness;
04675 
04676     /** Minimum size for a delivery operation plan satisfying this demand. */
04677     double minShipment;
04678 
04679     /** Hide this demand or not. */
04680     bool hidden;
04681 
04682     /** A list of operation plans to deliver this demand. */
04683     OperationPlan_list deli;
04684 };
04685 
04686 
04687 /** @brief This class is the default implementation of the abstract
04688   * Demand class. */
04689 class DemandDefault : public Demand
04690 {
04691   public:
04692     explicit DemandDefault(const string& str) : Demand(str) {initType(metadata);}
04693     virtual const MetaClass& getType() const {return *metadata;}
04694     static DECLARE_EXPORT const MetaClass* metadata;
04695     virtual size_t getSize() const
04696     {return sizeof(DemandDefault) + Demand::extrasize();}
04697     static int initialize();
04698 };
04699 
04700 
04701 /** @brief This class represents the resource capacity of an operationplan.
04702   *
04703   * For both the start and the end date of the operationplan, a loadplan
04704   * object is created. These are then inserted in the timeline structure
04705   * associated with a resource.
04706   */
04707 class LoadPlan : public TimeLine<LoadPlan>::EventChangeOnhand, public PythonExtensionBase
04708 {
04709     friend class OperationPlan::LoadPlanIterator;
04710   public:
04711     /** Public constructor.<br>
04712       * This constructor constructs the starting loadplan and will
04713       * also call a private constructor to creates the ending loadplan.
04714       * In other words, a single call to the constructor will create
04715       * two loadplan objects.
04716       */
04717     explicit DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*);
04718 
04719     /** Return the operationplan owning this loadplan. */
04720     OperationPlan* getOperationPlan() const {return oper;}
04721 
04722     /** Return the load of which this is a plan instance. */
04723     const Load* getLoad() const {return ld;}
04724 
04725     /** Return the resource. */
04726     const Resource* getResource() const {return ld->getResource();}
04727 
04728     /** Update the load of an already existing flowplan.<br>
04729       * The new load must belong to the same operation.
04730       */
04731     DECLARE_EXPORT void setLoad(const Load*);
04732 
04733     /** Return true when this loadplan marks the start of an operationplan. */
04734     bool isStart() const {return start_or_end == START;}
04735 
04736     /** Destructor. */
04737     DECLARE_EXPORT virtual ~LoadPlan();
04738 
04739     /** This function needs to be called whenever the loadplan date or
04740       * quantity are changed.
04741       */
04742     DECLARE_EXPORT void update();
04743 
04744     /** Return a pointer to the timeline data structure owning this loadplan. */
04745     TimeLine<LoadPlan>* getTimeLine() const
04746     {return &(ld->getResource()->loadplans);}
04747 
04748     /** Returns the current setup of the resource.<br> 
04749       * When the argument is true (= default) the current setup is returned.<br>
04750       * When the argument is false the setup just before the loadplan is returned.
04751       */
04752     DECLARE_EXPORT const string& getSetup(bool = true) const;
04753 
04754     /** Returns true when the loadplan is hidden.<br>
04755       * This is determined by looking at whether the load is hidden or not.
04756       */
04757     bool getHidden() const {return ld->getHidden();}
04758 
04759     /** Each operationplan has 2 loadplans per load: one at the start,
04760       * when the capacity consumption starts, and one at the end, when the
04761       * capacity consumption ends.<br>
04762       * This method returns the "companion" loadplan. It is not very
04763       * scalable: the performance is linear with the number of loadplans
04764       * on the resource.
04765       */
04766     DECLARE_EXPORT LoadPlan* getOtherLoadPlan() const;
04767 
04768     static int initialize();
04769     static DECLARE_EXPORT const MetaCategory* metadata;
04770     PyObject* getattro(const Attribute&);
04771 
04772   private:
04773     /** Private constructor. It is called from the public constructor.<br>
04774       * The public constructor constructs the starting loadplan, while this
04775       * constructor creates the ending loadplan.
04776       */
04777     DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*, LoadPlan*);
04778 
04779     /** This type is used to differentiate loadplans aligned with the START date
04780       * or the END date of operationplan. */
04781     enum type {START, END};
04782 
04783     /** Is this loadplan a starting one or an ending one. */
04784     type start_or_end;
04785 
04786     /** A pointer to the load model. */
04787     const Load *ld;
04788 
04789     /** A pointer to the operationplan owning this loadplan. */
04790     OperationPlan *oper;
04791 
04792     /** Points to the next loadplan owned by the same operationplan. */
04793     LoadPlan *nextLoadPlan;
04794 };
04795 
04796 
04797 inline Date Load::getLoadplanDate(const LoadPlan* lp) const
04798 {
04799   const DateRange & dr = lp->getOperationPlan()->getDates();
04800   if (lp->isStart())
04801     return dr.getStart() > getEffective().getStart() ?
04802       dr.getStart() :
04803       getEffective().getStart();
04804   else
04805     return dr.getEnd() < getEffective().getEnd() ?
04806       dr.getEnd() :
04807       getEffective().getEnd();
04808 }
04809 
04810 
04811 inline double Load::getLoadplanQuantity(const LoadPlan* lp) const
04812 {
04813   if (!lp->getOperationPlan()->getDates().overlap(getEffective()) 
04814     && (lp->getOperationPlan()->getDates().getDuration() 
04815          || !getEffective().within(lp->getOperationPlan()->getDates().getStart())))
04816     // Load is not effective during this time.
04817     // The extra check is required to make sure that zero duration operationplans
04818     // operationplans don't get resized to 0
04819     return 0.0;
04820   return lp->isStart() ? getQuantity() : -getQuantity();
04821 }
04822 
04823 
04824 
04825 /** @brief A problem of this class is created when an operationplan is being
04826   * planned in the past, i.e. it starts before the "current" date of
04827   * the plan.
04828   */
04829 class ProblemBeforeCurrent : public Problem
04830 {
04831   public:
04832     string getDescription() const
04833     {
04834       ostringstream ch;
04835       ch << "Job '" << static_cast<OperationPlan*>(getOwner())->getIdentifier()
04836       << "' planned in the past";
04837       return ch.str();
04838     }
04839     bool isFeasible() const {return false;}
04840     double getWeight() const
04841     {return dynamic_cast<OperationPlan*>(getOwner())->getQuantity();}
04842     explicit ProblemBeforeCurrent(OperationPlan* o) : Problem(o)
04843       {addProblem();}
04844     ~ProblemBeforeCurrent() {removeProblem();}
04845     string getEntity() const {return "operation";}
04846     Object* getOwner() const {return dynamic_cast<OperationPlan*>(owner);}
04847     const DateRange getDateRange() const
04848     {
04849       OperationPlan *o = dynamic_cast<OperationPlan*>(getOwner());
04850       if (o->getDates().getEnd() > Plan::instance().getCurrent())
04851         return DateRange(o->getDates().getStart(),
04852             Plan::instance().getCurrent());
04853       else
04854         return DateRange(o->getDates().getStart(),
04855             o->getDates().getEnd());
04856     }
04857     size_t getSize() const {return sizeof(ProblemBeforeCurrent);}
04858 
04859     /** Return a reference to the metadata structure. */
04860     const MetaClass& getType() const {return *metadata;}
04861 
04862     /** Storing metadata on this class. */
04863     static DECLARE_EXPORT const MetaClass* metadata;
04864 };
04865 
04866 
04867 /** @brief A problem of this class is created when an operationplan is being
04868   * planned before its fence date, i.e. it starts 1) before the "current"
04869   * date of the plan plus the release fence of the operation and 2) after the
04870   * current date of the plan.
04871   */
04872 class ProblemBeforeFence : public Problem
04873 {
04874   public:
04875     string getDescription() const
04876     {
04877       ostringstream ch;
04878       ch << "Job '" << static_cast<OperationPlan*>(getOwner())->getIdentifier()
04879       << "' planned before fence";
04880       return ch.str();
04881     }
04882     bool isFeasible() const {return true;}
04883     double getWeight() const
04884     {return static_cast<OperationPlan*>(getOwner())->getQuantity();}
04885     explicit ProblemBeforeFence(OperationPlan* o) : Problem(o)
04886       {addProblem();}
04887     ~ProblemBeforeFence() {removeProblem();}
04888     string getEntity() const {return "operation";}
04889     Object* getOwner() const {return dynamic_cast<OperationPlan*>(owner);}
04890     const DateRange getDateRange() const
04891     {
04892       OperationPlan *o = dynamic_cast<OperationPlan*>(owner);
04893       if (o->getDates().getEnd() > Plan::instance().getCurrent()
04894           + o->getOperation()->getFence())
04895         return DateRange(o->getDates().getStart(),
04896             Plan::instance().getCurrent() + o->getOperation()->getFence());
04897       else
04898         return DateRange(o->getDates().getStart(),
04899             o->getDates().getEnd());
04900     }
04901     size_t getSize() const {return sizeof(ProblemBeforeFence);}
04902 
04903     /** Return a reference to the metadata structure. */
04904     const MetaClass& getType() const {return *metadata;}
04905 
04906     /** Storing metadata on this class. */
04907     static DECLARE_EXPORT const MetaClass* metadata;
04908 };
04909 
04910 
04911 /** @brief A problem of this class is created when the sequence of two
04912   * operationplans in a routing isn't respected.
04913   */
04914 class ProblemPrecedence : public Problem
04915 {
04916   public:
04917     string getDescription() const
04918     {
04919       OperationPlan *o = static_cast<OperationPlan*>(getOwner());
04920       if (!o->nextsubopplan)
04921         return string("Bogus precendence problem on '")
04922           + o->getOperation()->getName() + "'";
04923       else
04924         return string("Operation '") + o->getOperation()->getName()
04925           + "' starts before operation '"
04926           + o->nextsubopplan->getOperation()->getName() +"' ends";
04927     }
04928     bool isFeasible() const {return false;}
04929     /** The weight of the problem is equal to the duration in days. */
04930     double getWeight() const
04931     {
04932       return static_cast<double>(getDateRange().getDuration()) / 86400;
04933     }
04934     explicit ProblemPrecedence(OperationPlan* o) : Problem(o) {addProblem();}
04935     ~ProblemPrecedence() {removeProblem();}
04936     string getEntity() const {return "operation";}
04937     Object* getOwner() const {return dynamic_cast<OperationPlan*>(owner);}
04938     const DateRange getDateRange() const
04939     {
04940       OperationPlan *o = static_cast<OperationPlan*>(getOwner());
04941       return DateRange(o->nextsubopplan->getDates().getStart(),
04942         o->getDates().getEnd());
04943     }
04944 
04945     /** Return a reference to the metadata structure. */
04946     const MetaClass& getType() const {return *metadata;}
04947 
04948     /** Storing metadata on this class. */
04949     static DECLARE_EXPORT const MetaClass* metadata;
04950     size_t getSize() const {return sizeof(ProblemPrecedence);}
04951 };
04952 
04953 
04954 /** @brief A Problem of this class is created in the model when a new demand is
04955   * brought in the system, but it hasn't been planned yet.
04956   *
04957   * As a special case, a demand with a requested quantity of 0.0 doesn't create
04958   * this type of problem.
04959   */
04960 class ProblemDemandNotPlanned : public Problem
04961 {
04962   public:
04963     string getDescription() const
04964       {return string("Demand '") + getDemand()->getName() + "' is not planned";}
04965     bool isFeasible() const {return false;}
04966     double getWeight() const {return getDemand()->getQuantity();}
04967     explicit ProblemDemandNotPlanned(Demand* d) : Problem(d) {addProblem();}
04968     ~ProblemDemandNotPlanned() {removeProblem();}
04969     string getEntity() const {return "demand";}
04970     const DateRange getDateRange() const
04971       {return DateRange(getDemand()->getDue(),getDemand()->getDue());}
04972     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
04973     Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
04974     size_t getSize() const {return sizeof(ProblemDemandNotPlanned);}
04975 
04976     /** Return a reference to the metadata structure. */
04977     const MetaClass& getType() const {return *metadata;}
04978 
04979     /** Storing metadata on this class. */
04980     static DECLARE_EXPORT const MetaClass* metadata;
04981 };
04982 
04983 
04984 /** @brief A problem of this class is created when a demand is satisfied later
04985   * than the accepted tolerance after its due date.
04986   */
04987 class ProblemLate : public Problem
04988 {
04989   public:
04990     DECLARE_EXPORT string getDescription() const;
04991     bool isFeasible() const {return true;}
04992 
04993     /** The weight is equal to the delay, expressed in days.<br>
04994       * The quantity being delayed is not included.
04995       */
04996     double getWeight() const
04997     {
04998       assert(getDemand() && !getDemand()->getDelivery().empty());
04999       return static_cast<double>(DateRange(
05000         getDemand()->getDue(),
05001         getDemand()->getLatestDelivery()->getDates().getEnd()
05002         ).getDuration()) / 86400;
05003     }
05004 
05005     /** Constructor. */
05006     explicit ProblemLate(Demand* d) : Problem(d) {addProblem();}
05007 
05008     /** Destructor. */
05009     ~ProblemLate() {removeProblem();}
05010 
05011     const DateRange getDateRange() const
05012     {
05013       assert(getDemand() && !getDemand()->getDelivery().empty());
05014       return DateRange(getDemand()->getDue(),
05015           getDemand()->getLatestDelivery()->getDates().getEnd());
05016     }
05017     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
05018     size_t getSize() const {return sizeof(ProblemLate);}
05019     string getEntity() const {return "demand";}
05020     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05021 
05022     /** Return a reference to the metadata structure. */
05023     const MetaClass& getType() const {return *metadata;}
05024 
05025     /** Storing metadata on this class. */
05026     static DECLARE_EXPORT const MetaClass* metadata;
05027 };
05028 
05029 
05030 /** @brief A problem of this class is created when a demand is planned earlier
05031   * than the accepted tolerance before its due date.
05032   */
05033 class ProblemEarly : public Problem
05034 {
05035   public:
05036     DECLARE_EXPORT string getDescription() const;
05037     bool isFeasible() const {return true;}
05038     double getWeight() const
05039     {
05040       assert(getDemand() && !getDemand()->getDelivery().empty());
05041       return static_cast<double>(DateRange(
05042         getDemand()->getDue(),
05043         getDemand()->getEarliestDelivery()->getDates().getEnd()
05044         ).getDuration()) / 86400;
05045     }
05046     explicit ProblemEarly(Demand* d) : Problem(d) {addProblem();}
05047     ~ProblemEarly() {removeProblem();}
05048     string getEntity() const {return "demand";}
05049     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05050     const DateRange getDateRange() const
05051     {
05052       assert(getDemand() && !getDemand()->getDelivery().empty());
05053       return DateRange(getDemand()->getDue(),
05054           getDemand()->getEarliestDelivery()->getDates().getEnd());
05055     }
05056     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
05057     size_t getSize() const {return sizeof(ProblemEarly);}
05058 
05059     /** Return a reference to the metadata structure. */
05060     const MetaClass& getType() const {return *metadata;}
05061 
05062     /** Storing metadata on this class. */
05063     static DECLARE_EXPORT const MetaClass* metadata;
05064 };
05065 
05066 
05067 /** @brief A problem of this class is created when a demand is planned for less than
05068   * the requested quantity.
05069   */
05070 class ProblemShort : public Problem
05071 {
05072   public:
05073     string getDescription() const
05074     {
05075       ostringstream ch;
05076       ch << "Demand '" << getDemand()->getName() << "' planned "
05077       << (getDemand()->getQuantity() - getDemand()->getPlannedQuantity())
05078       << " units short";
05079       return ch.str();
05080     }
05081     bool isFeasible() const {return true;}
05082     double getWeight() const
05083       {return getDemand()->getQuantity() - getDemand()->getPlannedQuantity();}
05084     explicit ProblemShort(Demand* d) : Problem(d) {addProblem();}
05085     ~ProblemShort() {removeProblem();}
05086     string getEntity() const {return "demand";}
05087     const DateRange getDateRange() const
05088       {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
05089     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05090     Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
05091     size_t getSize() const {return sizeof(ProblemShort);}
05092 
05093     /** Return a reference to the metadata structure. */
05094     const MetaClass& getType() const {return *metadata;}
05095 
05096     /** Storing metadata on this class. */
05097     static DECLARE_EXPORT const MetaClass* metadata;
05098 };
05099 
05100 
05101 /** @brief A problem of this class is created when a demand is planned for more
05102   * than the requested quantity.
05103   */
05104 class ProblemExcess : public Problem
05105 {
05106   public:
05107     string getDescription() const
05108     {
05109       ostringstream ch;
05110       ch << "Demand '" << getDemand()->getName() << "' planned "
05111       << (getDemand()->getPlannedQuantity() - getDemand()->getQuantity())
05112       << " units excess";
05113       return ch.str();
05114     }
05115     bool isFeasible() const {return true;}
05116     double getWeight() const
05117       {return getDemand()->getPlannedQuantity() - getDemand()->getQuantity();}
05118     explicit ProblemExcess(Demand* d) : Problem(d) {addProblem();}
05119     string getEntity() const {return "demand";}
05120     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05121     ~ProblemExcess() {removeProblem();}
05122     const DateRange getDateRange() const
05123       {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
05124     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
05125     size_t getSize() const {return sizeof(ProblemExcess);}
05126 
05127     /** Return a reference to the metadata structure. */
05128     const MetaClass& getType() const {return *metadata;}
05129 
05130     /** Storing metadata on this class. */
05131     static DECLARE_EXPORT const MetaClass* metadata;
05132 };
05133 
05134 
05135 /** @brief A problem of this class is created when a resource is being
05136   * overloaded during a certain period of time.
05137   */
05138 class ProblemCapacityOverload : public Problem
05139 {
05140   public:
05141     DECLARE_EXPORT string getDescription() const;
05142     bool isFeasible() const {return false;}
05143     double getWeight() const {return qty;}
05144     ProblemCapacityOverload(Resource* r, DateRange d, double q)
05145         : Problem(r), qty(q), dr(d) {addProblem();}
05146     ~ProblemCapacityOverload() {removeProblem();}
05147     string getEntity() const {return "capacity";}
05148     Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
05149     const DateRange getDateRange() const {return dr;}
05150     Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
05151     size_t getSize() const {return sizeof(ProblemCapacityOverload);}
05152 
05153     /** Return a reference to the metadata structure. */
05154     const MetaClass& getType() const {return *metadata;}
05155 
05156     /** Storing metadata on this class. */
05157     static DECLARE_EXPORT const MetaClass* metadata;
05158 
05159   private:
05160     /** Overload quantity. */
05161     double qty;
05162 
05163     /** The daterange of the problem. */
05164     DateRange dr;
05165 };
05166 
05167 
05168 /** @brief A problem of this class is created when a resource is loaded below
05169   * its minimum during a certain period of time.
05170   */
05171 class ProblemCapacityUnderload : public Problem
05172 {
05173   public:
05174     DECLARE_EXPORT string getDescription() const;
05175     bool isFeasible() const {return true;}
05176     double getWeight() const {return qty;}
05177     ProblemCapacityUnderload(Resource* r, DateRange d, double q)
05178         : Problem(r), qty(q), dr(d) {addProblem();}
05179     ~ProblemCapacityUnderload() {removeProblem();}
05180     string getEntity() const {return "capacity";}
05181     Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
05182     const DateRange getDateRange() const {return dr;}
05183     Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
05184     size_t getSize() const {return sizeof(ProblemCapacityUnderload);}
05185 
05186     /** Return a reference to the metadata structure. */
05187     const MetaClass& getType() const {return *metadata;}
05188 
05189     /** Storing metadata on this class. */
05190     static DECLARE_EXPORT const MetaClass* metadata;
05191 
05192   private:
05193     /** Underload quantity. */
05194     double qty;
05195 
05196     /** The daterange of the problem. */
05197     DateRange dr;
05198 };
05199 
05200 
05201 /** @brief A problem of this class is created when a buffer is having a
05202   * material shortage during a certain period of time.
05203   */
05204 class ProblemMaterialShortage : public Problem
05205 {
05206   public:
05207     DECLARE_EXPORT string getDescription() const;
05208     bool isFeasible() const {return false;}
05209     double getWeight() const {return qty;}
05210     ProblemMaterialShortage(Buffer* b, Date st, Date nd, double q)
05211         : Problem(b), qty(q), dr(st,nd) {addProblem();}
05212     string getEntity() const {return "material";}
05213     Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
05214     ~ProblemMaterialShortage() {removeProblem();}
05215     const DateRange getDateRange() const {return dr;}
05216     Buffer* getBuffer() const {return dynamic_cast<Buffer*>(getOwner());}
05217     size_t getSize() const {return sizeof(ProblemMaterialShortage);}
05218 
05219     /** Return a reference to the metadata structure. */
05220     const MetaClass& getType() const {return *metadata;}
05221 
05222     /** Storing metadata on this class. */
05223     static DECLARE_EXPORT const MetaClass* metadata;
05224 
05225   private:
05226     /** Shortage quantity. */
05227     double qty;
05228 
05229     /** The daterange of the problem. */
05230     DateRange dr;
05231 };
05232 
05233 
05234 /** @brief A problem of this class is created when a buffer is carrying too
05235   * much material during a certain period of time.
05236   */
05237 class ProblemMaterialExcess : public Problem
05238 {
05239   public:
05240     DECLARE_EXPORT string getDescription() const;
05241     bool isFeasible() const {return true;}
05242     double getWeight() const {return qty;}
05243     ProblemMaterialExcess(Buffer* b, Date st, Date nd, double q)
05244         : Problem(b), qty(q), dr(st,nd) {addProblem();}
05245     string getEntity() const {return "material";}
05246     ~ProblemMaterialExcess() {removeProblem();}
05247     const DateRange getDateRange() const {return dr;}
05248     Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
05249     Buffer* getBuffer() const {return dynamic_cast<Buffer*>(owner);}
05250     size_t getSize() const {return sizeof(ProblemMaterialExcess);}
05251 
05252     /** Return a reference to the metadata structure. */
05253     const MetaClass& getType() const {return *metadata;}
05254 
05255     /** Storing metadata on this class. */
05256     static DECLARE_EXPORT const MetaClass* metadata;
05257 
05258   private:
05259     /** Excess quantity. */
05260     double qty;
05261 
05262     /** The daterange of the problem. */
05263     DateRange dr;
05264 };
05265 
05266 
05267 /** @brief This command is used to create an operationplan.
05268   *
05269   * The operationplan will have its load and loadplans created when the
05270   * command is created. It is assigned an id and added to the list of all
05271   * operationplans when the command is committed.
05272   */
05273 class CommandCreateOperationPlan : public Command
05274 {
05275   public:
05276     /** Constructor. */
05277     CommandCreateOperationPlan
05278       (const Operation* o, double q, Date d1, Date d2, Demand* l,
05279       OperationPlan* ow=NULL, bool makeflowsloads=true)
05280     {
05281       opplan = o ?
05282           o->createOperationPlan(q, d1, d2, l, ow, 0, makeflowsloads)
05283           : NULL;
05284     }
05285     void execute()
05286     {
05287       if (opplan)
05288       {
05289        opplan->instantiate();
05290         opplan = NULL; // Avoid executing / initializing more than once
05291       }
05292     }
05293     void undo() {delete opplan; opplan = NULL;}
05294     bool undoable() const {return true;}
05295     ~CommandCreateOperationPlan() {if (opplan) delete opplan;}
05296     OperationPlan *getOperationPlan() const {return opplan;}
05297 
05298   private:
05299     /** Pointer to the newly created operationplan. */
05300     OperationPlan *opplan;
05301 };
05302 
05303 
05304 /** @brief This command is used to delete an operationplan.
05305   *
05306   * The operationplan will be deleted when the command is created.
05307   */
05308 class CommandDeleteOperationPlan : public Command
05309 {
05310   public:
05311     /** Constructor.<br>
05312       * Unlike most other commands the constructor already executes the deletion.
05313       */
05314     DECLARE_EXPORT CommandDeleteOperationPlan(OperationPlan* o);
05315     void execute() {oper = NULL;}
05316     DECLARE_EXPORT void undo();
05317     bool undoable() const {return true;}
05318     ~CommandDeleteOperationPlan() {if (oper) undo();}
05319 
05320   private:
05321     /** Operation pointer of the original operationplan. */
05322     Operation *oper;
05323 
05324     /** Daterange of the original operationplan. */
05325     DateRange dates;
05326 
05327     /** Quantity of the original operationplan. */
05328     double qty;
05329 
05330     /** Identifier of the original operationplan. */
05331     long unsigned id;
05332 
05333     /** Demand pointer of the original operationplan. */
05334     Demand *dmd;
05335 
05336     /** Owner of the original operationplan. */
05337     OperationPlan *ow;
05338 };
05339 
05340 
05341 /** @brief This class represents the command of moving an operationplan to a
05342   * new date and/or resizing it.
05343   * @todo Moving in a routing operation can't be undone with the current
05344   * implementation! The command will need to store all original dates of
05345   * the suboperationplans...
05346   */
05347 class CommandMoveOperationPlan : public Command
05348 {
05349   public:
05350     /** Constructor.<br>
05351       * Unlike most other commands the constructor already executes the change.
05352       * @param opplanptr Pointer to the operationplan being moved.
05353       * @param newStart New start date of the operationplan.
05354       * @param newEnd New end date of the operationplan.
05355       * @param newQty New quantity of the operationplan.The default is -1,
05356       * which indicates to leave the quantity unchanged.
05357       */
05358     DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan* opplanptr,
05359       Date newStart, Date newEnd, double newQty = -1.0);
05360 
05361     /** Default constructor. */
05362     DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan*);
05363 
05364     /** Commit the changes. */
05365     void execute() {opplan=NULL;}
05366 
05367     /** Undo the changes. */
05368     void undo() {restore(true); opplan = NULL;}
05369 
05370     /** Undo the changes. */
05371     DECLARE_EXPORT void restore(bool = false);
05372 
05373     bool undoable() const {return true;}
05374 
05375     /** Destructor. */
05376     ~CommandMoveOperationPlan() {if (opplan) undo();}
05377 
05378     /** Returns the operationplan being manipulated. */
05379     OperationPlan* getOperationPlan() const {return opplan;}
05380 
05381     /** Set another start date for the operationplan. */
05382     void setStart(Date d) {if (opplan) opplan->setStart(d);}
05383 
05384     /** Set another start date, end date and quantity for the operationplan. */
05385     void setParameters(Date s, Date e, double q, bool b) 
05386     {
05387       assert(opplan->getOperation());
05388       if (opplan) 
05389         opplan->getOperation()->setOperationPlanParameters(opplan, q, s, e, b);
05390     }
05391 
05392     /** Set another start date for the operationplan. */
05393     void setEnd(Date d) {if (opplan) opplan->setEnd(d);}
05394 
05395     /** Set another quantity for the operationplan. */
05396     void setQuantity(double q) {if (opplan) opplan->setQuantity(q);}
05397 
05398     /** Return the quantity of the original operationplan. */
05399     double getQuantity() const {return originalqty; }
05400 
05401     /** Return the dates of the original operationplan. */
05402     DateRange getDates() const {return originaldates;}
05403 
05404   private:
05405     /** This is a pointer to the operationplan being moved. */
05406     OperationPlan *opplan;
05407 
05408     /** These are the original dates of the operationplan before its move. */
05409     DateRange originaldates;
05410 
05411     /** This is the quantity of the operationplan before the command. */
05412     double originalqty;
05413 
05414     /** A pointer to a list of suboperationplan commands. */
05415     Command* firstCommand;
05416 };
05417 
05418 
05419 /** @brief This class models a iterator that walks over all available
05420   * HasProblem entities.
05421   *
05422   * This list is containing hard-coding the classes that are implementing
05423   * this class. It's not ideal, but we don't have an explicit container
05424   * of the objects (and we don't want one either) and this allows us also
05425   * to re-use the sorting used for the container classes.
05426   */
05427 class HasProblems::EntityIterator
05428 {
05429   private:
05430     /** This union contains iterators through the different entity types.
05431       * Only one of the different iterators will be active at a time, and
05432       * can thus save memory by collapsing the iterators into a single
05433       * union. */
05434     union
05435     {
05436       Buffer::iterator *bufIter;
05437       Resource::iterator *resIter;
05438       OperationPlan::iterator *operIter;
05439       Demand::iterator *demIter;
05440     };
05441 
05442     /** This type indicates which type of entity we are currently recursing
05443       * through.
05444       *  - 0: buffers
05445       *  - 1: resources
05446       *  - 2: operationplans
05447       *  - 3: demands
05448       */
05449     unsigned short type;
05450 
05451   public:
05452     /** Default constructor, which creates an iterator to the first
05453       * HasProblems object. */
05454     explicit DECLARE_EXPORT EntityIterator();
05455 
05456     /** Used to create an iterator pointing beyond the last HasProblems
05457       * object. */
05458     explicit EntityIterator(unsigned short i) : type(i) {}
05459 
05460     /** Copy constructor. */
05461     DECLARE_EXPORT EntityIterator(const EntityIterator& o);
05462 
05463     /** Assignment operator. */
05464     DECLARE_EXPORT EntityIterator& operator=(const EntityIterator& o);
05465 
05466     /** Destructor. */
05467     DECLARE_EXPORT ~EntityIterator();
05468 
05469     /** Pre-increment operator. */
05470     DECLARE_EXPORT EntityIterator& operator++();
05471 
05472     /** Inequality operator.<br>
05473       * Two iterators are different when they point to different objects.
05474       */
05475     DECLARE_EXPORT bool operator != (const EntityIterator& t) const;
05476 
05477     /** Equality operator.<br>
05478       * Two iterators are equal when they point to the same object.
05479       */
05480     bool operator == (const EntityIterator& t) const {return !(*this != t);}
05481 
05482     /** Dereference operator. */
05483     DECLARE_EXPORT HasProblems& operator*() const;
05484 
05485     /** Dereference operator. */
05486     DECLARE_EXPORT HasProblems* operator->() const;
05487 };
05488 
05489 
05490 /** @brief This class models an STL-like iterator that allows us to iterate
05491   * over the named entities in a simple and safe way.
05492   *
05493   * Objects of this class are returned by the begin() and end() functions.
05494   * @see Problem::begin()
05495   * @see Problem::begin(HasProblem*)
05496   * @see Problem::end()
05497   */
05498 class Problem::const_iterator
05499 {
05500     friend class Problem;
05501   private:
05502     /** A pointer to the current problem. If this pointer is NULL, we are
05503       * at the end of the list. */
05504     Problem* iter;
05505     HasProblems* owner;
05506     HasProblems::EntityIterator eiter;
05507 
05508   public:
05509     /** Creates an iterator that will loop through the problems of a
05510       * single entity only. <BR>
05511       * This constructor is also used to create a end-iterator, when passed
05512       * a NULL pointer as argument.
05513       */
05514     explicit const_iterator(HasProblems* o) : iter(o ? o->firstProblem : NULL),
05515       owner(o), eiter(4) {}
05516 
05517     /** Creates an iterator that will loop through the problems of all
05518       * entities. */
05519     explicit const_iterator() : owner(NULL)
05520     {
05521       // Loop till we find an entity with a problem
05522       while (eiter!=HasProblems::endEntity() && !(eiter->firstProblem))
05523         ++eiter;
05524       // Found a first problem, or no problem at all
05525       iter = (eiter!=HasProblems::endEntity()) ? eiter->firstProblem : NULL;
05526     }
05527 
05528     /** Pre-increment operator. */
05529     DECLARE_EXPORT const_iterator& operator++();
05530 
05531     /** Inequality operator. */
05532     bool operator != (const const_iterator& t) const {return iter!=t.iter;}
05533 
05534     /** Equality operator. */
05535     bool operator == (const const_iterator& t) const {return iter==t.iter;}
05536 
05537     Problem& operator*() const {return *iter;}
05538     Problem* operator->() const {return iter;}
05539 };
05540 
05541 
05542 /** @brief This class allows upstream and downstream navigation through
05543   * the plan.
05544   *
05545   * Downstream navigation follows the material flow from raw materials
05546   * towards the produced end item.<br>
05547   * Upstream navigation traces back the material flow from the end item up to
05548   * the consumed raw materials.<br>
05549   * The class is implemented as an STL-like iterator.
05550   *
05551   * @todo operationplans without flowplans are skipped by the iterator - not correct!
05552   */
05553 class PeggingIterator : public Object
05554 {
05555   public:
05556     /** Constructor. */
05557     DECLARE_EXPORT PeggingIterator(const Demand* e);
05558 
05559     /** Constructor. */
05560     PeggingIterator(const FlowPlan* e, bool b = true)
05561       : downstream(b), firstIteration(true)
05562     {
05563       if (!e) return;
05564       if (downstream)
05565         states.push(state(0,abs(e->getQuantity()),1.0,e,NULL));
05566       else
05567         states.push(state(0,abs(e->getQuantity()),1.0,NULL,e));
05568       initType(metadata);
05569     }
05570 
05571     /** Return the operationplan consuming the material. */
05572     OperationPlan* getConsumingOperationplan() const
05573     {
05574       const FlowPlan* x = states.top().cons_flowplan;
05575       return x ? x->getOperationPlan() : NULL;
05576     }
05577 
05578     /** Return the material buffer through which we are pegging. */
05579     Buffer *getBuffer() const
05580     {
05581       const FlowPlan* x = states.top().prod_flowplan;
05582       if (!x) x = states.top().cons_flowplan;
05583       return x ? x->getFlow()->getBuffer() : NULL;
05584     }
05585 
05586     /** Return the operationplan producing the material. */
05587     OperationPlan* getProducingOperationplan() const
05588     {
05589       const FlowPlan* x = states.top().prod_flowplan;
05590       return x ? x->getOperationPlan() : NULL;
05591     }
05592 
05593     /** Return the date when the material is consumed. */
05594     Date getConsumingDate() const
05595     {
05596       const FlowPlan* x = states.top().cons_flowplan;
05597       return x ? x->getDate() : Date::infinitePast;
05598     }
05599 
05600     /** Return the date when the material is produced. */
05601     Date getProducingDate() const
05602     {
05603       const FlowPlan* x = states.top().prod_flowplan;
05604       return x ? x->getDate() : Date::infinitePast;
05605     }
05606 
05607     /** Returns the recursion depth of the iterator.<br>
05608       * The original flowplan is at level 0, and each level (either upstream
05609       * or downstream) increments the value by 1.
05610       */
05611     short getLevel() const {return states.top().level;}
05612 
05613     /** Returns the quantity of the demand that is linked to this pegging
05614       * record.
05615       */
05616     double getQuantityDemand() const {return states.top().qty;}
05617 
05618     /** Returns the quantity of the buffer flowplans that is linked to this
05619       * pegging record.
05620       */
05621     double getQuantityBuffer() const
05622     {
05623       const state& t = states.top();
05624       return t.prod_flowplan
05625         ? t.factor * t.prod_flowplan->getOperationPlan()->getQuantity()
05626         : 0;
05627     }
05628 
05629     /** Returns which portion of the current flowplan is fed/supplied by the
05630       * original flowplan. */
05631     double getFactor() const {return states.top().factor;}
05632 
05633     /** Returns false if the flowplan remained unpegged, i.e. it wasn't
05634       * -either completely or paritally- unconsumed at the next level.
05635       */
05636     bool getPegged() const {return states.top().pegged;}
05637 
05638     /** Move the iterator foward to the next downstream flowplan. */
05639     DECLARE_EXPORT PeggingIterator& operator++();
05640 
05641     /** Move the iterator foward to the next downstream flowplan.<br>
05642       * This post-increment operator is less efficient than the pre-increment
05643       * operator.
05644       */
05645     PeggingIterator operator++(int)
05646       {PeggingIterator tmp = *this; ++*this; return tmp;}
05647 
05648     /** Move the iterator foward to the next upstream flowplan. */
05649     DECLARE_EXPORT PeggingIterator& operator--();
05650 
05651     /** Move the iterator foward to the next upstream flowplan.<br>
05652       * This post-increment operator is less efficient than the pre-decrement
05653       * operator.
05654       */
05655     PeggingIterator operator--(int)
05656       {PeggingIterator tmp = *this; --*this; return tmp;}
05657 
05658     /** Comparison operator. */
05659     bool operator==(const PeggingIterator& x) const {return states == x.states;}
05660 
05661     /** Inequality operator. */
05662     bool operator!=(const PeggingIterator& x) const {return states != x.states;}
05663 
05664     /** Conversion operator to a boolean value.
05665       * The return value is true when the iterator still has next elements to
05666       * explore. Returns false when the iteration is finished.
05667       */
05668     operator bool () const {return !states.empty();}
05669 
05670     /** Update the stack. */
05671     DECLARE_EXPORT void updateStack(short, double, double, const FlowPlan*, const FlowPlan*, bool = true);
05672 
05673     /** Returns true if this is a downstream iterator. */
05674     bool isDownstream() {return downstream;}
05675 
05676     /** Initialize the class. */
05677     static int initialize();
05678 
05679     virtual void endElement(XMLInput& i, const Attribute& a, const DataElement& d)
05680     {
05681       throw LogicException("Pegging can't be read");
05682     }
05683     virtual const MetaClass& getType() const {return *metadata;}
05684     static DECLARE_EXPORT const MetaCategory* metadata;
05685     size_t getSize() const {return sizeof(PeggingIterator);}
05686 
05687   private:
05688     /** This structure is used to keep track of the iterator states during the
05689       * iteration. */
05690     struct state
05691     {
05692       /** Stores the quantity of this flowplan that is involved. */
05693       double qty;
05694 
05695       /** Stores what portion of the flowplan is involved with the root flowplan
05696         * where the recursion started.
05697         */
05698       double factor;
05699 
05700       /** Keeps track of the number of levels we're removed from the root
05701         * flowplan where the recursion started.
05702         */
05703       short level;
05704 
05705       /** The current flowplan. */
05706       const FlowPlan* cons_flowplan;
05707 
05708       /** The current flowplan. */
05709       const FlowPlan* prod_flowplan;
05710 
05711       /** Set to false when unpegged quantities are involved. */
05712       bool pegged;
05713 
05714       /** Constructor. */
05715       state(unsigned int l, double d, double f,
05716         const FlowPlan* fc, const FlowPlan* fp, bool p = true)
05717           : qty(d), factor(f), level(l),
05718           cons_flowplan(fc), prod_flowplan(fp), pegged(p) {};
05719 
05720       /** Inequality operator. */
05721       bool operator != (const state& s) const
05722       {
05723         return cons_flowplan != s.cons_flowplan
05724           || prod_flowplan != s.prod_flowplan
05725           || level != s.level;
05726       }
05727 
05728       /** Equality operator. */
05729       bool operator == (const state& s) const
05730       {
05731         return cons_flowplan == s.cons_flowplan
05732           && prod_flowplan == s.prod_flowplan
05733           && level == s.level;
05734       }
05735     };
05736 
05737     /** A type to hold the iterator state. */
05738     typedef stack < state > statestack;
05739 
05740     /** A stack is used to store the iterator state. */
05741     statestack states;
05742 
05743     /** Iterate over the pegging in Python. */
05744     DECLARE_EXPORT PyObject *iternext();
05745 
05746     DECLARE_EXPORT PyObject* getattro(const Attribute&);
05747 
05748     /* Auxilary function to make recursive code possible. */
05749     DECLARE_EXPORT void followPegging(const OperationPlan*, short, double, double);
05750 
05751     /** Convenience variable during stack updates.
05752       * Depending on the value of this field, either the top element in the
05753       * stack is updated or a new state is pushed on the stack.
05754       */
05755     bool first;
05756 
05757     /** Downstream or upstream iterator. */
05758     bool downstream;
05759 
05760     /** A flag used by the Python iterators.
05761       * @see iternext()
05762       */
05763     bool firstIteration;
05764 };
05765 
05766 
05767 /** @brief An iterator class to go through all flowplans of an operationplan.
05768   * @see OperationPlan::beginFlowPlans
05769   * @see OperationPlan::endFlowPlans
05770   */
05771 class OperationPlan::FlowPlanIterator
05772 {
05773     friend class OperationPlan;
05774   private:
05775     FlowPlan* curflowplan;
05776     FlowPlan* prevflowplan;
05777     FlowPlanIterator(FlowPlan* b) : curflowplan(b), prevflowplan(NULL) {}
05778   public:
05779     FlowPlanIterator(const FlowPlanIterator& b)
05780     {
05781       curflowplan = b.curflowplan;
05782       prevflowplan = b.prevflowplan;
05783     }
05784     bool operator != (const FlowPlanIterator &b) const
05785       {return b.curflowplan != curflowplan;}
05786     bool operator == (const FlowPlanIterator &b) const
05787       {return b.curflowplan == curflowplan;}
05788     FlowPlanIterator& operator++()
05789     {
05790       prevflowplan = curflowplan;
05791       if (curflowplan) curflowplan = curflowplan->nextFlowPlan;
05792       return *this;
05793     }
05794     FlowPlanIterator operator++(int)
05795       {FlowPlanIterator tmp = *this; ++*this; return tmp;}
05796     FlowPlan* operator ->() const {return curflowplan;}
05797     FlowPlan& operator *() const {return *curflowplan;}
05798     void deleteFlowPlan()
05799     {
05800       if (!curflowplan) return;
05801       if (prevflowplan) prevflowplan->nextFlowPlan = curflowplan->nextFlowPlan;
05802       else curflowplan->oper->firstflowplan = curflowplan->nextFlowPlan;
05803       FlowPlan* tmp = curflowplan;
05804       // Move the iterator to the next element
05805       curflowplan = curflowplan->nextFlowPlan;
05806       delete tmp;
05807     }
05808 };
05809 
05810 inline OperationPlan::FlowPlanIterator OperationPlan::beginFlowPlans() const
05811   {return OperationPlan::FlowPlanIterator(firstflowplan);}
05812 
05813 inline OperationPlan::FlowPlanIterator OperationPlan::endFlowPlans() const
05814   {return OperationPlan::FlowPlanIterator(NULL);}
05815 
05816 inline int OperationPlan::sizeFlowPlans() const
05817 {
05818   int c = 0;
05819   for (FlowPlanIterator i = beginFlowPlans(); i != endFlowPlans(); ++i) ++c;
05820   return c;
05821 }
05822 
05823 
05824 /** @brief An iterator class to go through all loadplans of an operationplan.
05825   * @see OperationPlan::beginLoadPlans
05826   * @see OperationPlan::endLoadPlans
05827   */
05828 class OperationPlan::LoadPlanIterator
05829 {
05830     friend class OperationPlan;
05831   private:
05832     LoadPlan* curloadplan;
05833     LoadPlan* prevloadplan;
05834     LoadPlanIterator(LoadPlan* b) : curloadplan(b), prevloadplan(NULL) {}
05835   public:
05836     LoadPlanIterator(const LoadPlanIterator& b)
05837     {
05838       curloadplan = b.curloadplan;
05839       prevloadplan = b.prevloadplan;
05840     }
05841     bool operator != (const LoadPlanIterator &b) const
05842       {return b.curloadplan != curloadplan;}
05843     bool operator == (const LoadPlanIterator &b) const
05844       {return b.curloadplan == curloadplan;}
05845     LoadPlanIterator& operator++()
05846     {
05847       prevloadplan = curloadplan;
05848       if (curloadplan) curloadplan = curloadplan->nextLoadPlan;
05849       return *this;
05850     }
05851     LoadPlanIterator operator++(int)
05852       {LoadPlanIterator tmp = *this; ++*this; return tmp;}
05853     LoadPlan* operator ->() const {return curloadplan;}
05854     LoadPlan& operator *() const {return *curloadplan;}
05855     void deleteLoadPlan()
05856     {
05857       if (!curloadplan) return;
05858       if (prevloadplan) prevloadplan->nextLoadPlan = curloadplan->nextLoadPlan;
05859       else curloadplan->oper->firstloadplan = curloadplan->nextLoadPlan;
05860       LoadPlan* tmp = curloadplan;
05861       // Move the iterator to the next element
05862       curloadplan = curloadplan->nextLoadPlan;
05863       delete tmp;
05864     }
05865 };
05866 
05867 inline OperationPlan::LoadPlanIterator OperationPlan::beginLoadPlans() const
05868   {return OperationPlan::LoadPlanIterator(firstloadplan);}
05869 
05870 inline OperationPlan::LoadPlanIterator OperationPlan::endLoadPlans() const
05871   {return OperationPlan::LoadPlanIterator(NULL);}
05872 
05873 inline int OperationPlan::sizeLoadPlans() const
05874 {
05875   int c = 0;
05876   for (LoadPlanIterator i = beginLoadPlans(); i != endLoadPlans(); ++i) ++c;
05877   return c;
05878 }
05879 
05880 
05881 class ProblemIterator
05882   : public FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>
05883 {
05884 };
05885 
05886 
05887 class BufferIterator
05888   : public FreppleIterator<BufferIterator,Buffer::iterator,Buffer>
05889 {
05890 };
05891 
05892 
05893 class LocationIterator
05894   : public FreppleIterator<LocationIterator,Location::iterator,Location>
05895 {
05896 };
05897 
05898 
05899 class CustomerIterator
05900   : public FreppleIterator<CustomerIterator,Customer::iterator,Customer>
05901 {
05902 };
05903 
05904 
05905 class ItemIterator
05906   : public FreppleIterator<ItemIterator,Item::iterator,Item>
05907 {
05908 };
05909 
05910 class DemandIterator
05911   : public FreppleIterator<DemandIterator,Demand::iterator,Demand>
05912 {
05913 };
05914 
05915 
05916 class ResourceIterator
05917   : public FreppleIterator<ResourceIterator,Resource::iterator,Resource>
05918 {
05919 };
05920 
05921 
05922 class SolverIterator
05923   : public FreppleIterator<SolverIterator,Solver::iterator,Solver>
05924 {
05925 };
05926 
05927 
05928 class OperationIterator
05929   : public FreppleIterator<OperationIterator,Operation::iterator,Operation>
05930 {
05931 };
05932 
05933 
05934 class CalendarIterator
05935   : public FreppleIterator<CalendarIterator,Calendar::iterator,Calendar>
05936 {
05937 };
05938 
05939 
05940 class SetupMatrixIterator
05941   : public FreppleIterator<SetupMatrixIterator,SetupMatrix::iterator,SetupMatrix>
05942 {
05943 };
05944 
05945 
05946 //
05947 // SETUP MATRIX RULES
05948 //
05949 
05950 
05951 class SetupMatrixRuleIterator : public PythonExtension<SetupMatrixRuleIterator>
05952 {
05953   public:
05954     static int initialize();
05955 
05956     SetupMatrixRuleIterator(SetupMatrix* c) : matrix(c)
05957     {
05958       if (!c)
05959         throw LogicException("Creating rule iterator for NULL matrix");
05960       currule = c->beginRules();
05961     }
05962 
05963   private:
05964     SetupMatrix* matrix;
05965     SetupMatrix::RuleIterator currule;
05966     PyObject *iternext();
05967 };
05968 
05969 
05970 //
05971 // CALENDARS
05972 //
05973 
05974 
05975 class CalendarBucketIterator : public PythonExtension<CalendarBucketIterator>
05976 {
05977   public:
05978     static int initialize();
05979 
05980     CalendarBucketIterator(Calendar* c) : cal(c)
05981     {
05982       if (!c)
05983         throw LogicException("Creating bucket iterator for NULL calendar");
05984       i = c->beginBuckets();
05985     }
05986 
05987   private:
05988     Calendar* cal;
05989     Calendar::BucketIterator i;
05990     PyObject *iternext();
05991 };
05992 
05993 
05994 class CalendarEventIterator
05995   : public PythonExtension<CalendarEventIterator>
05996 {
05997   public:
05998     static int initialize();
05999 
06000     CalendarEventIterator(Calendar* c, Date d=Date::infinitePast, bool f=true)
06001       : cal(c), eventiter(c,d,f), forward(f) {}
06002 
06003   private:
06004     Calendar* cal;
06005     Calendar::EventIterator eventiter;
06006     bool forward;
06007     PyObject *iternext();
06008 };
06009 
06010 
06011 //
06012 // OPERATIONPLANS
06013 //
06014 
06015 
06016 class OperationPlanIterator
06017   : public FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>
06018 {
06019   public:
06020     /** Constructor to iterate over all operationplans. */
06021     OperationPlanIterator() {}
06022 
06023     /** Constructor to iterate over the operationplans of a single operation. */
06024     OperationPlanIterator(Operation* o)
06025       : FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>(o)
06026     {}
06027 
06028     /** Constructor to iterate over the suboperationplans of an operationplans. */
06029     OperationPlanIterator(OperationPlan* opplan)
06030       : FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>(opplan)
06031     {}
06032 };
06033 
06034 
06035 //
06036 // FLOWPLANS
06037 //
06038 
06039 
06040 class FlowPlanIterator : public PythonExtension<FlowPlanIterator>
06041 {
06042   public:
06043     static int initialize();
06044 
06045     FlowPlanIterator(Buffer* b) : buf(b), buffer_or_opplan(true)
06046     {
06047       if (!b)
06048         throw LogicException("Creating flowplan iterator for NULL buffer");
06049       bufiter = new Buffer::flowplanlist::const_iterator(b->getFlowPlans().begin());
06050     }
06051 
06052     FlowPlanIterator(OperationPlan* o) : opplan(o), buffer_or_opplan(false)
06053     {
06054       if (!o)
06055         throw LogicException("Creating flowplan iterator for NULL operationplan");
06056       opplaniter = new OperationPlan::FlowPlanIterator(o->beginFlowPlans());
06057     }
06058 
06059     ~FlowPlanIterator()
06060     {
06061       if (buffer_or_opplan) delete bufiter;
06062       else delete opplaniter;
06063     }
06064 
06065   private:
06066     union
06067     {
06068       Buffer* buf;
06069       OperationPlan* opplan;
06070     };
06071 
06072     union
06073     {
06074       Buffer::flowplanlist::const_iterator *bufiter;
06075       OperationPlan::FlowPlanIterator *opplaniter;
06076     };
06077 
06078     /** Flags whether we are browsing over the flowplans in a buffer or in an
06079       * operationplan. */
06080     bool buffer_or_opplan;
06081 
06082     PyObject *iternext();
06083 };
06084 
06085 
06086 //
06087 // LOADPLANS
06088 //
06089 
06090 
06091 class LoadPlanIterator : public PythonExtension<LoadPlanIterator>
06092 {
06093   public:
06094     static int initialize();
06095 
06096     LoadPlanIterator(Resource* r) : res(r), resource_or_opplan(true)
06097     {
06098       if (!r)
06099         throw LogicException("Creating loadplan iterator for NULL resource");
06100       resiter = new Resource::loadplanlist::const_iterator(r->getLoadPlans().begin());
06101     }
06102 
06103     LoadPlanIterator(OperationPlan* o) : opplan(o), resource_or_opplan(false)
06104     {
06105       if (!opplan)
06106         throw LogicException("Creating loadplan iterator for NULL operationplan");
06107       opplaniter = new OperationPlan::LoadPlanIterator(o->beginLoadPlans());
06108     }
06109 
06110     ~LoadPlanIterator()
06111     {
06112       if (resource_or_opplan) delete resiter;
06113       else delete opplaniter;
06114     }
06115 
06116   private:
06117     union
06118     {
06119       Resource* res;
06120       OperationPlan* opplan;
06121     };
06122 
06123     union
06124     {
06125       Resource::loadplanlist::const_iterator *resiter;
06126       OperationPlan::LoadPlanIterator *opplaniter;
06127     };
06128 
06129     /** Flags whether we are browsing over the flowplans in a buffer or in an
06130       * operationplan. */
06131     bool resource_or_opplan;
06132 
06133     PyObject *iternext();
06134 };
06135 
06136 
06137 //
06138 // DEMAND DELIVERY OPERATIONPLANS
06139 //
06140 
06141 
06142 class DemandPlanIterator : public PythonExtension<DemandPlanIterator>
06143 {
06144   public:
06145     static int initialize();
06146 
06147     DemandPlanIterator(Demand* r) : dem(r)
06148     {
06149       if (!r)
06150         throw LogicException("Creating demandplan iterator for NULL demand");
06151       i = r->getDelivery().begin();
06152     }
06153 
06154   private:
06155     Demand* dem;
06156     Demand::OperationPlan_list::const_iterator i;
06157     PyObject *iternext();
06158 };
06159 
06160 
06161 //
06162 // LOADS
06163 //
06164 
06165 
06166 class LoadIterator : public PythonExtension<LoadIterator>
06167 {
06168   public:
06169     static int initialize();
06170 
06171     LoadIterator(Resource* r)
06172       : res(r), ir(r ? r->getLoads().begin() : NULL), oper(NULL), io(NULL)
06173     {
06174       if (!r)
06175         throw LogicException("Creating loadplan iterator for NULL resource");
06176     }
06177 
06178     LoadIterator(Operation* o)
06179       : res(NULL), ir(NULL), oper(o), io(o ? o->getLoads().begin() : NULL)
06180     {
06181       if (!o)
06182         throw LogicException("Creating loadplan iterator for NULL operation");
06183     }
06184 
06185   private:
06186     Resource* res;
06187     Resource::loadlist::const_iterator ir;
06188     Operation* oper;
06189     Operation::loadlist::const_iterator io;
06190     PyObject *iternext();
06191 };
06192 
06193 
06194 //
06195 // FLOW
06196 //
06197 
06198 
06199 class FlowIterator : public PythonExtension<FlowIterator>
06200 {
06201   public:
06202     static int initialize();
06203 
06204     FlowIterator(Buffer* b)
06205       : buf(b), ib(b ? b->getFlows().begin() : NULL), oper(NULL), io(NULL)
06206     {
06207       if (!b)
06208         throw LogicException("Creating flowplan iterator for NULL buffer");
06209     }
06210 
06211     FlowIterator(Operation* o)
06212       : buf(NULL), ib(NULL), oper(o), io(o ? o->getFlows().begin() : NULL)
06213     {
06214       if (!o)
06215         throw LogicException("Creating flowplan iterator for NULL operation");
06216     }
06217 
06218   private:
06219     Buffer* buf;
06220     Buffer::flowlist::const_iterator ib;
06221     Operation* oper;
06222     Operation::flowlist::const_iterator io;
06223     PyObject *iternext();
06224 };
06225 
06226 
06227 }   // End namespace
06228 
06229 #endif