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

Documentation generated for frePPLe by  doxygen