model.h

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

Documentation generated for frePPLe by  doxygen