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
00031 namespace frepple
00032 {
00033
00034 template<class Operation> DECLARE_EXPORT Tree utils::HasName<Operation>::st;
00035 DECLARE_EXPORT const MetaCategory* Operation::metadata;
00036 DECLARE_EXPORT const MetaClass* OperationFixedTime::metadata,
00037 *OperationTimePer::metadata,
00038 *OperationRouting::metadata,
00039 *OperationAlternate::metadata,
00040 *OperationSetup::metadata;
00041 DECLARE_EXPORT Operation::Operationlist Operation::nosubOperations;
00042 DECLARE_EXPORT const Operation* OperationSetup::setupoperation;
00043
00044
00045 int Operation::initialize()
00046 {
00047
00048 metadata = new MetaCategory("operation", "operations", reader, writer);
00049
00050
00051 return FreppleCategory<Operation>::initialize();
00052 }
00053
00054
00055 int OperationFixedTime::initialize()
00056 {
00057
00058 metadata = new MetaClass("operation", "operation_fixed_time",
00059 Object::createString<OperationFixedTime>, true);
00060
00061
00062 return FreppleClass<OperationFixedTime,Operation>::initialize();
00063 }
00064
00065
00066 int OperationTimePer::initialize()
00067 {
00068
00069 metadata = new MetaClass("operation", "operation_time_per",
00070 Object::createString<OperationTimePer>);
00071
00072
00073 return FreppleClass<OperationTimePer,Operation>::initialize();
00074 }
00075
00076
00077 int OperationAlternate::initialize()
00078 {
00079
00080 metadata = new MetaClass("operation", "operation_alternate",
00081 Object::createString<OperationAlternate>);
00082
00083
00084 FreppleClass<OperationAlternate,Operation>::getType().addMethod("addAlternate", OperationAlternate::addAlternate, METH_KEYWORDS, "add an alternate");
00085 return FreppleClass<OperationAlternate,Operation>::initialize();
00086 }
00087
00088
00089 int OperationRouting::initialize()
00090 {
00091
00092 metadata = new MetaClass("operation", "operation_routing",
00093 Object::createString<OperationRouting>);
00094
00095
00096 FreppleClass<OperationRouting,Operation>::getType().addMethod("addStep", OperationRouting::addStep, METH_VARARGS , "add steps to the routing");
00097 return FreppleClass<OperationRouting,Operation>::initialize();
00098 }
00099
00100
00101 int OperationSetup::initialize()
00102 {
00103
00104
00105 metadata = new MetaClass("operation", "operation_setup");
00106
00107
00108 int tmp = FreppleClass<OperationSetup,Operation>::initialize();
00109
00110
00111
00112 setupoperation = add(new OperationSetup("setup operation"));
00113
00114 return tmp;
00115 }
00116
00117
00118 DECLARE_EXPORT Operation::~Operation()
00119 {
00120
00121 deleteOperationPlans(true);
00122
00123
00124
00125
00126
00127 for (Item::iterator k = Item::begin(); k != Item::end(); ++k)
00128 if (k->getOperation() == this) k->setOperation(NULL);
00129
00130
00131 for (Demand::iterator l = Demand::begin(); l != Demand::end(); ++l)
00132 if (l->getOperation() == this) l->setOperation(NULL);
00133
00134
00135 for (Buffer::iterator m = Buffer::begin(); m != Buffer::end(); ++m)
00136 if (m->getProducingOperation() == this) m->setProducingOperation(NULL);
00137
00138
00139
00140
00141
00142 while (!getSuperOperations().empty())
00143 removeSuperOperation(*getSuperOperations().begin());
00144 }
00145
00146
00147 DECLARE_EXPORT OperationRouting::~OperationRouting()
00148 {
00149
00150
00151
00152 while (!getSubOperations().empty())
00153 removeSubOperation(*getSubOperations().begin());
00154 }
00155
00156
00157 DECLARE_EXPORT OperationAlternate::~OperationAlternate()
00158 {
00159
00160
00161
00162 while (!getSubOperations().empty())
00163 removeSubOperation(*getSubOperations().begin());
00164 }
00165
00166
00167 DECLARE_EXPORT OperationPlan* Operation::createOperationPlan (double q, Date s, Date e,
00168 Demand* l, OperationPlan* ow, unsigned long i,
00169 bool makeflowsloads) const
00170 {
00171 OperationPlan *opplan = new OperationPlan();
00172 initOperationPlan(opplan,q,s,e,l,ow,i,makeflowsloads);
00173 return opplan;
00174 }
00175
00176
00177 DECLARE_EXPORT DateRange Operation::calculateOperationTime
00178 (Date thedate, TimePeriod duration, bool forward,
00179 TimePeriod *actualduration) const
00180 {
00181 int calcount = 0;
00182
00183 vector<Calendar::EventIterator*> cals(10);
00184
00185
00186 if (actualduration) *actualduration = duration;
00187
00188 try
00189 {
00190
00191
00192 if (loc && loc->getAvailable())
00193 cals[calcount++] = new Calendar::EventIterator(loc->getAvailable(), thedate, forward);
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 if (calcount == 0)
00216 return forward ?
00217 DateRange(thedate, thedate+duration) :
00218 DateRange(thedate-duration, thedate);
00219
00220
00221
00222 DateRange result;
00223 Date curdate = thedate;
00224 bool status = false;
00225 TimePeriod curduration = duration;
00226 while (true)
00227 {
00228
00229 bool available = true;
00230 for (int c = 0; c < calcount && available; c++)
00231 {
00232 if (cals[c]->getBucket())
00233 available = cals[c]->getBucket()->getBool();
00234 else
00235 available = cals[c]->getCalendar()->getBool();
00236 }
00237 curdate = cals[0]->getDate();
00238
00239 if (available && !status)
00240 {
00241
00242 thedate = curdate;
00243 status = true;
00244 if (forward && result.getStart() == Date::infinitePast)
00245
00246 result.setStart(curdate);
00247 else if (!forward && result.getEnd() == Date::infiniteFuture)
00248
00249 result.setEnd(curdate);
00250 }
00251 else if (!available && status)
00252 {
00253
00254 status = false;
00255 if (forward)
00256 {
00257
00258 TimePeriod delta = curdate - thedate;
00259 if (delta >= curduration)
00260 {
00261 result.setEnd(thedate + curduration);
00262 break;
00263 }
00264 else
00265 curduration -= delta;
00266 }
00267 else
00268 {
00269
00270 TimePeriod delta = thedate - curdate;
00271 if (delta >= curduration)
00272 {
00273 result.setStart(thedate - curduration);
00274 break;
00275 }
00276 else
00277 curduration -= delta;
00278 }
00279 }
00280 else if (forward && curdate == Date::infiniteFuture)
00281 {
00282
00283 if (available)
00284 {
00285 TimePeriod delta = curdate - thedate;
00286 if (delta >= curduration)
00287 result.setEnd(thedate + curduration);
00288 else if (actualduration)
00289 *actualduration = duration - curduration;
00290 }
00291 else if (actualduration)
00292 *actualduration = duration - curduration;
00293 break;
00294 }
00295 else if (!forward && curdate == Date::infinitePast)
00296 {
00297
00298 if (available)
00299 {
00300 TimePeriod delta = thedate - curdate;
00301 if (delta >= curduration)
00302 result.setStart(thedate - curduration);
00303 else if (actualduration)
00304 *actualduration = duration - curduration;
00305 }
00306 else if (actualduration)
00307 *actualduration = duration - curduration;
00308 break;
00309 }
00310
00311
00312 if (forward) ++(*cals[0]);
00313 else --(*cals[0]);
00314 }
00315
00316
00317 while (calcount) delete cals[--calcount];
00318 return result;
00319 }
00320 catch (...)
00321 {
00322
00323 while (calcount) delete cals[calcount--];
00324
00325 throw;
00326 }
00327 }
00328
00329
00330 DECLARE_EXPORT DateRange Operation::calculateOperationTime
00331 (Date start, Date end, TimePeriod *actualduration) const
00332 {
00333
00334 if (end < start)
00335 {
00336 Date tmp = start;
00337 start = end;
00338 end = tmp;
00339 }
00340
00341 int calcount = 0;
00342
00343 vector<Calendar::EventIterator*> cals(10);
00344
00345
00346 if (actualduration) *actualduration = 0L;
00347
00348 try
00349 {
00350
00351
00352 if (loc && loc->getAvailable())
00353 cals[calcount++] = new Calendar::EventIterator(loc->getAvailable(), start);
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 if (calcount == 0)
00376 {
00377 if (actualduration) *actualduration = end - start;
00378 return DateRange(start, end);
00379 }
00380
00381
00382
00383 DateRange result;
00384 Date curdate = start;
00385 bool status = false;
00386 while (true)
00387 {
00388
00389 bool available = true;
00390 for (int c = 0; c < calcount && available; c++)
00391 {
00392 if (cals[c]->getBucket())
00393 available = cals[c]->getBucket()->getBool();
00394 else
00395 available = cals[c]->getCalendar()->getBool();
00396 }
00397 curdate = cals[0]->getDate();
00398
00399 if (available && !status)
00400 {
00401
00402 if (curdate >= end)
00403 {
00404
00405 result.setEnd(start);
00406 break;
00407 }
00408 start = curdate;
00409 status = true;
00410 if (result.getStart() == Date::infinitePast)
00411
00412 result.setStart(curdate);
00413 }
00414 else if (!available && status)
00415 {
00416
00417 if (curdate >= end)
00418 {
00419
00420 if (actualduration) *actualduration += end - start;
00421 result.setEnd(end);
00422 break;
00423 }
00424 status = false;
00425 if (actualduration) *actualduration += curdate - start;
00426 start = curdate;
00427 }
00428 else if (curdate >= end)
00429 {
00430
00431 if (available)
00432 {
00433 if (actualduration) *actualduration += end - start;
00434 result.setEnd(end);
00435 break;
00436 }
00437 else
00438 result.setEnd(start);
00439 break;
00440 }
00441
00442
00443 ++(*cals[0]);
00444 }
00445
00446
00447 while (calcount) delete cals[--calcount];
00448 return result;
00449 }
00450 catch (...)
00451 {
00452
00453 while (calcount) delete cals[calcount--];
00454
00455 throw;
00456 }
00457 }
00458
00459
00460 DECLARE_EXPORT void Operation::initOperationPlan (OperationPlan* opplan,
00461 double q, const Date& s, const Date& e, Demand* l, OperationPlan* ow,
00462 unsigned long i, bool makeflowsloads) const
00463 {
00464 opplan->oper = const_cast<Operation*>(this);
00465 opplan->setDemand(l);
00466 opplan->id = i;
00467
00468
00469
00470 opplan->setOwner(ow);
00471
00472
00473 setOperationPlanParameters(opplan,q,s,e);
00474
00475
00476 if (makeflowsloads) opplan->createFlowLoads();
00477
00478
00479 opplan->update();
00480 }
00481
00482
00483 DECLARE_EXPORT void Operation::deleteOperationPlans(bool deleteLockedOpplans)
00484 {
00485 OperationPlan::deleteOperationPlans(this, deleteLockedOpplans);
00486 }
00487
00488
00489 DECLARE_EXPORT void Operation::writeElement(XMLOutput *o, const Keyword& tag, mode m) const
00490 {
00491
00492
00493 assert(m == NOHEADER);
00494
00495
00496 HasDescription::writeElement(o, tag);
00497 Plannable::writeElement(o, tag);
00498 if (post_time)
00499 o->writeElement(Tags::tag_posttime, post_time);
00500 if (pre_time)
00501 o->writeElement(Tags::tag_pretime, pre_time);
00502 if (getCost() != 0.0)
00503 o->writeElement(Tags::tag_cost, getCost());
00504 if (fence)
00505 o->writeElement(Tags::tag_fence, fence);
00506 if (size_minimum != 1.0)
00507 o->writeElement(Tags::tag_size_minimum, size_minimum);
00508 if (size_multiple > 0.0)
00509 o->writeElement(Tags::tag_size_multiple, size_multiple);
00510 if (size_maximum < DBL_MAX)
00511 o->writeElement(Tags::tag_size_maximum, size_maximum);
00512 if (loc)
00513 o->writeElement(Tags::tag_location, loc);
00514
00515
00516 if ((o->getContentType() == XMLOutput::PLAN
00517 || o->getContentType() == XMLOutput::PLANDETAIL) && first_opplan)
00518 {
00519 o->BeginObject(Tags::tag_operationplans);
00520 for (OperationPlan::iterator i(this); i!=OperationPlan::end(); ++i)
00521 o->writeElement(Tags::tag_operationplan, *i, FULL);
00522 o->EndObject(Tags::tag_operationplans);
00523 }
00524 }
00525
00526
00527 DECLARE_EXPORT void Operation::beginElement(XMLInput& pIn, const Attribute& pAttr)
00528 {
00529 if (pAttr.isA(Tags::tag_flow)
00530 && pIn.getParentElement().first.isA(Tags::tag_flows))
00531 {
00532 Flow *f =
00533 dynamic_cast<Flow*>(MetaCategory::ControllerDefault(Flow::metadata,pIn.getAttributes()));
00534 if (f) f->setOperation(this);
00535 pIn.readto(f);
00536 }
00537 else if (pAttr.isA (Tags::tag_load)
00538 && pIn.getParentElement().first.isA(Tags::tag_loads))
00539 {
00540 Load* l = new Load();
00541 l->setOperation(this);
00542 pIn.readto(&*l);
00543 }
00544 else if (pAttr.isA (Tags::tag_operationplan))
00545 pIn.readto(OperationPlan::createOperationPlan(OperationPlan::metadata, pIn.getAttributes()));
00546 else if (pAttr.isA (Tags::tag_location))
00547 pIn.readto( Location::reader(Location::metadata,pIn.getAttributes()) );
00548 }
00549
00550
00551 DECLARE_EXPORT void Operation::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00552 {
00553 if (pAttr.isA (Tags::tag_fence))
00554 setFence(pElement.getTimeperiod());
00555 else if (pAttr.isA (Tags::tag_size_minimum))
00556 setSizeMinimum(pElement.getDouble());
00557 else if (pAttr.isA (Tags::tag_cost))
00558 setCost(pElement.getDouble());
00559 else if (pAttr.isA (Tags::tag_size_multiple))
00560 setSizeMultiple(pElement.getDouble());
00561 else if (pAttr.isA (Tags::tag_size_maximum))
00562 setSizeMaximum(pElement.getDouble());
00563 else if (pAttr.isA (Tags::tag_pretime))
00564 setPreTime(pElement.getTimeperiod());
00565 else if (pAttr.isA (Tags::tag_posttime))
00566 setPostTime(pElement.getTimeperiod());
00567 else if (pAttr.isA (Tags::tag_location))
00568 {
00569 Location *l = dynamic_cast<Location*>(pIn.getPreviousObject());
00570 if (l) setLocation(l);
00571 else throw LogicException("Incorrect object type during read operation");
00572 }
00573 else
00574 {
00575 Plannable::endElement(pIn, pAttr, pElement);
00576 HasDescription::endElement(pIn, pAttr, pElement);
00577 }
00578 }
00579
00580
00581 DECLARE_EXPORT OperationPlanState
00582 OperationFixedTime::setOperationPlanParameters
00583 (OperationPlan* opplan, double q, Date s, Date e, bool preferEnd, bool execute) const
00584 {
00585
00586 if (!opplan || q<0)
00587 throw LogicException("Incorrect parameters for fixedtime operationplan");
00588 if (opplan->getLocked())
00589 return OperationPlanState(opplan);
00590
00591
00592 if (q > 0 && q < getSizeMinimum()) q = getSizeMinimum();
00593 if (fabs(q - opplan->getQuantity()) > ROUNDING_ERROR)
00594 q = opplan->setQuantity(q, false, false, execute);
00595
00596
00597 DateRange x;
00598 TimePeriod actualduration;
00599 if (e && s)
00600 {
00601 if (preferEnd) x = calculateOperationTime(e, duration, false, &actualduration);
00602 else x = calculateOperationTime(s, duration, true, &actualduration);
00603 }
00604 else if (s) x = calculateOperationTime(s, duration, true, &actualduration);
00605 else x = calculateOperationTime(e, duration, false, &actualduration);
00606 if (!execute)
00607
00608 return OperationPlanState(x, actualduration == duration ? q : 0);
00609 else if (actualduration == duration)
00610
00611 opplan->setStartAndEnd(x.getStart(), x.getEnd());
00612 else
00613
00614 opplan->setQuantity(0);
00615
00616
00617 return OperationPlanState(opplan);
00618 }
00619
00620
00621 DECLARE_EXPORT bool OperationFixedTime::extraInstantiate(OperationPlan* o)
00622 {
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635 if (!o->getIdentifier() && !o->getLocked() && !o->getOwner() && getLoads().empty())
00636 {
00637
00638 OperationPlan::iterator x(this);
00639 OperationPlan *y = NULL;
00640 for (; x != OperationPlan::end() && *x < *o; ++x)
00641 y = &*x;
00642 if (y && y->getDates() == o->getDates() && !y->getOwner()
00643 && y->getDemand() == o->getDemand() && !y->getLocked() && y->getIdentifier()
00644 && y->getQuantity() + o->getQuantity() < getSizeMaximum())
00645 {
00646
00647 OperationPlan::FlowPlanIterator fp1 = o->beginFlowPlans();
00648 OperationPlan::FlowPlanIterator fp2 = y->beginFlowPlans();
00649 while (fp1 != o->endFlowPlans())
00650 {
00651 if (fp1->getBuffer() != fp2->getBuffer())
00652
00653 return true;
00654 ++fp1;
00655 ++fp2;
00656 }
00657
00658 y->setQuantity(y->getQuantity() + o->getQuantity());
00659 return false;
00660 }
00661 if (x!= OperationPlan::end() && x->getDates() == o->getDates() && !x->getOwner()
00662 && x->getDemand() == o->getDemand() && !x->getLocked() && x->getIdentifier()
00663 && x->getQuantity() + o->getQuantity() < getSizeMaximum())
00664 {
00665
00666 OperationPlan::FlowPlanIterator fp1 = o->beginFlowPlans();
00667 OperationPlan::FlowPlanIterator fp2 = x->beginFlowPlans();
00668 while (fp1 != o->endFlowPlans())
00669 {
00670 if (fp1->getBuffer() != fp2->getBuffer())
00671
00672 return true;
00673 ++fp1;
00674 ++fp2;
00675 }
00676
00677 x->setQuantity(x->getQuantity() + o->getQuantity());
00678 return false;
00679 }
00680 }
00681 return true;
00682 }
00683
00684
00685 DECLARE_EXPORT void OperationFixedTime::writeElement
00686 (XMLOutput *o, const Keyword& tag, mode m) const
00687 {
00688
00689 if (m == REFERENCE)
00690 {
00691 o->writeElement
00692 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00693 return;
00694 }
00695
00696
00697 if (m != NOHEADER) o->BeginObject
00698 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00699
00700
00701 Operation::writeElement(o, tag, NOHEADER);
00702 if (duration) o->writeElement (Tags::tag_duration, duration);
00703 o->EndObject (tag);
00704 }
00705
00706
00707 DECLARE_EXPORT void OperationFixedTime::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00708 {
00709 if (pAttr.isA (Tags::tag_duration))
00710 setDuration (pElement.getTimeperiod());
00711 else
00712 Operation::endElement (pIn, pAttr, pElement);
00713 }
00714
00715
00716 DECLARE_EXPORT OperationPlanState
00717 OperationTimePer::setOperationPlanParameters
00718 (OperationPlan* opplan, double q, Date s, Date e, bool preferEnd, bool execute) const
00719 {
00720
00721 if (!opplan || q<0)
00722 throw LogicException("Incorrect parameters for timeper operationplan");
00723 if (opplan->getLocked())
00724 return OperationPlanState(opplan);
00725
00726
00727 if (q > 0 && q < getSizeMinimum()) q = getSizeMinimum();
00728
00729
00730 DateRange x;
00731 TimePeriod actual;
00732 if (s && e)
00733 {
00734
00735
00736 x = calculateOperationTime(s,e,&actual);
00737 if (actual < duration)
00738 {
00739
00740
00741 if (!execute) return OperationPlanState(x,0);
00742 opplan->setQuantity(0,true,false,execute);
00743 opplan->setEnd(e);
00744 }
00745 else
00746 {
00747
00748 if (duration_per)
00749 {
00750 if (q * duration_per < static_cast<double>(actual - duration) + 1)
00751
00752
00753 q = opplan->setQuantity(q, true, false, execute);
00754 else
00755
00756 q = opplan->setQuantity(
00757 static_cast<double>(actual - duration) / duration_per,
00758 true, false, execute);
00759 }
00760 else
00761
00762 q = opplan->setQuantity(q, true, false, execute);
00763
00764
00765 TimePeriod wanted(
00766 duration + static_cast<long>(duration_per * q)
00767 );
00768 if (preferEnd) x = calculateOperationTime(e, wanted, false, &actual);
00769 else x = calculateOperationTime(s, wanted, true, &actual);
00770 if (!execute) return OperationPlanState(x,q);
00771 opplan->setStartAndEnd(x.getStart(),x.getEnd());
00772 }
00773 }
00774 else if (e || !s)
00775 {
00776
00777
00778
00779
00780 q = opplan->setQuantity(q,true,false,execute);
00781 TimePeriod wanted(duration + static_cast<long>(duration_per * q));
00782 x = calculateOperationTime(e, wanted, false, &actual);
00783 if (actual == wanted)
00784 {
00785
00786 if (!execute) return OperationPlanState(x, q);
00787 opplan->setStartAndEnd(x.getStart(),x.getEnd());
00788 }
00789 else if (actual < duration)
00790 {
00791
00792 if (!execute) return OperationPlanState(x, 0);
00793 opplan->setQuantity(0,true,false);
00794 opplan->setStartAndEnd(e,e);
00795 }
00796 else
00797 {
00798
00799 double max_q = duration_per ?
00800 static_cast<double>(actual-duration) / duration_per :
00801 q;
00802 q = opplan->setQuantity(q < max_q ? q : max_q, true, false, execute);
00803 wanted = duration + static_cast<long>(duration_per * q);
00804 x = calculateOperationTime(e, wanted, false, &actual);
00805 if (!execute) return OperationPlanState(x, q);
00806 opplan->setStartAndEnd(x.getStart(),x.getEnd());
00807 }
00808 }
00809 else
00810 {
00811
00812
00813 q = opplan->setQuantity(q,true,false,execute);
00814 TimePeriod wanted(
00815 duration + static_cast<long>(duration_per * q)
00816 );
00817 TimePeriod actual;
00818 x = calculateOperationTime(s, wanted, true, &actual);
00819 if (actual == wanted)
00820 {
00821
00822 if (!execute) return OperationPlanState(x, q);
00823 opplan->setStartAndEnd(x.getStart(),x.getEnd());
00824 }
00825 else if (actual < duration)
00826 {
00827
00828 if (!execute) return OperationPlanState(x, 0);
00829 opplan->setQuantity(0,true,false);
00830 opplan->setStartAndEnd(s,s);
00831 }
00832 else
00833 {
00834
00835 double max_q = duration_per ?
00836 static_cast<double>(actual-duration) / duration_per :
00837 q;
00838 q = opplan->setQuantity(q < max_q ? q : max_q, true, false, execute);
00839 wanted = duration + static_cast<long>(duration_per * q);
00840 x = calculateOperationTime(e, wanted, false, &actual);
00841 if (!execute) return OperationPlanState(x, q);
00842 opplan->setStartAndEnd(x.getStart(),x.getEnd());
00843 }
00844 }
00845
00846
00847 return OperationPlanState(opplan);
00848 }
00849
00850
00851 DECLARE_EXPORT void OperationTimePer::writeElement
00852 (XMLOutput *o, const Keyword& tag, mode m) const
00853 {
00854
00855 if (m == REFERENCE)
00856 {
00857 o->writeElement
00858 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00859 return;
00860 }
00861
00862
00863 if (m != NOHEADER) o->BeginObject
00864 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00865
00866
00867 Operation::writeElement(o, tag, NOHEADER);
00868 o->writeElement(Tags::tag_duration, duration);
00869 o->writeElement(Tags::tag_duration_per, duration_per);
00870 o->EndObject(tag);
00871 }
00872
00873
00874 DECLARE_EXPORT void OperationTimePer::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00875 {
00876 if (pAttr.isA (Tags::tag_duration))
00877 setDuration (pElement.getTimeperiod());
00878 else if (pAttr.isA (Tags::tag_duration_per))
00879 setDurationPer (pElement.getTimeperiod());
00880 else
00881 Operation::endElement (pIn, pAttr, pElement);
00882 }
00883
00884
00885 DECLARE_EXPORT void OperationRouting::writeElement
00886 (XMLOutput *o, const Keyword& tag, mode m) const
00887 {
00888
00889 if (m == REFERENCE)
00890 {
00891 o->writeElement
00892 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00893 return;
00894 }
00895
00896
00897 if (m != NOHEADER) o->BeginObject
00898 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00899
00900
00901 Operation::writeElement(o, tag, NOHEADER);
00902 if (steps.size())
00903 {
00904 o->BeginObject(Tags::tag_steps);
00905 for (Operationlist::const_iterator i = steps.begin(); i!=steps.end(); ++i)
00906 o->writeElement(Tags::tag_operation, *i, REFERENCE);
00907 o->EndObject(Tags::tag_steps);
00908 }
00909 o->EndObject(tag);
00910 }
00911
00912
00913 DECLARE_EXPORT void OperationRouting::beginElement(XMLInput& pIn, const Attribute& pAttr)
00914 {
00915 if (pAttr.isA (Tags::tag_operation))
00916 pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
00917 else
00918 Operation::beginElement(pIn, pAttr);
00919 }
00920
00921
00922 DECLARE_EXPORT void OperationRouting::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00923 {
00924 if (pAttr.isA (Tags::tag_operation)
00925 && pIn.getParentElement().first.isA(Tags::tag_steps))
00926 {
00927 Operation *oper = dynamic_cast<Operation*>(pIn.getPreviousObject());
00928 if (oper) addStepBack (oper);
00929 else throw LogicException("Incorrect object type during read operation");
00930 }
00931 Operation::endElement (pIn, pAttr, pElement);
00932 }
00933
00934
00935 DECLARE_EXPORT OperationPlanState OperationRouting::setOperationPlanParameters
00936 (OperationPlan* opplan, double q, Date s, Date e, bool preferEnd, bool execute) const
00937 {
00938
00939 if (!opplan || q<0)
00940 throw LogicException("Incorrect parameters for routing operationplan");
00941 if (opplan->getLocked())
00942 return OperationPlanState(opplan);
00943
00944 if (!opplan->lastsubopplan || opplan->lastsubopplan->getOperation() == OperationSetup::setupoperation)
00945 {
00946
00947
00948 q = opplan->setQuantity(q,false,false,execute);
00949 if (!s && e) s = e;
00950 if (s && !e) e = s;
00951 if (!execute) return OperationPlanState(s, e, q);
00952 opplan->setStartAndEnd(s,e);
00953 return OperationPlanState(opplan);
00954 }
00955
00956
00957
00958
00959 OperationPlanState x;
00960 Date y;
00961 bool realfirst = true;
00962 if (e)
00963 {
00964
00965 for (OperationPlan* i = opplan->lastsubopplan; i; i = i->prevsubopplan)
00966 {
00967 if (i->getOperation() == OperationSetup::setupoperation) continue;
00968 x = i->getOperation()->setOperationPlanParameters(i,q,Date::infinitePast,e,preferEnd,execute);
00969 e = x.start;
00970 if (realfirst)
00971 {
00972 y = x.end;
00973 realfirst = false;
00974 }
00975 }
00976 return OperationPlanState(x.start, y, x.quantity);
00977 }
00978 else if (s)
00979 {
00980
00981 for (OperationPlan *i = opplan->firstsubopplan; i; i = i->nextsubopplan)
00982 {
00983 if (i->getOperation() == OperationSetup::setupoperation) continue;
00984 x = i->getOperation()->setOperationPlanParameters(i,q,s,Date::infinitePast,preferEnd,execute);
00985 s = x.end;
00986 if (realfirst)
00987 {
00988 y = x.start;
00989 realfirst = false;
00990 }
00991 }
00992 return OperationPlanState(y, x.end, x.quantity);
00993 }
00994 else
00995 throw LogicException(
00996 "Updating a routing operationplan without start or end date argument"
00997 );
00998 }
00999
01000
01001 DECLARE_EXPORT bool OperationRouting::extraInstantiate(OperationPlan* o)
01002 {
01003
01004 if (!o->lastsubopplan || o->lastsubopplan->getOperation() == OperationSetup::setupoperation)
01005 {
01006 logger << "extra" << endl;
01007 Date d = o->getDates().getEnd();
01008 OperationPlan *p = NULL;
01009
01010 if (d != Date::infiniteFuture)
01011 {
01012
01013 for (Operation::Operationlist::const_reverse_iterator e =
01014 getSubOperations().rbegin(); e != getSubOperations().rend(); ++e)
01015 {
01016 p = (*e)->createOperationPlan(o->getQuantity(), Date::infinitePast,
01017 d, NULL, o, 0, true);
01018 d = p->getDates().getStart();
01019 }
01020 }
01021 else
01022 {
01023
01024 d = o->getDates().getStart();
01025
01026 if (!d) d = Plan::instance().getCurrent();
01027 for (Operation::Operationlist::const_iterator e =
01028 getSubOperations().begin(); e != getSubOperations().end(); ++e)
01029 {
01030 p = (*e)->createOperationPlan(o->getQuantity(), d,
01031 Date::infinitePast, NULL, o, 0, true);
01032 d = p->getDates().getEnd();
01033 }
01034 }
01035 }
01036 return true;
01037 }
01038
01039
01040 DECLARE_EXPORT SearchMode decodeSearchMode(const string& c)
01041 {
01042 if (c == "PRIORITY") return PRIORITY;
01043 if (c == "MINCOST") return MINCOST;
01044 if (c == "MINPENALTY") return MINPENALTY;
01045 if (c == "MINCOSTPENALTY") return MINCOSTPENALTY;
01046 throw DataException("Invalid search mode " + c);
01047 }
01048
01049
01050 DECLARE_EXPORT void OperationAlternate::addAlternate
01051 (Operation* o, int prio, DateRange eff)
01052 {
01053 if (!o) return;
01054 Operationlist::iterator altIter = alternates.begin();
01055 alternatePropertyList::iterator propIter = alternateProperties.begin();
01056 while (altIter!=alternates.end() && prio >= propIter->first)
01057 {
01058 ++propIter;
01059 ++altIter;
01060 }
01061 alternateProperties.insert(propIter,alternateProperty(prio,eff));
01062 alternates.insert(altIter,o);
01063 o->addSuperOperation(this);
01064 }
01065
01066
01067 DECLARE_EXPORT const OperationAlternate::alternateProperty&
01068 OperationAlternate::getProperties(Operation* o) const
01069 {
01070 if (!o)
01071 throw LogicException("Null pointer passed when searching for a \
01072 suboperation of alternate operation '" + getName() + "'");
01073 Operationlist::const_iterator altIter = alternates.begin();
01074 alternatePropertyList::const_iterator propIter = alternateProperties.begin();
01075 while (altIter!=alternates.end() && *altIter != o)
01076 {
01077 ++propIter;
01078 ++altIter;
01079 }
01080 if (*altIter == o) return *propIter;
01081 throw DataException("Operation '" + o->getName() +
01082 "' isn't a suboperation of alternate operation '" + getName() + "'");
01083 }
01084
01085
01086 DECLARE_EXPORT void OperationAlternate::setPriority(Operation* o, int f)
01087 {
01088 if (!o) return;
01089 Operationlist::const_iterator altIter = alternates.begin();
01090 alternatePropertyList::iterator propIter = alternateProperties.begin();
01091 while (altIter!=alternates.end() && *altIter != o)
01092 {
01093 ++propIter;
01094 ++altIter;
01095 }
01096 if (*altIter == o)
01097 propIter->first = f;
01098 else
01099 throw DataException("Operation '" + o->getName() +
01100 "' isn't a suboperation of alternate operation '" + getName() + "'");
01101 }
01102
01103
01104 DECLARE_EXPORT void OperationAlternate::setEffective(Operation* o, DateRange dr)
01105 {
01106 if (!o) return;
01107 Operationlist::const_iterator altIter = alternates.begin();
01108 alternatePropertyList::iterator propIter = alternateProperties.begin();
01109 while (altIter!=alternates.end() && *altIter != o)
01110 {
01111 ++propIter;
01112 ++altIter;
01113 }
01114 if (*altIter == o)
01115 propIter->second = dr;
01116 else
01117 throw DataException("Operation '" + o->getName() +
01118 "' isn't a suboperation of alternate operation '" + getName() + "'");
01119 }
01120
01121
01122 DECLARE_EXPORT void OperationAlternate::writeElement
01123 (XMLOutput *o, const Keyword& tag, mode m) const
01124 {
01125
01126 if (m == REFERENCE)
01127 {
01128 o->writeElement
01129 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
01130 return;
01131 }
01132
01133
01134 if (m != NOHEADER) o->BeginObject
01135 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
01136
01137
01138 Operation::writeElement(o, tag, NOHEADER);
01139 if (search != PRIORITY)
01140 o->writeElement(Tags::tag_search, search);
01141
01142
01143 o->BeginObject(Tags::tag_alternates);
01144 alternatePropertyList::const_iterator propIter = alternateProperties.begin();
01145 for (Operationlist::const_iterator i = alternates.begin();
01146 i != alternates.end(); ++i)
01147 {
01148 o->BeginObject(Tags::tag_alternate);
01149 o->writeElement(Tags::tag_operation, *i, REFERENCE);
01150 o->writeElement(Tags::tag_priority, propIter->first);
01151 if (propIter->second.getStart() != Date::infinitePast)
01152 o->writeElement(Tags::tag_effective_start, propIter->second.getStart());
01153 if (propIter->second.getEnd() != Date::infiniteFuture)
01154 o->writeElement(Tags::tag_effective_end, propIter->second.getEnd());
01155 o->EndObject (Tags::tag_alternate);
01156 ++propIter;
01157 }
01158 o->EndObject(Tags::tag_alternates);
01159
01160
01161 o->EndObject(tag);
01162 }
01163
01164
01165 DECLARE_EXPORT void OperationAlternate::beginElement(XMLInput& pIn, const Attribute& pAttr)
01166 {
01167 if (pAttr.isA(Tags::tag_operation))
01168 pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
01169 else
01170 Operation::beginElement(pIn, pAttr);
01171 }
01172
01173
01174 DECLARE_EXPORT void OperationAlternate::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
01175 {
01176
01177 typedef pair<Operation*,alternateProperty> tempData;
01178
01179
01180 if (!pIn.getUserArea())
01181 pIn.setUserArea(new tempData(NULL,alternateProperty(1,DateRange())));
01182 tempData* tmp = static_cast<tempData*>(pIn.getUserArea());
01183
01184 if (pAttr.isA(Tags::tag_alternate))
01185 {
01186 addAlternate(tmp->first, tmp->second.first, tmp->second.second);
01187
01188 tmp->first = NULL;
01189 tmp->second.first = 1;
01190 tmp->second.second = DateRange();
01191 }
01192 else if (pAttr.isA(Tags::tag_priority))
01193 tmp->second.first = pElement.getInt();
01194 else if (pAttr.isA(Tags::tag_search))
01195 setSearch(pElement.getString());
01196 else if (pAttr.isA(Tags::tag_effective_start))
01197 tmp->second.second.setStart(pElement.getDate());
01198 else if (pAttr.isA(Tags::tag_effective_end))
01199 tmp->second.second.setEnd(pElement.getDate());
01200 else if (pAttr.isA(Tags::tag_operation)
01201 && pIn.getParentElement().first.isA(Tags::tag_alternate))
01202 {
01203 Operation * b = dynamic_cast<Operation*>(pIn.getPreviousObject());
01204 if (b) tmp->first = b;
01205 else throw LogicException("Incorrect object type during read operation");
01206 }
01207 Operation::endElement (pIn, pAttr, pElement);
01208
01209
01210 if (pIn.isObjectEnd()) delete static_cast<tempData*>(pIn.getUserArea());
01211 }
01212
01213
01214 DECLARE_EXPORT OperationPlanState
01215 OperationAlternate::setOperationPlanParameters
01216 (OperationPlan* opplan, double q, Date s, Date e, bool preferEnd,
01217 bool execute) const
01218 {
01219
01220 if (!opplan || q<0)
01221 throw LogicException("Incorrect parameters for alternate operationplan");
01222 if (opplan->getLocked())
01223 return OperationPlanState(opplan);
01224
01225 OperationPlan *x = opplan->lastsubopplan;
01226 while (x && x->getOperation() == OperationSetup::setupoperation)
01227 x = x->prevsubopplan;
01228 if (!x)
01229 {
01230
01231 if (execute)
01232 {
01233 opplan->setQuantity(q,false,false);
01234 opplan->setStartAndEnd(s, e);
01235 return OperationPlanState(opplan);
01236 }
01237 else
01238 return OperationPlanState(s, e, opplan->setQuantity(q,false,false,false));
01239 }
01240 else
01241
01242 return x->getOperation()
01243 ->setOperationPlanParameters(x,q,s,e,preferEnd, execute);
01244 }
01245
01246
01247 DECLARE_EXPORT bool OperationAlternate::extraInstantiate(OperationPlan* o)
01248 {
01249
01250
01251 if (!o->lastsubopplan || o->lastsubopplan->getOperation() == OperationSetup::setupoperation)
01252 {
01253
01254 Operationlist::const_iterator altIter = getSubOperations().begin();
01255 for (; altIter != getSubOperations().end(); )
01256 {
01257 const OperationAlternate::alternateProperty& props = getProperties(*altIter);
01258
01259 if (props.first != 0.0 && props.second.within(o->getDates().getEnd()))
01260 break;
01261 }
01262 if (altIter != getSubOperations().end())
01263
01264 (*altIter)->createOperationPlan(
01265 o->getQuantity(), o->getDates().getStart(),
01266 o->getDates().getEnd(), NULL, o, 0, true);
01267 }
01268 return true;
01269 }
01270
01271
01272 DECLARE_EXPORT void OperationAlternate::removeSubOperation(Operation *o)
01273 {
01274 Operationlist::iterator altIter = alternates.begin();
01275 alternatePropertyList::iterator propIter = alternateProperties.begin();
01276 while (altIter!=alternates.end() && *altIter != o)
01277 {
01278 ++propIter;
01279 ++altIter;
01280 }
01281 if (*altIter == o)
01282 {
01283 alternates.erase(altIter);
01284 alternateProperties.erase(propIter);
01285 o->superoplist.remove(this);
01286 setChanged();
01287 }
01288 else
01289 logger << "Warning: operation '" << *o
01290 << "' isn't a suboperation of alternate operation '" << *this
01291 << "'" << endl;
01292 }
01293
01294
01295 DECLARE_EXPORT OperationPlanState OperationSetup::setOperationPlanParameters
01296 (OperationPlan* opplan, double q, Date s, Date e, bool preferEnd, bool execute) const
01297 {
01298
01299 OperationPlan::LoadPlanIterator i = opplan->beginLoadPlans();
01300 LoadPlan *ldplan = NULL;
01301 if (i != opplan->endLoadPlans())
01302
01303 ldplan = &*i;
01304 else
01305 {
01306
01307 if (!opplan->getOwner())
01308 throw LogicException("Setup operationplan always must have an owner");
01309 for (loadlist::const_iterator g=opplan->getOwner()->getOperation()->getLoads().begin();
01310 g!=opplan->getOwner()->getOperation()->getLoads().end(); ++g)
01311 if (g->getResource()->getSetupMatrix() && !g->getSetup().empty())
01312 {
01313 ldplan = new LoadPlan(opplan, &*g);
01314 break;
01315 }
01316 if (!ldplan)
01317 throw LogicException("Can't find a setup on operation '"
01318 + opplan->getOwner()->getOperation()->getName() + "'");
01319 }
01320
01321
01322 const Load* lastld = NULL;
01323 Date boundary = s ? s : e;
01324 if (ldplan->getDate() < boundary)
01325 {
01326 for (TimeLine<LoadPlan>::const_iterator i = ldplan->getResource()->getLoadPlans().begin(ldplan);
01327 i != ldplan->getResource()->getLoadPlans().end() && i->getDate() <= boundary; ++i)
01328 {
01329 const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
01330 if (l && i->getQuantity() != 0.0
01331 && l->getOperationPlan() != opplan
01332 && l->getOperationPlan() != opplan->getOwner()
01333 && !l->getLoad()->getSetup().empty())
01334 lastld = l->getLoad();
01335 }
01336 }
01337 if (!lastld)
01338 {
01339 for (TimeLine<LoadPlan>::const_iterator i = ldplan->getResource()->getLoadPlans().begin(ldplan);
01340 i != ldplan->getResource()->getLoadPlans().end(); --i)
01341 {
01342 const LoadPlan *l = dynamic_cast<const LoadPlan*>(&*i);
01343 if (l && i->getQuantity() != 0.0
01344 && l->getOperationPlan() != opplan
01345 && l->getOperationPlan() != opplan->getOwner()
01346 && !l->getLoad()->getSetup().empty()
01347 && l->getDate() <= boundary)
01348 {
01349 lastld = l->getLoad();
01350 break;
01351 }
01352 }
01353 }
01354 string lastsetup = lastld ? lastld->getSetup() : ldplan->getResource()->getSetup();
01355
01356 TimePeriod duration(0L);
01357 if (lastsetup != ldplan->getLoad()->getSetup())
01358 {
01359
01360 SetupMatrix::Rule *conversionrule = ldplan->getLoad()->getResource()->getSetupMatrix()
01361 ->calculateSetup(lastsetup, ldplan->getLoad()->getSetup());
01362 duration = conversionrule ? conversionrule->getDuration() : TimePeriod(365L*86400L);
01363 }
01364
01365
01366 DateRange x;
01367 TimePeriod actualduration;
01368 if (e && s)
01369 {
01370 if (preferEnd) x = calculateOperationTime(e, duration, false, &actualduration);
01371 else x = calculateOperationTime(s, duration, true, &actualduration);
01372 }
01373 else if (s) x = calculateOperationTime(s, duration, true, &actualduration);
01374 else x = calculateOperationTime(e, duration, false, &actualduration);
01375 if (!execute)
01376
01377 return OperationPlanState(x, actualduration == duration ? q : 0);
01378 else if (actualduration == duration)
01379 {
01380
01381 opplan->setStartAndEnd(x.getStart(), x.getEnd());
01382 if (opplan->getOwner()->getDates().getStart() != opplan->getDates().getEnd())
01383 opplan->getOwner()->setStart(opplan->getDates().getEnd());
01384 }
01385 else
01386
01387 opplan->setQuantity(0);
01388
01389 return OperationPlanState(opplan);
01390 }
01391
01392
01393 DECLARE_EXPORT PyObject* Operation::getattro(const Attribute& attr)
01394 {
01395 if (attr.isA(Tags::tag_name))
01396 return PythonObject(getName());
01397 if (attr.isA(Tags::tag_description))
01398 return PythonObject(getDescription());
01399 if (attr.isA(Tags::tag_category))
01400 return PythonObject(getCategory());
01401 if (attr.isA(Tags::tag_subcategory))
01402 return PythonObject(getSubCategory());
01403 if (attr.isA(Tags::tag_location))
01404 return PythonObject(getLocation());
01405 if (attr.isA(Tags::tag_fence))
01406 return PythonObject(getFence());
01407 if (attr.isA(Tags::tag_size_minimum))
01408 return PythonObject(getSizeMinimum());
01409 if (attr.isA(Tags::tag_size_multiple))
01410 return PythonObject(getSizeMultiple());
01411 if (attr.isA(Tags::tag_size_maximum))
01412 return PythonObject(getSizeMaximum());
01413 if (attr.isA(Tags::tag_cost))
01414 return PythonObject(getCost());
01415 if (attr.isA(Tags::tag_pretime))
01416 return PythonObject(getPreTime());
01417 if (attr.isA(Tags::tag_posttime))
01418 return PythonObject(getPostTime());
01419 if (attr.isA(Tags::tag_hidden))
01420 return PythonObject(getHidden());
01421 if (attr.isA(Tags::tag_loads))
01422 return new LoadIterator(this);
01423 if (attr.isA(Tags::tag_flows))
01424 return new FlowIterator(this);
01425 if (attr.isA(Tags::tag_operationplans))
01426 return new OperationPlanIterator(this);
01427 if (attr.isA(Tags::tag_level))
01428 return PythonObject(getLevel());
01429 if (attr.isA(Tags::tag_cluster))
01430 return PythonObject(getCluster());
01431 return NULL;
01432 }
01433
01434
01435 DECLARE_EXPORT int Operation::setattro(const Attribute& attr, const PythonObject& field)
01436 {
01437 if (attr.isA(Tags::tag_name))
01438 setName(field.getString());
01439 else if (attr.isA(Tags::tag_description))
01440 setDescription(field.getString());
01441 else if (attr.isA(Tags::tag_category))
01442 setCategory(field.getString());
01443 else if (attr.isA(Tags::tag_subcategory))
01444 setSubCategory(field.getString());
01445 else if (attr.isA(Tags::tag_location))
01446 {
01447 if (!field.check(Location::metadata))
01448 {
01449 PyErr_SetString(PythonDataException, "buffer location must be of type location");
01450 return -1;
01451 }
01452 Location* y = static_cast<Location*>(static_cast<PyObject*>(field));
01453 setLocation(y);
01454 }
01455 else if (attr.isA(Tags::tag_fence))
01456 setFence(field.getTimeperiod());
01457 else if (attr.isA(Tags::tag_size_minimum))
01458 setSizeMinimum(field.getDouble());
01459 else if (attr.isA(Tags::tag_size_multiple))
01460 setSizeMultiple(field.getDouble());
01461 else if (attr.isA(Tags::tag_size_maximum))
01462 setSizeMaximum(field.getDouble());
01463 else if (attr.isA(Tags::tag_cost))
01464 setCost(field.getDouble());
01465 else if (attr.isA(Tags::tag_pretime))
01466 setPreTime(field.getTimeperiod());
01467 else if (attr.isA(Tags::tag_posttime))
01468 setPostTime(field.getTimeperiod());
01469 else if (attr.isA(Tags::tag_hidden))
01470 setHidden(field.getBool());
01471 else
01472 return -1;
01473 return 0;
01474 }
01475
01476
01477 DECLARE_EXPORT PyObject* OperationFixedTime::getattro(const Attribute& attr)
01478 {
01479 if (attr.isA(Tags::tag_duration))
01480 return PythonObject(getDuration());
01481 return Operation::getattro(attr);
01482 }
01483
01484
01485 DECLARE_EXPORT int OperationFixedTime::setattro(const Attribute& attr, const PythonObject& field)
01486 {
01487 if (attr.isA(Tags::tag_duration))
01488 setDuration(field.getTimeperiod());
01489 else
01490 return Operation::setattro(attr, field);
01491 return 0;
01492 }
01493
01494
01495 DECLARE_EXPORT PyObject* OperationTimePer::getattro(const Attribute& attr)
01496 {
01497 if (attr.isA(Tags::tag_duration))
01498 return PythonObject(getDuration());
01499 if (attr.isA(Tags::tag_duration))
01500 return PythonObject(getDurationPer());
01501 return Operation::getattro(attr);
01502 }
01503
01504
01505 DECLARE_EXPORT int OperationTimePer::setattro(const Attribute& attr, const PythonObject& field)
01506 {
01507 if (attr.isA(Tags::tag_duration))
01508 setDuration(field.getTimeperiod());
01509 else if (attr.isA(Tags::tag_duration_per))
01510 setDurationPer(field.getTimeperiod());
01511 else
01512 return Operation::setattro(attr, field);
01513 return 0;
01514 }
01515
01516
01517 DECLARE_EXPORT PyObject* OperationAlternate::getattro(const Attribute& attr)
01518 {
01519 if (attr.isA(Tags::tag_alternates))
01520 {
01521 PyObject* result = PyTuple_New(getSubOperations().size());
01522 int count = 0;
01523 for (Operation::Operationlist::const_iterator i = getSubOperations().begin(); i != getSubOperations().end(); ++i)
01524 PyTuple_SetItem(result, count++, PythonObject(*i));
01525 return result;
01526 }
01527 if (attr.isA(Tags::tag_search))
01528 {
01529 ostringstream ch;
01530 ch << getSearch();
01531 return PythonObject(ch.str());
01532 }
01533 return Operation::getattro(attr);
01534 }
01535
01536
01537 DECLARE_EXPORT int OperationAlternate::setattro(const Attribute& attr, const PythonObject& field)
01538 {
01539 if (attr.isA(Tags::tag_search))
01540 setSearch(field.getString());
01541 else
01542 return Operation::setattro(attr, field);
01543 return 0;
01544 }
01545
01546
01547 DECLARE_EXPORT PyObject* OperationAlternate::addAlternate(PyObject* self, PyObject* args, PyObject* kwdict)
01548 {
01549 try
01550 {
01551
01552 OperationAlternate *altoper = static_cast<OperationAlternate*>(self);
01553 if (!altoper) throw LogicException("Can't add alternates to NULL alternate");
01554
01555
01556 PyObject *oper = NULL;
01557 int prio = 1;
01558 PyObject *eff_start = NULL;
01559 PyObject *eff_end = NULL;
01560 static const char *kwlist[] = {"operation", "priority", "effective_start", "effective_end", NULL};
01561 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
01562 "O|iOO:addAlternate",
01563 const_cast<char**>(kwlist), &oper, &prio, &eff_start, &eff_end))
01564 return NULL;
01565 if (!PyObject_TypeCheck(oper, Operation::metadata->pythonClass))
01566 throw DataException("alternate operation must be of type operation");
01567 DateRange eff;
01568 if (eff_start)
01569 {
01570 PythonObject d(eff_start);
01571 eff.setStart(d.getDate());
01572 }
01573 if (eff_end)
01574 {
01575 PythonObject d(eff_end);
01576 eff.setEnd(d.getDate());
01577 }
01578
01579
01580 altoper->addAlternate(static_cast<Operation*>(oper), prio, eff);
01581 }
01582 catch(...)
01583 {
01584 PythonType::evalException();
01585 return NULL;
01586 }
01587 return Py_BuildValue("");
01588 }
01589
01590
01591 DECLARE_EXPORT PyObject* OperationRouting::getattro(const Attribute& attr)
01592 {
01593 if (attr.isA(Tags::tag_steps))
01594 {
01595 PyObject* result = PyTuple_New(getSubOperations().size());
01596 int count = 0;
01597 for (Operation::Operationlist::const_iterator i = getSubOperations().begin(); i != getSubOperations().end(); ++i)
01598 PyTuple_SetItem(result, count++, PythonObject(*i));
01599 return result;
01600 }
01601 return Operation::getattro(attr);
01602 }
01603
01604
01605 PyObject *OperationRouting::addStep(PyObject *self, PyObject *args)
01606 {
01607 try
01608 {
01609
01610 OperationRouting *oper = static_cast<OperationRouting*>(self);
01611 if (!oper) throw LogicException("Can't add steps to NULL routing");
01612
01613
01614 PyObject *steps[4];
01615 for (unsigned int i=0; i<4; ++i) steps[i] = NULL;
01616 if (PyArg_UnpackTuple(args, "addStep", 1, 4, &steps[0], &steps[1], &steps[2], &steps[3]))
01617 for (unsigned int i=0; i<4 && steps[i]; ++i)
01618 {
01619 if (!PyObject_TypeCheck(steps[i], Operation::metadata->pythonClass))
01620 throw DataException("routing steps must be of type operation");
01621 oper->addStepBack(static_cast<Operation*>(steps[i]));
01622 }
01623 }
01624 catch(...)
01625 {
01626 PythonType::evalException();
01627 return NULL;
01628 }
01629 return Py_BuildValue("");
01630 }
01631
01632 }