00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #define FREPPLE_CORE
00029 #include "frepple/model.h"
00030 namespace frepple
00031 {
00032
00033 DECLARE_EXPORT const MetaCategory* Load::metadata;
00034
00035
00036 int Load::initialize()
00037 {
00038
00039 metadata = new MetaCategory
00040 ("load", "loads", MetaCategory::ControllerDefault, writer);
00041 const_cast<MetaCategory*>(metadata)->registerClass(
00042 "load","load",true,Object::createDefault<Load>
00043 );
00044
00045
00046 PythonType& x = FreppleCategory<Load>::getType();
00047 x.setName("load");
00048 x.setDoc("frePPLe load");
00049 x.supportgetattro();
00050 x.supportsetattro();
00051 x.supportcreate(create);
00052 x.addMethod("toXML", toXML, METH_VARARGS, "return a XML representation");
00053 const_cast<MetaCategory*>(Load::metadata)->pythonClass = x.type_object();
00054 return x.typeReady();
00055 }
00056
00057
00058 void Load::writer(const MetaCategory* c, XMLOutput* o)
00059 {
00060 bool firstload = true;
00061 for (Operation::iterator i = Operation::begin(); i != Operation::end(); ++i)
00062 for (Operation::loadlist::const_iterator j = i->getLoads().begin(); j != i->getLoads().end(); ++j)
00063 {
00064 if (firstload)
00065 {
00066 o->BeginObject(Tags::tag_loads);
00067 firstload = false;
00068 }
00069
00070
00071 o->writeElement(Tags::tag_load, &*j, FULL);
00072 }
00073 if (!firstload) o->EndObject(Tags::tag_loads);
00074 }
00075
00076
00077 DECLARE_EXPORT void Load::validate(Action action)
00078 {
00079
00080 Operation *oper = getOperation();
00081 Resource *res = getResource();
00082 if (!oper || !res)
00083 {
00084
00085 delete this;
00086 if (!oper && !res)
00087 throw DataException("Missing operation and resource on a load");
00088 else if (!oper)
00089 throw DataException("Missing operation on a load on resource '"
00090 + res->getName() + "'");
00091 else if (!res)
00092 throw DataException("Missing resource on a load on operation '"
00093 + oper->getName() + "'");
00094 }
00095
00096
00097
00098 Operation::loadlist::const_iterator i = oper->getLoads().begin();
00099 for (;i != oper->getLoads().end(); ++i)
00100 if (i->getResource() == res
00101 && i->getEffective().overlap(getEffective())
00102 && &*i != this)
00103 break;
00104
00105
00106 switch (action)
00107 {
00108 case ADD:
00109 if (i != oper->getLoads().end())
00110 {
00111 delete this;
00112 throw DataException("Load of '" + oper->getName() + "' and '"
00113 + res->getName() + "' already exists");
00114 }
00115 break;
00116 case CHANGE:
00117 delete this;
00118 throw DataException("Can't update a load");
00119 case ADD_CHANGE:
00120
00121 if (i == oper->getLoads().end()) break;
00122 delete this;
00123 throw DataException("Can't update a load");
00124 case REMOVE:
00125
00126 delete this;
00127 if (i == oper->getLoads().end())
00128
00129 throw DataException("Can't remove nonexistent load of '"
00130 + oper->getName() + "' and '" + res->getName() + "'");
00131 delete &*i;
00132
00133 HasLevel::triggerLazyRecomputation();
00134 return;
00135 }
00136
00137
00138
00139
00140
00141 if (res->hasOwner() && action!=REMOVE) new Load(oper, res->getOwner(), qty);
00142
00143
00144 HasLevel::triggerLazyRecomputation();
00145 }
00146
00147
00148 DECLARE_EXPORT Load::~Load()
00149 {
00150
00151 HasLevel::triggerLazyRecomputation();
00152
00153
00154 if (getOperation() && getResource())
00155 {
00156
00157 for(OperationPlan::iterator i(getOperation()); i != OperationPlan::end(); ++i)
00158
00159 for(OperationPlan::LoadPlanIterator j = i->beginLoadPlans(); j != i->endLoadPlans(); )
00160 if (j->getLoad() == this) j.deleteLoadPlan();
00161 else ++j;
00162 }
00163
00164
00165 if (getOperation()) getOperation()->loaddata.erase(this);
00166 if (getResource()) getResource()->loads.erase(this);
00167
00168
00169 if (hasAlts)
00170 {
00171
00172
00173
00174 unsigned short cnt = 0;
00175 int minprio = INT_MAX;
00176 Load* newLeader = NULL;
00177 for (Operation::loadlist::iterator i = getOperation()->loaddata.begin();
00178 i != getOperation()->loaddata.end(); ++i)
00179 if (i->altLoad == this)
00180 {
00181 cnt++;
00182 if (i->priority < minprio)
00183 {
00184 newLeader = &*i;
00185 minprio = i->priority;
00186 }
00187 }
00188 if (cnt < 1)
00189 throw LogicException("Alternate loads update failure");
00190 else if (cnt == 1)
00191
00192 newLeader->altLoad = NULL;
00193 else
00194 {
00195
00196 newLeader->hasAlts = true;
00197 newLeader->altLoad = NULL;
00198 for (Operation::loadlist::iterator i = getOperation()->loaddata.begin();
00199 i != getOperation()->loaddata.end(); ++i)
00200 if (i->altLoad == this) i->altLoad = newLeader;
00201 }
00202 }
00203 if (altLoad)
00204 {
00205
00206
00207
00208 bool only_one = true;
00209 for (Operation::loadlist::iterator i = getOperation()->loaddata.begin();
00210 i != getOperation()->loaddata.end(); ++i)
00211 if (i->altLoad == altLoad)
00212 {
00213 only_one = false;
00214 break;
00215 }
00216 if (only_one) altLoad->hasAlts = false;
00217 }
00218 }
00219
00220
00221 DECLARE_EXPORT void Load::setAlternate(Load *f)
00222 {
00223
00224 if (!f)
00225 throw DataException("Setting NULL alternate load");
00226 if (hasAlts || f->altLoad)
00227 throw DataException("Nested alternate loads are not allowed");
00228
00229
00230 f->hasAlts = true;
00231 altLoad = f;
00232 }
00233
00234
00235 DECLARE_EXPORT void Load::setAlternate(const string& n)
00236 {
00237 if (!getOperation())
00238 throw LogicException("Can't set an alternate load before setting the operation");
00239 Load *x = getOperation()->loaddata.find(n);
00240 if (!x) throw DataException("Can't find load with name '" + n + "'");
00241 setAlternate(x);
00242 }
00243
00244
00245 DECLARE_EXPORT void Load::setSetup(const string n)
00246 {
00247 setup = n;
00248
00249 if (!setup.empty())
00250 {
00251
00252
00253 for (Operation::loadlist::iterator i = getOperation()->loaddata.begin();
00254 i != getOperation()->loaddata.end(); ++i)
00255 if (&*i != this && !i->setup.empty()
00256 && i->getAlternate() != this && getAlternate() != &*i
00257 && i->getAlternate() != getAlternate())
00258 throw DataException("Only a single load of an operation can specify a setup");
00259 }
00260 }
00261
00262
00263 DECLARE_EXPORT void Load::writeElement(XMLOutput *o, const Keyword& tag, mode m) const
00264 {
00265
00266
00267 if (m == REFERENCE) return;
00268 assert(m != NOHEADER);
00269
00270 o->BeginObject(tag);
00271
00272
00273
00274 if (!dynamic_cast<Operation*>(o->getPreviousObject()))
00275 o->writeElement(Tags::tag_operation, getOperation());
00276
00277
00278
00279 if (!dynamic_cast<Resource*>(o->getPreviousObject()))
00280 o->writeElement(Tags::tag_resource, getResource());
00281
00282
00283 if (qty != 1.0) o->writeElement(Tags::tag_quantity, qty);
00284 if (getPriority()!=1) o->writeElement(Tags::tag_priority, getPriority());
00285 if (!getName().empty()) o->writeElement(Tags::tag_name, getName());
00286 if (getAlternate())
00287 o->writeElement(Tags::tag_alternate, getAlternate()->getName());
00288 if (search != PRIORITY)
00289 {
00290 ostringstream ch;
00291 ch << getSearch();
00292 o->writeElement(Tags::tag_search, ch.str());
00293 }
00294
00295
00296 if (getEffective().getStart() != Date::infinitePast)
00297 o->writeElement(Tags::tag_effective_start, getEffective().getStart());
00298 if (getEffective().getEnd() != Date::infiniteFuture)
00299 o->writeElement(Tags::tag_effective_end, getEffective().getEnd());
00300
00301
00302 if (!setup.empty()) o->writeElement(Tags::tag_setup, setup);
00303
00304 o->EndObject(tag);
00305 }
00306
00307
00308 DECLARE_EXPORT void Load::beginElement(XMLInput& pIn, const Attribute& pAttr)
00309 {
00310 if (pAttr.isA (Tags::tag_resource))
00311 pIn.readto( Resource::reader(Resource::metadata,pIn.getAttributes()) );
00312 else if (pAttr.isA (Tags::tag_operation))
00313 pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
00314 }
00315
00316
00317 DECLARE_EXPORT void Load::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00318 {
00319 if (pAttr.isA (Tags::tag_resource))
00320 {
00321 Resource * r = dynamic_cast<Resource*>(pIn.getPreviousObject());
00322 if (r) setResource(r);
00323 else throw LogicException("Incorrect object type during read operation");
00324 }
00325 else if (pAttr.isA (Tags::tag_operation))
00326 {
00327 Operation * o = dynamic_cast<Operation*>(pIn.getPreviousObject());
00328 if (o) setOperation(o);
00329 else throw LogicException("Incorrect object type during read operation");
00330 }
00331 else if (pAttr.isA(Tags::tag_quantity))
00332 setQuantity(pElement.getDouble());
00333 else if (pAttr.isA(Tags::tag_priority))
00334 setPriority(pElement.getInt());
00335 else if (pAttr.isA(Tags::tag_name))
00336 setName(pElement.getString());
00337 else if (pAttr.isA(Tags::tag_alternate))
00338 setAlternate(pElement.getString());
00339 else if (pAttr.isA(Tags::tag_search))
00340 setSearch(pElement.getString());
00341 else if (pAttr.isA(Tags::tag_setup))
00342 setSetup(pElement.getString());
00343 else if (pAttr.isA(Tags::tag_action))
00344 {
00345 delete static_cast<Action*>(pIn.getUserArea());
00346 pIn.setUserArea(
00347 new Action(MetaClass::decodeAction(pElement.getString().c_str()))
00348 );
00349 }
00350 else if (pAttr.isA(Tags::tag_effective_end))
00351 setEffectiveEnd(pElement.getDate());
00352 else if (pAttr.isA(Tags::tag_effective_start))
00353 setEffectiveStart(pElement.getDate());
00354 else if (pIn.isObjectEnd())
00355 {
00356
00357 validate(!pIn.getUserArea() ?
00358 ADD_CHANGE :
00359 *static_cast<Action*>(pIn.getUserArea())
00360 );
00361 delete static_cast<Action*>(pIn.getUserArea());
00362 }
00363 }
00364
00365
00366 DECLARE_EXPORT PyObject* Load::getattro(const Attribute& attr)
00367 {
00368 if (attr.isA(Tags::tag_resource))
00369 return PythonObject(getResource());
00370 if (attr.isA(Tags::tag_operation))
00371 return PythonObject(getOperation());
00372 if (attr.isA(Tags::tag_quantity))
00373 return PythonObject(getQuantity());
00374 if (attr.isA(Tags::tag_priority))
00375 return PythonObject(getPriority());
00376 if (attr.isA(Tags::tag_effective_end))
00377 return PythonObject(getEffective().getEnd());
00378 if (attr.isA(Tags::tag_effective_start))
00379 return PythonObject(getEffective().getStart());
00380 if (attr.isA(Tags::tag_name))
00381 return PythonObject(getName());
00382 if (attr.isA(Tags::tag_alternate))
00383 return PythonObject(getAlternate());
00384 if (attr.isA(Tags::tag_search))
00385 {
00386 ostringstream ch;
00387 ch << getSearch();
00388 return PythonObject(ch.str());
00389 }
00390 if (attr.isA(Tags::tag_setup))
00391 return PythonObject(getSetup());
00392 return NULL;
00393 }
00394
00395
00396 DECLARE_EXPORT int Load::setattro(const Attribute& attr, const PythonObject& field)
00397 {
00398 if (attr.isA(Tags::tag_resource))
00399 {
00400 if (!field.check(Resource::metadata))
00401 {
00402 PyErr_SetString(PythonDataException, "load resource must be of type resource");
00403 return -1;
00404 }
00405 Resource* y = static_cast<Resource*>(static_cast<PyObject*>(field));
00406 setResource(y);
00407 }
00408 else if (attr.isA(Tags::tag_operation))
00409 {
00410 if (!field.check(Operation::metadata))
00411 {
00412 PyErr_SetString(PythonDataException, "load operation must be of type operation");
00413 return -1;
00414 }
00415 Operation* y = static_cast<Operation*>(static_cast<PyObject*>(field));
00416 setOperation(y);
00417 }
00418 else if (attr.isA(Tags::tag_quantity))
00419 setQuantity(field.getDouble());
00420 else if (attr.isA(Tags::tag_priority))
00421 setPriority(field.getInt());
00422 else if (attr.isA(Tags::tag_effective_end))
00423 setEffectiveEnd(field.getDate());
00424 else if (attr.isA(Tags::tag_effective_start))
00425 setEffectiveStart(field.getDate());
00426 else if (attr.isA(Tags::tag_name))
00427 setName(field.getString());
00428 else if (attr.isA(Tags::tag_alternate))
00429 {
00430 if (!field.check(Load::metadata))
00431 setAlternate(field.getString());
00432 else
00433 {
00434 Load *y = static_cast<Load*>(static_cast<PyObject*>(field));
00435 setAlternate(y);
00436 }
00437 }
00438 else if (attr.isA(Tags::tag_search))
00439 setSearch(field.getString());
00440 else if (attr.isA(Tags::tag_setup))
00441 setSetup(field.getString());
00442 else
00443 return -1;
00444 return 0;
00445 }
00446
00447
00448
00449 PyObject* Load::create(PyTypeObject* pytype, PyObject* args, PyObject* kwds)
00450 {
00451 try
00452 {
00453
00454 PyObject* oper = PyDict_GetItemString(kwds,"operation");
00455 if (!PyObject_TypeCheck(oper, Operation::metadata->pythonClass))
00456 throw DataException("load operation must be of type operation");
00457
00458
00459 PyObject* res = PyDict_GetItemString(kwds,"resource");
00460 if (!PyObject_TypeCheck(res, Resource::metadata->pythonClass))
00461 throw DataException("load resource must be of type resource");
00462
00463
00464 PyObject* q1 = PyDict_GetItemString(kwds,"quantity");
00465 double q2 = q1 ? PythonObject(q1).getDouble() : 1.0;
00466
00467
00468 Load *l = new Load(
00469 static_cast<Operation*>(oper),
00470 static_cast<Resource*>(res),
00471 q2
00472 );
00473
00474
00475 PyObject* eff_start = PyDict_GetItemString(kwds,"effective_start");
00476 if (eff_start)
00477 {
00478 PythonObject d(eff_start);
00479 l->setEffectiveStart(d.getDate());
00480 }
00481
00482
00483 PyObject* eff_end = PyDict_GetItemString(kwds,"effective_end");
00484 if (eff_end)
00485 {
00486 PythonObject d(eff_end);
00487 l->setEffectiveEnd(d.getDate());
00488 }
00489
00490
00491 Py_INCREF(l);
00492 return static_cast<PyObject*>(l);
00493 }
00494 catch (...)
00495 {
00496 PythonType::evalException();
00497 return NULL;
00498 }
00499 }
00500
00501
00502 int LoadIterator::initialize()
00503 {
00504
00505 PythonType& x = PythonExtension<LoadIterator>::getType();
00506 x.setName("loadIterator");
00507 x.setDoc("frePPLe iterator for loads");
00508 x.supportiter();
00509 return x.typeReady();
00510 }
00511
00512
00513 PyObject* LoadIterator::iternext()
00514 {
00515 PyObject* result;
00516 if (res)
00517 {
00518
00519 if (ir == res->getLoads().end()) return NULL;
00520 result = const_cast<Load*>(&*ir);
00521 ++ir;
00522 }
00523 else
00524 {
00525
00526 if (io == oper->getLoads().end()) return NULL;
00527 result = const_cast<Load*>(&*io);
00528 ++io;
00529 }
00530 Py_INCREF(result);
00531 return result;
00532 }
00533
00534 }