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 #define FREPPLE_CORE
00028 #include "frepple/model.h"
00029
00030 namespace frepple
00031 {
00032
00033 template<class Operation> DECLARE_EXPORT Tree utils::HasName<Operation>::st;
00034 DECLARE_EXPORT Operation::Operationlist Operation::nosubOperations;
00035
00036
00037 DECLARE_EXPORT Operation::~Operation()
00038 {
00039
00040 deleteOperationPlans(true);
00041
00042
00043
00044
00045
00046 for (Item::iterator k = Item::begin(); k != Item::end(); ++k)
00047 if (k->getOperation() == this) k->setOperation(NULL);
00048
00049
00050 for (Demand::iterator l = Demand::begin(); l != Demand::end(); ++l)
00051 if (l->getOperation() == this) l->setOperation(NULL);
00052
00053
00054 for (Buffer::iterator m = Buffer::begin(); m != Buffer::end(); ++m)
00055 if (m->getProducingOperation() == this)
00056 m->setProducingOperation(NULL);
00057
00058
00059
00060
00061
00062 while (!getSuperOperations().empty())
00063 removeSuperOperation(*getSuperOperations().begin());
00064 }
00065
00066
00067 DECLARE_EXPORT OperationRouting::~OperationRouting()
00068 {
00069
00070
00071
00072 while (!getSubOperations().empty())
00073 removeSubOperation(*getSubOperations().begin());
00074 }
00075
00076
00077 DECLARE_EXPORT OperationAlternate::~OperationAlternate()
00078 {
00079
00080
00081
00082 while (!getSubOperations().empty())
00083 removeSubOperation(*getSubOperations().begin());
00084 }
00085
00086
00087 DECLARE_EXPORT OperationPlan* Operation::createOperationPlan (double q, Date s, Date e,
00088 Demand* l, OperationPlan* ow, unsigned long i,
00089 bool makeflowsloads) const
00090 {
00091 OperationPlan *opplan = new OperationPlan();
00092 initOperationPlan(opplan,q,s,e,l,ow,i,makeflowsloads);
00093 return opplan;
00094 }
00095
00096
00097 DECLARE_EXPORT DateRange Operation::calculateOperationTime
00098 (Date thedate, TimePeriod duration, bool forward,
00099 TimePeriod *actualduration) const
00100 {
00101
00102 if (!actualduration)
00103 throw LogicException("Null argument in calculateOperationTime function");
00104
00105 int calcount = 0;
00106
00107 vector<Calendar::EventIterator*> cals(10);
00108
00109
00110 *actualduration = duration;
00111
00112 try
00113 {
00114
00115
00116 if (loc && loc->getAvailable())
00117 cals[calcount++] = new Calendar::EventIterator(loc->getAvailable(), thedate, forward);
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 if (calcount == 0)
00140 return forward ?
00141 DateRange(thedate, thedate+duration) :
00142 DateRange(thedate-duration, thedate);
00143
00144
00145
00146 DateRange result;
00147 Date curdate = thedate;
00148 bool status = false;
00149 TimePeriod curduration = duration;
00150 while (true)
00151 {
00152
00153 bool available = true;
00154 for (int c = 0; c < calcount && available; c++)
00155 {
00156 if (cals[c]->getBucket())
00157 available = cals[c]->getBucket()->getBool();
00158 else
00159 available = cals[c]->getCalendar()->getBool();
00160 }
00161 curdate = cals[0]->getDate();
00162
00163 if (available && !status)
00164 {
00165
00166 thedate = curdate;
00167 status = true;
00168 if (forward && result.getStart() == Date::infinitePast)
00169
00170 result.setStart(curdate);
00171 else if (!forward && result.getEnd() == Date::infiniteFuture)
00172
00173 result.setEnd(curdate);
00174 }
00175 else if (!available && status)
00176 {
00177
00178 status = false;
00179 if (forward)
00180 {
00181
00182 TimePeriod delta = curdate - thedate;
00183 if (delta >= curduration)
00184 {
00185 result.setEnd(thedate + curduration);
00186 break;
00187 }
00188 else
00189 curduration -= delta;
00190 }
00191 else
00192 {
00193
00194 TimePeriod delta = thedate - curdate;
00195 if (delta >= curduration)
00196 {
00197 result.setStart(thedate - curduration);
00198 break;
00199 }
00200 else
00201 curduration -= delta;
00202 }
00203 }
00204 else if (forward && curdate == Date::infiniteFuture)
00205 {
00206
00207 if (available)
00208 {
00209 TimePeriod delta = curdate - thedate;
00210 if (delta >= curduration)
00211 result.setEnd(thedate + curduration);
00212 else
00213 *actualduration = duration - curduration;
00214 }
00215 else
00216 *actualduration = duration - curduration;
00217 break;
00218 }
00219 else if (!forward && curdate == Date::infinitePast)
00220 {
00221
00222 if (available)
00223 {
00224 TimePeriod delta = thedate - curdate;
00225 if (delta >= curduration)
00226 result.setStart(thedate - curduration);
00227 else
00228 *actualduration = duration - curduration;
00229 }
00230 else
00231 *actualduration = duration - curduration;
00232 break;
00233 }
00234
00235
00236 if (forward) ++(*cals[0]);
00237 else --(*cals[0]);
00238 }
00239
00240
00241 while (calcount) delete cals[--calcount];
00242 return result;
00243 }
00244 catch (...)
00245 {
00246
00247 while (calcount) delete cals[calcount--];
00248
00249 throw;
00250 }
00251 }
00252
00253
00254 DECLARE_EXPORT DateRange Operation::calculateOperationTime
00255 (Date start, Date end, TimePeriod *actualduration) const
00256 {
00257
00258 if (!actualduration)
00259 throw LogicException("Null argument in calculateOperationTime function");
00260
00261
00262 if (end < start)
00263 {
00264 Date tmp = start;
00265 start = end;
00266 end = tmp;
00267 }
00268
00269 int calcount = 0;
00270
00271 vector<Calendar::EventIterator*> cals(10);
00272
00273
00274 *actualduration = 0L;
00275
00276 try
00277 {
00278
00279
00280 if (loc && loc->getAvailable())
00281 cals[calcount++] = new Calendar::EventIterator(loc->getAvailable(), start);
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303 if (calcount == 0)
00304 {
00305 *actualduration = end - start;
00306 return DateRange(start, end);
00307 }
00308
00309
00310
00311 DateRange result;
00312 Date curdate = start;
00313 bool status = false;
00314 while (true)
00315 {
00316
00317 bool available = true;
00318 for (int c = 0; c < calcount && available; c++)
00319 {
00320 if (cals[c]->getBucket())
00321 available = cals[c]->getBucket()->getBool();
00322 else
00323 available = cals[c]->getCalendar()->getBool();
00324 }
00325 curdate = cals[0]->getDate();
00326
00327 if (available && !status)
00328 {
00329
00330 if (curdate >= end)
00331 {
00332
00333 result.setEnd(start);
00334 break;
00335 }
00336 start = curdate;
00337 status = true;
00338 if (result.getStart() == Date::infinitePast)
00339
00340 result.setStart(curdate);
00341 }
00342 else if (!available && status)
00343 {
00344
00345 if (curdate >= end)
00346 {
00347
00348 *actualduration += end - start;
00349 result.setEnd(end);
00350 break;
00351 }
00352 status = false;
00353 *actualduration += curdate - start;
00354 start = curdate;
00355 }
00356 else if (curdate >= end)
00357 {
00358
00359 if (available)
00360 {
00361 *actualduration += end - start;
00362 result.setEnd(end);
00363 break;
00364 }
00365 else
00366 result.setEnd(start);
00367 break;
00368 }
00369
00370
00371 ++(*cals[0]);
00372 }
00373
00374
00375 while (calcount) delete cals[--calcount];
00376 return result;
00377 }
00378 catch (...)
00379 {
00380
00381 while (calcount) delete cals[calcount--];
00382
00383 throw;
00384 }
00385 }
00386
00387
00388 DECLARE_EXPORT void Operation::initOperationPlan (OperationPlan* opplan,
00389 double q, const Date& s, const Date& e, Demand* l, OperationPlan* ow,
00390 unsigned long i, bool makeflowsloads) const
00391 {
00392 opplan->oper = const_cast<Operation*>(this);
00393 opplan->setDemand(l);
00394 opplan->id = i;
00395
00396
00397
00398 opplan->setOwner(ow);
00399
00400
00401 setOperationPlanParameters(opplan,q,s,e);
00402
00403
00404 if (makeflowsloads) opplan->createFlowLoads();
00405
00406
00407 opplan->update();
00408 }
00409
00410
00411 void Operation::deleteOperationPlans(bool deleteLockedOpplans)
00412 {
00413 OperationPlan::deleteOperationPlans(this, deleteLockedOpplans);
00414 }
00415
00416
00417 DECLARE_EXPORT void Operation::writeElement(XMLOutput *o, const Keyword& tag, mode m) const
00418 {
00419
00420
00421 assert(m == NOHEADER);
00422
00423
00424 HasDescription::writeElement(o, tag);
00425 Plannable::writeElement(o, tag);
00426 if (post_time)
00427 o->writeElement(Tags::tag_posttime, post_time);
00428 if (pre_time)
00429 o->writeElement(Tags::tag_pretime, pre_time);
00430 if (getCost() != 0.0)
00431 o->writeElement(Tags::tag_cost, getCost());
00432 if (fence)
00433 o->writeElement(Tags::tag_fence, fence);
00434 if (size_minimum != 1.0)
00435 o->writeElement(Tags::tag_size_minimum, size_minimum);
00436 if (size_multiple > 0.0)
00437 o->writeElement(Tags::tag_size_multiple, size_multiple);
00438 if (loc)
00439 o->writeElement(Tags::tag_location, loc);
00440
00441
00442 if ((o->getContentType() == XMLOutput::PLAN
00443 || o->getContentType() == XMLOutput::PLANDETAIL) && first_opplan)
00444 {
00445 o->BeginObject(Tags::tag_operationplans);
00446 for (OperationPlan::iterator i(this); i!=OperationPlan::end(); ++i)
00447 o->writeElement(Tags::tag_operationplan, *i, FULL);
00448 o->EndObject(Tags::tag_operationplans);
00449 }
00450 }
00451
00452
00453 DECLARE_EXPORT void Operation::beginElement (XMLInput& pIn, const Attribute& pAttr)
00454 {
00455 if (pAttr.isA(Tags::tag_flow)
00456 && pIn.getParentElement().first.isA(Tags::tag_flows))
00457 {
00458 Flow *f =
00459 dynamic_cast<Flow*>(MetaCategory::ControllerDefault(Flow::metadata,pIn.getAttributes()));
00460 if (f) f->setOperation(this);
00461 pIn.readto(f);
00462 }
00463 else if (pAttr.isA (Tags::tag_load)
00464 && pIn.getParentElement().first.isA(Tags::tag_loads))
00465 {
00466 Load* l = new Load();
00467 l->setOperation(this);
00468 pIn.readto(&*l);
00469 }
00470 else if (pAttr.isA (Tags::tag_operationplan))
00471 pIn.readto(OperationPlan::createOperationPlan(OperationPlan::metadata, pIn.getAttributes()));
00472 else if (pAttr.isA (Tags::tag_location))
00473 pIn.readto( Location::reader(Location::metadata,pIn.getAttributes()) );
00474 }
00475
00476
00477 DECLARE_EXPORT void Operation::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00478 {
00479 if (pAttr.isA (Tags::tag_fence))
00480 setFence(pElement.getTimeperiod());
00481 else if (pAttr.isA (Tags::tag_size_minimum))
00482 setSizeMinimum(pElement.getDouble());
00483 else if (pAttr.isA (Tags::tag_cost))
00484 setCost(pElement.getDouble());
00485 else if (pAttr.isA (Tags::tag_size_multiple))
00486 setSizeMultiple(pElement.getDouble());
00487 else if (pAttr.isA (Tags::tag_pretime))
00488 setPreTime(pElement.getTimeperiod());
00489 else if (pAttr.isA (Tags::tag_posttime))
00490 setPostTime(pElement.getTimeperiod());
00491 else if (pAttr.isA (Tags::tag_location))
00492 {
00493 Location *l = dynamic_cast<Location*>(pIn.getPreviousObject());
00494 if (l) setLocation(l);
00495 else throw LogicException("Incorrect object type during read operation");
00496 }
00497 else
00498 {
00499 Plannable::endElement(pIn, pAttr, pElement);
00500 HasDescription::endElement(pIn, pAttr, pElement);
00501 }
00502 }
00503
00504
00505 DECLARE_EXPORT void OperationFixedTime::setOperationPlanParameters
00506 (OperationPlan* oplan, double q, Date s, Date e, bool preferEnd) const
00507 {
00508
00509 if (!oplan || q<0)
00510 throw LogicException("Incorrect parameters for fixedtime operationplan");
00511 if (oplan->getLocked()) return;
00512
00513
00514 if (q > 0 && q < getSizeMinimum()) q = getSizeMinimum();
00515 if (fabs(q - oplan->getQuantity()) > ROUNDING_ERROR)
00516 oplan->setQuantity(q, false, false);
00517
00518
00519 DateRange x;
00520 TimePeriod actualduration;
00521 if (e && s)
00522 {
00523 if (preferEnd) x = calculateOperationTime(e, duration, false, &actualduration);
00524 else x = calculateOperationTime(s, duration, true, &actualduration);
00525 }
00526 else if (s) x = calculateOperationTime(s, duration, true, &actualduration);
00527 else x = calculateOperationTime(e, duration, false, &actualduration);
00528 if (actualduration == duration)
00529 oplan->setStartAndEnd(x.getStart(), x.getEnd());
00530 else
00531
00532 oplan->setQuantity(0);
00533 }
00534
00535
00536 DECLARE_EXPORT void OperationFixedTime::writeElement
00537 (XMLOutput *o, const Keyword& tag, mode m) const
00538 {
00539
00540 if (m == REFERENCE)
00541 {
00542 o->writeElement
00543 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00544 return;
00545 }
00546
00547
00548 if (m != NOHEADER) o->BeginObject
00549 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00550
00551
00552 Operation::writeElement(o, tag, NOHEADER);
00553 if (duration) o->writeElement (Tags::tag_duration, duration);
00554 o->EndObject (tag);
00555 }
00556
00557
00558 DECLARE_EXPORT void OperationFixedTime::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00559 {
00560 if (pAttr.isA (Tags::tag_duration))
00561 setDuration (pElement.getTimeperiod());
00562 else
00563 Operation::endElement (pIn, pAttr, pElement);
00564 }
00565
00566
00567 DECLARE_EXPORT void OperationTimePer::setOperationPlanParameters
00568 (OperationPlan* oplan, double q, Date s, Date e, bool preferEnd) const
00569 {
00570
00571 if (!oplan || q<0)
00572 throw LogicException("Incorrect parameters for timeper operationplan");
00573 if (oplan->getLocked()) return;
00574
00575
00576 if (q > 0 && q < getSizeMinimum()) q = getSizeMinimum();
00577
00578
00579 DateRange x;
00580 TimePeriod actual;
00581 if (s && e)
00582 {
00583
00584
00585
00586 x = calculateOperationTime(s,e,&actual);
00587 if (actual < duration)
00588 {
00589
00590
00591 oplan->setQuantity(0,true,false);
00592 oplan->setEnd(e);
00593 }
00594 else
00595 {
00596
00597
00598 double max_q = duration_per ?
00599 static_cast<double>(actual - duration) / duration_per :
00600 q;
00601
00602
00603
00604 oplan->setQuantity(q < max_q ? q : max_q, true, false);
00605
00606
00607 TimePeriod wanted(
00608 duration + static_cast<long>(duration_per * oplan->getQuantity())
00609 );
00610 if (preferEnd) x = calculateOperationTime(e, wanted, false, &actual);
00611 else x = calculateOperationTime(s, wanted, true, &actual);
00612 oplan->setStartAndEnd(x.getStart(),x.getEnd());
00613 }
00614 }
00615 else if (e || !s)
00616 {
00617
00618
00619
00620
00621 oplan->setQuantity(q,true,false);
00622 TimePeriod wanted(
00623 duration + static_cast<long>(duration_per * oplan->getQuantity())
00624 );
00625 x = calculateOperationTime(e, wanted, false, &actual);
00626 if (actual == wanted)
00627
00628 oplan->setStartAndEnd(x.getStart(),x.getEnd());
00629 else if (actual < duration)
00630 {
00631
00632 oplan->setQuantity(0,true,false);
00633 oplan->setStartAndEnd(e,e);
00634 }
00635 else
00636 {
00637
00638 double max_q = duration_per ?
00639 static_cast<double>(actual-duration) / duration_per :
00640 q;
00641 oplan->setQuantity(q < max_q ? q : max_q, true, false);
00642 oplan->setStartAndEnd(x.getStart(),x.getEnd());
00643 }
00644 }
00645 else
00646 {
00647
00648
00649 oplan->setQuantity(q,true,false);
00650 TimePeriod wanted(
00651 duration + static_cast<long>(duration_per * oplan->getQuantity())
00652 );
00653 TimePeriod actual;
00654 x = calculateOperationTime(s, wanted, true, &actual);
00655 if (actual == wanted)
00656
00657 oplan->setStartAndEnd(x.getStart(),x.getEnd());
00658 else if (actual < duration)
00659 {
00660
00661 oplan->setQuantity(0,true,false);
00662 oplan->setStartAndEnd(s,s);
00663 }
00664 else
00665 {
00666
00667 double max_q = duration_per ?
00668 static_cast<double>(actual-duration) / duration_per :
00669 q;
00670 oplan->setQuantity(q < max_q ? q : max_q, true, false);
00671 oplan->setStartAndEnd(x.getStart(),x.getEnd());
00672 }
00673 }
00674 }
00675
00676
00677 DECLARE_EXPORT void OperationTimePer::writeElement
00678 (XMLOutput *o, const Keyword& tag, mode m) const
00679 {
00680
00681 if (m == REFERENCE)
00682 {
00683 o->writeElement
00684 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00685 return;
00686 }
00687
00688
00689 if (m != NOHEADER) o->BeginObject
00690 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00691
00692
00693 Operation::writeElement(o, tag, NOHEADER);
00694 o->writeElement(Tags::tag_duration, duration);
00695 o->writeElement(Tags::tag_duration_per, duration_per);
00696 o->EndObject(tag);
00697 }
00698
00699
00700 DECLARE_EXPORT void OperationTimePer::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00701 {
00702 if (pAttr.isA (Tags::tag_duration))
00703 setDuration (pElement.getTimeperiod());
00704 else if (pAttr.isA (Tags::tag_duration_per))
00705 setDurationPer (pElement.getTimeperiod());
00706 else
00707 Operation::endElement (pIn, pAttr, pElement);
00708 }
00709
00710
00711 DECLARE_EXPORT void OperationRouting::writeElement
00712 (XMLOutput *o, const Keyword& tag, mode m) const
00713 {
00714
00715 if (m == REFERENCE)
00716 {
00717 o->writeElement
00718 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00719 return;
00720 }
00721
00722
00723 if (m != NOHEADER) o->BeginObject
00724 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00725
00726
00727 Operation::writeElement(o, tag, NOHEADER);
00728 if (steps.size())
00729 {
00730 o->BeginObject(Tags::tag_steps);
00731 for (Operationlist::const_iterator i = steps.begin(); i!=steps.end(); ++i)
00732 o->writeElement(Tags::tag_operation, *i, REFERENCE);
00733 o->EndObject(Tags::tag_steps);
00734 }
00735 o->EndObject(tag);
00736 }
00737
00738
00739 DECLARE_EXPORT void OperationRouting::beginElement (XMLInput& pIn, const Attribute& pAttr)
00740 {
00741 if (pAttr.isA (Tags::tag_operation))
00742 pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
00743 else
00744 Operation::beginElement(pIn, pAttr);
00745 }
00746
00747
00748 DECLARE_EXPORT void OperationRouting::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00749 {
00750 if (pAttr.isA (Tags::tag_operation)
00751 && pIn.getParentElement().first.isA(Tags::tag_steps))
00752 {
00753 Operation *oper = dynamic_cast<Operation*>(pIn.getPreviousObject());
00754 if (oper) addStepBack (oper);
00755 else throw LogicException("Incorrect object type during read operation");
00756 }
00757 Operation::endElement (pIn, pAttr, pElement);
00758 }
00759
00760
00761 DECLARE_EXPORT void OperationRouting::setOperationPlanParameters
00762 (OperationPlan* oplan, double q, Date s, Date e, bool preferEnd) const
00763 {
00764 OperationPlanRouting *op = dynamic_cast<OperationPlanRouting*>(oplan);
00765
00766
00767 if (!op || q<0)
00768 throw LogicException("Incorrect parameters for routing operationplan");
00769 if (op->getLocked()) return;
00770
00771 if (op->step_opplans.empty())
00772 {
00773
00774
00775 oplan->setQuantity(q,false,false);
00776 if (!s && e) s = e;
00777 if (s && !e) e = s;
00778 oplan->setStartAndEnd(s,e);
00779 return;
00780 }
00781
00782
00783
00784
00785 bool firstOp = true;
00786 if (e)
00787 {
00788
00789 for (list<OperationPlan*>::reverse_iterator i = op->step_opplans.rbegin();
00790 i != op->step_opplans.rend(); ++i)
00791 {
00792 if ((*i)->getDates().getEnd() > e || firstOp)
00793 {
00794 (*i)->getOperation()->setOperationPlanParameters(*i,q,Date::infinitePast,e,preferEnd);
00795 e = (*i)->getDates().getStart();
00796 firstOp = false;
00797 }
00798 else
00799
00800
00801 return;
00802 }
00803 }
00804 else
00805 {
00806
00807 for (list<OperationPlan*>::const_iterator i = op->step_opplans.begin();
00808 i != op->step_opplans.end(); ++i)
00809 {
00810 if ((*i)->getDates().getStart() < s || firstOp)
00811 {
00812 (*i)->getOperation()->setOperationPlanParameters(*i,q,s,Date::infinitePast,preferEnd);
00813 s = (*i)->getDates().getEnd();
00814 firstOp = false;
00815 }
00816 else
00817
00818
00819 return;
00820 }
00821 }
00822 }
00823
00824
00825 DECLARE_EXPORT OperationPlan* OperationRouting::createOperationPlan
00826 (double q, Date s, Date e, Demand* l, OperationPlan* ow,
00827 unsigned long i, bool makeflowsloads) const
00828 {
00829
00830 OperationPlan *opplan = new OperationPlanRouting();
00831 initOperationPlan(opplan,q,s,e,l,ow,i,makeflowsloads);
00832 return opplan;
00833 }
00834
00835
00836 DECLARE_EXPORT void OperationAlternate::addAlternate
00837 (Operation* o, int prio, DateRange eff)
00838 {
00839 if (!o) return;
00840 Operationlist::iterator altIter = alternates.begin();
00841 alternatePropertyList::iterator propIter = alternateProperties.begin();
00842 while (altIter!=alternates.end() && prio >= propIter->first)
00843 {
00844 ++propIter;
00845 ++altIter;
00846 }
00847 alternateProperties.insert(propIter,alternateProperty(prio,eff));
00848 alternates.insert(altIter,o);
00849 o->addSuperOperation(this);
00850 }
00851
00852
00853 DECLARE_EXPORT const OperationAlternate::alternateProperty&
00854 OperationAlternate::getProperties(Operation* o) const
00855 {
00856 if (!o)
00857 throw LogicException("Null pointer passed when searching for a \
00858 suboperation of alternate operation '" + getName() + "'");
00859 Operationlist::const_iterator altIter = alternates.begin();
00860 alternatePropertyList::const_iterator propIter = alternateProperties.begin();
00861 while (altIter!=alternates.end() && *altIter != o)
00862 {
00863 ++propIter;
00864 ++altIter;
00865 }
00866 if (*altIter == o) return *propIter;
00867 throw DataException("Operation '" + o->getName() +
00868 "' isn't a suboperation of alternate operation '" + getName() + "'");
00869 }
00870
00871
00872 DECLARE_EXPORT void OperationAlternate::setPriority(Operation* o, int f)
00873 {
00874 if (!o) return;
00875 Operationlist::const_iterator altIter = alternates.begin();
00876 alternatePropertyList::iterator propIter = alternateProperties.begin();
00877 while (altIter!=alternates.end() && *altIter != o)
00878 {
00879 ++propIter;
00880 ++altIter;
00881 }
00882 if (*altIter == o)
00883 propIter->first = f;
00884 else
00885 throw DataException("Operation '" + o->getName() +
00886 "' isn't a suboperation of alternate operation '" + getName() + "'");
00887 }
00888
00889
00890 DECLARE_EXPORT void OperationAlternate::setEffective(Operation* o, DateRange dr)
00891 {
00892 if (!o) return;
00893 Operationlist::const_iterator altIter = alternates.begin();
00894 alternatePropertyList::iterator propIter = alternateProperties.begin();
00895 while (altIter!=alternates.end() && *altIter != o)
00896 {
00897 ++propIter;
00898 ++altIter;
00899 }
00900 if (*altIter == o)
00901 propIter->second = dr;
00902 else
00903 throw DataException("Operation '" + o->getName() +
00904 "' isn't a suboperation of alternate operation '" + getName() + "'");
00905 }
00906
00907
00908 DECLARE_EXPORT void OperationAlternate::writeElement
00909 (XMLOutput *o, const Keyword& tag, mode m) const
00910 {
00911
00912 if (m == REFERENCE)
00913 {
00914 o->writeElement
00915 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00916 return;
00917 }
00918
00919
00920 if (m != NOHEADER) o->BeginObject
00921 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00922
00923
00924 Operation::writeElement(o, tag, NOHEADER);
00925
00926
00927 o->BeginObject(Tags::tag_alternates);
00928 alternatePropertyList::const_iterator propIter = alternateProperties.begin();
00929 for (Operationlist::const_iterator i = alternates.begin();
00930 i != alternates.end(); ++i)
00931 {
00932 o->BeginObject(Tags::tag_alternate);
00933 o->writeElement(Tags::tag_operation, *i, REFERENCE);
00934 o->writeElement(Tags::tag_priority, propIter->first);
00935 if (propIter->second.getStart() != Date::infinitePast)
00936 o->writeElement(Tags::tag_effective_start, propIter->second.getStart());
00937 if (propIter->second.getEnd() != Date::infiniteFuture)
00938 o->writeElement(Tags::tag_effective_end, propIter->second.getEnd());
00939 o->EndObject (Tags::tag_alternate);
00940 ++propIter;
00941 }
00942 o->EndObject(Tags::tag_alternates);
00943
00944
00945 o->EndObject(tag);
00946 }
00947
00948
00949 DECLARE_EXPORT void OperationAlternate::beginElement (XMLInput& pIn, const Attribute& pAttr)
00950 {
00951 if (pAttr.isA(Tags::tag_operation))
00952 pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
00953 else
00954 Operation::beginElement(pIn, pAttr);
00955 }
00956
00957
00958 DECLARE_EXPORT void OperationAlternate::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00959 {
00960
00961 typedef pair<Operation*,alternateProperty> tempData;
00962
00963
00964 if (!pIn.getUserArea())
00965 pIn.setUserArea(new tempData(NULL,alternateProperty(1,DateRange())));
00966 tempData* tmp = static_cast<tempData*>(pIn.getUserArea());
00967
00968 if (pAttr.isA(Tags::tag_alternate))
00969 {
00970 addAlternate(tmp->first, tmp->second.first, tmp->second.second);
00971
00972 tmp->first = NULL;
00973 tmp->second.first = 1;
00974 tmp->second.second = DateRange();
00975 }
00976 else if (pAttr.isA(Tags::tag_priority))
00977 tmp->second.first = pElement.getInt();
00978 else if (pAttr.isA(Tags::tag_effective_start))
00979 tmp->second.second.setStart(pElement.getDate());
00980 else if (pAttr.isA(Tags::tag_effective_end))
00981 tmp->second.second.setEnd(pElement.getDate());
00982 else if (pAttr.isA(Tags::tag_operation)
00983 && pIn.getParentElement().first.isA(Tags::tag_alternate))
00984 {
00985 Operation * b = dynamic_cast<Operation*>(pIn.getPreviousObject());
00986 if (b) tmp->first = b;
00987 else throw LogicException("Incorrect object type during read operation");
00988 }
00989 Operation::endElement (pIn, pAttr, pElement);
00990
00991
00992 if (pIn.isObjectEnd()) delete static_cast<tempData*>(pIn.getUserArea());
00993 }
00994
00995
00996 DECLARE_EXPORT OperationPlan* OperationAlternate::createOperationPlan (double q,
00997 Date s, Date e, Demand* l, OperationPlan* ow,
00998 unsigned long i, bool makeflowsloads) const
00999 {
01000
01001 OperationPlan *opplan = new OperationPlanAlternate();
01002 if (!s) s = e;
01003 if (!e) e = s;
01004 initOperationPlan(opplan,q,s,e,l,ow,i,makeflowsloads);
01005 return opplan;
01006 }
01007
01008
01009 DECLARE_EXPORT void OperationAlternate::setOperationPlanParameters
01010 (OperationPlan* oplan, double q, Date s, Date e, bool preferEnd) const
01011 {
01012
01013 OperationPlanAlternate *oa = dynamic_cast<OperationPlanAlternate*>(oplan);
01014
01015
01016 if (!oa || q<0)
01017 throw LogicException("Incorrect parameters for alternate operationplan");
01018 if (oa->getLocked()) return;
01019
01020 if (!oa->altopplan)
01021 {
01022
01023 oplan->setQuantity(q,false,false);
01024 oplan->setStartAndEnd(s, e);
01025 }
01026 else
01027
01028 oa->altopplan->getOperation()
01029 ->setOperationPlanParameters(oa->altopplan,q,s,e,preferEnd);
01030 }
01031
01032
01033 DECLARE_EXPORT void OperationAlternate::removeSubOperation(Operation *o)
01034 {
01035 Operationlist::iterator altIter = alternates.begin();
01036 alternatePropertyList::iterator propIter = alternateProperties.begin();
01037 while (altIter!=alternates.end() && *altIter != o)
01038 {
01039 ++propIter;
01040 ++altIter;
01041 }
01042 if (*altIter == o)
01043 {
01044 alternates.erase(altIter);
01045 alternateProperties.erase(propIter);
01046 o->superoplist.remove(this);
01047 setChanged();
01048 }
01049 else
01050 logger << "Warning: operation '" << *o
01051 << "' isn't a suboperation of alternate operation '" << *this
01052 << "'" << endl;
01053 }
01054
01055
01056 DECLARE_EXPORT PyObject* PythonOperation::getattro(const Attribute& attr)
01057 {
01058 if (!obj) return Py_BuildValue("");
01059 if (attr.isA(Tags::tag_name))
01060 return PythonObject(obj->getName());
01061 if (attr.isA(Tags::tag_description))
01062 return PythonObject(obj->getDescription());
01063 if (attr.isA(Tags::tag_category))
01064 return PythonObject(obj->getCategory());
01065 if (attr.isA(Tags::tag_subcategory))
01066 return PythonObject(obj->getSubCategory());
01067 if (attr.isA(Tags::tag_location))
01068 return PythonObject(obj->getLocation());
01069 if (attr.isA(Tags::tag_fence))
01070 return PythonObject(obj->getFence());
01071 if (attr.isA(Tags::tag_size_minimum))
01072 return PythonObject(obj->getSizeMinimum());
01073 if (attr.isA(Tags::tag_size_multiple))
01074 return PythonObject(obj->getSizeMultiple());
01075 if (attr.isA(Tags::tag_cost))
01076 return PythonObject(obj->getCost());
01077 if (attr.isA(Tags::tag_pretime))
01078 return PythonObject(obj->getPreTime());
01079 if (attr.isA(Tags::tag_posttime))
01080 return PythonObject(obj->getPostTime());
01081 if (attr.isA(Tags::tag_hidden))
01082 return PythonObject(obj->getHidden());
01083 if (attr.isA(Tags::tag_loads))
01084 return new PythonLoadIterator(obj);
01085 if (attr.isA(Tags::tag_flows))
01086 return new PythonFlowIterator(obj);
01087 if (attr.isA(Tags::tag_operationplans))
01088 return new PythonOperationPlanIterator(obj);
01089 if (attr.isA(Tags::tag_level))
01090 return PythonObject(obj->getLevel());
01091 if (attr.isA(Tags::tag_cluster))
01092 return PythonObject(obj->getCluster());
01093 return NULL;
01094 }
01095
01096
01097 DECLARE_EXPORT int PythonOperation::setattro(const Attribute& attr, const PythonObject& field)
01098 {
01099 if (attr.isA(Tags::tag_name))
01100 obj->setName(field.getString());
01101 else if (attr.isA(Tags::tag_description))
01102 obj->setDescription(field.getString());
01103 else if (attr.isA(Tags::tag_category))
01104 obj->setCategory(field.getString());
01105 else if (attr.isA(Tags::tag_subcategory))
01106 obj->setSubCategory(field.getString());
01107 else if (attr.isA(Tags::tag_location))
01108 {
01109 if (!field.check(PythonLocation::getType()))
01110 {
01111 PyErr_SetString(PythonDataException, "buffer location must be of type location");
01112 return -1;
01113 }
01114 Location* y = static_cast<PythonLocation*>(static_cast<PyObject*>(field))->obj;
01115 obj->setLocation(y);
01116 }
01117 else if (attr.isA(Tags::tag_fence))
01118 obj->setFence(field.getTimeperiod());
01119 else if (attr.isA(Tags::tag_size_minimum))
01120 obj->setSizeMinimum(field.getDouble());
01121 else if (attr.isA(Tags::tag_size_multiple))
01122 obj->setSizeMultiple(field.getDouble());
01123 else if (attr.isA(Tags::tag_cost))
01124 obj->setCost(field.getDouble());
01125 else if (attr.isA(Tags::tag_pretime))
01126 obj->setPreTime(field.getTimeperiod());
01127 else if (attr.isA(Tags::tag_posttime))
01128 obj->setPostTime(field.getTimeperiod());
01129 else if (attr.isA(Tags::tag_hidden))
01130 obj->setHidden(field.getBool());
01131 else
01132 return -1;
01133 return 0;
01134 }
01135
01136
01137 DECLARE_EXPORT PyObject* PythonOperationFixedTime::getattro(const Attribute& attr)
01138 {
01139 if (!obj) return Py_BuildValue("");
01140 if (attr.isA(Tags::tag_duration))
01141 return PythonObject(obj->getDuration());
01142 return PythonOperation(obj).getattro(attr);
01143 }
01144
01145
01146 DECLARE_EXPORT int PythonOperationFixedTime::setattro(const Attribute& attr, const PythonObject& field)
01147 {
01148 if (!obj) return -1;
01149 if (attr.isA(Tags::tag_duration))
01150 obj->setDuration(field.getTimeperiod());
01151 else
01152 return PythonOperation(obj).setattro(attr, field);
01153 return 0;
01154 }
01155
01156
01157 DECLARE_EXPORT PyObject* PythonOperationTimePer::getattro(const Attribute& attr)
01158 {
01159 if (!obj) return Py_BuildValue("");
01160 if (attr.isA(Tags::tag_duration))
01161 return PythonObject(obj->getDuration());
01162 if (attr.isA(Tags::tag_duration))
01163 return PythonObject(obj->getDurationPer());
01164 return PythonOperation(obj).getattro(attr);
01165 }
01166
01167
01168 DECLARE_EXPORT int PythonOperationTimePer::setattro(const Attribute& attr, const PythonObject& field)
01169 {
01170 if (!obj) return -1;
01171 if (attr.isA(Tags::tag_duration))
01172 obj->setDuration(field.getTimeperiod());
01173 else if (attr.isA(Tags::tag_duration_per))
01174 obj->setDurationPer(field.getTimeperiod());
01175 else
01176 return PythonOperation(obj).setattro(attr, field);
01177 return 0;
01178 }
01179
01180
01181 DECLARE_EXPORT PyObject* PythonOperationAlternate::getattro(const Attribute& attr)
01182 {
01183 if (!obj) return Py_BuildValue("");
01184 if (attr.isA(Tags::tag_alternates))
01185 {
01186 PyObject* result = PyTuple_New(obj->getSubOperations().size());
01187 int count = 0;
01188 for (Operation::Operationlist::const_iterator i = obj->getSubOperations().begin(); i != obj->getSubOperations().end(); ++i)
01189 PyTuple_SetItem(result, count++, PythonObject(*i));
01190 return result;
01191 }
01192 return PythonOperation(obj).getattro(attr);
01193 }
01194
01195
01196 DECLARE_EXPORT int PythonOperationAlternate::setattro(const Attribute& attr, const PythonObject& field)
01197 {
01198 return PythonOperation(obj).setattro(attr, field);
01199 }
01200
01201
01202 DECLARE_EXPORT PyObject* PythonOperationAlternate::addAlternate(PyObject* self, PyObject* args, PyObject* kwdict)
01203 {
01204 try
01205 {
01206
01207 OperationAlternate *altoper = static_cast<PythonOperationAlternate*>(self)->obj;
01208 if (!altoper) throw LogicException("Can't add alternates to NULL alternate");
01209
01210
01211 PyObject *oper = NULL;
01212 int prio = 1;
01213 PyObject *eff_start = NULL;
01214 PyObject *eff_end = NULL;
01215 static const char *kwlist[] = {"operation", "priority", "effective_start", "effective_end", NULL};
01216 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
01217 "O|iOO:addAlternate",
01218 const_cast<char**>(kwlist), &oper, &prio, &eff_start, &eff_end))
01219 return NULL;
01220 if (!PyObject_TypeCheck(oper, PythonOperation::getType().type_object()))
01221 throw DataException("alternate operation must be of type operation");
01222 DateRange eff;
01223 if (eff_start)
01224 {
01225 PythonObject d(eff_start);
01226 eff.setStart(d.getDate());
01227 }
01228 if (eff_end)
01229 {
01230 PythonObject d(eff_end);
01231 eff.setEnd(d.getDate());
01232 }
01233
01234
01235 altoper->addAlternate(static_cast<PythonOperation*>(oper)->obj, prio, eff);
01236 }
01237 catch(...)
01238 {
01239 PythonType::evalException();
01240 return NULL;
01241 }
01242 return Py_BuildValue("");
01243 }
01244
01245
01246 DECLARE_EXPORT PyObject* PythonOperationRouting::getattro(const Attribute& attr)
01247 {
01248 if (!obj) return Py_BuildValue("");
01249 if (attr.isA(Tags::tag_steps))
01250 {
01251 PyObject* result = PyTuple_New(obj->getSubOperations().size());
01252 int count = 0;
01253 for (Operation::Operationlist::const_iterator i = obj->getSubOperations().begin(); i != obj->getSubOperations().end(); ++i)
01254 PyTuple_SetItem(result, count++, PythonObject(*i));
01255 return result;
01256 }
01257 return PythonOperation(obj).getattro(attr);
01258 }
01259
01260
01261 DECLARE_EXPORT int PythonOperationRouting::setattro(const Attribute& attr, const PythonObject& field)
01262 {
01263 return PythonOperation(obj).setattro(attr, field);
01264 }
01265
01266
01267 PyObject *PythonOperationRouting::addStep(PyObject *self, PyObject *args)
01268 {
01269 try
01270 {
01271
01272 OperationRouting *oper = static_cast<PythonOperationRouting*>(self)->obj;
01273 if (!oper) throw LogicException("Can't add steps to NULL routing");
01274
01275
01276 PyObject *steps[4];
01277 for (unsigned int i=0; i<4; ++i) steps[i] = NULL;
01278 if (PyArg_UnpackTuple(args, "addStep", 1, 4, &steps[0], &steps[1], &steps[2], &steps[3]))
01279 for (unsigned int i=0; i<4 && steps[i]; ++i)
01280 {
01281 if (!PyObject_TypeCheck(steps[i], PythonOperation::getType().type_object()))
01282 throw DataException("routing steps must be of type operation");
01283 oper->addStepBack(static_cast<PythonOperation*>(steps[i])->obj);
01284 }
01285 }
01286 catch(...)
01287 {
01288 PythonType::evalException();
01289 return NULL;
01290 }
01291 return Py_BuildValue("");
01292 }
01293
01294 }