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: 1519 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2011-09-25 18:48:30 +0200 (Sun, 25 Sep 2011) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007-2011 by Johan De Taeye, frePPLe bvba                 *
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, int priority=0) :
00150           nm(name), startdate(start), enddate(end), nextBucket(NULL),
00151           prevBucket(NULL), priority(priority), 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         int 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, int priority=0)
00376       {return new Bucket(this, start, end, name, priority);}
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, int priority=0)
00404           : Bucket(c,start,end,name,priority), 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, int priority=0)
00542       {return new BucketValue(this, start, end, name, priority);}
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, int priority=0)
00579           : Bucket(c,start,end,name,priority), 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, int priority=0)
00743       {return new BucketPointer(this,start,end,name,priority);}
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 list 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 algorithms 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 loads. */
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 activate()
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()));
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 operationplan is a delivery.
02066       * If the operationplan isn't a delivery, 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.<br>
02074       * It is the sum of all setup penalties of the resources it loads. */
02075     DECLARE_EXPORT double getPenalty() const;
02076 
02077     /** Calculate the unavailable time during the operationplan. The regular 
02078       * duration is extended with this amount.
02079       */
02080     DECLARE_EXPORT TimePeriod getUnavailable() const;
02081 
02082     /** Returns whether the operationplan is locked. A locked operationplan
02083       * is never changed.
02084       */
02085     bool getLocked() const {return flags & IS_LOCKED;}
02086 
02087     /** Deletes all operationplans of a certain operation. A boolean flag
02088       * allows to specify whether locked operationplans are to be deleted too.
02089       */
02090     static DECLARE_EXPORT void deleteOperationPlans(Operation* o, bool deleteLocked=false);
02091 
02092     /** Locks/unlocks an operationplan. A locked operationplan is never
02093       * changed.
02094       */
02095     virtual DECLARE_EXPORT void setLocked(bool b = true);
02096 
02097     /** Returns a pointer to the operation being instantiated. */
02098     Operation* getOperation() const {return oper;}
02099 
02100     /** Fixes the start and end date of an operationplan. Note that this
02101       * overrules the standard duration given on the operation, i.e. no logic
02102       * kicks in to verify the data makes sense. This is up to the user to
02103       * take care of.<br>
02104       * The methods setStart(Date) and setEnd(Date) are therefore preferred
02105       * since they properly apply all appropriate logic.
02106       */
02107     void setStartAndEnd(Date st, Date nd)
02108     {
02109       dates.setStartAndEnd(st,nd);
02110       update();
02111     }
02112 
02113     /** A method to restore a previous state of an operationplan.<br>
02114       * NO validity checks are done on the parameters.
02115       */
02116     void restore(const OperationPlanState& x);
02117 
02118     /** Updates the operationplan owning this operationplan. In case of
02119       * a OperationRouting steps this will be the operationplan representing the
02120       * complete routing. */
02121     void DECLARE_EXPORT setOwner(OperationPlan* o);
02122 
02123     /** Returns a pointer to the operationplan for which this operationplan
02124       * a sub-operationplan.<br>
02125       * The method returns NULL if there is no owner defined.<br>
02126       * E.g. Sub-operationplans of a routing refer to the overall routing
02127       * operationplan.<br>
02128       * E.g. An alternate sub-operationplan refers to its parent.
02129       * @see getTopOwner
02130       */
02131     OperationPlan* getOwner() const {return owner;}
02132 
02133     /** Returns a pointer to the operationplan owning a set of
02134       * sub-operationplans. There can be multiple levels of suboperations.<br>
02135       * If no owner exists the method returns the current operationplan.
02136       * @see getOwner
02137       */
02138     const OperationPlan* getTopOwner() const
02139     {
02140       if (owner)
02141       {
02142         // There is an owner indeed
02143         OperationPlan* o(owner);
02144         while (o->owner) o = o->owner;
02145         return o;
02146       }
02147       else
02148         // This operationplan is itself the top of a hierarchy
02149         return this;
02150     }
02151 
02152     /** Returns the start and end date of this operationplan. */
02153     const DateRange & getDates() const {return dates;}
02154 
02155     /** Return true if the operationplan is redundant, ie all material
02156       * it produces is not used at all.<br>
02157       * If the optional argument is false (which is the default value), we 
02158       * check with the minimum stock level of the buffers. If the argument
02159       * is true, we check with 0.
02160       */
02161     DECLARE_EXPORT bool isExcess(bool = false) const;
02162 
02163     /** Returns a unique identifier of the operationplan.<br>
02164       * The identifier can be specified in the data input (in which case
02165       * we check for the uniqueness during the read operation).<br>
02166       * For operationplans created during a solver run, the identifier is
02167       * assigned in the instantiate() function. The numbering starts with the
02168       * highest identifier read in from the input and is then incremented
02169       * for every operationplan that is registered.
02170       */
02171     unsigned long getIdentifier() const {return id;}
02172 
02173     /** Updates the end date of the operationplan and compute the start
02174       * date.<br>
02175       * Locked operationplans are not updated by this function.<br>
02176       * Slack can be introduced between sub operationaplans by this method,
02177       * i.e. the sub operationplans are only moved if required to meet the
02178       * end date.
02179       */
02180     virtual DECLARE_EXPORT void setEnd(Date);
02181 
02182     /** Updates the start date of the operationplan and compute the end
02183       * date.<br>
02184       * Locked operation_plans are not updated by this function.<br>
02185       * Slack can be introduced between sub operationaplans by this method,
02186       * i.e. the sub operationplans are only moved if required to meet the
02187       * start date.
02188       */
02189     virtual DECLARE_EXPORT void setStart(Date);
02190 
02191     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02192     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02193     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02194     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02195     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02196     static int initialize();
02197 
02198     PyObject* str() const
02199     {          
02200       ostringstream ch;
02201       ch << id;
02202       return PythonObject(ch.str());
02203     }
02204 
02205     static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
02206 
02207     /** Initialize the operationplan. The initialization function should be
02208       * called when the operationplan is ready to be 'officially' added. The
02209       * initialization performs the following actions:
02210       * <ol>
02211       * <li> assign an identifier</li>
02212       * <li> create the flow and loadplans if these hadn't been created
02213       * before</li>
02214       * <li> add the operationplan to the global list of operationplans</li>
02215       * <li> create a link with a demand object if this is a delivery
02216       * operationplan</li>
02217       * </ol>
02218       * Every operationplan subclass that has sub-operations will normally
02219       * need to create an override of this function.<br>
02220       *
02221       * The return value indicates whether the initialization was successfull.
02222       * If the operationplan is invalid, it will be DELETED and the return value
02223       * is 'false'.
02224       */
02225     DECLARE_EXPORT bool activate(bool useMinCounter = true);
02226 
02227     /** Remove an operationplan from the list of officially registered ones.<br>
02228       * The operationplan will keep its loadplans and flowplans after unregistration.
02229       */
02230     DECLARE_EXPORT void deactivate();
02231 
02232     /** This method links the operationplan in the list of all operationplans
02233       * maintained on the operation.<br>
02234       * In most cases calling this method is not required since it included
02235       * in the activate method. In exceptional cases the solver already
02236       * needs to see uncommitted operationplans in the list - eg for the
02237       * procurement buffer.
02238       * @see activate
02239       */
02240     DECLARE_EXPORT void insertInOperationplanList();
02241 
02242     /** This method remove the operationplan from the list of all operationplans
02243       * maintained on the operation.<br>
02244       * @see deactivate
02245       */
02246     DECLARE_EXPORT void removeFromOperationplanList();
02247 
02248     /** Add a sub-operationplan to the list. */
02249     virtual DECLARE_EXPORT void addSubOperationPlan(OperationPlan*);
02250 
02251     /** Remove a sub-operation_plan from the list. */
02252     virtual DECLARE_EXPORT void eraseSubOperationPlan(OperationPlan*);
02253 
02254     /** This function is used to create the loadplans, flowplans and
02255       * setup operationplans.
02256       */
02257     DECLARE_EXPORT void createFlowLoads();
02258 
02259     /** This function is used to delete the loadplans, flowplans and
02260       * setup operationplans.
02261       */
02262     DECLARE_EXPORT void deleteFlowLoads();
02263 
02264     bool getHidden() const {return getOperation()->getHidden();}
02265 
02266     /** Searches for an OperationPlan with a given identifier.<br>
02267       * Returns a NULL pointer if no such OperationPlan can be found.<br>
02268       * The method is of complexity O(n), i.e. involves a LINEAR search through
02269       * the existing operationplans, and can thus be quite slow in big models.<br>
02270       * The method is O(1), i.e. constant time regardless of the model size,
02271       * when the parameter passed is bigger than the operationplan counter.
02272       */
02273     static DECLARE_EXPORT OperationPlan* findId(unsigned long l);
02274 
02275     /** Problem detection is actually done by the Operation class. That class
02276       * actually "delegates" the responsability to this class, for efficiency.
02277       */
02278     virtual void updateProblems();
02279 
02280     /** Implement the pure virtual function from the HasProblem class. */
02281     Plannable* getEntity() const {return oper;}
02282 
02283     /** Return the metadata. We return the metadata of the operation class,
02284       * not the one of the operationplan class!
02285       */
02286     const MetaClass& getType() const {return *metadata;}
02287 
02288     static DECLARE_EXPORT const MetaClass* metadata;
02289 
02290     static DECLARE_EXPORT const MetaCategory* metacategory;
02291 
02292     virtual size_t getSize() const
02293       {return sizeof(OperationPlan);}
02294 
02295     /** Handles the persistence of operationplan objects. */
02296     static DECLARE_EXPORT void writer(const MetaCategory*, XMLOutput*);
02297 
02298     /** Comparison of 2 OperationPlans.
02299       * To garantuee that the problems are sorted in a consistent and stable
02300       * way, the following sorting criteria are used (in order of priority):
02301       * <ol><li>Operation</li>
02302       * <li>Start date (earliest dates first)</li>
02303       * <li>Quantity (biggest quantities first)</li></ol>
02304       * Multiple operationplans for the same values of the above keys can exist.
02305       */
02306     DECLARE_EXPORT bool operator < (const OperationPlan& a) const;
02307 
02308     /** Copy constructor.<br>
02309       * If the optional argument is false, the new copy is not initialized
02310       * and won't have flowplans and loadplans.
02311       */
02312     DECLARE_EXPORT OperationPlan(const OperationPlan&, bool = true);
02313 
02314   private:
02315     /** Private copy constructor.<br>
02316       * It is used in the public copy constructor to make a deep clone of suboperationplans.
02317       * @see OperationPlan(const OperationPlan&, bool = true)
02318       */
02319     DECLARE_EXPORT OperationPlan(const OperationPlan&, OperationPlan*);
02320 
02321     /** Updates the operationplan based on the latest information of quantity,
02322       * date and locked flag.<br>
02323       * This method will also update parent and child operationplans.
02324       * @see resizeFlowLoadPlans
02325       */
02326     virtual DECLARE_EXPORT void update();
02327 
02328     /** Update the loadplans and flowplans of the operationplan based on the 
02329       * latest information of quantity, date and locked flag.<br>
02330       * This method will NOT update parent or child operationplans. 
02331       * @see update
02332       */
02333     DECLARE_EXPORT void resizeFlowLoadPlans();
02334 
02335     /** Default constructor.<br>
02336       * This way of creating operationplan objects is not intended for use by
02337       * any client applications. Client applications should use the factory
02338       * method on the operation class instead.<br>
02339       * Subclasses of the Operation class may use this constructor in their
02340       * own override of the createOperationPlan method.
02341       * @see Operation::createOperationPlan
02342       */
02343     OperationPlan() : owner(NULL), quantity(0.0), flags(0), dmd(NULL),
02344       id(0), oper(NULL), firstflowplan(NULL), firstloadplan(NULL),
02345       prev(NULL), next(NULL), firstsubopplan(NULL), lastsubopplan(NULL),
02346       nextsubopplan(NULL), prevsubopplan(NULL)
02347         {initType(metadata);}
02348 
02349   private:
02350     static const short IS_LOCKED = 1;
02351     static const short IS_SETUP = 2;
02352     static const short HAS_SETUP = 4;
02353 
02354     /** Pointer to a higher level OperationPlan. */
02355     OperationPlan *owner;
02356 
02357     /** Quantity. */
02358     double quantity;
02359 
02360     /** Is this operationplan locked? A locked operationplan doesn't accept
02361       * any changes. This field is only relevant for top-operationplans. */
02362     short flags;
02363 
02364     /** Counter of OperationPlans, which is used to automatically assign a
02365       * unique identifier for each operationplan.<br>
02366       * The value of the counter is the first available identifier value that
02367       * can be used for a new operationplan.<br>
02368       * The first value is 1, and each operationplan increases it by 1.
02369       * @see counterMax
02370       * @see getIdentifier()
02371       */
02372     static DECLARE_EXPORT unsigned long counterMin;
02373     
02374     /** Counter of OperationPlans, which is used to automatically assign a
02375       * unique identifier for each operationplan.<br>
02376       * The first value is a very high number, and each operationplan 
02377       * decreases it by 1.
02378       * @see counterMin
02379       * @see getIdentifier()
02380       */
02381     static DECLARE_EXPORT unsigned long counterMax;
02382 
02383     /** Pointer to the demand.<br>
02384       * Only delivery operationplans have this field set. The field is NULL 
02385       * for all other operationplans. 
02386       */
02387     Demand *dmd;
02388 
02389     /** Unique identifier.<br>
02390       * The field is 0 while the operationplan is not fully registered yet.
02391       */
02392     unsigned long id;
02393 
02394     /** Start and end date. */
02395     DateRange dates;
02396 
02397     /** Pointer to the operation. */
02398     Operation *oper;
02399 
02400     /** Root of a single linked list of flowplans. */
02401     FlowPlan* firstflowplan;
02402 
02403     /** Single linked list of loadplans. */
02404     LoadPlan* firstloadplan;
02405 
02406     /** Pointer to the previous operationplan.<br>
02407       * Operationplans are chained in a doubly linked list for each operation.
02408       * @see next
02409       */
02410     OperationPlan* prev;
02411 
02412     /** Pointer to the next operationplan.<br>
02413       * Operationplans are chained in a doubly linked list for each operation.
02414       * @see prev
02415       */
02416     OperationPlan* next;
02417 
02418     /** Pointer to the first suboperationplan of this operationplan. */
02419     OperationPlan* firstsubopplan;
02420 
02421     /** Pointer to the last suboperationplan of this operationplan. */
02422     OperationPlan* lastsubopplan;
02423 
02424     /** Pointer to the next suboperationplan of the parent operationplan. */
02425     OperationPlan* nextsubopplan;
02426 
02427     /** Pointer to the previous suboperationplan of the parent operationplan. */
02428     OperationPlan* prevsubopplan;
02429 };
02430 
02431 
02432 /** @brief A simple class to easily remember the date, quantity and owner of
02433   * an operationplan. */
02434 class OperationPlanState  // @todo should also be able to remember and restore suboperationplans!!!
02435 {
02436   public:
02437     Date start;
02438     Date end;
02439     double quantity;
02440 
02441     /** Default constructor. */
02442     OperationPlanState() : quantity(0.0) {}
02443 
02444     /** Constructor. */
02445     OperationPlanState(const OperationPlan* x)
02446     {
02447       if (!x) 
02448       {
02449         quantity = 0.0;
02450         return;
02451       }
02452       else
02453       {
02454         start = x->getDates().getStart();
02455         end = x->getDates().getEnd();
02456         quantity = x->getQuantity();
02457       }
02458     }
02459 
02460     /** Constructor. */
02461     OperationPlanState(const Date x, const Date y, double q) 
02462       : start(x), end(y), quantity(q) {}
02463 
02464     /** Constructor. */
02465     OperationPlanState(const DateRange& x, double q) 
02466       : start(x.getStart()), end(x.getEnd()), quantity(q) {}
02467 };
02468 
02469 
02470 /** @brief Models an operation that takes a fixed amount of time, independent
02471   * of the quantity. */
02472 class OperationFixedTime : public Operation
02473 {
02474   public:
02475     /** Constructor. */
02476     explicit OperationFixedTime(const string& s) : Operation(s) {initType(metadata);}
02477 
02478     /** Returns the length of the operation. */
02479     const TimePeriod getDuration() const {return duration;}
02480 
02481     /** Updates the duration of the operation. Existing operation plans of this
02482       * operation are not automatically refreshed to reflect the change. */
02483     void setDuration(TimePeriod t)
02484     {
02485       if (t<0L)
02486         throw DataException("FixedTime operation can't have a negative duration");
02487       duration = t;
02488     }
02489 
02490     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02491     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02492     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02493     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02494     static int initialize();
02495 
02496     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02497 
02498     virtual const MetaClass& getType() const {return *metadata;}
02499     static DECLARE_EXPORT const MetaClass* metadata;
02500     virtual size_t getSize() const
02501     {return sizeof(OperationFixedTime) + Operation::extrasize();}
02502 
02503     /** A operation of this type enforces the following rules on its
02504       * operationplans:
02505       *  - The duration is always constant.
02506       *  - If the end date is specified, we use that and ignore the start
02507       *    date that could have been passed.
02508       *  - If no end date but only a start date are specified, we'll use
02509       *    that date.
02510       *  - If no dates are specified, we don't update the dates of the
02511       *    operationplan.
02512       *  - The quantity can be any positive number.
02513       *  - Locked operationplans can't be updated.
02514       * @see Operation::setOperationPlanParameters
02515       */
02516     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02517       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02518   
02519   protected:
02520     DECLARE_EXPORT virtual bool extraInstantiate(OperationPlan* o);
02521 
02522   private:
02523     /** Stores the lengh of the Operation. */
02524     TimePeriod duration;
02525 };
02526 
02527 
02528 /** @brief Models an operation to convert a setup on a resource. */
02529 class OperationSetup : public Operation
02530 {
02531   public:
02532     /** Constructor. */
02533     explicit OperationSetup(const string& s) : Operation(s) {initType(metadata);}
02534 
02535     // Never write the setup operation
02536     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const {}
02537     static int initialize();
02538 
02539     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02540 
02541     virtual const MetaClass& getType() const {return *metadata;}
02542     static DECLARE_EXPORT const MetaClass* metadata;
02543     virtual size_t getSize() const
02544     {return sizeof(OperationSetup) + Operation::extrasize();}
02545 
02546     /** A operation of this type enforces the following rules on its
02547       * operationplans:
02548       *  - The duration is calculated based on the conversion type.
02549       */
02550     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02551       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02552 
02553     /** A pointer to the operation that is instantiated for all conversions. */
02554     static DECLARE_EXPORT const Operation* setupoperation;
02555 };
02556 
02557 
02558 /** @brief Models an operation whose duration is the sum of a constant time,
02559   * plus a cetain time per unit.
02560   */
02561 class OperationTimePer : public Operation
02562 {
02563   public:
02564     /** Constructor. */
02565     explicit OperationTimePer(const string& s) : Operation(s) {initType(metadata);}
02566 
02567     /** Returns the constant part of the operation time. */
02568     TimePeriod getDuration() const {return duration;}
02569 
02570     /** Sets the constant part of the operation time. */
02571     void setDuration(TimePeriod t)
02572     {
02573       if(t<0L)
02574         throw DataException("TimePer operation can't have a negative duration");
02575       duration = t;
02576     }
02577 
02578     /** Returns the time per unit of the operation time. */
02579     TimePeriod getDurationPer() const {return duration_per;}
02580 
02581     /** Sets the time per unit of the operation time. */
02582     void setDurationPer(TimePeriod t)
02583     {
02584       if(t<0L)
02585         throw DataException("TimePer operation can't have a negative duration-per");
02586       duration_per = t;
02587     }
02588 
02589     /** A operation of this type enforces the following rules on its
02590       * operationplans:
02591       *   - If both the start and end date are specified, the quantity is
02592       *     computed to match these dates.
02593       *     If the time difference between the start and end date is too
02594       *     small to fit the fixed duration, the quantity is set to 0.
02595       *   - If only an end date is specified, it will be respected and we
02596       *     compute a start date based on the quantity.
02597       *   - If only a start date is specified, it will be respected and we
02598       *     compute an end date based on the quantity.
02599       *   - If no date is specified, we respect the quantity and the end
02600       *     date of the operation. A new start date is being computed.
02601       * @see Operation::setOperationPlanParameters
02602       */
02603     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02604       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02605 
02606     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02607     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02608     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02609     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02610     static int initialize();
02611 
02612     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02613 
02614     virtual const MetaClass& getType() const {return *metadata;}
02615     static DECLARE_EXPORT const MetaClass* metadata;
02616     virtual size_t getSize() const
02617     {return sizeof(OperationTimePer) + Operation::extrasize();}
02618 
02619   private:
02620     /** Constant part of the operation time. */
02621     TimePeriod duration;
02622 
02623     /** Variable part of the operation time. */
02624     TimePeriod duration_per;
02625 };
02626 
02627 
02628 /** @brief Represents a routing operation, i.e. an operation consisting of
02629   * multiple, sequential sub-operations.
02630   */
02631 class OperationRouting : public Operation
02632 {
02633   public:
02634     /** Constructor. */
02635     explicit OperationRouting(const string& c) : Operation(c) {initType(metadata);}
02636 
02637     /** Destructor. */
02638     DECLARE_EXPORT ~OperationRouting();
02639 
02640     /** Adds a new steps to routing at the start of the routing. */
02641     void addStepFront(Operation *o)
02642     {
02643       if (!o) throw DataException("Adding NULL operation to routing");
02644       steps.push_front(o);
02645       o->addSuperOperation(this);
02646     }
02647 
02648     /** Adds a new steps to routing at the end of the routing. */
02649     void addStepBack(Operation *o)
02650     {
02651       if (!o) throw DataException("Adding NULL operation to routing");
02652       steps.push_back(o);
02653       o->addSuperOperation(this);
02654     }
02655 
02656     /** Add one or more steps to a routing. */
02657     static DECLARE_EXPORT PyObject* addStep(PyObject*, PyObject*);
02658 
02659     /** Remove a step from a routing. */
02660     void removeSubOperation(Operation *o)
02661     {steps.remove(o); o->superoplist.remove(this);}
02662 
02663     /** A operation of this type enforces the following rules on its
02664       * operationplans:
02665       *  - If an end date is given, sequentially use this method on the
02666       *    different steps. The steps are stepped through starting from the
02667       *    last step, and each step will adjust to meet the requested end date.
02668       *    If there is slack between the routings' step operationplans, it can
02669       *    be used to "absorb" the change.
02670       *  - When a start date is given, the behavior is similar to the previous
02671       *    case, except that we step through the operationplans from the
02672       *    first step this time.
02673       *  - If both a start and an end date are given, we use only the end date.
02674       *  - If there are no sub operationplans yet, apply the requested changes
02675       *    blindly.
02676       * @see Operation::setOperationPlanParameters
02677       */
02678     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02679       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02680 
02681     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02682     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02683     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02684     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02685     static int initialize();
02686 
02687     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02688 
02689     /** Return a list of all sub-operationplans. */
02690     virtual const Operationlist& getSubOperations() const {return steps;}
02691 
02692     virtual const MetaClass& getType() const {return *metadata;}
02693     static DECLARE_EXPORT const MetaClass* metadata;
02694     virtual size_t getSize() const
02695     {
02696       return sizeof(OperationRouting) + Operation::extrasize()
02697         + steps.size() * 2 * sizeof(Operation*);
02698     }
02699 
02700   protected:
02701     /** Extra logic to be used when instantiating an operationplan. */
02702     virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o);
02703 
02704   private:
02705     /** Stores a double linked list of all step operations. */
02706     Operationlist steps;
02707 };
02708 
02709 
02710 inline void OperationPlan::restore(const OperationPlanState& x)
02711 {
02712   getOperation()->setOperationPlanParameters(this, x.quantity, x.start, x.end, true);
02713   assert(quantity == x.quantity);
02714   assert(dates.getStart() == x.start || x.start!=x.end);
02715   assert(dates.getEnd() == x.end || x.start!=x.end);
02716 }
02717 
02718 
02719 /** This type defines what mode used to search the alternates. */
02720 enum SearchMode
02721 {
02722   /** Select the alternate with the lowest priority number.<br>
02723     * This is the default.
02724     */
02725   PRIORITY = 0,
02726   /** Select the alternate which gives the lowest cost. */
02727   MINCOST = 1,
02728   /** Select the alternate which gives the lowest penalty. */
02729   MINPENALTY = 2,
02730   /** Select the alternate which gives the lowest sum of the cost and
02731     * penalty. */
02732   MINCOSTPENALTY = 3
02733 };
02734 
02735 
02736 /** Writes a search mode to an output stream. */
02737 inline ostream & operator << (ostream & os, const SearchMode & d)
02738 {
02739   switch (d)
02740   {
02741     case PRIORITY: os << "PRIORITY"; return os;
02742     case MINCOST: os << "MINCOST"; return os;
02743     case MINPENALTY: os << "MINPENALTY"; return os;
02744     case MINCOSTPENALTY: os << "MINCOSTPENALTY"; return os;
02745     default: assert(false); return os;
02746   }
02747 }
02748 
02749 
02750 /** Translate a string to a search mode value. */
02751 DECLARE_EXPORT SearchMode decodeSearchMode(const string& c);
02752 
02753 
02754 /** @brief This class represents a choice between multiple operations. The
02755   * alternates are sorted in order of priority.
02756   */
02757 class OperationAlternate : public Operation
02758 {
02759   public:
02760     typedef pair<int,DateRange> alternateProperty;
02761 
02762     /** Constructor. */
02763     explicit OperationAlternate(const string& c)
02764       : Operation(c), search(PRIORITY) {initType(metadata);}
02765 
02766     /** Destructor. */
02767     DECLARE_EXPORT ~OperationAlternate();
02768 
02769     /** Add a new alternate operation.<br>
02770       * The lower the priority value, the more important this alternate
02771       * operation is. */
02772     DECLARE_EXPORT void addAlternate
02773       (Operation*, int = 1, DateRange = DateRange());
02774 
02775     /** Removes an alternate from the list. */
02776     DECLARE_EXPORT void removeSubOperation(Operation *);
02777 
02778     /** Returns the properties of a certain suboperation.
02779       * @exception LogicException Generated when the argument operation is
02780       *     null or when it is not a sub-operation of this alternate.
02781       */
02782     DECLARE_EXPORT const alternateProperty& getProperties(Operation* o) const;
02783 
02784     /** Updates the priority of a certain suboperation.
02785       * @exception DataException Generated when the argument operation is
02786       *     not null and not a sub-operation of this alternate.
02787       */
02788     DECLARE_EXPORT void setPriority(Operation*, int);
02789 
02790     /** Updates the effective daterange of a certain suboperation.
02791       * @exception DataException Generated when the argument operation is
02792       *     not null and not a sub-operation of this alternate.
02793       */
02794     DECLARE_EXPORT void setEffective(Operation*, DateRange);
02795 
02796     /** Return the search mode. */
02797     SearchMode getSearch() const {return search;}
02798 
02799     /** Update the search mode. */
02800     void setSearch(const string a) {search = decodeSearchMode(a);}
02801 
02802     /** A operation of this type enforces the following rules on its
02803       * operationplans:
02804       *  - Very simple, call the method with the same name on the alternate
02805       *    suboperationplan.
02806       * @see Operation::setOperationPlanParameters
02807       */
02808     DECLARE_EXPORT OperationPlanState setOperationPlanParameters
02809       (OperationPlan*, double, Date, Date, bool=true, bool=true) const;
02810 
02811     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02812     DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02813     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02814     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02815     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02816     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
02817     virtual const Operationlist& getSubOperations() const {return alternates;}
02818     static int initialize();
02819 
02820     /** Add an alternate to the operation.<br>
02821       * The keyword arguments are "operation", "priority", "effective_start"
02822       * and "effective_end"
02823       */
02824     static DECLARE_EXPORT PyObject* addAlternate(PyObject*, PyObject*, PyObject*);
02825 
02826     virtual const MetaClass& getType() const {return *metadata;}
02827     static DECLARE_EXPORT const MetaClass* metadata;
02828     virtual size_t getSize() const
02829     {
02830       return sizeof(OperationAlternate) + Operation::extrasize()
02831           + alternates.size() * (5*sizeof(Operation*)+sizeof(alternateProperty));
02832     }
02833 
02834   protected:
02835     /** Extra logic to be used when instantiating an operationplan. */
02836     virtual DECLARE_EXPORT bool extraInstantiate(OperationPlan* o);
02837 
02838   private:
02839     typedef list<alternateProperty> alternatePropertyList;
02840 
02841     /** List of the priorities of the different alternate operations. The list
02842       * is maintained such that it is sorted in ascending order of priority. */
02843     alternatePropertyList alternateProperties;
02844 
02845     /** List of all alternate operations. The list is sorted with the operation
02846       * with the highest priority at the start of the list.<br>
02847       * Note that the list of operations and the list of priorities go hand in
02848       * hand: they have an equal number of elements and the order of the
02849       * elements is matching in both lists.
02850       */
02851     Operationlist alternates;
02852 
02853     /** Mode to select the preferred alternates. */
02854     SearchMode search;
02855 };
02856 
02857 
02858 /** @brief An item defines the products being planned, sold, stored and/or
02859   * manufactured. Buffers and demands have a reference an item.
02860   *
02861   * This is an abstract class.
02862   */
02863 class Item : public HasHierarchy<Item>, public HasDescription
02864 {
02865   public:
02866     /** Constructor. Don't use this directly! */
02867     explicit Item(const string& str) : HasHierarchy<Item>(str),
02868       deliveryOperation(NULL), price(0.0) {}
02869 
02870     /** Returns the delivery operation.<br>
02871       * This field is inherited from a parent item, if it hasn't been
02872       * specified.
02873       */
02874     Operation* getOperation() const
02875     {
02876       // Current item has a non-empty deliveryOperation field
02877       if (deliveryOperation) return deliveryOperation;
02878 
02879       // Look for a non-empty deliveryOperation field on owners
02880       for (Item* i = getOwner(); i; i=i->getOwner())
02881         if (i->deliveryOperation) return i->deliveryOperation;
02882 
02883       // The field is not specified on the item or any of its parents.
02884       return NULL;
02885     }
02886 
02887     /** Updates the delivery operation.<br>
02888       * If some demands have already been planned using the old delivery
02889       * operation they are left untouched and won't be replanned.
02890       */
02891     void setOperation(Operation* o) {deliveryOperation = o;}
02892 
02893     /** Return the selling price of the item.<br>
02894       * The default value is 0.0.
02895       */
02896     double getPrice() const {return price;}
02897 
02898     /** Update the selling price of the item. */
02899     void setPrice(const double c)
02900     {
02901       if (c >= 0) price = c;
02902       else throw DataException("Item price must be positive");
02903     }
02904 
02905     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
02906     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
02907     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
02908     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
02909     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
02910     static int initialize();
02911 
02912     /** Destructor. */
02913     virtual DECLARE_EXPORT ~Item();
02914 
02915     virtual const MetaClass& getType() const {return *metadata;}
02916     static DECLARE_EXPORT const MetaCategory* metadata;
02917 
02918   private:
02919     /** This is the operation used to satisfy a demand for this item.
02920       * @see Demand
02921       */
02922     Operation* deliveryOperation;
02923 
02924     /** Selling price of the item. */
02925     double price;
02926 };
02927 
02928 
02929 /** @brief This class is the default implementation of the abstract Item
02930   * class. */
02931 class ItemDefault : public Item
02932 {
02933   public:
02934     explicit ItemDefault(const string& str) : Item(str) {initType(metadata);}
02935     virtual const MetaClass& getType() const {return *metadata;}
02936     static DECLARE_EXPORT const MetaClass* metadata;
02937     virtual size_t getSize() const
02938     {
02939       return sizeof(ItemDefault) + getName().size()
02940         + HasDescription::extrasize();
02941     }
02942     static int initialize();
02943 };
02944 
02945 
02946 /** @brief A buffer represents a combination of a item and location.<br>
02947   * It is the entity for keeping modeling inventory.
02948   */
02949 class Buffer : public HasHierarchy<Buffer>, public HasLevel,
02950       public Plannable, public HasDescription
02951 {
02952     friend class Flow;
02953     friend class FlowPlan;
02954 
02955   public:
02956     typedef TimeLine<FlowPlan> flowplanlist;
02957     typedef Association<Operation,Buffer,Flow>::ListB flowlist;
02958 
02959     /** Constructor. Implicit creation of instances is disallowed. */
02960     explicit Buffer(const string& str) : HasHierarchy<Buffer>(str),
02961         hidden(false), producing_operation(NULL), loc(NULL), it(NULL),
02962         min_val(0), max_val(default_max), min_cal(NULL), max_cal(NULL), 
02963         carrying_cost(0.0) {}
02964 
02965     /** Returns the operation that is used to supply extra supply into this
02966       * buffer. */
02967     Operation* getProducingOperation() const {return producing_operation;}
02968 
02969     /** Updates the operation that is used to supply extra supply into this
02970       * buffer. */
02971     void setProducingOperation(Operation* o)
02972       {producing_operation = o; setChanged();}
02973 
02974     /** Returns the item stored in this buffer. */
02975     Item* getItem() const {return it;}
02976 
02977     /** Updates the Item stored in this buffer. */
02978     void setItem(Item* i) {it = i; setChanged();}
02979 
02980     /** Returns the Location of this buffer. */
02981     Location* getLocation() const {return loc;}
02982 
02983     /** Updates the location of this buffer. */
02984     void setLocation(Location* i) {loc = i;}
02985 
02986     /** Returns the minimum inventory level. */
02987     double getMinimum() const {return min_val;}
02988 
02989     /** Returns a pointer to a calendar for storing the minimum inventory
02990       * level. */
02991     CalendarDouble* getMinimumCalendar() const {return min_cal;}
02992 
02993     /** Returns the maximum inventory level. */
02994     double getMaximum() const {return max_val;}
02995 
02996     /** Returns a pointer to a calendar for storing the maximum inventory
02997       * level. */
02998     CalendarDouble* getMaximumCalendar() const {return max_cal;}
02999 
03000     /** Updates the minimum inventory target for the buffer. */
03001     DECLARE_EXPORT void setMinimum(double);
03002 
03003     /** Updates the minimum inventory target for the buffer. */
03004     DECLARE_EXPORT void setMinimumCalendar(CalendarDouble *);
03005 
03006     /** Updates the minimum inventory target for the buffer. */
03007     DECLARE_EXPORT void setMaximum(double);
03008 
03009     /** Updates the minimum inventory target for the buffer. */
03010     DECLARE_EXPORT void setMaximumCalendar(CalendarDouble *);
03011 
03012     /** Return the carrying cost.<br>
03013       * The cost of carrying inventory in this buffer. The value is a
03014       * percentage of the item sales price, per year and per unit.
03015       */
03016     double getCarryingCost() const {return carrying_cost;}
03017 
03018     /** Return the carrying cost.<br>
03019       * The cost of carrying inventory in this buffer. The value is a
03020       * percentage of the item sales price, per year and per unit.<br>
03021       * The default value is 0.0.
03022       */
03023     void setCarryingCost(const double c)
03024     {
03025       if (c >= 0) carrying_cost = c;
03026       else throw DataException("Buffer carrying_cost must be positive");
03027     }
03028 
03029     DECLARE_EXPORT virtual void beginElement(XMLInput&, const Attribute&);
03030     DECLARE_EXPORT virtual void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03031     DECLARE_EXPORT virtual void endElement(XMLInput&, const Attribute&, const DataElement&);
03032     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03033     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03034 
03035     size_t extrasize() const
03036     {return getName().size() + HasDescription::extrasize();}
03037 
03038     /** Initialize the class. */
03039     static int initialize();
03040 
03041     /** Destructor. */
03042     virtual DECLARE_EXPORT ~Buffer();
03043 
03044     /** Returns the available material on hand immediately after the
03045       * given date.
03046       */
03047     DECLARE_EXPORT double getOnHand(Date d = Date::infinitePast) const;
03048 
03049     /** Update the on-hand inventory at the start of the planning horizon. */
03050     DECLARE_EXPORT void setOnHand(double f);
03051 
03052     /** Returns minimum or maximum available material on hand in the given
03053       * daterange. The third parameter specifies whether we return the
03054       * minimum (which is the default) or the maximum value.
03055       * The computation is INclusive the start and end dates.
03056       */
03057     DECLARE_EXPORT double getOnHand(Date, Date, bool min = true) const;
03058 
03059     /** Returns a reference to the list of all flows of this buffer. */
03060     const flowlist& getFlows() const {return flows;}
03061 
03062     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03063 
03064     /** Returns a reference to the list of all flow plans of this buffer. */
03065     const flowplanlist& getFlowPlans() const {return flowplans;}
03066 
03067     /** Returns a reference to the list of all flow plans of this buffer. */
03068     flowplanlist& getFlowPlans() {return flowplans;}
03069 
03070     /** Return the flow that is associates a given operation with this
03071       * buffer.<br>Returns NULL is no such flow exists. */
03072     Flow* findFlow(const Operation* o, Date d) const
03073     {return flows.find(o,d);}
03074 
03075     /** Deletes all operationplans consuming from or producing from this
03076       * buffer. The boolean parameter controls whether we delete also locked
03077       * operationplans or not.
03078       */
03079     DECLARE_EXPORT void deleteOperationPlans(bool deleteLockedOpplans = false);
03080 
03081     virtual DECLARE_EXPORT void updateProblems();
03082 
03083     void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
03084     bool getHidden() const {return hidden;}
03085 
03086     virtual const MetaClass& getType() const {return *metadata;}
03087     static DECLARE_EXPORT const MetaCategory* metadata;
03088 
03089     /** This function matches producing and consuming operationplans
03090       * with each other, and updates the pegging iterator accordingly.
03091       */
03092     virtual DECLARE_EXPORT void followPegging
03093       (PeggingIterator&, FlowPlan*, short, double, double);
03094 
03095   private:
03096     /** A constant defining the default max inventory target.\\
03097       * Theoretically we should set this to DBL_MAX, but then the results
03098       * are not portable across platforms.
03099       */
03100     static DECLARE_EXPORT const double default_max;
03101 
03102     /** This models the dynamic part of the plan, representing all planned
03103       * material flows on this buffer. */
03104     flowplanlist flowplans;
03105 
03106     /** This models the defined material flows on this buffer. */
03107     flowlist flows;
03108 
03109     /** Hide this entity from serialization or not. */
03110     bool hidden;
03111 
03112     /** This is the operation used to create extra material in this buffer. */
03113     Operation *producing_operation;
03114 
03115     /** Location of this buffer.<br>
03116       * This field is only used as information.<br>
03117       * The default is NULL.
03118       */
03119     Location* loc;
03120 
03121     /** Item being stored in this buffer.<br>
03122       * The default value is NULL.
03123       */
03124     Item* it;
03125 
03126     /** Minimum inventory target.<br>
03127       * If a minimum calendar is specified this field is ignored.
03128       * @see min_cal
03129       */
03130     double min_val;
03131 
03132     /** Maximum inventory target. <br>
03133       * If a maximum calendar is specified this field is ignored.
03134       * @see max_cal
03135       */
03136     double max_val;
03137 
03138     /** Points to a calendar to store the minimum inventory level.<br>
03139       * The default value is NULL, resulting in a constant minimum level
03140       * of 0.
03141       */
03142     CalendarDouble *min_cal;
03143 
03144     /** Points to a calendar to store the maximum inventory level.<br>
03145       * The default value is NULL, resulting in a buffer without excess
03146       * inventory problems.
03147       */
03148     CalendarDouble *max_cal;
03149 
03150     /** Carrying cost.<br>
03151       * The cost of carrying inventory in this buffer. The value is a
03152       * percentage of the item sales price, per year and per unit.
03153       */
03154     double carrying_cost;
03155 };
03156 
03157 
03158 
03159 /** @brief This class is the default implementation of the abstract Buffer class. */
03160 class BufferDefault : public Buffer
03161 {
03162   public:
03163     explicit BufferDefault(const string& str) : Buffer(str) {initType(metadata);}
03164     virtual const MetaClass& getType() const {return *metadata;}
03165     virtual size_t getSize() const
03166     {return sizeof(BufferDefault) + Buffer::extrasize();}
03167     static DECLARE_EXPORT const MetaClass* metadata;
03168     static int initialize();
03169 };
03170 
03171 
03172 /** @brief  This class represents a material buffer with an infinite supply of extra
03173   * material.
03174   *
03175   * In other words, it never constrains the plan and it doesn't propagate any
03176   * requirements upstream.
03177   */
03178 class BufferInfinite : public Buffer
03179 {
03180   public:
03181     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03182     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03183     virtual const MetaClass& getType() const {return *metadata;}
03184     virtual size_t getSize() const
03185       {return sizeof(BufferInfinite) + Buffer::extrasize();}
03186     explicit BufferInfinite(const string& c) : Buffer(c)
03187       {setDetectProblems(false); initType(metadata);}
03188     static DECLARE_EXPORT const MetaClass* metadata;
03189     static int initialize();
03190 };
03191 
03192 
03193 /** @brief This class models a buffer that is replenish by an external supplier
03194   * using a reorder-point policy.
03195   *
03196   * It represents a material buffer where a replenishment is triggered
03197   * whenever the inventory drops below the minimum level. The buffer is then
03198   * replenished to the maximum inventory level.<br>
03199   * A leadtime is taken into account for the replenishments.<br>
03200   * The following parameters control this replenishment:
03201   *  - <b>MinimumInventory</b>:<br>
03202   *    Inventory level triggering a new replenishment.<br>
03203   *    The actual inventory can drop below this value.
03204   *  - <b>MaximumInventory</b>:<br>
03205   *    Inventory level to which we try to replenish.<br>
03206   *    The actual inventory can exceed this value.
03207   *  - <b>Leadtime</b>:<br>
03208   *    Time taken between placing the purchase order with the supplier and the
03209   *    delivery of the material.
03210   *
03211   * Using the additional parameters described below the replenishments can be
03212   * controlled in more detail. The resulting inventory profile can end up
03213   * to be completely different from the classical saw-tooth pattern!
03214   *
03215   * The timing of the replenishments can be constrained by the following
03216   * parameters:
03217   *  - <b>MinimumInterval</b>:<br>
03218   *    Minimum time between replenishments.<br>
03219   *    The order quantity will be increased such that it covers at least
03220   *    the demand in the minimum interval period. The actual inventory can
03221   *    exceed the target set by the MinimumInventory parameter.
03222   *  - <b>MaximumInterval</b>:<br>
03223   *    Maximum time between replenishments.<br>
03224   *    The order quantity will replenish to an inventory value less than the
03225   *    maximum when this maximum interval is reached.
03226   * When the minimum and maximum interval are equal we basically define a fixed
03227   * schedule replenishment policy.
03228   *
03229   * The quantity of the replenishments can be constrained by the following
03230   * parameters:
03231   *  - <b>MinimumQuantity</b>:<br>
03232   *    Minimum quantity for a replenishment.<br>
03233   *    This parameter can cause the actual inventory to exceed the target set
03234   *    by the MinimumInventory parameter.
03235   *  - <b>MaximumQuantity</b>:<br>
03236   *    Maximum quantity for a replenishment.<br>
03237   *    This parameter can cause the maximum inventory target never to be
03238   *    reached.
03239   *  - <b>MultipleQuantity</b>:<br>
03240   *    All replenishments are rounded up to a multiple of this value.
03241   * When the minimum and maximum quantity are equal we basically define a fixed
03242   * quantity replenishment policy.
03243   */
03244 class BufferProcure : public Buffer
03245 {
03246   public:
03247     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03248     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03249     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03250     virtual const MetaClass& getType() const {return *metadata;}
03251     virtual size_t getSize() const
03252       {return sizeof(BufferProcure) + Buffer::extrasize();}
03253     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03254     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03255     static int initialize();
03256 
03257     /** Constructor. */
03258     explicit BufferProcure(const string& c) : Buffer(c), 
03259       size_minimum(0), size_maximum(DBL_MAX), size_multiple(0),
03260       oper(NULL) {initType(metadata);}
03261     static DECLARE_EXPORT const MetaClass* metadata;
03262 
03263     /** Return the purchasing leadtime. */
03264     TimePeriod getLeadtime() const {return leadtime;}
03265 
03266     /** Update the procurement leadtime. */
03267     void setLeadtime(TimePeriod p)
03268     {
03269       if (p<0L)
03270         throw DataException("Procurement buffer can't have a negative lead time");
03271       leadtime = p;
03272     }
03273 
03274     /** Return the release time fence. */
03275     TimePeriod getFence() const {return fence;}
03276 
03277     /** Update the release time fence. */
03278     void setFence(TimePeriod p) {fence = p;}
03279 
03280     /** Return the inventory level that will trigger creation of a
03281       * purchasing.
03282       */
03283     double getMinimumInventory() const 
03284       {return getFlowPlans().getMin(Date::infiniteFuture);}
03285 
03286     /** Update the inventory level that will trigger the creation of a 
03287       * replenishment.<br>
03288       * Because of the replenishment leadtime, the actual inventory will drop
03289       * below this value. It is up to the user to set an appropriate minimum
03290       * value.
03291       */
03292     void setMinimumInventory(double f)
03293     {
03294       if (f<0)
03295         throw DataException("Procurement buffer can't have a negative minimum inventory");
03296       flowplanlist::EventMinQuantity* min = getFlowPlans().getMinEvent(Date::infiniteFuture);
03297       if (min)
03298         min->setMin(f);
03299       else
03300       {
03301         // Create and insert a new minimum event
03302         min = new flowplanlist::EventMinQuantity(Date::infinitePast, f);
03303         getFlowPlans().insert(min);
03304       }
03305       // The minimum is increased over the maximum: auto-increase the maximum.
03306       if (getFlowPlans().getMax(Date::infiniteFuture) < f) 
03307         setMaximumInventory(f);
03308     }
03309 
03310     /** Return the maximum inventory level to which we wish to replenish. */
03311     double getMaximumInventory() const 
03312       {return getFlowPlans().getMax(Date::infiniteFuture);}
03313 
03314     /** Update the maximum inventory level to which we plan to replenish.<br>
03315       * This is not a hard limit - other parameters can make that the actual
03316       * inventory either never reaches this value or always exceeds it.
03317       */    
03318     void setMaximumInventory(double f)
03319     {
03320       if (f<0)
03321         throw DataException("Procurement buffer can't have a negative maximum inventory");
03322       flowplanlist::EventMaxQuantity* max = getFlowPlans().getMaxEvent(Date::infiniteFuture);
03323       if (max)
03324         max->setMax(f);
03325       else
03326       {
03327         // Create and insert a new maximum event
03328         max = new flowplanlist::EventMaxQuantity(Date::infinitePast, f);
03329         getFlowPlans().insert(max);
03330       }
03331       // The maximum is lowered below the minimum: auto-decrease the minimum
03332       if (f < getFlowPlans().getMin(Date::infiniteFuture)) 
03333         setMinimumInventory(f);
03334     }
03335 
03336     /** Return the minimum interval between purchasing operations.<br>
03337       * This parameter doesn't control the timing of the first purchasing
03338       * operation, but only to the subsequent ones.
03339       */
03340     TimePeriod getMinimumInterval() const {return min_interval;}
03341 
03342     /** Update the minimum time between replenishments. */
03343     void setMinimumInterval(TimePeriod p)
03344     {
03345       if (p<0L)
03346         throw DataException("Procurement buffer can't have a negative minimum interval");
03347       min_interval = p;
03348       // minimum is increased over the maximum: auto-increase the maximum
03349       if (max_interval < min_interval) max_interval = min_interval;
03350     }
03351 
03352     /** Return the maximum time interval between sytem-generated replenishment
03353       * operations.
03354       */
03355     TimePeriod getMaximumInterval() const {return max_interval;}
03356 
03357     /** Update the minimum time between replenishments. */
03358     void setMaximumInterval(TimePeriod p)
03359     {
03360       if (p<0L)
03361         throw DataException("Procurement buffer can't have a negative maximum interval");
03362       max_interval = p;
03363       // maximum is lowered below the minimum: auto-decrease the minimum
03364       if (max_interval < min_interval) min_interval = max_interval;
03365     }
03366 
03367     /** Return the minimum quantity of a purchasing operation. */
03368     double getSizeMinimum() const {return size_minimum;}
03369 
03370     /** Update the minimum replenishment quantity. */
03371     void setSizeMinimum(double f)
03372     {
03373       if (f<0)
03374         throw DataException("Procurement buffer can't have a negative minimum size");
03375       size_minimum = f;
03376       // minimum is increased over the maximum: auto-increase the maximum
03377       if (size_maximum < size_minimum) size_maximum = size_minimum;
03378    }
03379 
03380     /** Return the maximum quantity of a purchasing operation. */
03381     double getSizeMaximum() const {return size_maximum;}
03382 
03383     /** Update the maximum replenishment quantity. */
03384     void setSizeMaximum(double f)
03385     {
03386       if (f<0)
03387         throw DataException("Procurement buffer can't have a negative maximum size");
03388       size_maximum = f;
03389       // maximum is lowered below the minimum: auto-decrease the minimum
03390       if (size_maximum < size_minimum) size_minimum = size_maximum;
03391     }
03392 
03393     /** Return the multiple quantity of a purchasing operation. */
03394     double getSizeMultiple() const {return size_multiple;}
03395 
03396     /** Update the multiple quantity. */
03397     void setSizeMultiple(double f)
03398     {
03399       if (f<0)
03400         throw DataException("Procurement buffer can't have a negative multiple size");
03401       size_multiple = f;
03402     }
03403 
03404     /** Returns the operation that is automatically created to represent the
03405       * procurements.
03406       */
03407     DECLARE_EXPORT Operation* getOperation() const;
03408 
03409   private:
03410     /** Purchasing leadtime.<br>
03411       * Within this leadtime fence no additional purchase orders can be generated.
03412       */
03413     TimePeriod leadtime;
03414 
03415     /** Time window from the current date in which all procurements are expected
03416       * to be released.
03417       */
03418     TimePeriod fence;
03419 
03420     /** Minimum time interval between purchasing operations. */
03421     TimePeriod min_interval;
03422 
03423     /** Maximum time interval between purchasing operations. */
03424     TimePeriod max_interval;
03425 
03426     /** Minimum purchasing quantity.<br>
03427       * The default value is 0, meaning no minimum.
03428       */
03429     double size_minimum;
03430 
03431     /** Maximum purchasing quantity.<br>
03432       * The default value is 0, meaning no maximum limit.
03433       */
03434     double size_maximum;
03435 
03436     /** Purchases are always rounded up to a multiple of this quantity.<br>
03437       * The default value is 0, meaning no multiple needs to be applied.
03438       */
03439     double size_multiple;
03440 
03441     /** A pointer to the procurement operation. */
03442     Operation* oper;
03443 };
03444 
03445 
03446 /** @brief This class defines a material flow to/from a buffer, linked with an
03447   * operation. This default implementation plans the material flow at the
03448   * start of the operation.
03449   */
03450 class Flow : public Object, public Association<Operation,Buffer,Flow>::Node,
03451       public Solvable
03452 {
03453   public:
03454     /** Destructor. */
03455     virtual DECLARE_EXPORT ~Flow();
03456 
03457     /** Constructor. */
03458     explicit Flow(Operation* o, Buffer* b, double q)
03459       : quantity(q), priority(1), hasAlts(false), altFlow(NULL), search(PRIORITY)
03460     {
03461       setOperation(o);
03462       setBuffer(b);
03463       initType(metadata);
03464       try { validate(ADD); }
03465       catch (...)
03466       {
03467         if (getOperation()) getOperation()->flowdata.erase(this);
03468         if (getBuffer()) getBuffer()->flows.erase(this);
03469         resetReferenceCount();
03470         throw;
03471       }
03472     }
03473 
03474     /** Constructor. */
03475     explicit Flow(Operation* o, Buffer* b, double q, DateRange e)
03476       : quantity(q), priority(1), hasAlts(false), altFlow(NULL), search(PRIORITY)
03477     {
03478       setOperation(o);
03479       setBuffer(b);
03480       setEffective(e);
03481       initType(metadata);
03482       try { validate(ADD); }
03483       catch (...)
03484       {
03485         if (getOperation()) getOperation()->flowdata.erase(this);
03486         if (getBuffer()) getBuffer()->flows.erase(this);
03487         resetReferenceCount();
03488         throw;
03489       }
03490     }
03491 
03492     /** Returns the operation. */
03493     Operation* getOperation() const {return getPtrA();}
03494 
03495     /** Updates the operation of this flow. This method can be called only ONCE
03496       * for each flow. In case that doesn't suit you, delete the existing flow
03497       * and create a new one.
03498       */
03499     void setOperation(Operation* o) {if (o) setPtrA(o,o->getFlows());}
03500 
03501     /** Returns true if this flow consumes material from the buffer. */
03502     bool isConsumer() const {return quantity < 0;}
03503 
03504     /** Returns true if this flow produces material into the buffer. */
03505     bool isProducer() const {return quantity >= 0;}
03506 
03507     /** Returns the material flow PER UNIT of the operationplan. */
03508     double getQuantity() const {return quantity;}
03509 
03510     /** Updates the material flow PER UNIT of the operationplan. Existing
03511       * flowplans are NOT updated to take the new quantity in effect. Only new
03512       * operationplans and updates to existing ones will use the new quantity
03513       * value.
03514       */
03515     void setQuantity(double f) {quantity = f;}
03516 
03517     /** Returns the buffer. */
03518     Buffer* getBuffer() const {return getPtrB();}
03519 
03520     /** Updates the buffer of this flow. This method can be called only ONCE
03521       * for each flow. In case that doesn't suit you, delete the existing flow
03522       * and create a new one.
03523       */
03524     void setBuffer(Buffer* b) {if (b) setPtrB(b,b->getFlows());}
03525 
03526     /** Update the priority of a flow. */
03527     void setPriority(int i) {priority = i;}
03528 
03529     /** Return the priority of a flow. */
03530     int getPriority() const {return priority;}
03531 
03532     /** Returns true if there are alternates for this flow. */
03533     bool hasAlternates() const {return hasAlts;}
03534 
03535     /** Returns the flow of which this one is an alternate.<br>
03536       * NULL is return where there is none.
03537       */
03538     Flow* getAlternate() const {return altFlow;}
03539 
03540     /** Define the flow of which this one is an alternate. */
03541     DECLARE_EXPORT void setAlternate(Flow *);
03542 
03543     /** Define the flow of which this one is an alternate. */
03544     DECLARE_EXPORT void setAlternate(const string& n);
03545 
03546     /** Return the search mode. */
03547     SearchMode getSearch() const {return search;}
03548 
03549     /** Update the search mode. */
03550     void setSearch(const string a) {search = decodeSearchMode(a);}
03551 
03552     /** A flow is considered hidden when either its buffer or operation
03553       * are hidden. */
03554     virtual bool getHidden() const
03555     {
03556       return (getBuffer() && getBuffer()->getHidden())
03557         || (getOperation() && getOperation()->getHidden());
03558     }
03559 
03560     /** This method holds the logic the compute the date of a flowplan. */
03561     virtual Date getFlowplanDate(const FlowPlan*) const;
03562 
03563     /** This method holds the logic the compute the quantity of a flowplan. */
03564     virtual double getFlowplanQuantity(const FlowPlan*) const;
03565 
03566     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03567     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
03568     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03569     static int initialize();
03570     static void writer(const MetaCategory*, XMLOutput*);
03571 
03572     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03573 
03574     virtual const MetaClass& getType() const {return *metadata;}
03575     static DECLARE_EXPORT const MetaCategory* metadata;
03576     virtual size_t getSize() const {return sizeof(Flow) + getName().size();}
03577 
03578   protected:
03579     /** Default constructor. */
03580     explicit Flow() : quantity(0.0), priority(1), hasAlts(false), 
03581       altFlow(NULL), search(PRIORITY) {initType(metadata);}
03582 
03583   private:
03584     /** Verifies whether a flow meets all requirements to be valid. <br>
03585       * An exception is thrown if the flow is invalid.
03586       */
03587     DECLARE_EXPORT void validate(Action action);
03588 
03589     /** Quantity of the flow. */
03590     double quantity;
03591 
03592     /** Priority of the flow - used in case of alternate flows. */
03593     int priority;
03594 
03595     /** Flag that is set to true when a flow has alternates. */
03596     bool hasAlts;
03597 
03598     /** A flow representing the main flow of a set of alternate flows. */
03599     Flow* altFlow;
03600 
03601     /** Mode to select the preferred alternates. */
03602     SearchMode search;
03603 
03604     static PyObject* create(PyTypeObject* pytype, PyObject* args, PyObject* kwds);
03605     DECLARE_EXPORT PyObject* getattro(const Attribute&);
03606     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03607 };
03608 
03609 
03610 /** @brief This class defines a material flow to/from a buffer, linked with an
03611   * operation. This subclass represents a flow that is at the start date of
03612   * the operation.
03613   */
03614 class FlowStart : public Flow
03615 {
03616   public:
03617     /** Constructor. */
03618     explicit FlowStart(Operation* o, Buffer* b, double q) : Flow(o,b,q) {}
03619 
03620     /** Constructor. */
03621     explicit FlowStart(Operation* o, Buffer* b, double q, DateRange e) : Flow(o,b,q,e) {}
03622 
03623     /** This constructor is called from the plan begin_element function. */
03624     explicit FlowStart() {}
03625 
03626     virtual const MetaClass& getType() const {return *metadata;}
03627     static DECLARE_EXPORT const MetaClass* metadata;
03628     virtual size_t getSize() const {return sizeof(FlowStart);}
03629     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03630 };
03631 
03632 
03633 /** @brief This class defines a material flow to/from a buffer, linked with an
03634   * operation. This subclass represents a flow that is at end date of the
03635   * operation.
03636   */
03637 class FlowEnd : public Flow
03638 {
03639   public:
03640     /** Constructor. */
03641     explicit FlowEnd(Operation* o, Buffer* b, double q) : Flow(o,b,q) {}
03642 
03643     /** Constructor. */
03644     explicit FlowEnd(Operation* o, Buffer* b, double q, DateRange e) : Flow(o,b,q,e) {}
03645 
03646     /** This constructor is called from the plan begin_element function. */
03647     explicit FlowEnd() {}
03648 
03649     /** This method holds the logic the compute the date of a flowplan. */
03650     virtual Date getFlowplanDate(const FlowPlan* fl) const;
03651 
03652     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03653 
03654     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
03655 
03656     virtual const MetaClass& getType() const {return *metadata;}
03657     static DECLARE_EXPORT const MetaClass* metadata;
03658     virtual size_t getSize() const {return sizeof(FlowEnd);}
03659 };
03660 
03661 
03662 /** @brief A flowplan represents a planned material flow in or out of a buffer.
03663   *
03664   * Flowplans are owned by operationplans, which manage a container to store
03665   * them.
03666   */
03667 class FlowPlan : public TimeLine<FlowPlan>::EventChangeOnhand, public PythonExtensionBase
03668 {
03669     friend class OperationPlan::FlowPlanIterator;
03670   private:
03671     /** Points to the flow instantiated by this flowplan. */
03672     const Flow *fl;
03673 
03674     /** Python interface method. */
03675     PyObject* getattro(const Attribute&);
03676 
03677     /** Points to the operationplan owning this flowplan. */
03678     OperationPlan *oper;
03679 
03680     /** Points to the next flowplan owned by the same operationplan. */
03681     FlowPlan *nextFlowPlan;
03682 
03683   public:
03684 
03685     static DECLARE_EXPORT const MetaCategory* metadata;
03686     static int initialize();
03687 
03688     /** Constructor. */
03689     explicit DECLARE_EXPORT FlowPlan(OperationPlan*, const Flow*);
03690 
03691     /** Returns the flow of which this is an plan instance. */
03692     const Flow* getFlow() const {return fl;}
03693 
03694     /** Returns the buffer. */
03695     const Buffer* getBuffer() const {return fl->getBuffer();}
03696 
03697     /** Update the flow of an already existing flowplan.<br>
03698       * The new flow must belong to the same operation.
03699       */
03700     DECLARE_EXPORT void setFlow(const Flow*);
03701 
03702     /** Returns the operationplan owning this flowplan. */
03703     OperationPlan* getOperationPlan() const {return oper;}
03704 
03705     /** Destructor. */
03706     virtual ~FlowPlan()
03707     {
03708       Buffer* b = getFlow()->getBuffer();
03709       b->setChanged();
03710       b->flowplans.erase(this);
03711     }
03712 
03713     /** Writing the element.
03714       * This method has the same prototype as a usual instance of the Object
03715       * class, but this is only superficial: FlowPlan isn't a subclass of
03716       * Object at all.
03717       */
03718     void DECLARE_EXPORT writeElement
03719       (XMLOutput*, const Keyword&, mode=DEFAULT) const;
03720 
03721     /** Updates the quantity of the flowplan by changing the quantity of the
03722       * operationplan owning this flowplan.<br>
03723       * The boolean parameter is used to control whether to round up (false)
03724       * or down (true) in case the operation quantity must be a multiple.
03725       */
03726     void setQuantity(double qty, bool b=false, bool u = true)
03727     {
03728       if (getFlow()->getEffective().within(getDate()))
03729         oper->setQuantity(qty / getFlow()->getQuantity(), b, u);
03730     }
03731 
03732     /** This function needs to be called whenever the flowplan date or
03733       * quantity are changed.
03734       */
03735     DECLARE_EXPORT void update();
03736 
03737     /** Return a pointer to the timeline data structure owning this flowplan. */
03738     TimeLine<FlowPlan>* getTimeLine() const
03739     {return &(getFlow()->getBuffer()->flowplans);}
03740 
03741     /** Returns true when the flowplan is hidden.<br>
03742       * This is determined by looking at whether the flow is hidden or not.
03743       */
03744     bool getHidden() const {return fl->getHidden();}
03745 };
03746 
03747 
03748 inline double Flow::getFlowplanQuantity(const FlowPlan* fl) const
03749 {
03750   return getEffective().within(fl->getDate()) ?
03751     fl->getOperationPlan()->getQuantity() * getQuantity() :
03752     0.0;
03753 }
03754 
03755 
03756 inline Date Flow::getFlowplanDate(const FlowPlan* fl) const
03757 {
03758   return fl->getOperationPlan()->getDates().getStart();
03759 }
03760 
03761 
03762 inline Date FlowEnd::getFlowplanDate(const FlowPlan* fl) const
03763 {
03764   return fl->getOperationPlan()->getDates().getEnd();
03765 }
03766 
03767 
03768 /** @brief This class is used to represent a matrix defining the changeover
03769   * times between setups.
03770   */
03771 class SetupMatrix : public HasName<SetupMatrix>
03772 {
03773   public:
03774     class RuleIterator; // Forward declaration
03775    /** @brief An specific changeover rule in a setup matrix. */
03776    class Rule : public Object
03777     {
03778       friend class RuleIterator;
03779       friend class SetupMatrix;
03780       public:
03781         /** Constructor. */
03782         DECLARE_EXPORT Rule(SetupMatrix *s, int p = 0);
03783 
03784         /** Destructor. */
03785         DECLARE_EXPORT ~Rule();
03786 
03787         virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03788         DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03789         virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03790         virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03791         static int initialize();
03792 
03793         virtual const MetaClass& getType() const {return *metadata;}
03794         static DECLARE_EXPORT const MetaCategory* metadata;
03795 
03796         size_t getSize() const
03797           {return sizeof(Rule) + from.size() + to.size();}
03798 
03799         /** Update the priority.<br>
03800           * The priority value is a key field. If multiple rules have the
03801           * same priority a data exception is thrown.
03802           */
03803         DECLARE_EXPORT void setPriority(const int);
03804 
03805         /** Return the priority. */
03806         double getPriority() const {return priority;}
03807 
03808         /** Update the from setup. */
03809         void setFromSetup(const string f) {from = f;}
03810 
03811         /** Return the from setup. */
03812         const string& getFromSetup() const {return from;}
03813 
03814         /** Update the from setup. */
03815         void setToSetup(const string f) {to = f;}
03816 
03817         /** Return the from setup. */
03818         const string& getToSetup() const {return to;}
03819 
03820         /** Update the conversion duration. */
03821         void setDuration(const TimePeriod p) {duration = p;}
03822 
03823         /** Return the conversion duration. */
03824         TimePeriod getDuration() const {return duration;}
03825 
03826         /** Update the conversion cost. */
03827         void setCost(const double p) {cost = p;}
03828 
03829         /** Return the conversion cost. */
03830         double getCost() const {return cost;}
03831 
03832       private:
03833         /** Original setup. */
03834         string from;
03835 
03836         /** New setup. */
03837         string to;
03838 
03839         /** Changeover time. */
03840         TimePeriod duration;
03841 
03842         /** Changeover cost. */
03843         double cost;
03844 
03845         /** Priority of the rule.<br>
03846           * This field is the key field, i.e. within a setup matrix all rules
03847           * need to have different priorities.
03848           */
03849         int priority;
03850 
03851         /** Pointer to the owning matrix. */
03852         SetupMatrix *matrix;
03853 
03854         /** Pointer to the next rule in this matrix. */
03855         Rule *nextRule;
03856 
03857         /** Pointer to the previous rule in this matrix. */
03858         Rule *prevRule;
03859     };
03860 
03861     /** @brief An iterator class to go through all rules of a setup matrix. */
03862     class RuleIterator
03863     {
03864       private:
03865         Rule* curRule;
03866       public:
03867         /** Constructor. */
03868         RuleIterator(Rule* c = NULL) : curRule(c) {}
03869         bool operator != (const RuleIterator &b) const
03870           {return b.curRule != curRule;}
03871         bool operator == (const RuleIterator &b) const
03872           {return b.curRule == curRule;}
03873         RuleIterator& operator++()
03874           {if (curRule) curRule = curRule->nextRule; return *this;}
03875         RuleIterator operator++(int)
03876           {RuleIterator tmp = *this; ++*this; return tmp;}
03877         RuleIterator& operator--()
03878           {if(curRule) curRule = curRule->prevRule; return *this;}
03879         RuleIterator operator--(int)
03880           {RuleIterator tmp = *this; --*this; return tmp;}
03881         Rule* operator ->() const {return curRule;}
03882         Rule& operator *() const {return *curRule;}
03883     };
03884 
03885   public:
03886     /** Default constructor. */
03887     SetupMatrix(const string& n) : HasName<SetupMatrix>(n), firstRule(NULL) {}
03888 
03889     /** Destructor. */
03890     DECLARE_EXPORT ~SetupMatrix();
03891 
03892     /** This is a factory method that creates a new rule<br>
03893       * This method is intended to be used to create objects when reading
03894       * XML input data.
03895       */
03896     DECLARE_EXPORT Rule* createRule(const AttributeList&);
03897 
03898     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
03899     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
03900     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
03901     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
03902     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
03903     static int initialize();
03904 
03905     virtual const MetaClass& getType() const {return *metadata;}
03906     static DECLARE_EXPORT const MetaCategory* metadata;
03907 
03908     virtual size_t getSize() const
03909     {
03910       size_t i = sizeof(SetupMatrix) + getName().size();
03911       for (RuleIterator j = beginRules(); j!= endRules(); ++j)
03912         i += j->getSize();
03913       return i;
03914     }
03915 
03916     size_t extrasize() const {return getName().size();}
03917 
03918     /** Returns an iterator to go through the list of buckets. */
03919     RuleIterator beginRules() const {return RuleIterator(firstRule);}
03920 
03921     /** Returns an iterator to go through the list of buckets. */
03922     RuleIterator endRules() const {return RuleIterator(NULL);}
03923 
03924     /** Python interface to add a new rule. */
03925     static DECLARE_EXPORT PyObject* addPythonRule(PyObject*, PyObject*, PyObject*);
03926 
03927     /** Computes the changeover time and cost between 2 setup values.
03928       *
03929       * To compute the time of a changeover the algorithm will evaluate all
03930       * rules in sequence (in order of priority).<br>
03931       * For a rule to match the changeover between the original setup X to
03932       * a new setup Y, two conditions need to be fulfilled:
03933       *  - The original setup X must match with the fromsetup of the rule.<br>
03934       *    If the fromsetup field is empty, it is considered a match.
03935       *  - The new setup Y must match with the tosetup of the rule.<br>
03936       *    If the tosetup field is empty, it is considered a match.
03937       * The wildcard characters * and ? can be used in the fromsetup and
03938       * tosetup fields.<br>
03939       * As soon as a matching rule is found, it is applied and subsequent
03940       * rules are not evaluated.<br>
03941       * If no matching rule is found, the changeover is not allowed: a NULL
03942       * pointer is returned.
03943       */
03944     DECLARE_EXPORT Rule* calculateSetup(const string, const string) const;
03945 
03946   private:
03947     /** Head of the list of rules. */
03948     Rule *firstRule;
03949 };
03950 
03951 
03952 /** @brief This class is the default implementation of the abstract
03953   * SetupMatrix class.
03954   */
03955 class SetupMatrixDefault : public SetupMatrix
03956 {
03957   public:
03958     explicit SetupMatrixDefault(const string& str) : SetupMatrix(str) {initType(metadata);}
03959     virtual const MetaClass& getType() const {return *metadata;}
03960     static DECLARE_EXPORT const MetaClass* metadata;
03961     virtual size_t getSize() const
03962     {return sizeof(SetupMatrixDefault) + SetupMatrix::extrasize();}
03963     static int initialize();
03964 };
03965 
03966 
03967 /** @brief This class represents a workcentre, a physical or logical
03968   * representation of capacity.
03969   */
03970 class Resource : public HasHierarchy<Resource>,
03971       public HasLevel, public Plannable, public HasDescription
03972 {
03973     friend class Load;
03974     friend class LoadPlan;
03975 
03976   public:
03977     /** The default time window before the ask date where we look for
03978       * available capacity. */
03979     static const long defaultMaxEarly = 100*86400L;
03980 
03981     /** Constructor. */
03982     explicit Resource(const string& str) : HasHierarchy<Resource>(str),
03983       size_max_cal(NULL), size_max(0), loc(NULL), cost(0.0), hidden(false), maxearly(defaultMaxEarly),
03984       setupmatrix(NULL) { setMaximum(1); };
03985 
03986     /** Destructor. */
03987     virtual DECLARE_EXPORT ~Resource();
03988 
03989     /** Updates the size of a resource, when it is time-dependent. */
03990     DECLARE_EXPORT void setMaximumCalendar(CalendarDouble*);
03991 
03992     /** Updates the size of a resource. */
03993     DECLARE_EXPORT void setMaximum(double);
03994 
03995     /** Return a pointer to the maximum capacity profile. */
03996     CalendarDouble* getMaximumCalendar() const {return size_max_cal;}
03997 
03998     /** Return a pointer to the maximum capacity. */
03999     double getMaximum() const {return size_max;}
04000 
04001     /** Returns the cost of using 1 unit of this resource for 1 hour.<br>
04002       * The default value is 0.0.
04003       */
04004     double getCost() const {return cost;}
04005 
04006     /** Update the cost of using 1 unit of this resource for 1 hour. */
04007     void setCost(const double c)
04008     {
04009       if (c >= 0) cost = c;
04010       else throw DataException("Resource cost must be positive");
04011     }
04012 
04013     typedef Association<Operation,Resource,Load>::ListB loadlist;
04014     typedef TimeLine<LoadPlan> loadplanlist;
04015 
04016     /** Returns a reference to the list of loadplans. */
04017     const loadplanlist& getLoadPlans() const {return loadplans;}
04018 
04019     /** Returns a reference to the list of loadplans. */
04020     loadplanlist& getLoadPlans() {return loadplans;}
04021 
04022     /** Returns a constant reference to the list of loads. It defines
04023       * which operations are using the resource.
04024       */
04025     const loadlist& getLoads() const {return loads;}
04026 
04027     /** Return the load that is associates a given operation with this
04028       * resource. Returns NULL is no such load exists. */
04029     Load* findLoad(const Operation* o, Date d) const
04030     {return loads.find(o,d);}
04031 
04032     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04033     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04034     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04035     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
04036     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04037 
04038     /** Initialize the class. */
04039     static int initialize();
04040 
04041     size_t extrasize() const
04042     {return getName().size() + HasDescription::extrasize() + setup.size();}
04043 
04044     /** Returns the location of this resource. */
04045     Location* getLocation() const {return loc;}
04046 
04047     /** Updates the location of this resource. */
04048     void setLocation(Location* i) {loc = i;}
04049 
04050     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04051 
04052     /** Deletes all operationplans loading this resource. The boolean parameter
04053       * controls whether we delete also locked operationplans or not.
04054       */
04055     DECLARE_EXPORT void deleteOperationPlans(bool = false);
04056 
04057     /** Recompute the problems of this resource. */
04058     virtual DECLARE_EXPORT void updateProblems();
04059 
04060     /** Scan the setups of this resource. */
04061     virtual DECLARE_EXPORT void updateSetups(const LoadPlan* = NULL);
04062 
04063     void setHidden(bool b) {if (hidden!=b) setChanged(); hidden = b;}
04064     bool getHidden() const {return hidden;}
04065 
04066     virtual const MetaClass& getType() const {return *metadata;}
04067     static DECLARE_EXPORT const MetaCategory* metadata;
04068 
04069     /** Returns the maximum inventory buildup allowed in case of capacity
04070       * shortages. */
04071     TimePeriod getMaxEarly() const {return maxearly;}
04072 
04073     /** Updates the maximum inventory buildup allowed in case of capacity
04074       * shortages. */
04075     void setMaxEarly(TimePeriod c)
04076     {
04077       if (c >= 0L) maxearly = c;
04078       else throw DataException("MaxEarly must be positive");
04079     }
04080 
04081     /** Return a pointer to the setup matrix. */
04082     SetupMatrix* getSetupMatrix() const {return setupmatrix;}
04083 
04084     /** Update the reference to the setup matrix. */
04085     void setSetupMatrix(SetupMatrix *s) {setupmatrix = s;}
04086 
04087     /** Return the current setup. */
04088     const string& getSetup() const {return setup;}
04089 
04090     /** Update the current setup. */
04091     void setSetup(const string s) {setup = s;}
04092 
04093   private:
04094     /** This calendar is used to updates to the resource size. */
04095     CalendarDouble* size_max_cal;
04096 
04097     /** The maximum resource size.<br>
04098       * If a calendar is specified, this field is ignored.
04099       */
04100     double size_max;
04101 
04102     /** Stores the collection of all loadplans of this resource. */
04103     loadplanlist loadplans;
04104 
04105     /** This is a list of all load models that are linking this resource with
04106       * operations. */
04107     loadlist loads;
04108 
04109     /** A pointer to the location of the resource. */
04110     Location* loc;
04111 
04112     /** The cost of using 1 unit of this resource for 1 hour. */
04113     double cost;
04114 
04115     /** Specifies whether this resource is hidden for serialization. */
04116     bool hidden;
04117 
04118     /** Maximum inventory buildup allowed in case of capacity shortages. */
04119     TimePeriod maxearly;
04120 
04121     /** Reference to the setup matrix. */
04122     SetupMatrix *setupmatrix;
04123 
04124     /** Current setup. */
04125     string setup;
04126 };
04127 
04128 
04129 /** @brief This class is the default implementation of the abstract
04130   * Resource class.
04131   */
04132 class ResourceDefault : public Resource
04133 {
04134   public:
04135     explicit ResourceDefault(const string& str) : Resource(str) {initType(metadata);}
04136     virtual const MetaClass& getType() const {return *metadata;}
04137     static DECLARE_EXPORT const MetaClass* metadata;
04138     virtual size_t getSize() const
04139     {return sizeof(ResourceDefault) + Resource::extrasize();}
04140     static int initialize();
04141 };
04142 
04143 
04144 /** @brief This class represents a resource that'll never have any
04145   * capacity shortage. */
04146 class ResourceInfinite : public Resource
04147 {
04148   public:
04149     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04150     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04151     virtual const MetaClass& getType() const {return *metadata;}
04152     explicit ResourceInfinite(const string& c) : Resource(c)
04153       {setDetectProblems(false); initType(metadata);}
04154     static DECLARE_EXPORT const MetaClass* metadata;
04155     virtual size_t getSize() const
04156     {return sizeof(ResourceInfinite) + Resource::extrasize();}
04157     static int initialize();
04158 };
04159 
04160 
04161 /** @brief This class links a resource to a certain operation. */
04162 class Load
04163       : public Object, public Association<Operation,Resource,Load>::Node,
04164       public Solvable
04165 {
04166     friend class Resource;
04167     friend class Operation;
04168 
04169   public:
04170     /** Constructor. */
04171     explicit Load(Operation* o, Resource* r, double u)
04172       : priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY)
04173     {
04174       setOperation(o);
04175       setResource(r);
04176       setQuantity(u);
04177       initType(metadata);
04178       try { validate(ADD); }
04179       catch (...)
04180       {
04181         if (getOperation()) getOperation()->loaddata.erase(this);
04182         if (getResource()) getResource()->loads.erase(this);
04183       resetReferenceCount();
04184       throw;
04185       }
04186     }
04187 
04188     /** Constructor. */
04189     explicit Load(Operation* o, Resource* r, double u, DateRange e)
04190       : priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY)
04191     {
04192       setOperation(o);
04193       setResource(r);
04194       setQuantity(u);
04195       setEffective(e);
04196       initType(metadata);
04197       try { validate(ADD); }
04198       catch (...)
04199       {
04200       if (getOperation()) getOperation()->loaddata.erase(this);
04201       if (getResource()) getResource()->loads.erase(this);
04202       resetReferenceCount();
04203       throw;
04204       }
04205     }
04206 
04207     /** Destructor. */
04208     DECLARE_EXPORT ~Load();
04209 
04210     /** Returns the operation consuming the resource capacity. */
04211     Operation* getOperation() const {return getPtrA();}
04212 
04213     /** Updates the operation being loaded. This method can only be called
04214       * once for a load. */
04215     void setOperation(Operation* o) {if (o) setPtrA(o,o->getLoads());}
04216 
04217     /** Returns the capacity resource being consumed. */
04218     Resource* getResource() const {return getPtrB();}
04219 
04220     /** Updates the capacity being consumed. This method can only be called
04221       * once on a resource. */
04222     void setResource(Resource* r) {if (r) setPtrB(r,r->getLoads());}
04223 
04224     /** Returns how much capacity is consumed during the duration of the
04225       * operationplan. */
04226     double getQuantity() const {return qty;}
04227 
04228     /** Updates the quantity of the load.
04229       * @exception DataException When a negative number is passed.
04230       */
04231     void setQuantity(double f)
04232     {
04233       if (f < 0) throw DataException("Load quantity can't be negative");
04234       qty = f;
04235     }
04236 
04237     /** Update the priority of a load. */
04238     void setPriority(int i) {priority = i;}
04239 
04240     /** Return the priority of a load. */
04241     int getPriority() const {return priority;}
04242 
04243     /** Returns true if there are alternates for this load. */
04244     bool hasAlternates() const {return hasAlts;}
04245 
04246     /** Returns the load of which this one is an alternate.<br>
04247       * NULL is return where there is none.
04248       */
04249     Load* getAlternate() const {return altLoad;}
04250 
04251     /** Define the load of which this one is an alternate. */
04252     DECLARE_EXPORT void setAlternate(Load *);
04253 
04254     /** Define the load of which this one is an alternate. */
04255     DECLARE_EXPORT void setAlternate(const string& n);
04256 
04257     /** Update the required resource setup. */
04258     DECLARE_EXPORT void setSetup(const string);
04259 
04260     /** Return the required resource setup. */
04261     const string& getSetup() const {return setup;}
04262 
04263     /** This method holds the logic the compute the date of a loadplan. */
04264     virtual Date getLoadplanDate(const LoadPlan*) const;
04265 
04266     /** This method holds the logic the compute the quantity of a loadplan. */
04267     virtual double getLoadplanQuantity(const LoadPlan*) const;
04268 
04269     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04270     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04271     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04272     DECLARE_EXPORT PyObject* getattro(const Attribute&);
04273     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04274     static int initialize();
04275     static void writer(const MetaCategory*, XMLOutput*);
04276 
04277     bool getHidden() const
04278      {
04279       return (getResource() && getResource()->getHidden())
04280         || (getOperation() && getOperation()->getHidden());
04281     }
04282     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04283 
04284     virtual const MetaClass& getType() const {return *metadata;}
04285     static DECLARE_EXPORT const MetaCategory* metadata;
04286     virtual size_t getSize() const
04287       {return sizeof(Load) + getName().size() + getSetup().size();}
04288 
04289     /** Default constructor. */
04290     Load() : qty(1.0), priority(1), hasAlts(false), altLoad(NULL), search(PRIORITY)
04291       {initType(metadata);}
04292 
04293     /** Return the search mode. */
04294     SearchMode getSearch() const {return search;}
04295 
04296     /** Update the search mode. */
04297     void setSearch(const string a) {search = decodeSearchMode(a);}
04298 
04299   private:
04300     /** This method is called to check the validity of the object.<br>
04301       * An exception is thrown if the load is invalid.
04302       */
04303     DECLARE_EXPORT void validate(Action action);
04304 
04305     /** Stores how much capacity is consumed during the duration of an
04306       * operationplan. */
04307     double qty;
04308 
04309     /** Priority of the load - used in case of alternate loads. */
04310     int priority;
04311 
04312     /** Flag that is set to true when a load has alternates. */
04313     bool hasAlts;
04314 
04315     /** A load representing the main load of a set of alternates. */
04316     Load* altLoad;
04317 
04318     /** Required setup. */
04319     string setup;
04320 
04321     /** Mode to select the preferred alternates. */
04322     SearchMode search;
04323 
04324     /** Factory method. */
04325     static PyObject* create(PyTypeObject*, PyObject*, PyObject*);
04326 };
04327 
04328 
04329 
04330 /** @brief This is the (logical) top class of the complete model.
04331   *
04332   * This is a singleton class: only a single instance can be created.
04333   * The data model has other limitations that make it not obvious to support
04334   * building multiple models/plans in memory of the same application: e.g.
04335   * the operations, resources, problems, operationplans... etc are all
04336   * implemented in static, global lists. An entity can't be simply linked with
04337   * a particular plan if multiple ones would exist.
04338   */
04339 class Plan : public Plannable, public Object
04340 {
04341   private:
04342     /** Current Date of this plan. */
04343     Date cur_Date;
04344 
04345     /** A name for this plan. */
04346     string name;
04347 
04348     /** A getDescription of this plan. */
04349     string descr;
04350 
04351     /** Pointer to the singleton plan object. */
04352     static DECLARE_EXPORT Plan* thePlan;
04353 
04354     /** The only constructor of this class is made private. An object of this
04355       * class is created by the instance() member function.
04356       */
04357     Plan() : cur_Date(Date::now()) {initType(metadata);}
04358 
04359   public:
04360     /** Return a pointer to the singleton plan object.
04361       * The singleton object is created during the initialization of the
04362       * library.
04363       */
04364     static Plan& instance() {return *thePlan;}
04365 
04366     /** Destructor.
04367       * @warning In multi threaded applications, the destructor is never called
04368       * and the plan object leaks when we exit the application.
04369       * In single-threaded applications this function is called properly, when
04370       * the static plan variable is deleted.
04371       */
04372     DECLARE_EXPORT ~Plan();
04373 
04374     /** Returns the plan name. */
04375     const string& getName() const {return name;}
04376 
04377     /** Updates the plan name. */
04378     void setName(const string& s) {name = s;}
04379 
04380     /** Returns the current Date of the plan. */
04381     const Date & getCurrent() const {return cur_Date;}
04382 
04383     /** Updates the current date of the plan. This method can be relatively
04384       * heavy in a plan where operationplans already exist, since the
04385       * detection for BeforeCurrent problems needs to be rerun.
04386       */
04387     DECLARE_EXPORT void setCurrent(Date);
04388 
04389     /** Returns the description of the plan. */
04390     const string& getDescription() const {return descr;}
04391 
04392     /** Updates the description of the plan. */
04393     void setDescription(const string& str) {descr = str;}
04394 
04395     /** This method writes out the model information. Depending on a flag in
04396       * the XMLOutput object a complete model is written, or only the
04397       * dynamic plan information.
04398       * @see CommandSave, CommandSavePlan
04399       */
04400     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04401     DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04402     DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04403     DECLARE_EXPORT PyObject* getattro(const Attribute&);
04404     DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04405 
04406     /** Initialize the class. */
04407     static int initialize();
04408 
04409     virtual void updateProblems() {};
04410 
04411     /** This method basically solves the whole planning problem. */
04412     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04413 
04414     const MetaClass& getType() const {return *metadata;}
04415     static DECLARE_EXPORT const MetaCategory* metadata;
04416     virtual size_t getSize() const
04417       {return sizeof(Plan) + name.size() + descr.size();}
04418 };
04419 
04420 
04421 /** @brief Represents the (independent) demand in the system. It can represent a
04422   * customer order or a forecast.
04423   *
04424   * This is an abstract class.
04425   */
04426 class Demand
04427       : public HasHierarchy<Demand>, public Plannable, public HasDescription
04428 {
04429   public:
04430     typedef slist<OperationPlan*> OperationPlan_list;
04431 
04432     /** Constructor. */
04433     explicit Demand(const string& str) : HasHierarchy<Demand>(str),
04434       it(NULL), oper(NULL), cust(NULL), qty(0.0), prio(0),
04435       maxLateness(TimePeriod::MAX), minShipment(1), hidden(false) {}
04436 
04437     /** Destructor. Deleting the demand will also delete all delivery operation
04438       * plans (including locked ones). */
04439     virtual ~Demand() 
04440     {
04441       deleteOperationPlans(true);
04442     }
04443 
04444     /** Returns the quantity of the demand. */
04445     double getQuantity() const {return qty;}
04446 
04447     /** Updates the quantity of the demand. The quantity must be be greater
04448       * than or equal to 0. */
04449     virtual DECLARE_EXPORT void setQuantity(double);
04450 
04451     /** Returns the priority of the demand.<br>
04452       * Lower numbers indicate a higher priority level.
04453       */
04454     int getPriority() const {return prio;}
04455 
04456     /** Updates the due date of the demand.<br>
04457       * Lower numbers indicate a higher priority level.
04458       */
04459     virtual void setPriority(int i) {prio=i; setChanged();}
04460 
04461     /** Returns the item/product being requested. */
04462     Item* getItem() const {return it;}
04463 
04464     /** Updates the item/product being requested. */
04465     virtual void setItem(Item *i) {it=i; setChanged();}
04466 
04467     /** This fields points to an operation that is to be used to plan the
04468       * demand. By default, the field is left to NULL and the demand will then
04469       * be planned using the delivery operation of its item.
04470       * @see Item::getDelivery()
04471       */
04472     Operation* getOperation() const {return oper;}
04473 
04474     /** This function returns the operation that is to be used to satisfy this
04475       * demand. In sequence of priority this goes as follows:
04476       *   1) If the "operation" field on the demand is set, use it.
04477       *   2) Otherwise, use the "delivery" field of the requested item.
04478       *   3) Else, return NULL. This demand can't be satisfied!
04479       */
04480     DECLARE_EXPORT Operation* getDeliveryOperation() const;
04481 
04482     /** Returns the cluster which this demand belongs to. */
04483     int getCluster() const
04484     {
04485       Operation* o = getDeliveryOperation();
04486       return o ? o->getCluster() : 0;
04487     }
04488 
04489     /** Updates the operation being used to plan the demand. */
04490     virtual void setOperation(Operation* o) {oper=o; setChanged();}
04491 
04492     /** Returns the delivery operationplan list. */
04493     DECLARE_EXPORT const OperationPlan_list& getDelivery() const;
04494 
04495     /** Returns the latest delivery operationplan. */
04496     DECLARE_EXPORT OperationPlan* getLatestDelivery() const;
04497 
04498     /** Returns the earliest delivery operationplan. */
04499     DECLARE_EXPORT OperationPlan* getEarliestDelivery() const;
04500 
04501     /** Adds a delivery operationplan for this demand. */
04502     DECLARE_EXPORT void addDelivery(OperationPlan *o);
04503 
04504     /** Removes a delivery operationplan for this demand. */
04505     DECLARE_EXPORT void removeDelivery(OperationPlan *o);
04506 
04507     /** Deletes all delivery operationplans of this demand.<br>
04508       * The (optional) boolean parameter controls whether we delete also locked
04509       * operationplans or not.<br>
04510       * The second (optional) argument is a command list that can be used to
04511       * remove the operationplans in an undo-able way.
04512       */
04513     DECLARE_EXPORT void deleteOperationPlans
04514       (bool deleteLockedOpplans = false, CommandManager* = NULL);
04515 
04516     /** Returns the due date of the demand. */
04517     const Date& getDue() const {return dueDate;}
04518 
04519     /** Updates the due date of the demand. */
04520     virtual void setDue(Date d) {dueDate = d; setChanged();}
04521 
04522     /** Returns the customer. */
04523     Customer* getCustomer() const {return cust;}
04524 
04525     /** Updates the customer. */
04526     virtual void setCustomer(Customer* c) {cust = c; setChanged();}
04527 
04528     /** Return a reference to the constraint list. */
04529     const Problem::List& getConstraints() const {return constraints;}
04530 
04531     /** Return a reference to the constraint list. */
04532     Problem::List& getConstraints() {return constraints;}
04533 
04534     /** Returns the total amount that has been planned. */
04535     DECLARE_EXPORT double getPlannedQuantity() const;
04536 
04537     virtual DECLARE_EXPORT void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
04538     virtual DECLARE_EXPORT void endElement(XMLInput&, const Attribute&, const DataElement&);
04539     virtual DECLARE_EXPORT void beginElement(XMLInput&, const Attribute&);
04540     virtual DECLARE_EXPORT PyObject* getattro(const Attribute&);
04541     virtual DECLARE_EXPORT int setattro(const Attribute&, const PythonObject&);
04542     static int initialize();
04543 
04544     size_t extrasize() const
04545     {
04546       return getName().size() + HasDescription::extrasize()
04547         + sizeof(void*) * 2 * deli.size();
04548     }
04549 
04550     virtual void solve(Solver &s, void* v = NULL) const {s.solve(this,v);}
04551 
04552     /** Return the maximum delay allowed in satisfying this demand.<br>
04553       * The default value is infinite.
04554       */
04555     TimePeriod getMaxLateness() const {return maxLateness;}
04556 
04557     /** Updates the maximum allowed lateness for this demand.<br>
04558       * The default value is infinite.<br>
04559       * The argument must be a positive time period.
04560       */
04561     virtual void setMaxLateness(TimePeriod m)
04562     {
04563       if (m < 0L)
04564         throw DataException("The maximum demand lateness must be positive");
04565       maxLateness = m;
04566     }
04567 
04568     /** Return the minimum shipment quantity allowed in satisfying this
04569       * demand.<br>
04570       * The default value is 1.
04571       */
04572     double getMinShipment() const {return minShipment;}
04573 
04574     /** Updates the maximum allowed lateness for this demand.<br>
04575       * The default value is infinite.<br>
04576       * The argument must be a positive time period.
04577       */
04578     virtual void setMinShipment(double m)
04579     {
04580       if (m < 0.0)
04581         throw DataException("The minumum demand shipment quantity must be positive");
04582       minShipment = m;
04583     }
04584 
04585     /** Recompute the problems. */
04586     virtual DECLARE_EXPORT void updateProblems();
04587 
04588     /** Specifies whether of not this demand is to be hidden from
04589       * serialization. The default value is false. */
04590     void setHidden(bool b) {hidden = b;}
04591 
04592     /** Returns true if this demand is to be hidden from serialization. */
04593     bool getHidden() const {return hidden;}
04594 
04595     virtual const MetaClass& getType() const {return *metadata;}
04596     static DECLARE_EXPORT const MetaCategory* metadata;
04597 
04598   private:
04599     /** Requested item. */
04600     Item *it;
04601 
04602     /** Delivery Operation. Can be left NULL, in which case the delivery
04603       * operation can be specified on the requested item. */
04604     Operation *oper;
04605 
04606     /** Customer creating this demand. */
04607     Customer *cust;
04608 
04609     /** Requested quantity. Only positive numbers are allowed. */
04610     double qty;
04611 
04612     /** Priority. Lower numbers indicate a higher priority level.*/
04613     int prio;
04614 
04615     /** Due date. */
04616     Date dueDate;
04617 
04618     /** Maximum lateness allowed when planning this demand.<br>
04619       * The default value is TimePeriod::MAX.
04620       */
04621     TimePeriod maxLateness;
04622 
04623     /** Minimum size for a delivery operation plan satisfying this demand. */
04624     double minShipment;
04625 
04626     /** Hide this demand or not. */
04627     bool hidden;
04628 
04629     /** A list of operation plans to deliver this demand. */
04630     OperationPlan_list deli;
04631 
04632     /** A list of constraints preventing this demand from being planned in
04633       * full and on time. */
04634     Problem::List constraints;
04635 };
04636 
04637 
04638 /** @brief This class is the default implementation of the abstract
04639   * Demand class. */
04640 class DemandDefault : public Demand
04641 {
04642   public:
04643     explicit DemandDefault(const string& str) : Demand(str) {initType(metadata);}
04644     virtual const MetaClass& getType() const {return *metadata;}
04645     static DECLARE_EXPORT const MetaClass* metadata;
04646     virtual size_t getSize() const
04647     {return sizeof(DemandDefault) + Demand::extrasize();}
04648     static int initialize();
04649 };
04650 
04651 
04652 /** @brief This class represents the resource capacity of an operationplan.
04653   *
04654   * For both the start and the end date of the operationplan, a loadplan
04655   * object is created. These are then inserted in the timeline structure
04656   * associated with a resource.
04657   */
04658 class LoadPlan : public TimeLine<LoadPlan>::EventChangeOnhand, public PythonExtensionBase
04659 {
04660     friend class OperationPlan::LoadPlanIterator;
04661   public:
04662     /** Public constructor.<br>
04663       * This constructor constructs the starting loadplan and will
04664       * also call a private constructor to creates the ending loadplan.
04665       * In other words, a single call to the constructor will create
04666       * two loadplan objects.
04667       */
04668     explicit DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*);
04669 
04670     /** Return the operationplan owning this loadplan. */
04671     OperationPlan* getOperationPlan() const {return oper;}
04672 
04673     /** Return the load of which this is a plan instance. */
04674     const Load* getLoad() const {return ld;}
04675 
04676     /** Return the resource. */
04677     const Resource* getResource() const {return ld->getResource();}
04678 
04679     /** Update the load of an already existing flowplan.<br>
04680       * The new load must belong to the same operation.
04681       */
04682     DECLARE_EXPORT void setLoad(const Load*);
04683 
04684     /** Return true when this loadplan marks the start of an operationplan. */
04685     bool isStart() const {return start_or_end == START;}
04686 
04687     /** Destructor. */
04688     DECLARE_EXPORT virtual ~LoadPlan();
04689 
04690     /** This function needs to be called whenever the loadplan date or
04691       * quantity are changed.
04692       */
04693     DECLARE_EXPORT void update();
04694 
04695     /** Return a pointer to the timeline data structure owning this loadplan. */
04696     TimeLine<LoadPlan>* getTimeLine() const
04697     {return &(ld->getResource()->loadplans);}
04698 
04699     /** Returns the current setup of the resource.<br> 
04700       * When the argument is true (= default) the current setup is returned.<br>
04701       * When the argument is false the setup just before the loadplan is returned.
04702       */
04703     DECLARE_EXPORT const string& getSetup(bool = true) const;
04704 
04705     /** Returns true when the loadplan is hidden.<br>
04706       * This is determined by looking at whether the load is hidden or not.
04707       */
04708     bool getHidden() const {return ld->getHidden();}
04709 
04710     /** Each operationplan has 2 loadplans per load: one at the start,
04711       * when the capacity consumption starts, and one at the end, when the
04712       * capacity consumption ends.<br>
04713       * This method returns the "companion" loadplan. It is not very
04714       * scalable: the performance is linear with the number of loadplans
04715       * on the resource.
04716       */
04717     DECLARE_EXPORT LoadPlan* getOtherLoadPlan() const;
04718 
04719     static int initialize();
04720     static DECLARE_EXPORT const MetaCategory* metadata;
04721     PyObject* getattro(const Attribute&);
04722 
04723   private:
04724     /** Private constructor. It is called from the public constructor.<br>
04725       * The public constructor constructs the starting loadplan, while this
04726       * constructor creates the ending loadplan.
04727       */
04728     DECLARE_EXPORT LoadPlan(OperationPlan*, const Load*, LoadPlan*);
04729 
04730     /** This type is used to differentiate loadplans aligned with the START date
04731       * or the END date of operationplan. */
04732     enum type {START, END};
04733 
04734     /** Is this loadplan a starting one or an ending one. */
04735     type start_or_end;
04736 
04737     /** A pointer to the load model. */
04738     const Load *ld;
04739 
04740     /** A pointer to the operationplan owning this loadplan. */
04741     OperationPlan *oper;
04742 
04743     /** Points to the next loadplan owned by the same operationplan. */
04744     LoadPlan *nextLoadPlan;
04745 };
04746 
04747 
04748 inline Date Load::getLoadplanDate(const LoadPlan* lp) const
04749 {
04750   const DateRange & dr = lp->getOperationPlan()->getDates();
04751   if (lp->isStart())
04752     return dr.getStart() > getEffective().getStart() ?
04753       dr.getStart() :
04754       getEffective().getStart();
04755   else
04756     return dr.getEnd() < getEffective().getEnd() ?
04757       dr.getEnd() :
04758       getEffective().getEnd();
04759 }
04760 
04761 
04762 inline double Load::getLoadplanQuantity(const LoadPlan* lp) const
04763 {
04764   if (!lp->getOperationPlan()->getDates().overlap(getEffective()) 
04765     && (lp->getOperationPlan()->getDates().getDuration() 
04766          || !getEffective().within(lp->getOperationPlan()->getDates().getStart())))
04767     // Load is not effective during this time.
04768     // The extra check is required to make sure that zero duration operationplans
04769     // operationplans don't get resized to 0
04770     return 0.0;
04771   return lp->isStart() ? getQuantity() : -getQuantity();
04772 }
04773 
04774 
04775 
04776 /** @brief A problem of this class is created when an operationplan is being
04777   * planned in the past, i.e. it starts before the "current" date of
04778   * the plan.
04779   */
04780 class ProblemBeforeCurrent : public Problem
04781 {
04782   public:
04783     string getDescription() const
04784     {
04785       ostringstream ch;
04786       ch << "Operation '" 
04787         << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation())
04788         << "' planned in the past";
04789       return ch.str();
04790     }
04791     bool isFeasible() const {return false;}
04792     double getWeight() const
04793     {return oper ? state.quantity : dynamic_cast<OperationPlan*>(getOwner())->getQuantity();}
04794     explicit ProblemBeforeCurrent(OperationPlan* o, bool add = true) : Problem(o), oper(NULL) 
04795       {if (add) addProblem();}
04796     explicit ProblemBeforeCurrent(Operation* o, Date st, Date nd, double q) 
04797       : oper(o), state(st, nd, q) {}
04798     ~ProblemBeforeCurrent() {removeProblem();}
04799     string getEntity() const {return "operation";}
04800     Object* getOwner() const 
04801       {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);}
04802     const DateRange getDates() const
04803     {
04804       if (oper) return DateRange(state.start, state.end);
04805       OperationPlan *o = dynamic_cast<OperationPlan*>(getOwner());
04806       if (o->getDates().getEnd() > Plan::instance().getCurrent())
04807         return DateRange(o->getDates().getStart(),
04808             Plan::instance().getCurrent());
04809       else
04810         return DateRange(o->getDates().getStart(),
04811             o->getDates().getEnd());
04812     }
04813     size_t getSize() const {return sizeof(ProblemBeforeCurrent);}
04814 
04815     /** Return a reference to the metadata structure. */
04816     const MetaClass& getType() const {return *metadata;}
04817 
04818     /** Storing metadata on this class. */
04819     static DECLARE_EXPORT const MetaClass* metadata;
04820 
04821   private:
04822     Operation* oper;
04823     OperationPlanState state;
04824 };
04825 
04826 
04827 /** @brief A problem of this class is created when an operationplan is being
04828   * planned before its fence date, i.e. it starts 1) before the "current"
04829   * date of the plan plus the release fence of the operation and 2) after the
04830   * current date of the plan.
04831   */
04832 class ProblemBeforeFence : public Problem
04833 {
04834   public:
04835     string getDescription() const
04836     {
04837       ostringstream ch;
04838       ch << "Operation '" 
04839         << (oper ? oper : static_cast<OperationPlan*>(getOwner())->getOperation())
04840         << "' planned before fence";
04841       return ch.str();
04842     }
04843     bool isFeasible() const {return true;}
04844     double getWeight() const
04845     {return oper ? state.quantity : static_cast<OperationPlan*>(getOwner())->getQuantity();}
04846     explicit ProblemBeforeFence(OperationPlan* o, bool add = true) 
04847       : Problem(o), oper(NULL)
04848       {if (add) addProblem();}
04849     explicit ProblemBeforeFence(Operation* o, Date st, Date nd, double q) 
04850       : oper(o), state(st, nd, q) {}
04851     ~ProblemBeforeFence() {removeProblem();}
04852     string getEntity() const {return "operation";}
04853     Object* getOwner() const 
04854       {return oper ? static_cast<Object*>(oper) : dynamic_cast<OperationPlan*>(owner);}
04855     const DateRange getDates() const
04856     {
04857       if (oper) return DateRange(state.start, state.end);
04858       OperationPlan *o = dynamic_cast<OperationPlan*>(owner);
04859       if (o->getDates().getEnd() > Plan::instance().getCurrent()
04860           + o->getOperation()->getFence())
04861         return DateRange(o->getDates().getStart(),
04862             Plan::instance().getCurrent() + o->getOperation()->getFence());
04863       else
04864         return DateRange(o->getDates().getStart(),
04865             o->getDates().getEnd());
04866     }
04867     size_t getSize() const {return sizeof(ProblemBeforeFence);}
04868 
04869     /** Return a reference to the metadata structure. */
04870     const MetaClass& getType() const {return *metadata;}
04871 
04872     /** Storing metadata on this class. */
04873     static DECLARE_EXPORT const MetaClass* metadata;
04874 
04875   private:
04876     Operation* oper;
04877     OperationPlanState state;
04878 };
04879 
04880 
04881 /** @brief A problem of this class is created when the sequence of two
04882   * operationplans in a routing isn't respected.
04883   */
04884 class ProblemPrecedence : public Problem
04885 {
04886   public:
04887     string getDescription() const
04888     {
04889       OperationPlan *o = static_cast<OperationPlan*>(getOwner());
04890       if (!o->nextsubopplan)
04891         return string("Bogus precedence problem on '")
04892           + o->getOperation()->getName() + "'";
04893       else
04894         return string("Operation '") + o->getOperation()->getName()
04895           + "' starts before operation '"
04896           + o->nextsubopplan->getOperation()->getName() +"' ends";
04897     }
04898     bool isFeasible() const {return false;}
04899     /** The weight of the problem is equal to the duration in days. */
04900     double getWeight() const
04901     {
04902       return static_cast<double>(getDates().getDuration()) / 86400;
04903     }
04904     explicit ProblemPrecedence(OperationPlan* o, bool add = true) : Problem(o) 
04905       {if (add) addProblem();}
04906     ~ProblemPrecedence() {removeProblem();}
04907     string getEntity() const {return "operation";}
04908     Object* getOwner() const {return dynamic_cast<OperationPlan*>(owner);}
04909     const DateRange getDates() const
04910     {
04911       OperationPlan *o = static_cast<OperationPlan*>(getOwner());
04912       return DateRange(o->nextsubopplan->getDates().getStart(),
04913         o->getDates().getEnd());
04914     }
04915 
04916     /** Return a reference to the metadata structure. */
04917     const MetaClass& getType() const {return *metadata;}
04918 
04919     /** Storing metadata on this class. */
04920     static DECLARE_EXPORT const MetaClass* metadata;
04921     size_t getSize() const {return sizeof(ProblemPrecedence);}
04922 };
04923 
04924 
04925 /** @brief A Problem of this class is created in the model when a new demand is
04926   * brought in the system, but it hasn't been planned yet.
04927   *
04928   * As a special case, a demand with a requested quantity of 0.0 doesn't create
04929   * this type of problem.
04930   */
04931 class ProblemDemandNotPlanned : public Problem
04932 {
04933   public:
04934     string getDescription() const
04935       {return string("Demand '") + getDemand()->getName() + "' is not planned";}
04936     bool isFeasible() const {return false;}
04937     double getWeight() const {return getDemand()->getQuantity();}
04938     explicit ProblemDemandNotPlanned(Demand* d, bool add = true) : Problem(d) 
04939       {if (add) addProblem();}
04940     ~ProblemDemandNotPlanned() {removeProblem();}
04941     string getEntity() const {return "demand";}
04942     const DateRange getDates() const
04943       {return DateRange(getDemand()->getDue(),getDemand()->getDue());}
04944     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
04945     Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
04946     size_t getSize() const {return sizeof(ProblemDemandNotPlanned);}
04947 
04948     /** Return a reference to the metadata structure. */
04949     const MetaClass& getType() const {return *metadata;}
04950 
04951     /** Storing metadata on this class. */
04952     static DECLARE_EXPORT const MetaClass* metadata;
04953 };
04954 
04955 
04956 /** @brief A problem of this class is created when a demand is satisfied later
04957   * than the accepted tolerance after its due date.
04958   */
04959 class ProblemLate : public Problem
04960 {
04961   public:
04962     DECLARE_EXPORT string getDescription() const;
04963     bool isFeasible() const {return true;}
04964 
04965     /** The weight is equal to the delay, expressed in days.<br>
04966       * The quantity being delayed is not included.
04967       */
04968     double getWeight() const
04969     {
04970       assert(getDemand() && !getDemand()->getDelivery().empty());
04971       return static_cast<double>(DateRange(
04972         getDemand()->getDue(),
04973         getDemand()->getLatestDelivery()->getDates().getEnd()
04974         ).getDuration()) / 86400;
04975     }
04976 
04977     /** Constructor. */
04978     explicit ProblemLate(Demand* d, bool add = true) : Problem(d) 
04979       {if (add) addProblem();}
04980 
04981     /** Destructor. */
04982     ~ProblemLate() {removeProblem();}
04983 
04984     const DateRange getDates() const
04985     {
04986       assert(getDemand() && !getDemand()->getDelivery().empty());
04987       return DateRange(getDemand()->getDue(),
04988           getDemand()->getLatestDelivery()->getDates().getEnd());
04989     }
04990     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
04991     size_t getSize() const {return sizeof(ProblemLate);}
04992     string getEntity() const {return "demand";}
04993     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
04994 
04995     /** Return a reference to the metadata structure. */
04996     const MetaClass& getType() const {return *metadata;}
04997 
04998     /** Storing metadata on this class. */
04999     static DECLARE_EXPORT const MetaClass* metadata;
05000 };
05001 
05002 
05003 /** @brief A problem of this class is created when a demand is planned earlier
05004   * than the accepted tolerance before its due date.
05005   */
05006 class ProblemEarly : public Problem
05007 {
05008   public:
05009     DECLARE_EXPORT string getDescription() const;
05010     bool isFeasible() const {return true;}
05011     double getWeight() const
05012     {
05013       assert(getDemand() && !getDemand()->getDelivery().empty());
05014       return static_cast<double>(DateRange(
05015         getDemand()->getDue(),
05016         getDemand()->getEarliestDelivery()->getDates().getEnd()
05017         ).getDuration()) / 86400;
05018     }
05019     explicit ProblemEarly(Demand* d, bool add = true) : Problem(d) 
05020       {if (add) addProblem();}
05021     ~ProblemEarly() {removeProblem();}
05022     string getEntity() const {return "demand";}
05023     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05024     const DateRange getDates() const
05025     {
05026       assert(getDemand() && !getDemand()->getDelivery().empty());
05027       return DateRange(getDemand()->getDue(),
05028           getDemand()->getEarliestDelivery()->getDates().getEnd());
05029     }
05030     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
05031     size_t getSize() const {return sizeof(ProblemEarly);}
05032 
05033     /** Return a reference to the metadata structure. */
05034     const MetaClass& getType() const {return *metadata;}
05035 
05036     /** Storing metadata on this class. */
05037     static DECLARE_EXPORT const MetaClass* metadata;
05038 };
05039 
05040 
05041 /** @brief A Problem of this class is created in the model when a data exception 
05042   * prevents planning of certain objects
05043   */
05044 class ProblemInvalidData : public Problem
05045 {
05046   public:
05047     string getDescription() const {return description;}
05048     bool isFeasible() const {return false;}
05049     double getWeight() const {return qty;}
05050     explicit ProblemInvalidData(HasProblems* o, string d, string e, 
05051       Date st, Date nd, double q, bool add = true) 
05052       : Problem(o), description(d), entity(e), dates(st,nd), qty(q)
05053         {if (add) addProblem();}
05054     ~ProblemInvalidData() {removeProblem();}
05055     string getEntity() const {return entity;}
05056     const DateRange getDates() const {return dates;}
05057     Object* getOwner() const
05058     {
05059       if (entity == "demand") return dynamic_cast<Demand*>(owner);
05060       if (entity == "buffer") return dynamic_cast<Buffer*>(owner);
05061       if (entity == "resource") return dynamic_cast<Resource*>(owner);
05062       if (entity == "operation") return dynamic_cast<Operation*>(owner);
05063       throw LogicException("Unknown problem entity type");
05064     }
05065     size_t getSize() const 
05066       {return sizeof(ProblemInvalidData) + description.size() + entity.size();}
05067 
05068     /** Return a reference to the metadata structure. */
05069     const MetaClass& getType() const {return *metadata;}
05070 
05071     /** Storing metadata on this class. */
05072     static DECLARE_EXPORT const MetaClass* metadata;
05073 
05074   private:
05075     /** Description of the data issue. */
05076     string description;
05077     string entity;
05078     DateRange dates;
05079     double qty;
05080 };
05081 
05082 
05083 /** @brief A problem of this class is created when a demand is planned for less than
05084   * the requested quantity.
05085   */
05086 class ProblemShort : public Problem
05087 {
05088   public:
05089     string getDescription() const
05090     {
05091       ostringstream ch;
05092       ch << "Demand '" << getDemand()->getName() << "' planned "
05093       << (getDemand()->getQuantity() - getDemand()->getPlannedQuantity())
05094       << " units short";
05095       return ch.str();
05096     }
05097     bool isFeasible() const {return true;}
05098     double getWeight() const
05099       {return getDemand()->getQuantity() - getDemand()->getPlannedQuantity();}
05100     explicit ProblemShort(Demand* d, bool add = true) : Problem(d) 
05101       {if (add) addProblem();}
05102     ~ProblemShort() {removeProblem();}
05103     string getEntity() const {return "demand";}
05104     const DateRange getDates() const
05105       {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
05106     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05107     Demand* getDemand() const {return dynamic_cast<Demand*>(owner);}
05108     size_t getSize() const {return sizeof(ProblemShort);}
05109 
05110     /** Return a reference to the metadata structure. */
05111     const MetaClass& getType() const {return *metadata;}
05112 
05113     /** Storing metadata on this class. */
05114     static DECLARE_EXPORT const MetaClass* metadata;
05115 };
05116 
05117 
05118 /** @brief A problem of this class is created when a demand is planned for more
05119   * than the requested quantity.
05120   */
05121 class ProblemExcess : public Problem
05122 {
05123   public:
05124     string getDescription() const
05125     {
05126       ostringstream ch;
05127       ch << "Demand '" << getDemand()->getName() << "' planned "
05128       << (getDemand()->getPlannedQuantity() - getDemand()->getQuantity())
05129       << " units excess";
05130       return ch.str();
05131     }
05132     bool isFeasible() const {return true;}
05133     double getWeight() const
05134       {return getDemand()->getPlannedQuantity() - getDemand()->getQuantity();}
05135     explicit ProblemExcess(Demand* d, bool add = true) : Problem(d) 
05136       {if (add) addProblem();}
05137     string getEntity() const {return "demand";}
05138     Object* getOwner() const {return dynamic_cast<Demand*>(owner);}
05139     ~ProblemExcess() {removeProblem();}
05140     const DateRange getDates() const
05141       {return DateRange(getDemand()->getDue(), getDemand()->getDue());}
05142     Demand* getDemand() const {return dynamic_cast<Demand*>(getOwner());}
05143     size_t getSize() const {return sizeof(ProblemExcess);}
05144 
05145     /** Return a reference to the metadata structure. */
05146     const MetaClass& getType() const {return *metadata;}
05147 
05148     /** Storing metadata on this class. */
05149     static DECLARE_EXPORT const MetaClass* metadata;
05150 };
05151 
05152 
05153 /** @brief A problem of this class is created when a resource is being
05154   * overloaded during a certain period of time.
05155   */
05156 class ProblemCapacityOverload : public Problem
05157 {
05158   public:
05159     DECLARE_EXPORT string getDescription() const;
05160     bool isFeasible() const {return false;}
05161     double getWeight() const {return qty;}
05162     ProblemCapacityOverload(Resource* r, Date st, Date nd, double q, bool add = true)
05163         : Problem(r), qty(q), dr(st,nd) {if (add) addProblem();}
05164     ~ProblemCapacityOverload() {removeProblem();}
05165     string getEntity() const {return "capacity";}
05166     Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
05167     const DateRange getDates() const {return dr;}
05168     Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
05169     size_t getSize() const {return sizeof(ProblemCapacityOverload);}
05170 
05171     /** Return a reference to the metadata structure. */
05172     const MetaClass& getType() const {return *metadata;}
05173 
05174     /** Storing metadata on this class. */
05175     static DECLARE_EXPORT const MetaClass* metadata;
05176 
05177   private:
05178     /** Overload quantity. */
05179     double qty;
05180 
05181     /** The daterange of the problem. */
05182     DateRange dr;
05183 };
05184 
05185 
05186 /** @brief A problem of this class is created when a resource is loaded below
05187   * its minimum during a certain period of time.
05188   */
05189 class ProblemCapacityUnderload : public Problem
05190 {
05191   public:
05192     DECLARE_EXPORT string getDescription() const;
05193     bool isFeasible() const {return true;}
05194     double getWeight() const {return qty;}
05195     ProblemCapacityUnderload(Resource* r, DateRange d, double q, bool add = true)
05196         : Problem(r), qty(q), dr(d) {if (add) addProblem();}
05197     ~ProblemCapacityUnderload() {removeProblem();}
05198     string getEntity() const {return "capacity";}
05199     Object* getOwner() const {return dynamic_cast<Resource*>(owner);}
05200     const DateRange getDates() const {return dr;}
05201     Resource* getResource() const {return dynamic_cast<Resource*>(getOwner());}
05202     size_t getSize() const {return sizeof(ProblemCapacityUnderload);}
05203 
05204     /** Return a reference to the metadata structure. */
05205     const MetaClass& getType() const {return *metadata;}
05206 
05207     /** Storing metadata on this class. */
05208     static DECLARE_EXPORT const MetaClass* metadata;
05209 
05210   private:
05211     /** Underload quantity. */
05212     double qty;
05213 
05214     /** The daterange of the problem. */
05215     DateRange dr;
05216 };
05217 
05218 
05219 /** @brief A problem of this class is created when a buffer is having a
05220   * material shortage during a certain period of time.
05221   */
05222 class ProblemMaterialShortage : public Problem
05223 {
05224   public:
05225     DECLARE_EXPORT string getDescription() const;
05226     bool isFeasible() const {return false;}
05227     double getWeight() const {return qty;}
05228     ProblemMaterialShortage(Buffer* b, Date st, Date nd, double q, bool add = true)
05229         : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();}
05230     string getEntity() const {return "material";}
05231     Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
05232     ~ProblemMaterialShortage() {removeProblem();}
05233     const DateRange getDates() const {return dr;}
05234     Buffer* getBuffer() const {return dynamic_cast<Buffer*>(getOwner());}
05235     size_t getSize() const {return sizeof(ProblemMaterialShortage);}
05236 
05237     /** Return a reference to the metadata structure. */
05238     const MetaClass& getType() const {return *metadata;}
05239 
05240     /** Storing metadata on this class. */
05241     static DECLARE_EXPORT const MetaClass* metadata;
05242 
05243   private:
05244     /** Shortage quantity. */
05245     double qty;
05246 
05247     /** The daterange of the problem. */
05248     DateRange dr;
05249 };
05250 
05251 
05252 /** @brief A problem of this class is created when a buffer is carrying too
05253   * much material during a certain period of time.
05254   */
05255 class ProblemMaterialExcess : public Problem
05256 {
05257   public:
05258     DECLARE_EXPORT string getDescription() const;
05259     bool isFeasible() const {return true;}
05260     double getWeight() const {return qty;}
05261     ProblemMaterialExcess(Buffer* b, Date st, Date nd, double q, bool add = true)
05262         : Problem(b), qty(q), dr(st,nd) {if (add) addProblem();}
05263     string getEntity() const {return "material";}
05264     ~ProblemMaterialExcess() {removeProblem();}
05265     const DateRange getDates() const {return dr;}
05266     Object* getOwner() const {return dynamic_cast<Buffer*>(owner);}
05267     Buffer* getBuffer() const {return dynamic_cast<Buffer*>(owner);}
05268     size_t getSize() const {return sizeof(ProblemMaterialExcess);}
05269 
05270     /** Return a reference to the metadata structure. */
05271     const MetaClass& getType() const {return *metadata;}
05272 
05273     /** Storing metadata on this class. */
05274     static DECLARE_EXPORT const MetaClass* metadata;
05275 
05276   private:
05277     /** Excess quantity. */
05278     double qty;
05279 
05280     /** The daterange of the problem. */
05281     DateRange dr;
05282 };
05283 
05284 
05285 /** @brief This command is used to create an operationplan.
05286   *
05287   * The operationplan will have its loadplans and flowplans created when the
05288   * command is created. It is assigned an id and added to the list of all
05289   * operationplans when the command is committed.
05290   */
05291 class CommandCreateOperationPlan : public Command
05292 {
05293   public:
05294     /** Constructor. */
05295     CommandCreateOperationPlan
05296       (const Operation* o, double q, Date d1, Date d2, Demand* l,
05297       OperationPlan* ow=NULL, bool makeflowsloads=true)
05298     {
05299       opplan = o ?
05300           o->createOperationPlan(q, d1, d2, l, ow, 0, makeflowsloads)
05301           : NULL;
05302     }
05303     void commit()
05304     {
05305       if (opplan)
05306       {
05307         opplan->activate();
05308         opplan = NULL; // Avoid executing / initializing more than once
05309       }
05310     }
05311     virtual void rollback() {delete opplan; opplan = NULL;}
05312     virtual void undo() {if (opplan) opplan->deleteFlowLoads();}
05313     virtual void redo() {if (opplan) opplan->createFlowLoads();}
05314     virtual ~CommandCreateOperationPlan() {if (opplan) delete opplan;}
05315     OperationPlan *getOperationPlan() const {return opplan;}
05316 
05317   private:
05318     /** Pointer to the newly created operationplan. */
05319     OperationPlan *opplan;
05320 };
05321 
05322 
05323 /** @brief This command is used to delete an operationplan. */
05324 class CommandDeleteOperationPlan : public Command
05325 {
05326   public:
05327     /** Constructor. */
05328     DECLARE_EXPORT CommandDeleteOperationPlan(OperationPlan* o);
05329     virtual void commit()
05330     {
05331       if (opplan) delete opplan;
05332       opplan = NULL;
05333     }
05334     virtual void undo()
05335     {
05336       if (!opplan) return;
05337       opplan->createFlowLoads();
05338       if (opplan->getIdentifier())
05339       {
05340         opplan->insertInOperationplanList();
05341         if (opplan->getDemand())
05342           opplan->getDemand()->addDelivery(opplan);
05343       }
05344     }
05345     virtual void redo()
05346     {
05347       if (!opplan) return;
05348       opplan->deleteFlowLoads();
05349       if (opplan->getIdentifier())
05350       {
05351         opplan->removeFromOperationplanList();
05352         if (opplan->getDemand())
05353           opplan->getDemand()->removeDelivery(opplan);
05354       }
05355     }
05356     virtual void rollback()
05357     {
05358       undo();
05359       opplan = NULL;
05360     }
05361     virtual ~CommandDeleteOperationPlan() {undo();}
05362 
05363   private:
05364     /** Pointer to the operationplan being deleted.<br>
05365       * Until the command is committed we don't deallocate the memory for the
05366       * operationplan, but only remove all pointers to it from various places.
05367       */
05368     OperationPlan *opplan;
05369 };
05370 
05371 
05372 /** @brief This class represents the command of moving an operationplan to a
05373   * new date and/or resizing it.
05374   * @todo Moving in a routing operation can't be undone with the current
05375   * implementation! The command will need to store all original dates of
05376   * the suboperationplans...
05377   */
05378 class CommandMoveOperationPlan : public Command
05379 {
05380   public:
05381     /** Constructor.<br>
05382       * Unlike most other commands the constructor already executes the change.
05383       * @param opplanptr Pointer to the operationplan being moved.
05384       * @param newStart New start date of the operationplan.
05385       * @param newEnd New end date of the operationplan.
05386       * @param newQty New quantity of the operationplan.The default is -1,
05387       * which indicates to leave the quantity unchanged.
05388       */
05389     DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan* opplanptr,
05390       Date newStart, Date newEnd, double newQty = -1.0);
05391 
05392     /** Default constructor. */
05393     DECLARE_EXPORT CommandMoveOperationPlan(OperationPlan*);
05394 
05395     /** Commit the changes. */
05396     virtual void commit() {opplan=NULL;}
05397 
05398     /** Undo the changes. */
05399     virtual void rollback() {restore(true); opplan = NULL;}
05400 
05401     virtual void undo() {restore(false);}
05402     virtual DECLARE_EXPORT void redo();
05403 
05404     /** Undo the changes.<br>
05405       * When the argument is true, subcommands for suboperationplans are deleted. */
05406     DECLARE_EXPORT void restore(bool = false);
05407 
05408     /** Destructor. */
05409     virtual ~CommandMoveOperationPlan() {if (opplan) rollback();}
05410 
05411     /** Returns the operationplan being manipulated. */
05412     OperationPlan* getOperationPlan() const {return opplan;}
05413 
05414     /** Set another start date for the operationplan. */
05415     void setStart(Date d) {if (opplan) opplan->setStart(d);}
05416 
05417     /** Set another start date, end date and quantity for the operationplan. */
05418     void setParameters(Date s, Date e, double q, bool b) 
05419     {
05420       assert(opplan->getOperation());
05421       if (opplan) 
05422         opplan->getOperation()->setOperationPlanParameters(opplan, q, s, e, b);
05423     }
05424 
05425     /** Set another start date for the operationplan. */
05426     void setEnd(Date d) {if (opplan) opplan->setEnd(d);}
05427 
05428     /** Set another quantity for the operationplan. */
05429     void setQuantity(double q) {if (opplan) opplan->setQuantity(q);}
05430 
05431     /** Return the quantity of the original operationplan. */
05432     double getQuantity() const {return originalqty; }
05433 
05434     /** Return the dates of the original operationplan. */
05435     DateRange getDates() const {return originaldates;}
05436 
05437   private:
05438     /** This is a pointer to the operationplan being moved. */
05439     OperationPlan *opplan;
05440 
05441     /** These are the original dates of the operationplan before its move. */
05442     DateRange originaldates;
05443 
05444     /** This is the quantity of the operationplan before the command. */
05445     double originalqty;
05446 
05447     /** A pointer to a list of suboperationplan commands. */
05448     Command* firstCommand;
05449 };
05450 
05451 
05452 /** @brief This class models a iterator that walks over all available
05453   * HasProblem entities.
05454   *
05455   * This list is containing hard-coding the classes that are implementing
05456   * this class. It's not ideal, but we don't have an explicit container
05457   * of the objects (and we don't want one either) and this allows us also
05458   * to re-use the sorting used for the container classes.
05459   */
05460 class HasProblems::EntityIterator
05461 {
05462   private:
05463     /** This union contains iterators through the different entity types.
05464       * Only one of the different iterators will be active at a time, and
05465       * can thus save memory by collapsing the iterators into a single
05466       * union. */
05467     union
05468     {
05469       Buffer::iterator *bufIter;
05470       Resource::iterator *resIter;
05471       OperationPlan::iterator *operIter;
05472       Demand::iterator *demIter;
05473     };
05474 
05475     /** This type indicates which type of entity we are currently recursing
05476       * through.
05477       *  - 0: buffers
05478       *  - 1: resources
05479       *  - 2: operationplans
05480       *  - 3: demands
05481       */
05482     unsigned short type;
05483 
05484   public:
05485     /** Default constructor, which creates an iterator to the first
05486       * HasProblems object. */
05487     explicit DECLARE_EXPORT EntityIterator();
05488 
05489     /** Used to create an iterator pointing beyond the last HasProblems
05490       * object. */
05491     explicit EntityIterator(unsigned short i) : type(i) {}
05492 
05493     /** Copy constructor. */
05494     DECLARE_EXPORT EntityIterator(const EntityIterator& o);
05495 
05496     /** Assignment operator. */
05497     DECLARE_EXPORT EntityIterator& operator=(const EntityIterator& o);
05498 
05499     /** Destructor. */
05500     DECLARE_EXPORT ~EntityIterator();
05501 
05502     /** Pre-increment operator. */
05503     DECLARE_EXPORT EntityIterator& operator++();
05504 
05505     /** Inequality operator.<br>
05506       * Two iterators are different when they point to different objects.
05507       */
05508     DECLARE_EXPORT bool operator != (const EntityIterator& t) const;
05509 
05510     /** Equality operator.<br>
05511       * Two iterators are equal when they point to the same object.
05512       */
05513     bool operator == (const EntityIterator& t) const {return !(*this != t);}
05514 
05515     /** Dereference operator. */
05516     DECLARE_EXPORT HasProblems& operator*() const;
05517 
05518     /** Dereference operator. */
05519     DECLARE_EXPORT HasProblems* operator->() const;
05520 };
05521 
05522 
05523 /** @brief This class models an STL-like iterator that allows us to iterate
05524   * over the named entities in a simple and safe way.
05525   *
05526   * Objects of this class are returned by the begin() and end() functions.
05527   * @see Problem::begin()
05528   * @see Problem::begin(HasProblem*)
05529   * @see Problem::end()
05530   */
05531 class Problem::const_iterator
05532 {
05533     friend class Problem;
05534   private:
05535     /** A pointer to the current problem. If this pointer is NULL, we are
05536       * at the end of the list. */
05537     Problem* iter;
05538     HasProblems* owner;
05539     HasProblems::EntityIterator eiter;
05540 
05541   public:
05542     /** Creates an iterator that will loop through the problems of a
05543       * single entity only. <BR>
05544       * This constructor is also used to create a end-iterator, when passed
05545       * a NULL pointer as argument.
05546       */
05547     explicit const_iterator(HasProblems* o) : iter(o ? o->firstProblem : NULL),
05548       owner(o), eiter(4) {}
05549 
05550     /** Creates an iterator that will loop through the constraints of
05551       * a demand.
05552       */
05553     explicit const_iterator(Problem* o) : iter(o),
05554       owner(NULL), eiter(4) {}
05555 
05556     /** Creates an iterator that will loop through the problems of all
05557       * entities. */
05558     explicit const_iterator() : owner(NULL)
05559     {
05560       // Loop till we find an entity with a problem
05561       while (eiter!=HasProblems::endEntity() && !(eiter->firstProblem))
05562         ++eiter;
05563       // Found a first problem, or no problem at all
05564       iter = (eiter!=HasProblems::endEntity()) ? eiter->firstProblem : NULL;
05565     }
05566 
05567     /** Pre-increment operator. */
05568     DECLARE_EXPORT const_iterator& operator++();
05569 
05570     /** Inequality operator. */
05571     bool operator != (const const_iterator& t) const {return iter!=t.iter;}
05572 
05573     /** Equality operator. */
05574     bool operator == (const const_iterator& t) const {return iter==t.iter;}
05575 
05576     Problem& operator*() const {return *iter;}
05577     Problem* operator->() const {return iter;}
05578 };
05579 
05580 
05581 /** Retrieve an iterator for the list. */
05582 inline Problem::const_iterator Problem::List::begin() const 
05583   {return Problem::const_iterator(first);}
05584 
05585 
05586 /** Stop iterator. */
05587 inline Problem::const_iterator Problem::List::end() const
05588   {return Problem::const_iterator(static_cast<Problem*>(NULL));}
05589 
05590 
05591 /** @brief This class allows upstream and downstream navigation through
05592   * the plan.
05593   *
05594   * Downstream navigation follows the material flow from raw materials
05595   * towards the produced end item.<br>
05596   * Upstream navigation traces back the material flow from the end item up to
05597   * the consumed raw materials.<br>
05598   * The class is implemented as an STL-like iterator.
05599   *
05600   * @todo operationplans without flowplans are skipped by the iterator - not correct!
05601   */
05602 class PeggingIterator : public Object
05603 {
05604   public:
05605     /** Constructor. */
05606     DECLARE_EXPORT PeggingIterator(const Demand* e);
05607 
05608     /** Constructor. */
05609     PeggingIterator(const FlowPlan* e, bool b = true)
05610       : downstream(b), firstIteration(true)
05611     {
05612       if (!e) return;
05613       if (downstream)
05614         states.push(state(0,abs(e->getQuantity()),1.0,e,NULL));
05615       else
05616         states.push(state(0,abs(e->getQuantity()),1.0,NULL,e));
05617       initType(metadata);
05618     }
05619 
05620     /** Return the operationplan consuming the material. */
05621     OperationPlan* getConsumingOperationplan() const
05622     {
05623       const FlowPlan* x = states.top().cons_flowplan;
05624       return x ? x->getOperationPlan() : NULL;
05625     }
05626 
05627     /** Return the material buffer through which we are pegging. */
05628     Buffer *getBuffer() const
05629     {
05630       const FlowPlan* x = states.top().prod_flowplan;
05631       if (!x) x = states.top().cons_flowplan;
05632       return x ? x->getFlow()->getBuffer() : NULL;
05633     }
05634 
05635     /** Return the operationplan producing the material. */
05636     OperationPlan* getProducingOperationplan() const
05637     {
05638       const FlowPlan* x = states.top().prod_flowplan;
05639       return x ? x->getOperationPlan() : NULL;
05640     }
05641 
05642     /** Return the date when the material is consumed. */
05643     Date getConsumingDate() const
05644     {
05645       const FlowPlan* x = states.top().cons_flowplan;
05646       return x ? x->getDate() : Date::infinitePast;
05647     }
05648 
05649     /** Return the date when the material is produced. */
05650     Date getProducingDate() const
05651     {
05652       const FlowPlan* x = states.top().prod_flowplan;
05653       return x ? x->getDate() : Date::infinitePast;
05654     }
05655 
05656     /** Returns the recursion depth of the iterator.<br>
05657       * The original flowplan is at level 0, and each level (either upstream
05658       * or downstream) increments the value by 1.
05659       */
05660     short getLevel() const {return states.top().level;}
05661 
05662     /** Returns the quantity of the demand that is linked to this pegging
05663       * record.
05664       */
05665     double getQuantityDemand() const {return states.top().qty;}
05666 
05667     /** Returns the quantity of the buffer flowplans that is linked to this
05668       * pegging record.
05669       */
05670     double getQuantityBuffer() const
05671     {
05672       const state& t = states.top();
05673       return t.prod_flowplan
05674         ? t.factor * t.prod_flowplan->getOperationPlan()->getQuantity()
05675         : 0;
05676     }
05677 
05678     /** Returns which portion of the current flowplan is fed/supplied by the
05679       * original flowplan. */
05680     double getFactor() const {return states.top().factor;}
05681 
05682     /** Returns false if the flowplan remained unpegged, i.e. it wasn't
05683       * -either completely or paritally- unconsumed at the next level.
05684       */
05685     bool getPegged() const {return states.top().pegged;}
05686 
05687     /** Move the iterator foward to the next downstream flowplan. */
05688     DECLARE_EXPORT PeggingIterator& operator++();
05689 
05690     /** Move the iterator foward to the next downstream flowplan.<br>
05691       * This post-increment operator is less efficient than the pre-increment
05692       * operator.
05693       */
05694     PeggingIterator operator++(int)
05695       {PeggingIterator tmp = *this; ++*this; return tmp;}
05696 
05697     /** Move the iterator foward to the next upstream flowplan. */
05698     DECLARE_EXPORT PeggingIterator& operator--();
05699 
05700     /** Move the iterator foward to the next upstream flowplan.<br>
05701       * This post-increment operator is less efficient than the pre-decrement
05702       * operator.
05703       */
05704     PeggingIterator operator--(int)
05705       {PeggingIterator tmp = *this; --*this; return tmp;}
05706 
05707     /** Comparison operator. */
05708     bool operator==(const PeggingIterator& x) const {return states == x.states;}
05709 
05710     /** Inequality operator. */
05711     bool operator!=(const PeggingIterator& x) const {return states != x.states;}
05712 
05713     /** Conversion operator to a boolean value.
05714       * The return value is true when the iterator still has next elements to
05715       * explore. Returns false when the iteration is finished.
05716       */
05717     operator bool () const {return !states.empty();}
05718 
05719     /** Update the stack. */
05720     DECLARE_EXPORT void updateStack(short, double, double, const FlowPlan*, const FlowPlan*, bool = true);
05721 
05722     /** Returns true if this is a downstream iterator. */
05723     bool isDownstream() {return downstream;}
05724 
05725     /** Initialize the class. */
05726     static int initialize();
05727 
05728     virtual void endElement(XMLInput& i, const Attribute& a, const DataElement& d)
05729     {
05730       throw LogicException("Pegging can't be read");
05731     }
05732     virtual const MetaClass& getType() const {return *metadata;}
05733     static DECLARE_EXPORT const MetaCategory* metadata;
05734     size_t getSize() const {return sizeof(PeggingIterator);}
05735 
05736   private:
05737     /** This structure is used to keep track of the iterator states during the
05738       * iteration. */
05739     struct state
05740     {
05741       /** Stores the quantity of this flowplan that is involved. */
05742       double qty;
05743 
05744       /** Stores what portion of the flowplan is involved with the root flowplan
05745         * where the recursion started.
05746         */
05747       double factor;
05748 
05749       /** Keeps track of the number of levels we're removed from the root
05750         * flowplan where the recursion started.
05751         */
05752       short level;
05753 
05754       /** The current flowplan. */
05755       const FlowPlan* cons_flowplan;
05756 
05757       /** The current flowplan. */
05758       const FlowPlan* prod_flowplan;
05759 
05760       /** Set to false when unpegged quantities are involved. */
05761       bool pegged;
05762 
05763       /** Constructor. */
05764       state(unsigned int l, double d, double f,
05765         const FlowPlan* fc, const FlowPlan* fp, bool p = true)
05766           : qty(d), factor(f), level(l),
05767           cons_flowplan(fc), prod_flowplan(fp), pegged(p) {};
05768 
05769       /** Inequality operator. */
05770       bool operator != (const state& s) const
05771       {
05772         return cons_flowplan != s.cons_flowplan
05773           || prod_flowplan != s.prod_flowplan
05774           || level != s.level;
05775       }
05776 
05777       /** Equality operator. */
05778       bool operator == (const state& s) const
05779       {
05780         return cons_flowplan == s.cons_flowplan
05781           && prod_flowplan == s.prod_flowplan
05782           && level == s.level;
05783       }
05784     };
05785 
05786     /** A type to hold the iterator state. */
05787     typedef stack < state > statestack;
05788 
05789     /** A stack is used to store the iterator state. */
05790     statestack states;
05791 
05792     /** Iterate over the pegging in Python. */
05793     DECLARE_EXPORT PyObject *iternext();
05794 
05795     DECLARE_EXPORT PyObject* getattro(const Attribute&);
05796 
05797     /* Auxilary function to make recursive code possible. */
05798     DECLARE_EXPORT void followPegging(const OperationPlan*, short, double, double);
05799 
05800     /** Convenience variable during stack updates.
05801       * Depending on the value of this field, either the top element in the
05802       * stack is updated or a new state is pushed on the stack.
05803       */
05804     bool first;
05805 
05806     /** Downstream or upstream iterator. */
05807     bool downstream;
05808 
05809     /** A flag used by the Python iterators.
05810       * @see iternext()
05811       */
05812     bool firstIteration;
05813 };
05814 
05815 
05816 /** @brief An iterator class to go through all flowplans of an operationplan.
05817   * @see OperationPlan::beginFlowPlans
05818   * @see OperationPlan::endFlowPlans
05819   */
05820 class OperationPlan::FlowPlanIterator
05821 {
05822     friend class OperationPlan;
05823   private:
05824     FlowPlan* curflowplan;
05825     FlowPlan* prevflowplan;
05826     FlowPlanIterator(FlowPlan* b) : curflowplan(b), prevflowplan(NULL) {}
05827   public:
05828     FlowPlanIterator(const FlowPlanIterator& b)
05829     {
05830       curflowplan = b.curflowplan;
05831       prevflowplan = b.prevflowplan;
05832     }
05833     bool operator != (const FlowPlanIterator &b) const
05834       {return b.curflowplan != curflowplan;}
05835     bool operator == (const FlowPlanIterator &b) const
05836       {return b.curflowplan == curflowplan;}
05837     FlowPlanIterator& operator++()
05838     {
05839       prevflowplan = curflowplan;
05840       if (curflowplan) curflowplan = curflowplan->nextFlowPlan;
05841       return *this;
05842     }
05843     FlowPlanIterator operator++(int)
05844       {FlowPlanIterator tmp = *this; ++*this; return tmp;}
05845     FlowPlan* operator ->() const {return curflowplan;}
05846     FlowPlan& operator *() const {return *curflowplan;}
05847     void deleteFlowPlan()
05848     {
05849       if (!curflowplan) return;
05850       if (prevflowplan) prevflowplan->nextFlowPlan = curflowplan->nextFlowPlan;
05851       else curflowplan->oper->firstflowplan = curflowplan->nextFlowPlan;
05852       FlowPlan* tmp = curflowplan;
05853       // Move the iterator to the next element
05854       curflowplan = curflowplan->nextFlowPlan;
05855       delete tmp;
05856     }
05857 };
05858 
05859 inline OperationPlan::FlowPlanIterator OperationPlan::beginFlowPlans() const
05860   {return OperationPlan::FlowPlanIterator(firstflowplan);}
05861 
05862 inline OperationPlan::FlowPlanIterator OperationPlan::endFlowPlans() const
05863   {return OperationPlan::FlowPlanIterator(NULL);}
05864 
05865 inline int OperationPlan::sizeFlowPlans() const
05866 {
05867   int c = 0;
05868   for (FlowPlanIterator i = beginFlowPlans(); i != endFlowPlans(); ++i) ++c;
05869   return c;
05870 }
05871 
05872 
05873 /** @brief An iterator class to go through all loadplans of an operationplan.
05874   * @see OperationPlan::beginLoadPlans
05875   * @see OperationPlan::endLoadPlans
05876   */
05877 class OperationPlan::LoadPlanIterator
05878 {
05879     friend class OperationPlan;
05880   private:
05881     LoadPlan* curloadplan;
05882     LoadPlan* prevloadplan;
05883     LoadPlanIterator(LoadPlan* b) : curloadplan(b), prevloadplan(NULL) {}
05884   public:
05885     LoadPlanIterator(const LoadPlanIterator& b)
05886     {
05887       curloadplan = b.curloadplan;
05888       prevloadplan = b.prevloadplan;
05889     }
05890     bool operator != (const LoadPlanIterator &b) const
05891       {return b.curloadplan != curloadplan;}
05892     bool operator == (const LoadPlanIterator &b) const
05893       {return b.curloadplan == curloadplan;}
05894     LoadPlanIterator& operator++()
05895     {
05896       prevloadplan = curloadplan;
05897       if (curloadplan) curloadplan = curloadplan->nextLoadPlan;
05898       return *this;
05899     }
05900     LoadPlanIterator operator++(int)
05901       {LoadPlanIterator tmp = *this; ++*this; return tmp;}
05902     LoadPlan* operator ->() const {return curloadplan;}
05903     LoadPlan& operator *() const {return *curloadplan;}
05904     void deleteLoadPlan()
05905     {
05906       if (!curloadplan) return;
05907       if (prevloadplan) prevloadplan->nextLoadPlan = curloadplan->nextLoadPlan;
05908       else curloadplan->oper->firstloadplan = curloadplan->nextLoadPlan;
05909       LoadPlan* tmp = curloadplan;
05910       // Move the iterator to the next element
05911       curloadplan = curloadplan->nextLoadPlan;
05912       delete tmp;
05913     }
05914 };
05915 
05916 
05917 inline OperationPlan::LoadPlanIterator OperationPlan::beginLoadPlans() const
05918   {return OperationPlan::LoadPlanIterator(firstloadplan);}
05919 
05920 
05921 inline OperationPlan::LoadPlanIterator OperationPlan::endLoadPlans() const
05922   {return OperationPlan::LoadPlanIterator(NULL);}
05923 
05924 
05925 inline int OperationPlan::sizeLoadPlans() const
05926 {
05927   int c = 0;
05928   for (LoadPlanIterator i = beginLoadPlans(); i != endLoadPlans(); ++i) ++c;
05929   return c;
05930 }
05931 
05932 
05933 class ProblemIterator
05934   : public FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>
05935 {
05936   public:
05937     /** Constructor starting the iteration from a certain problem. */
05938     ProblemIterator(Problem *x) : 
05939         FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(x) {}
05940 
05941     /** Constructor starting the iteration from a certain problem. */
05942     ProblemIterator(Problem &x) : 
05943         FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>(&x) {}
05944 
05945     /** Default constructor. */
05946     ProblemIterator() : 
05947         FreppleIterator<ProblemIterator,Problem::const_iterator,Problem>() {}
05948 };
05949 
05950 
05951 class BufferIterator
05952   : public FreppleIterator<BufferIterator,Buffer::memberIterator,Buffer>
05953 {
05954   public:
05955     BufferIterator(Buffer* b) : FreppleIterator<BufferIterator,Buffer::memberIterator,Buffer>(b) {}
05956     BufferIterator() {}
05957 };
05958 
05959 
05960 class LocationIterator
05961   : public FreppleIterator<LocationIterator,Location::memberIterator,Location>
05962 {
05963   public:
05964     LocationIterator(Location* b) : FreppleIterator<LocationIterator,Location::memberIterator,Location>(b) {}
05965     LocationIterator() {}
05966 };
05967 
05968 
05969 class CustomerIterator
05970   : public FreppleIterator<CustomerIterator,Customer::memberIterator,Customer>
05971 {
05972   public:
05973     CustomerIterator(Customer* b) : FreppleIterator<CustomerIterator,Customer::memberIterator,Customer>(b) {}
05974     CustomerIterator() {}
05975 };
05976 
05977 
05978 class ItemIterator
05979   : public FreppleIterator<ItemIterator,Item::memberIterator,Item>
05980 {
05981   public:
05982     ItemIterator(Item* b) : FreppleIterator<ItemIterator,Item::memberIterator,Item>(b) {}
05983     ItemIterator() {}
05984 };
05985 
05986 
05987 class DemandIterator
05988   : public FreppleIterator<DemandIterator,Demand::memberIterator,Demand>
05989 {
05990   public:
05991     DemandIterator(Demand* b) : FreppleIterator<DemandIterator,Demand::memberIterator,Demand>(b) {}
05992     DemandIterator() {}
05993 };
05994 
05995 
05996 class ResourceIterator
05997   : public FreppleIterator<ResourceIterator,Resource::memberIterator,Resource>
05998 {
05999   public:
06000     ResourceIterator(Resource* b) : FreppleIterator<ResourceIterator,Resource::memberIterator,Resource>(b) {}
06001     ResourceIterator() {}
06002 };
06003 
06004 
06005 class SolverIterator
06006   : public FreppleIterator<SolverIterator,Solver::iterator,Solver>
06007 {
06008 };
06009 
06010 
06011 class OperationIterator
06012   : public FreppleIterator<OperationIterator,Operation::iterator,Operation>
06013 {
06014 };
06015 
06016 
06017 class CalendarIterator
06018   : public FreppleIterator<CalendarIterator,Calendar::iterator,Calendar>
06019 {
06020 };
06021 
06022 
06023 class SetupMatrixIterator
06024   : public FreppleIterator<SetupMatrixIterator,SetupMatrix::iterator,SetupMatrix>
06025 {
06026 };
06027 
06028 
06029 //
06030 // SETUP MATRIX RULES
06031 //
06032 
06033 
06034 class SetupMatrixRuleIterator : public PythonExtension<SetupMatrixRuleIterator>
06035 {
06036   public:
06037     static int initialize();
06038 
06039     SetupMatrixRuleIterator(SetupMatrix* c) : matrix(c)
06040     {
06041       if (!c)
06042         throw LogicException("Creating rule iterator for NULL matrix");
06043       currule = c->beginRules();
06044     }
06045 
06046   private:
06047     SetupMatrix* matrix;
06048     SetupMatrix::RuleIterator currule;
06049     PyObject *iternext();
06050 };
06051 
06052 
06053 //
06054 // CALENDARS
06055 //
06056 
06057 
06058 class CalendarBucketIterator : public PythonExtension<CalendarBucketIterator>
06059 {
06060   public:
06061     static int initialize();
06062 
06063     CalendarBucketIterator(Calendar* c) : cal(c)
06064     {
06065       if (!c)
06066         throw LogicException("Creating bucket iterator for NULL calendar");
06067       i = c->beginBuckets();
06068     }
06069 
06070   private:
06071     Calendar* cal;
06072     Calendar::BucketIterator i;
06073     PyObject *iternext();
06074 };
06075 
06076 
06077 class CalendarEventIterator
06078   : public PythonExtension<CalendarEventIterator>
06079 {
06080   public:
06081     static int initialize();
06082 
06083     CalendarEventIterator(Calendar* c, Date d=Date::infinitePast, bool f=true)
06084       : cal(c), eventiter(c,d,f), forward(f) {}
06085 
06086   private:
06087     Calendar* cal;
06088     Calendar::EventIterator eventiter;
06089     bool forward;
06090     PyObject *iternext();
06091 };
06092 
06093 
06094 //
06095 // OPERATIONPLANS
06096 //
06097 
06098 
06099 class OperationPlanIterator
06100   : public FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>
06101 {
06102   public:
06103     /** Constructor to iterate over all operationplans. */
06104     OperationPlanIterator() {}
06105 
06106     /** Constructor to iterate over the operationplans of a single operation. */
06107     OperationPlanIterator(Operation* o)
06108       : FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>(o)
06109     {}
06110 
06111     /** Constructor to iterate over the suboperationplans of an operationplans. */
06112     OperationPlanIterator(OperationPlan* opplan)
06113       : FreppleIterator<OperationPlanIterator,OperationPlan::iterator,OperationPlan>(opplan)
06114     {}
06115 };
06116 
06117 
06118 //
06119 // FLOWPLANS
06120 //
06121 
06122 
06123 class FlowPlanIterator : public PythonExtension<FlowPlanIterator>
06124 {
06125   public:
06126     static int initialize();
06127 
06128     FlowPlanIterator(Buffer* b) : buf(b), buffer_or_opplan(true)
06129     {
06130       if (!b)
06131         throw LogicException("Creating flowplan iterator for NULL buffer");
06132       bufiter = new Buffer::flowplanlist::const_iterator(b->getFlowPlans().begin());
06133     }
06134 
06135     FlowPlanIterator(OperationPlan* o) : opplan(o), buffer_or_opplan(false)
06136     {
06137       if (!o)
06138         throw LogicException("Creating flowplan iterator for NULL operationplan");
06139       opplaniter = new OperationPlan::FlowPlanIterator(o->beginFlowPlans());
06140     }
06141 
06142     ~FlowPlanIterator()
06143     {
06144       if (buffer_or_opplan) delete bufiter;
06145       else delete opplaniter;
06146     }
06147 
06148   private:
06149     union
06150     {
06151       Buffer* buf;
06152       OperationPlan* opplan;
06153     };
06154 
06155     union
06156     {
06157       Buffer::flowplanlist::const_iterator *bufiter;
06158       OperationPlan::FlowPlanIterator *opplaniter;
06159     };
06160 
06161     /** Flags whether we are browsing over the flowplans in a buffer or in an
06162       * operationplan. */
06163     bool buffer_or_opplan;
06164 
06165     PyObject *iternext();
06166 };
06167 
06168 
06169 //
06170 // LOADPLANS
06171 //
06172 
06173 
06174 class LoadPlanIterator : public PythonExtension<LoadPlanIterator>
06175 {
06176   public:
06177     static int initialize();
06178 
06179     LoadPlanIterator(Resource* r) : res(r), resource_or_opplan(true)
06180     {
06181       if (!r)
06182         throw LogicException("Creating loadplan iterator for NULL resource");
06183       resiter = new Resource::loadplanlist::const_iterator(r->getLoadPlans().begin());
06184     }
06185 
06186     LoadPlanIterator(OperationPlan* o) : opplan(o), resource_or_opplan(false)
06187     {
06188       if (!opplan)
06189         throw LogicException("Creating loadplan iterator for NULL operationplan");
06190       opplaniter = new OperationPlan::LoadPlanIterator(o->beginLoadPlans());
06191     }
06192 
06193     ~LoadPlanIterator()
06194     {
06195       if (resource_or_opplan) delete resiter;
06196       else delete opplaniter;
06197     }
06198 
06199   private:
06200     union
06201     {
06202       Resource* res;
06203       OperationPlan* opplan;
06204     };
06205 
06206     union
06207     {
06208       Resource::loadplanlist::const_iterator *resiter;
06209       OperationPlan::LoadPlanIterator *opplaniter;
06210     };
06211 
06212     /** Flags whether we are browsing over the flowplans in a buffer or in an
06213       * operationplan. */
06214     bool resource_or_opplan;
06215 
06216     PyObject *iternext();
06217 };
06218 
06219 
06220 //
06221 // DEMAND DELIVERY OPERATIONPLANS
06222 //
06223 
06224 
06225 class DemandPlanIterator : public PythonExtension<DemandPlanIterator>
06226 {
06227   public:
06228     static int initialize();
06229 
06230     DemandPlanIterator(Demand* r) : dem(r)
06231     {
06232       if (!r)
06233         throw LogicException("Creating demandplan iterator for NULL demand");
06234       i = r->getDelivery().begin();
06235     }
06236 
06237   private:
06238     Demand* dem;
06239     Demand::OperationPlan_list::const_iterator i;
06240     PyObject *iternext();
06241 };
06242 
06243 
06244 //
06245 // LOADS
06246 //
06247 
06248 
06249 class LoadIterator : public PythonExtension<LoadIterator>
06250 {
06251   public:
06252     static int initialize();
06253 
06254     LoadIterator(Resource* r)
06255       : res(r), ir(r ? r->getLoads().begin() : NULL), oper(NULL), io(NULL)
06256     {
06257       if (!r)
06258         throw LogicException("Creating loadplan iterator for NULL resource");
06259     }
06260 
06261     LoadIterator(Operation* o)
06262       : res(NULL), ir(NULL), oper(o), io(o ? o->getLoads().begin() : NULL)
06263     {
06264       if (!o)
06265         throw LogicException("Creating loadplan iterator for NULL operation");
06266     }
06267 
06268   private:
06269     Resource* res;
06270     Resource::loadlist::const_iterator ir;
06271     Operation* oper;
06272     Operation::loadlist::const_iterator io;
06273     PyObject *iternext();
06274 };
06275 
06276 
06277 //
06278 // FLOW
06279 //
06280 
06281 
06282 class FlowIterator : public PythonExtension<FlowIterator>
06283 {
06284   public:
06285     static int initialize();
06286 
06287     FlowIterator(Buffer* b)
06288       : buf(b), ib(b ? b->getFlows().begin() : NULL), oper(NULL), io(NULL)
06289     {
06290       if (!b)
06291         throw LogicException("Creating flowplan iterator for NULL buffer");
06292     }
06293 
06294     FlowIterator(Operation* o)
06295       : buf(NULL), ib(NULL), oper(o), io(o ? o->getFlows().begin() : NULL)
06296     {
06297       if (!o)
06298         throw LogicException("Creating flowplan iterator for NULL operation");
06299     }
06300 
06301   private:
06302     Buffer* buf;
06303     Buffer::flowlist::const_iterator ib;
06304     Operation* oper;
06305     Operation::flowlist::const_iterator io;
06306     PyObject *iternext();
06307 };
06308 
06309 
06310 /** @brief This Python function is used for reading XML input.
06311   *
06312   * The function takes up to three arguments:
06313   *   - XML data file to be processed.
06314   *     If this argument is omitted or None, the standard input is read.
06315   *   - Optional validate flag, defining whether or not the input data needs to be
06316   *     validated against the XML schema definition.
06317   *     The validation is switched ON by default.
06318   *     Switching it ON is recommended in situations where there is no 100% guarantee
06319   *     on the validity of the input data.
06320   *   - Optional validate_only flag, which allows us to validate the data but
06321   *     skip any processing.
06322   */
06323 DECLARE_EXPORT PyObject* readXMLfile(PyObject*, PyObject*);
06324 
06325 
06326 /** @brief This Python function is used for processing XML input data from a string.
06327   *
06328   * The function takes up to three arguments:
06329   *   - XML data string to be processed
06330   *   - Optional validate flag, defining whether or not the input data needs to be
06331   *     validated against the XML schema definition.
06332   *     The validation is switched ON by default.
06333   *     Switching it ON is recommended in situations where there is no 100% guarantee
06334   *     on the validity of the input data.
06335   *   - Optional validate_only flag, which allows us to validate the data but
06336   *     skip any processing.
06337   */
06338 DECLARE_EXPORT PyObject* readXMLdata(PyObject *, PyObject *);
06339 
06340 
06341 /** @brief This Python function writes the dynamic part of the plan to an text file.
06342   *
06343   * This saved information covers the buffer flowplans, operationplans,
06344   * resource loading, demand, problems, etc...<br>
06345   * The main use of this function is in the test suite: a simple text file
06346   * comparison allows us to identify changes quickly. The output format is
06347   * only to be seen in this context of testing, and is not intended to be used
06348   * as an official method for publishing plans to other systems.
06349   */
06350 DECLARE_EXPORT PyObject* savePlan(PyObject*, PyObject*);
06351 
06352 
06353 /** @brief This Python function prints a summary of the dynamically allocated
06354   * memory to the standard output. This is useful for understanding better the
06355   * size of your model.
06356   *
06357   * The numbers reported by this function won't match the memory size as
06358   * reported by the operating system, since the dynamically allocated memory
06359   * is only a part of the total memory used by a program.
06360   */
06361 DECLARE_EXPORT PyObject* printModelSize(PyObject* self, PyObject* args);
06362 
06363 
06364 /** @brief This python function writes the complete model to an XML-file.
06365   *
06366   * Both the static model (i.e. items, locations, buffers, resources,
06367   * calendars, etc...) and the dynamic data (i.e. the actual plan including
06368   * the operationplans, demand, problems, etc...).<br>
06369   * The format is such that the output file can be re-read to restore the
06370   * very same model.<br>
06371   * The function takes the following arguments:
06372   *   - Name of the output file
06373   *   - Type of output desired: STANDARD, PLAN or PLANDETAIL.
06374   *     The default value is STANDARD.
06375   */
06376 DECLARE_EXPORT PyObject* saveXMLfile(PyObject*, PyObject*);
06377 
06378 
06379 /** @brief This Python function erases the model or the plan from memory.
06380   *
06381   * The function allows the following modes to control what to delete:
06382   *  - plan:<br>
06383   *    Deletes the dynamic modelling constructs, such as operationplans,
06384   *    loadplans and flowplans only. Locked operationplans are not
06385   *    deleted.<br>
06386   *    The static model is left intact.<br>
06387   *    This is the default mode.
06388   *  - model:<br>
06389   *    The dynamic as well as the static objects are removed. You'll end
06390   *    up with a completely empty model.
06391   *    Due to the logic required in the object destructors this mode doesn't
06392   *    scale linear with the model size.
06393   */
06394 DECLARE_EXPORT PyObject* eraseModel(PyObject* self, PyObject* args);
06395 
06396 
06397 }   // End namespace
06398 
06399 #endif

Documentation generated for frePPLe by  doxygen