demand.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/src/model/demand.cpp $
00003   version : $LastChangedRevision: 746 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2008-04-19 11:23:51 +0200 (Sat, 19 Apr 2008) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007 by Johan De Taeye                                    *
00010  *                                                                         *
00011  * This library is free software; you can redistribute it and/or modify it *
00012  * under the terms of the GNU Lesser General Public License as published   *
00013  * by the Free Software Foundation; either version 2.1 of the License, or  *
00014  * (at your option) any later version.                                     *
00015  *                                                                         *
00016  * This library is distributed in the hope that it will be useful,         *
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
00019  * General Public License for more details.                                *
00020  *                                                                         *
00021  * You should have received a copy of the GNU Lesser General Public        *
00022  * License along with this library; if not, write to the Free Software     *
00023  * Foundation Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA *
00024  *                                                                         *
00025  ***************************************************************************/
00026 
00027 #define FREPPLE_CORE
00028 #include "frepple/model.h"
00029 
00030 namespace frepple
00031 {
00032 
00033 template<class Demand> DECLARE_EXPORT Tree HasName<Demand>::st;
00034 
00035 
00036 DECLARE_EXPORT void Demand::setQuantity(double f)
00037 {
00038   // Reject negative quantities, and no-change updates
00039   double delta(f - qty);
00040   if (f < 0.0 || fabs(delta)<ROUNDING_ERROR) return;
00041 
00042   // Update the quantity
00043   qty = f;
00044   setChanged();
00045 }
00046 
00047 
00048 DECLARE_EXPORT void Demand::deleteOperationPlans (bool deleteLockedOpplans)
00049 {
00050   // Delete all opplans
00051   for (OperationPlan_list::iterator i = deli.begin(); i!=deli.end(); )
00052     if (deleteLockedOpplans || !(*i)->getLocked())
00053     {
00054       // Setting the demand pointer to NULL is required to prevent the
00055       // deletion of the operationplan calling the function removeDelivery.
00056       // We can't use the regular method setDemand() to do this!
00057       (*i)->dmd = NULL;
00058       delete *i;
00059       // Remove from the list - while trying to maintain a valid iterator to
00060       // the next element.
00061       OperationPlan_list::iterator todelete = i;
00062       ++i;
00063       deli.erase(todelete);
00064     }
00065     else ++i;
00066 
00067   // Mark the demand as being changed, so the problems can be redetected
00068   setChanged();
00069 }
00070 
00071 
00072 DECLARE_EXPORT void Demand::removeDelivery(OperationPlan * o)
00073 {
00074   // Valid opplan check
00075   if (!o) return;
00076 
00077   // See if the demand field on the operationplan points to this demand
00078   if (o->dmd != this)
00079     throw LogicException("Delivery operationplan incorrectly registered");
00080 
00081   // Remove the reference on the operationplan
00082   o->dmd = NULL;  // Required to avoid endless loop
00083   o->setDemand(NULL);
00084 
00085   // Find in the list of deliveries
00086   OperationPlan_list::iterator j = deli.begin();
00087   while (j!=deli.end() && *j!=o) ++j;
00088 
00089   // Check that the operation is found
00090   // It is possible it is not found! This happens if e.g. an operationplan
00091   // is created but destroyed again before it is initialized.
00092   if (j!=deli.end())
00093   {
00094     // Remove from the list
00095     deli.erase(j);
00096     // Mark the demand as being changed, so the problems can be redetected
00097     setChanged();
00098   }
00099 }
00100 
00101 
00102 DECLARE_EXPORT const Demand::OperationPlan_list& Demand::getDelivery() const
00103 {
00104   // We need to check the sorting order of the list first! It could be disturbed
00105   // when operationplans are being moved around.
00106   // The sorting routine isn't very efficient, but should suffice since the
00107   // list of delivery operationplans is short and isn't expected to be
00108   // disturbed very often.
00109   for (bool swapped(!deli.empty()); swapped; swapped=false)
00110   {
00111     OperationPlan_list::iterator j = const_cast<Demand*>(this)->deli.begin();
00112     ++j;
00113     for (OperationPlan_list::iterator i =
00114           const_cast<Demand*>(this)->deli.begin();
00115         j!=const_cast<Demand*>(this)->deli.end(); ++j)
00116     {
00117       if ((*i)->getDates().getEnd() < (*j)->getDates().getEnd())
00118       {
00119         // Oh yes, the ordering was disrupted indeed...
00120         iter_swap(i,j);
00121         // The Borland compiler doesn't understand that this variable is used.
00122         // It gives a incorrect warning message...
00123         swapped = true;
00124         break;
00125       }
00126       ++i;
00127     }
00128   }
00129 
00130   return deli;
00131 }
00132 
00133 
00134 DECLARE_EXPORT void Demand::addDelivery (OperationPlan * o)
00135 {
00136   // Dummy call to this function
00137   if (!o) return;
00138 
00139   // Check if it is already in the list.
00140   // If it is, simply exit the function. No need to give a warning message
00141   // since it's harmless.
00142   for (OperationPlan_list::iterator i = deli.begin(); i!=deli.end(); ++i)
00143     if (*i == o) return;
00144 
00145   // Add to the list of delivery operationplans. The insertion is such
00146   // that the delivery list is sorted in terms of descending end time.
00147   // i.e. the opplan with the latest end date is on the front of the list.
00148   // Note: We're forcing resorting the deliveries with the getDelivery()
00149   // method. Operation plans dates could have changed, thus disturbing the
00150   // original order.
00151   getDelivery();
00152   OperationPlan_list::iterator j = deli.begin();
00153   while (j!=deli.end() && (*j)->getDates().getEnd()>o->getDates().getEnd()) ++j;
00154   deli.insert(j, o);
00155 
00156   // Mark the demand as being changed, so the problems can be redetected
00157   setChanged();
00158 
00159   // Create link between operationplan and demand
00160   o->setDemand(this);
00161 
00162   // Check validity of operation being used
00163   Operation* tmpOper = getDeliveryOperation();
00164   if (tmpOper && tmpOper != o->getOperation())
00165     logger << "Warning: Delivery Operation '" << o->getOperation()
00166     << "' different than expected '" << tmpOper
00167     << "' for demand '" << this << "'" << endl;
00168 }
00169 
00170 
00171 DECLARE_EXPORT Operation* Demand::getDeliveryOperation() const
00172 {
00173   // Operation can be specified on the demand itself,
00174   if (oper) return oper;
00175   // ... or on the item,
00176   if (it) return it->getOperation();
00177   // ... or it doesn't exist at all
00178   return NULL;
00179 }
00180 
00181 
00182 DECLARE_EXPORT double Demand::getPlannedQuantity() const
00183 {
00184   double delivered(0.0);
00185   for (OperationPlan_list::const_iterator i=deli.begin(); i!=deli.end(); ++i)
00186     delivered += (*i)->getQuantity();
00187   return delivered;
00188 }
00189 
00190 
00191 DECLARE_EXPORT void Demand::writeElement(XMLOutput *o, const Keyword& tag, mode m) const
00192 {
00193   // Writing a reference
00194   if (m == REFERENCE)
00195   {
00196     o->writeElement(tag, Tags::tag_name, getName());
00197     return;
00198   }
00199 
00200   // Write the complete object
00201   if (m != NOHEADER) o->BeginObject(tag, Tags::tag_name, getName());
00202 
00203   // Write the fields
00204   HasDescription::writeElement(o, tag);
00205   HasHierarchy<Demand>::writeElement(o, tag);
00206   o->writeElement(Tags::tag_operation, oper);
00207   o->writeElement(Tags::tag_customer, cust);
00208   Plannable::writeElement(o, tag);
00209 
00210   o->writeElement(Tags::tag_quantity, qty);
00211   o->writeElement(Tags::tag_item, it);
00212   o->writeElement(Tags::tag_due, dueDate);
00213   if (getPriority()) o->writeElement(Tags::tag_priority, getPriority());
00214   if (getMaxLateness() != TimePeriod::MAX)
00215     o->writeElement(Tags::tag_maxlateness, getMaxLateness());
00216   if (getMinShipment())
00217     o->writeElement(Tags::tag_minshipment, getMinShipment());
00218 
00219   // Write extra plan information
00220   if ((o->getContentType() == XMLOutput::PLAN
00221       || o->getContentType() == XMLOutput::PLANDETAIL) && !deli.empty())
00222   {
00223     o->BeginObject(Tags::tag_operationplans);
00224     for (OperationPlan_list::const_iterator i=deli.begin(); i!=deli.end(); ++i)
00225       o->writeElement(Tags::tag_operationplan, *i, FULL);
00226     o->EndObject(Tags::tag_operationplans);
00227   }
00228   o->EndObject(tag);
00229 }
00230 
00231 
00232 DECLARE_EXPORT void Demand::beginElement(XMLInput& pIn, const Attribute& pAttr)
00233 {
00234   if (pAttr.isA (Tags::tag_item))
00235     pIn.readto( Item::reader(Item::metadata,pIn.getAttributes()) );
00236   else if (pAttr.isA (Tags::tag_operation))
00237     pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
00238   else if (pAttr.isA (Tags::tag_customer))
00239     pIn.readto( Customer::reader(Customer::metadata,pIn.getAttributes()) );
00240   else if (pAttr.isA(Tags::tag_operationplan))
00241     pIn.readto(OperationPlan::createOperationPlan(OperationPlan::metadata,pIn.getAttributes()));
00242   else
00243     HasHierarchy<Demand>::beginElement(pIn, pAttr);
00244 }
00245 
00246 
00247 DECLARE_EXPORT void Demand::endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00248 {
00249   if (pAttr.isA (Tags::tag_quantity))
00250     setQuantity (pElement.getDouble());
00251   else if (pAttr.isA (Tags::tag_priority))
00252     setPriority (pElement.getInt());
00253   else if (pAttr.isA (Tags::tag_due))
00254     setDue(pElement.getDate());
00255   else if (pAttr.isA (Tags::tag_operation))
00256   {
00257     Operation *o = dynamic_cast<Operation*>(pIn.getPreviousObject());
00258     if (o) setOperation(o);
00259     else throw LogicException("Incorrect object type during read operation");
00260   }
00261   else if (pAttr.isA (Tags::tag_customer))
00262   {
00263     Customer *c = dynamic_cast<Customer*>(pIn.getPreviousObject());
00264     if (c) setCustomer(c);
00265     else throw LogicException("Incorrect object type during read operation");
00266   }
00267   else if (pAttr.isA (Tags::tag_item))
00268   {
00269     Item *i = dynamic_cast<Item*>(pIn.getPreviousObject());
00270     if (i) setItem(i);
00271     else throw LogicException("Incorrect object type during read operation");
00272   }
00273   else if (pAttr.isA (Tags::tag_maxlateness))
00274     setMaxLateness(pElement.getTimeperiod());
00275   else if (pAttr.isA (Tags::tag_minshipment))
00276     setMinShipment(pElement.getDouble());
00277   else if (pAttr.isA(Tags::tag_operationplan))
00278   {
00279     OperationPlan* opplan
00280       = dynamic_cast<OperationPlan*>(pIn.getPreviousObject());
00281     if (opplan) addDelivery(opplan);
00282     else throw LogicException("Incorrect object type during read operation");
00283   }
00284   else
00285   {
00286     Plannable::endElement(pIn, pAttr, pElement);
00287     HasDescription::endElement(pIn, pAttr, pElement);
00288     HasHierarchy<Demand>::endElement (pIn, pAttr, pElement);
00289   }
00290 }
00291 
00292 }

Documentation generated by  doxygen