loadplan.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.9.1/src/model/loadplan.cpp $
00003   version : $LastChangedRevision: 1656 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2012-03-27 19:05:34 +0200 (Tue, 27 Mar 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 Lesser General Public License as published   *
00013  * by the Free Software Foundation; either version 2.1 of the License, or  *
00014  * (at your option) any later version.                                     *
00015  *                                                                         *
00016  * This library is distributed in the hope that it will be useful,         *
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
00019  * General Public License for more details.                                *
00020  *                                                                         *
00021  * You should have received a copy of the GNU Lesser General Public        *
00022  * License along with this library; if not, write to the Free Software     *
00023  * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,*
00024  * USA                                                                     *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 #define FREPPLE_CORE
00029 #include "frepple/model.h"
00030 
00031 namespace frepple
00032 {
00033 
00034 DECLARE_EXPORT const MetaCategory* LoadPlan::metadata;
00035 
00036 
00037 int LoadPlan::initialize()
00038 {
00039   // Initialize the metadata
00040   metadata = new MetaCategory("loadplan", "loadplans");
00041 
00042   // Initialize the Python type
00043   PythonType& x = FreppleCategory<LoadPlan>::getType();
00044   x.setName("loadplan");
00045   x.setDoc("frePPLe loadplan");
00046   x.supportgetattro();
00047   const_cast<MetaCategory*>(metadata)->pythonClass = x.type_object();
00048   return x.typeReady();
00049 }
00050 
00051 
00052 DECLARE_EXPORT LoadPlan::LoadPlan(OperationPlan *o, const Load *r)
00053 {
00054   assert(o);
00055   ld = const_cast<Load*>(r);
00056   oper = o;
00057   start_or_end = START;
00058 
00059   // Add to the operationplan
00060   nextLoadPlan = NULL;
00061   if (o->firstloadplan)
00062   {
00063     // Append to the end
00064     LoadPlan *c = o->firstloadplan;
00065     while (c->nextLoadPlan) c = c->nextLoadPlan;
00066     c->nextLoadPlan = this;
00067   }
00068   else
00069     // First in the list
00070     o->firstloadplan = this;
00071 
00072   // Insert in the resource timeline
00073   r->getResource()->loadplans.insert(
00074     this,
00075     ld->getLoadplanQuantity(this),
00076     ld->getLoadplanDate(this)
00077   );
00078 
00079   // Initialize the Python type
00080   initType(metadata);
00081 
00082   // Create a loadplan to mark the end of the operationplan.
00083   new LoadPlan(o, r, this);
00084 
00085   // Mark the operation and resource as being changed. This will trigger
00086   // the recomputation of their problems
00087   r->getResource()->setChanged();
00088   r->getOperation()->setChanged();
00089 }
00090 
00091 
00092 DECLARE_EXPORT LoadPlan::LoadPlan(OperationPlan *o, const Load *r, LoadPlan *lp)
00093 {
00094   ld = const_cast<Load*>(r);
00095   oper = o;
00096   start_or_end = END;
00097 
00098   // Add to the operationplan
00099   nextLoadPlan = NULL;
00100   if (o->firstloadplan)
00101   {
00102     // Append to the end
00103     LoadPlan *c = o->firstloadplan;
00104     while (c->nextLoadPlan) c = c->nextLoadPlan;
00105     c->nextLoadPlan = this;
00106   }
00107   else
00108     // First in the list
00109     o->firstloadplan = this;
00110 
00111   // Insert in the resource timeline
00112   r->getResource()->loadplans.insert(
00113     this,
00114     ld->getLoadplanQuantity(this),
00115     ld->getLoadplanDate(this)
00116   );
00117 
00118   // Initialize the Python type
00119   initType(metadata);
00120 }
00121 
00122 
00123 DECLARE_EXPORT LoadPlan* LoadPlan::getOtherLoadPlan() const
00124 {
00125   for (LoadPlan *i = oper->firstloadplan; i; i = i->nextLoadPlan)
00126     if (i->ld == ld && i != this) return i;
00127   throw LogicException("No matching loadplan found");
00128 }
00129 
00130 
00131 DECLARE_EXPORT void LoadPlan::update()
00132 {
00133   // Update the timeline data structure
00134   ld->getResource()->getLoadPlans().update(
00135     this,
00136     ld->getLoadplanQuantity(this),
00137     ld->getLoadplanDate(this)
00138   );
00139 
00140   // Review adjacent setups
00141   if (!isStart()) ld->getResource()->updateSetups(this);
00142 
00143   // Mark the operation and resource as being changed. This will trigger
00144   // the recomputation of their problems
00145   ld->getResource()->setChanged();
00146   ld->getOperation()->setChanged();
00147 }
00148 
00149 
00150 DECLARE_EXPORT const string& LoadPlan::getSetup(bool current) const
00151 {
00152   // This resource has no setupmatrix
00153   static string nosetup;
00154   assert(ld);
00155   if (!ld->getResource()->getSetupMatrix()) return nosetup;
00156 
00157   // Current load has a setup
00158   if (!ld->getSetup().empty() && current) return ld->getSetup();
00159 
00160   // Scan earlier setups
00161   for (Resource::loadplanlist::const_iterator i(this);
00162       i != getResource()->getLoadPlans().end(); --i)
00163   {
00164     const LoadPlan* j = dynamic_cast<const LoadPlan*>(&*i);
00165     if (j && !j->getLoad()->getSetup().empty() && (current || j != this))
00166       return j->getLoad()->getSetup();
00167   }
00168 
00169   // No conversions found - return the original setup
00170   return ld->getResource()->getSetup();
00171 }
00172 
00173 
00174 DECLARE_EXPORT LoadPlan::~LoadPlan()
00175 {
00176   ld->getResource()->setChanged();
00177   LoadPlan *prevldplan = NULL;
00178   if (!isStart() && oper->getOperation() == OperationSetup::setupoperation)
00179   {
00180     for (TimeLine<LoadPlan>::const_iterator i = getResource()->getLoadPlans().begin(isStart() ? getOtherLoadPlan() : this);
00181         i != getResource()->getLoadPlans().end(); --i)
00182     {
00183       const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
00184       if (l && l->getOperationPlan() != getOperationPlan()
00185           && l->getOperationPlan() != getOperationPlan()->getOwner()
00186           && !l->isStart())
00187       {
00188         prevldplan = const_cast<LoadPlan*>(l);
00189         break;
00190       }
00191     }
00192     if (!prevldplan)
00193     {
00194       for (TimeLine<LoadPlan>::const_iterator i = getResource()->getLoadPlans().begin(isStart() ? getOtherLoadPlan() : this);
00195           i != getResource()->getLoadPlans().end(); ++i)
00196       {
00197         const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
00198         if (l && l->getOperationPlan() != getOperationPlan()
00199             && l->getOperationPlan() != getOperationPlan()->getOwner()
00200             && !l->isStart())
00201         {
00202           prevldplan = const_cast<LoadPlan*>(l);
00203           break;
00204         }
00205       }
00206     }
00207   }
00208   ld->getResource()->loadplans.erase(this);
00209   if (prevldplan) ld->getResource()->updateSetups(prevldplan);
00210 }
00211 
00212 
00213 DECLARE_EXPORT void LoadPlan::setLoad(const Load* newld)
00214 {
00215   // No change
00216   if (newld == ld) return;
00217 
00218   // Verify the data
00219   if (!newld) throw LogicException("Can't switch to NULL load");
00220   if (ld && ld->getOperation() != newld->getOperation())
00221     throw LogicException("Only switching to a load on the same operation is allowed");
00222 
00223   // Mark entities as changed
00224   if (oper) oper->getOperation()->setChanged();
00225   if (ld) ld->getResource()->setChanged();
00226   newld->getResource()->setChanged();
00227 
00228   // Update also the setup operationplan
00229   if (oper && oper->getOperation() != OperationSetup::setupoperation)
00230   {
00231     bool oldHasSetup = ld && !ld->getSetup().empty()
00232         && ld->getResource()->getSetupMatrix();
00233     bool newHasSetup = !newld->getSetup().empty()
00234         && newld->getResource()->getSetupMatrix();
00235     OperationPlan *setupOpplan = NULL;
00236     if (oldHasSetup)
00237     {
00238       for (OperationPlan::iterator i(oper); i != oper->end(); ++i)
00239         if (i->getOperation() == OperationSetup::setupoperation)
00240         {
00241           setupOpplan = &*i;
00242           break;
00243         }
00244       if (!setupOpplan) oldHasSetup = false;
00245     }
00246     if (oldHasSetup)
00247     {
00248       if (newHasSetup)
00249       {
00250         // Case 1: Both the old and new load require a setup
00251         LoadPlan *setupLdplan = NULL;
00252         for (OperationPlan::LoadPlanIterator j = setupOpplan->beginLoadPlans();
00253             j != setupOpplan->endLoadPlans(); ++j)
00254           if (j->getLoad() == ld)
00255           {
00256             setupLdplan = &*j;
00257             break;
00258           }
00259         if (!setupLdplan)
00260           throw LogicException("Can't find loadplan on setup operationplan");
00261         // Update the loadplan
00262         setupLdplan->setLoad(newld);
00263         setupOpplan->setEnd(setupOpplan->getDates().getEnd());
00264       }
00265       else
00266       {
00267         // Case 2: Delete the old setup which is not required any more
00268         oper->eraseSubOperationPlan(setupOpplan);
00269       }
00270     }
00271     else
00272     {
00273       if (newHasSetup)
00274       {
00275         // Case 3: Create a new setup operationplan
00276         OperationSetup::setupoperation->createOperationPlan(
00277           1, Date::infinitePast, oper->getDates().getEnd(), NULL, oper);
00278       }
00279       //else:
00280       // Case 4: No setup for the old or new load
00281     }
00282   }
00283 
00284   // Find the loadplan before the setup
00285   LoadPlan *prevldplan = NULL;
00286   if (getOperationPlan()->getOperation() == OperationSetup::setupoperation)
00287   {
00288     for (TimeLine<LoadPlan>::const_iterator i = getResource()->getLoadPlans().begin(isStart() ? getOtherLoadPlan() : this);
00289         i != getResource()->getLoadPlans().end(); --i)
00290     {
00291       const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
00292       if (l && l->getOperationPlan() != getOperationPlan()
00293           && l->getOperationPlan() != getOperationPlan()->getOwner()
00294           && !l->isStart())
00295       {
00296         prevldplan = const_cast<LoadPlan*>(l);
00297         break;
00298       }
00299     }
00300     if (!prevldplan)
00301     {
00302       for (TimeLine<LoadPlan>::const_iterator i = getResource()->getLoadPlans().begin(isStart() ? getOtherLoadPlan() : this);
00303           i != getResource()->getLoadPlans().end(); ++i)
00304       {
00305         const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
00306         if (l && l->getOperationPlan() != getOperationPlan()
00307             && l->getOperationPlan() != getOperationPlan()->getOwner()
00308             && !l->isStart())
00309         {
00310           prevldplan = const_cast<LoadPlan*>(l);
00311           break;
00312         }
00313       }
00314     }
00315   }
00316 
00317   // Change this loadplan and its brother
00318   for (LoadPlan *ldplan = getOtherLoadPlan(); true; )
00319   {
00320     // Remove from the old resource, if there is one
00321     if (ldplan->ld)
00322       ldplan->ld->getResource()->loadplans.erase(ldplan);
00323 
00324     // Insert in the new resource
00325     ldplan->ld = newld;
00326     newld->getResource()->loadplans.insert(
00327       ldplan,
00328       newld->getLoadplanQuantity(ldplan),
00329       newld->getLoadplanDate(ldplan)
00330     );
00331 
00332     // Repeat for the brother loadplan or exit
00333     if (ldplan != this) ldplan = this;
00334     else break;
00335   }
00336 
00337   // Update the setups on the old resource
00338   if (prevldplan)
00339     prevldplan->ld->getResource()->updateSetups(prevldplan);
00340 }
00341 
00342 
00343 PyObject* LoadPlan::getattro(const Attribute& attr)
00344 {
00345   if (attr.isA(Tags::tag_operationplan))
00346     return PythonObject(getOperationPlan());
00347   if (attr.isA(Tags::tag_quantity))
00348     return PythonObject(getQuantity());
00349   if (attr.isA(Tags::tag_startdate))
00350     return PythonObject(getDate());
00351   if (attr.isA(Tags::tag_enddate))
00352     return PythonObject(getOtherLoadPlan()->getDate());
00353   if (attr.isA(Tags::tag_resource)) // Convenient shortcut
00354     return PythonObject(getLoad()->getResource());
00355   if (attr.isA(Tags::tag_operation)) // Convenient shortcut
00356     return PythonObject(getLoad()->getOperation());
00357   if (attr.isA(Tags::tag_load))
00358     return PythonObject(getLoad());
00359   if (attr.isA(Tags::tag_onhand))
00360     return PythonObject(getOnhand());
00361   if (attr.isA(Tags::tag_setup))
00362     return PythonObject(getSetup());
00363   return NULL;
00364 }
00365 
00366 
00367 int LoadPlanIterator::initialize()
00368 {
00369   // Initialize the type
00370   PythonType& x = PythonExtension<LoadPlanIterator>::getType();
00371   x.setName("loadplanIterator");
00372   x.setDoc("frePPLe iterator for loadplan");
00373   x.supportiter();
00374   return x.typeReady();
00375 }
00376 
00377 
00378 PyObject* LoadPlanIterator::iternext()
00379 {
00380   LoadPlan* ld;
00381   if (resource_or_opplan)
00382   {
00383     // Skip zero quantity loadplans
00384     while (*resiter != res->getLoadPlans().end() && (*resiter)->getQuantity()==0.0)
00385       ++(*resiter);
00386     if (*resiter == res->getLoadPlans().end()) return NULL;
00387 
00388     // Return result
00389     ld = const_cast<LoadPlan*>(static_cast<const LoadPlan*>(&*((*resiter)++)));
00390   }
00391   else
00392   {
00393     while (*opplaniter != opplan->endLoadPlans() && (*opplaniter)->getQuantity()==0.0)
00394       ++(*opplaniter);
00395     if (*opplaniter == opplan->endLoadPlans()) return NULL;
00396     ld = static_cast<LoadPlan*>(&*((*opplaniter)++));
00397   }
00398   Py_INCREF(ld);
00399   return const_cast<LoadPlan*>(ld);
00400 }
00401 
00402 } // end namespace

Documentation generated for frePPLe by  doxygen