flow.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/src/model/flow.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 
00028 #define FREPPLE_CORE
00029 #include "frepple/model.h"
00030 namespace frepple
00031 {
00032 
00033 
00034 DECLARE_EXPORT void Flow::validate(Action action)
00035 {
00036   // Catch null operation and buffer pointers
00037   Operation* oper = getOperation();
00038   Buffer* buf = getBuffer();
00039   if (!oper || !buf)
00040   {
00041     // This flow is not a valid one since it misses essential information
00042     delete this;
00043     if (!oper && !buf)
00044       throw DataException("Missing operation and buffer on a flow");
00045     else if (!oper)
00046       throw DataException("Missing operation on a flow with buffer '"
00047           + buf->getName() + "'");
00048     else
00049       throw DataException("Missing buffer on a flow with operation '"
00050           + oper->getName() + "'");
00051   }
00052 
00053   // Check if a flow with 1) identical buffer, 2) identical operation and 
00054   // 3) overlapping effectivity dates already exists
00055   Operation::flowlist::const_iterator i = oper->getFlows().begin();
00056   for (; i != oper->getFlows().end(); ++i)
00057     if (i->getBuffer() == buf 
00058       && i->getEffective().overlap(getEffective()) 
00059       && &*i != this) 
00060         break;
00061 
00062   // Apply the appropriate action
00063   switch (action)
00064   {
00065     case ADD:
00066       if (i != oper->getFlows().end())
00067       {
00068         delete this;
00069         throw DataException("Flow of '" + oper->getName() + "' and '" +
00070             buf->getName() + "' already exists.");
00071       }
00072       break;
00073     case CHANGE:
00074       delete this;
00075       throw DataException("Can't update a flow");
00076     case ADD_CHANGE:
00077       // ADD is handled in the code after the switch statement
00078       if (i == oper->getFlows().end()) break;
00079       delete this;
00080       throw DataException("Can't update a flow");
00081     case REMOVE:
00082       // Delete the temporary flow object
00083       delete this;
00084       // Nothing to delete
00085       if (i == oper->getFlows().end())
00086         throw DataException("Can't remove nonexistent flow of '"
00087             + oper->getName() + "' and '" + buf->getName() + "'");
00088       // Delete
00089       delete &*i;
00090  }
00091 
00092   // Attach to buffers higher up in the hierarchy
00093   // Note that the owner can create more loads if it has an owner too.
00094   if (buf->hasOwner() && action!=REMOVE) new Flow(oper, buf->getOwner(), quantity);
00095 
00096   // Set a flag to make sure the level computation is triggered again
00097   HasLevel::triggerLazyRecomputation();
00098 }
00099 
00100 
00101 DECLARE_EXPORT Flow::~Flow()
00102 {
00103   // Set a flag to make sure the level computation is triggered again
00104   HasLevel::triggerLazyRecomputation();
00105 
00106   // Delete existing flowplans
00107   if (getOperation() && getBuffer())
00108   {
00109     // Loop over operationplans
00110     for(OperationPlan::iterator i(getOperation()); i != OperationPlan::end(); ++i)
00111       // Loop over flowplans
00112       for(OperationPlan::FlowPlanIterator j = i->beginFlowPlans(); j != i->endFlowPlans(); )
00113         if (j->getFlow() == this) j.deleteFlowPlan();
00114         else ++j;
00115   }
00116 
00117   // Delete the flow from the operation and the buffer
00118   if (getOperation()) getOperation()->flowdata.erase(this);
00119   if (getBuffer()) getBuffer()->flows.erase(this);
00120 }
00121 
00122 
00123 DECLARE_EXPORT void Flow::writeElement (XMLOutput *o, const Keyword& tag, mode m) const
00124 {
00125   // If the flow has already been saved, no need to repeat it again
00126   // A 'reference' to a flow is not useful to be saved.
00127   if (m == REFERENCE) return;
00128   assert(m != NOHEADER);
00129 
00130   // Write the header
00131   o->BeginObject(tag, Tags::tag_type, getType().type);
00132 
00133   // If the flow is defined inside of an operation tag, we don't need to save
00134   // the operation. Otherwise we do save it...
00135   if (!dynamic_cast<Operation*>(o->getPreviousObject()))
00136     o->writeElement(Tags::tag_operation, getOperation());
00137 
00138   // If the flow is defined inside of an buffer tag, we don't need to save
00139   // the buffer. Otherwise we do save it...
00140   if (!dynamic_cast<Buffer*>(o->getPreviousObject()))
00141     o->writeElement(Tags::tag_buffer, getBuffer());
00142 
00143   // Write the quantity
00144   o->writeElement(Tags::tag_quantity, quantity);
00145 
00146   // Write the effective daterange
00147   if (getEffective().getStart() != Date::infinitePast)
00148     o->writeElement(Tags::tag_effective_start, getEffective().getStart());
00149   if (getEffective().getEnd() != Date::infiniteFuture)
00150     o->writeElement(Tags::tag_effective_end, getEffective().getEnd());
00151 
00152   // End of flow object
00153   o->EndObject(tag);
00154 }
00155 
00156 
00157 DECLARE_EXPORT void Flow::beginElement (XMLInput& pIn, const Attribute& pAttr)
00158 {
00159   if (pAttr.isA (Tags::tag_buffer))
00160     pIn.readto( Buffer::reader(Buffer::metadata,pIn.getAttributes()) );
00161   else if (pAttr.isA (Tags::tag_operation))
00162     pIn.readto( Operation::reader(Operation::metadata,pIn.getAttributes()) );
00163 }
00164 
00165 
00166 DECLARE_EXPORT void Flow::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00167 {
00168   if (pAttr.isA (Tags::tag_buffer))
00169   {
00170     Buffer * b = dynamic_cast<Buffer*>(pIn.getPreviousObject());
00171     if (b) setBuffer(b);
00172     else throw LogicException("Incorrect object type during read operation");
00173   }
00174   else if (pAttr.isA (Tags::tag_operation))
00175   {
00176     Operation * o = dynamic_cast<Operation*>(pIn.getPreviousObject());
00177     if (o) setOperation(o);
00178     else throw LogicException("Incorrect object type during read operation");
00179   }
00180   else if (pAttr.isA(Tags::tag_quantity))
00181     setQuantity(pElement.getDouble());
00182   else if (pAttr.isA(Tags::tag_action))
00183   {
00184     delete static_cast<Action*>(pIn.getUserArea());
00185     pIn.setUserArea(
00186       new Action(MetaClass::decodeAction(pElement.getString().c_str()))
00187     );
00188   }
00189   else if (pAttr.isA(Tags::tag_effective_end))
00190     setEffectiveEnd(pElement.getDate());
00191   else if (pAttr.isA(Tags::tag_effective_start))
00192     setEffectiveStart(pElement.getDate());
00193   else if (pIn.isObjectEnd())
00194   {
00195     // The flow data are now all read in. See if it makes sense now...
00196     Action a = pIn.getUserArea() ?
00197       *static_cast<Action*>(pIn.getUserArea()) :
00198       ADD_CHANGE;
00199     delete static_cast<Action*>(pIn.getUserArea());
00200     validate(a);
00201   }
00202 }
00203 
00204 
00205 DECLARE_EXPORT void FlowEnd::writeElement
00206 (XMLOutput *o, const Keyword& tag, mode m) const
00207 {
00208   // If the flow has already been saved, no need to repeat it again
00209   // A 'reference' to a flow is not useful to be saved.
00210   if (m == REFERENCE) return;
00211   assert(m != NOHEADER);
00212 
00213   // Write the header
00214   o->BeginObject(tag, Tags::tag_type, getType().type);
00215 
00216   // If the flow is defined inside of an operation tag, we don't need to save
00217   // the operation. Otherwise we do save it...
00218   if (!dynamic_cast<Operation*>(o->getPreviousObject()))
00219     o->writeElement(Tags::tag_operation, getOperation());
00220 
00221   // If the flow is defined inside of an buffer tag, we don't need to save
00222   // the buffer. Otherwise we do save it...
00223   if (!dynamic_cast<Buffer*>(o->getPreviousObject()))
00224     o->writeElement(Tags::tag_buffer, getBuffer());
00225 
00226   // Write the quantity
00227   o->writeElement(Tags::tag_quantity, getQuantity());
00228 
00229   // End of flow object
00230   o->EndObject(tag);
00231 }
00232 
00233 
00234 }

Documentation generated by  doxygen