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
