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

Documentation generated for frePPLe by  doxygen