setupmatrix.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: http://svn.code.sf.net/p/frepple/code/trunk/src/model/setupmatrix.cpp $
00003   version : $LastChangedRevision: 1713 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2012-07-18 11:46:01 +0200 (Wed, 18 Jul 2012) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2009 by Johan De Taeye, frePPLe bvba                                    *
00010  *                                                                         *
00011  * This library is free software; you can redistribute it and/or modify it *
00012  * under the terms of the GNU Affero General Public License as published   *
00013  * by the Free Software Foundation; either version 3 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            *
00019  * GNU Affero General Public License for more details.                     *
00020  *                                                                         *
00021  * You should have received a copy of the GNU Affero General Public        *
00022  * License along with this program.                                        *
00023  * If not, see <http://www.gnu.org/licenses/>.                             *
00024  *                                                                         *
00025  ***************************************************************************/
00026 
00027 #define FREPPLE_CORE
00028 #include "frepple/model.h"
00029 
00030 namespace frepple
00031 {
00032 
00033 template<class SetupMatrix> DECLARE_EXPORT Tree utils::HasName<SetupMatrix>::st;
00034 DECLARE_EXPORT const MetaCategory* SetupMatrix::metadata;
00035 DECLARE_EXPORT const MetaClass* SetupMatrixDefault::metadata;
00036 DECLARE_EXPORT const MetaCategory* SetupMatrix::Rule::metadata;
00037 
00038 
00039 int SetupMatrix::initialize()
00040 {
00041   // Initialize the metadata
00042   metadata = new MetaCategory("setupmatrix", "setupmatrices", reader, writer);
00043 
00044   // Initialize the Python class
00045   FreppleCategory<SetupMatrix>::getType().addMethod("addRule", addPythonRule, METH_KEYWORDS, "add a new setup rule");
00046   return FreppleCategory<SetupMatrix>::initialize()
00047       + Rule::initialize()
00048       + SetupMatrixRuleIterator::initialize();
00049 }
00050 
00051 
00052 int SetupMatrix::Rule::initialize()
00053 {
00054   // Initialize the metadata
00055   metadata = new MetaCategory("setupmatrixrule", "setupmatrixrules");
00056 
00057   // Initialize the Python class
00058   PythonType& x = PythonExtension<SetupMatrix::Rule>::getType();
00059   x.setName("setupmatrixrule");
00060   x.setDoc("frePPLe setupmatrixrule");
00061   x.supportgetattro();
00062   x.supportsetattro();
00063   const_cast<MetaCategory*>(metadata)->pythonClass = x.type_object();
00064   return x.typeReady();
00065 }
00066 
00067 
00068 int SetupMatrixDefault::initialize()
00069 {
00070   // Initialize the metadata
00071   SetupMatrixDefault::metadata = new MetaClass(
00072     "setupmatrix",
00073     "setupmatrix_default",
00074     Object::createString<SetupMatrixDefault>, true);
00075 
00076   // Initialize the Python class
00077   return FreppleClass<SetupMatrixDefault,SetupMatrix>::initialize();
00078 }
00079 
00080 
00081 DECLARE_EXPORT SetupMatrix::~SetupMatrix()
00082 {
00083   // Destroy the rules.
00084   // Note that the rule destructor updates the firstRule field.
00085   while (firstRule) delete firstRule;
00086 
00087   // Remove all references to this setup matrix from resources
00088   for (Resource::iterator m = Resource::begin(); m != Resource::end(); ++m)
00089     if (m->getSetupMatrix() == this) m->setSetupMatrix(NULL);
00090 }
00091 
00092 
00093 DECLARE_EXPORT void SetupMatrix::writeElement(XMLOutput *o, const Keyword& tag, mode m) const
00094 {
00095   // Writing a reference
00096   if (m == REFERENCE)
00097   {
00098     o->writeElement
00099     (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00100     return;
00101   }
00102 
00103   // Write the complete object
00104   if (m != NOHEADER) o->BeginObject
00105     (tag, Tags::tag_name, XMLEscape(getName()), Tags::tag_type, getType().type);
00106 
00107   // Write all rules
00108   o->BeginObject (Tags::tag_rules);
00109   for (RuleIterator i = beginRules(); i != endRules(); ++i)
00110     // We use the FULL mode, to force the rules being written regardless
00111     // of the depth in the XML tree.
00112     o->writeElement(Tags::tag_rule, *i, FULL);
00113   o->EndObject(Tags::tag_rules);
00114 
00115   o->EndObject(tag);
00116 }
00117 
00118 
00119 DECLARE_EXPORT void SetupMatrix::beginElement(XMLInput& pIn, const Attribute& pAttr)
00120 {
00121   if (pAttr.isA(Tags::tag_rule)
00122       && pIn.getParentElement().first.isA(Tags::tag_rules))
00123     // A new rule
00124     pIn.readto(createRule(pIn.getAttributes()));
00125 }
00126 
00127 
00128 DECLARE_EXPORT SetupMatrix::Rule* SetupMatrix::createRule(const AttributeList& atts)
00129 {
00130   // Pick up the start, end and name attributes
00131   int priority = atts.get(Tags::tag_priority)->getInt();
00132 
00133   // Check for existence of a rule with the same priority
00134   Rule* result = firstRule;
00135   while (result && priority > result->priority)
00136     result = result->nextRule;
00137   if (result && result->priority != priority) result = NULL;
00138 
00139   // Pick up the action attribute and update the rule accordingly
00140   switch (MetaClass::decodeAction(atts))
00141   {
00142     case ADD:
00143       // Only additions are allowed
00144       if (result)
00145       {
00146         ostringstream o;
00147         o << "Rule with priority "  << priority
00148           << " already exists in setup matrix '" << getName() << "'";
00149         throw DataException(o.str());
00150       }
00151       result = new Rule(this, priority);
00152       return result;
00153     case CHANGE:
00154       // Only changes are allowed
00155       if (!result)
00156       {
00157         ostringstream o;
00158         o << "No rule with priority " << priority
00159           << " exists in setup matrix '" << getName() << "'";
00160         throw DataException(o.str());
00161       }
00162       return result;
00163     case REMOVE:
00164       // Delete the entity
00165       if (!result)
00166       {
00167         ostringstream o;
00168         o << "No rule with priority " << priority
00169           << " exists in setup matrix '" << getName() << "'";
00170         throw DataException(o.str());
00171       }
00172       else
00173       {
00174         // Delete it
00175         delete result;
00176         return NULL;
00177       }
00178     case ADD_CHANGE:
00179       if (!result)
00180         // Adding a new rule
00181         result = new Rule(this, priority);
00182       return result;
00183   }
00184 
00185   // This part of the code isn't expected not be reached
00186   throw LogicException("Unreachable code reached");
00187 }
00188 
00189 
00190 DECLARE_EXPORT void SetupMatrix::endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00191 {
00192   HasName<SetupMatrix>::endElement(pIn, pAttr, pElement);
00193 }
00194 
00195 
00196 DECLARE_EXPORT PyObject* SetupMatrix::getattro(const Attribute& attr)
00197 {
00198   if (attr.isA(Tags::tag_name))
00199     return PythonObject(getName());
00200   if (attr.isA(Tags::tag_rules))
00201     return new SetupMatrixRuleIterator(this);
00202   return NULL;
00203 }
00204 
00205 
00206 DECLARE_EXPORT int SetupMatrix::setattro(const Attribute& attr, const PythonObject& field)
00207 {
00208   if (attr.isA(Tags::tag_name))
00209     setName(field.getString());
00210   else
00211     return -1;  // Error
00212   return 0;
00213 }
00214 
00215 
00216 DECLARE_EXPORT PyObject* SetupMatrix::addPythonRule(PyObject* self, PyObject* args, PyObject* kwdict)
00217 {
00218   try
00219   {
00220     // Pick up the setup matrix
00221     SetupMatrix *matrix = static_cast<SetupMatrix*>(self);
00222     if (!matrix) throw LogicException("Can't add a rule to a NULL setupmatrix");
00223 
00224     // Parse the arguments
00225     int prio = 0;
00226     PyObject *pyfrom = NULL;
00227     PyObject *pyto = NULL;
00228     long duration = 0;
00229     double cost = 0;
00230     static const char *kwlist[] = {"priority", "fromsetup", "tosetup", "duration", "cost", NULL};
00231     if (!PyArg_ParseTupleAndKeywords(args, kwdict,
00232         "i|ssld:addRule",
00233         const_cast<char**>(kwlist), &prio, &pyfrom, &pyto, &duration, &cost))
00234       return NULL;
00235 
00236     // Add the new rule
00237     Rule * r = new Rule(matrix, prio);
00238     if (pyfrom) r->setFromSetup(PythonObject(pyfrom).getString());
00239     if (pyto) r->setToSetup(PythonObject(pyfrom).getString());
00240     r->setDuration(duration);
00241     r->setCost(cost);
00242     return PythonObject(r);
00243   }
00244   catch(...)
00245   {
00246     PythonType::evalException();
00247     return NULL;
00248   }
00249 }
00250 
00251 
00252 DECLARE_EXPORT SetupMatrix::Rule::Rule(SetupMatrix *s, int p)
00253   : cost(0), priority(p), matrix(s), nextRule(NULL), prevRule(NULL)
00254 {
00255   // Validate the arguments
00256   if (!matrix) throw DataException("Can't add a rule to NULL setup matrix");
00257 
00258   // Find the right place in the list
00259   Rule *next = matrix->firstRule, *prev = NULL;
00260   while (next && p > next->priority)
00261   {
00262     prev = next;
00263     next = next->nextRule;
00264   }
00265 
00266   // Duplicate priority
00267   if (next && next->priority == p)
00268     throw DataException("Multiple rules with identical priority in setup matrix");
00269 
00270   // Maintain linked list
00271   nextRule = next;
00272   prevRule = prev;
00273   if (prev) prev->nextRule = this;
00274   else matrix->firstRule = this;
00275   if (next) next->prevRule = this;
00276 
00277   // Initialize the Python type
00278   initType(metadata);
00279 }
00280 
00281 
00282 DECLARE_EXPORT SetupMatrix::Rule::~Rule()
00283 {
00284   // Maintain linked list
00285   if (nextRule) nextRule->prevRule = prevRule;
00286   if (prevRule) prevRule->nextRule = nextRule;
00287   else matrix->firstRule = nextRule;
00288 }
00289 
00290 
00291 DECLARE_EXPORT void SetupMatrix::Rule::writeElement
00292 (XMLOutput *o, const Keyword& tag, mode m) const
00293 {
00294   o->BeginObject(tag, Tags::tag_priority, priority);
00295   if (!from.empty()) o->writeElement(Tags::tag_fromsetup, from);
00296   if (!to.empty()) o->writeElement(Tags::tag_tosetup, to);
00297   if (duration) o->writeElement(Tags::tag_duration, duration);
00298   if (cost) o->writeElement(Tags::tag_cost, cost);
00299   o->EndObject(tag);
00300 }
00301 
00302 
00303 DECLARE_EXPORT void SetupMatrix::Rule::endElement (XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00304 {
00305   if (pAttr.isA(Tags::tag_priority))
00306     setPriority(pElement.getInt());
00307   else if (pAttr.isA(Tags::tag_fromsetup))
00308     setFromSetup(pElement.getString());
00309   else if (pAttr.isA(Tags::tag_tosetup))
00310     setToSetup(pElement.getString());
00311   else if (pAttr.isA(Tags::tag_duration))
00312     setDuration(pElement.getTimeperiod());
00313   else if (pAttr.isA(Tags::tag_cost))
00314     setCost(pElement.getDouble());
00315 }
00316 
00317 
00318 DECLARE_EXPORT PyObject* SetupMatrix::Rule::getattro(const Attribute& attr)
00319 {
00320   if (attr.isA(Tags::tag_priority))
00321     return PythonObject(priority);
00322   if (attr.isA(Tags::tag_setupmatrix))
00323     return PythonObject(matrix);
00324   if (attr.isA(Tags::tag_fromsetup))
00325     return PythonObject(from);
00326   if (attr.isA(Tags::tag_tosetup))
00327     return PythonObject(to);
00328   if (attr.isA(Tags::tag_duration))
00329     return PythonObject(duration);
00330   if (attr.isA(Tags::tag_cost))
00331     return PythonObject(cost);
00332   return NULL;
00333 }
00334 
00335 
00336 DECLARE_EXPORT int SetupMatrix::Rule::setattro(const Attribute& attr, const PythonObject& field)
00337 {
00338   if (attr.isA(Tags::tag_priority))
00339     setPriority(field.getInt());
00340   else if (attr.isA(Tags::tag_fromsetup))
00341     setFromSetup(field.getString());
00342   else if (attr.isA(Tags::tag_tosetup))
00343     setToSetup(field.getString());
00344   else if (attr.isA(Tags::tag_duration))
00345     setDuration(field.getTimeperiod());
00346   else if (attr.isA(Tags::tag_cost))
00347     setCost(field.getDouble());
00348   else
00349     return -1;  // Error
00350   return 0;  // OK
00351 }
00352 
00353 
00354 DECLARE_EXPORT void SetupMatrix::Rule::setPriority(const int n)
00355 {
00356   // Update the field
00357   priority = n;
00358 
00359   // Check ordering on the left
00360   while (prevRule && priority < prevRule->priority)
00361   {
00362     Rule* next = nextRule;
00363     Rule* prev = prevRule;
00364     if (prev && prev->prevRule) prev->prevRule->nextRule = this;
00365     else matrix->firstRule = this;
00366     if (prev) prev->nextRule = nextRule;
00367     nextRule = prev;
00368     prevRule = prev ? prev->prevRule : NULL;
00369     if (next && next->nextRule) next->nextRule->prevRule = prev;
00370     if (next) next->prevRule = prev;
00371     if (prev) prev->prevRule = this;
00372   }
00373 
00374   // Check ordering on the right
00375   while (nextRule && priority > nextRule->priority)
00376   {
00377     Rule* next = nextRule;
00378     Rule* prev = prevRule;
00379     nextRule = next->nextRule;
00380     if (next && next->nextRule) next->nextRule->prevRule = this;
00381     if (prev) prev->nextRule = next;
00382     if (next) next->nextRule = this;
00383     if (next) next->prevRule = prev;
00384     prevRule = next;
00385   }
00386 
00387   // Check for duplicate priorities
00388   if ((prevRule && prevRule->priority == priority)
00389       || (nextRule && nextRule->priority == priority))
00390   {
00391     ostringstream o;
00392     o << "Duplicate priority " << priority << " in setup matrix '"
00393       << matrix->getName() << "'";
00394     throw DataException(o.str());
00395   }
00396 }
00397 
00398 
00399 int SetupMatrixRuleIterator::initialize()
00400 {
00401   // Initialize the type
00402   PythonType& x = PythonExtension<SetupMatrixRuleIterator>::getType();
00403   x.setName("setupmatrixRuleIterator");
00404   x.setDoc("frePPLe iterator for setupmatrix rules");
00405   x.supportiter();
00406   return x.typeReady();
00407 }
00408 
00409 
00410 PyObject* SetupMatrixRuleIterator::iternext()
00411 {
00412   if (currule == matrix->endRules()) return NULL;
00413   PyObject *result = &*(currule++);
00414   Py_INCREF(result);
00415   return result;
00416 }
00417 
00418 
00419 DECLARE_EXPORT SetupMatrix::Rule* SetupMatrix::calculateSetup
00420 (const string oldsetup, const string newsetup) const
00421 {
00422   // No need to look
00423   if (oldsetup == newsetup) return NULL;
00424 
00425   // Loop through all rules
00426   for (Rule *curRule = firstRule; curRule; curRule = curRule->nextRule)
00427   {
00428     // Need a match on the fromsetup
00429     if (!curRule->getFromSetup().empty()
00430         && !matchWildcard(curRule->getFromSetup().c_str(), oldsetup.c_str()))
00431       continue;
00432     // Need a match on the tosetup
00433     if (!curRule->getToSetup().empty()
00434         && !matchWildcard(curRule->getToSetup().c_str(), newsetup.c_str()))
00435       continue;
00436     // Found a match
00437     return curRule;
00438   }
00439 
00440   // No matching rule was found
00441   logger << "Warning: Conversion from '" << oldsetup << "' to '" << newsetup
00442       << "' undefined in setup matrix '" << getName() << endl;
00443   return NULL;
00444 }
00445 
00446 } // end namespace

Documentation generated for frePPLe by  doxygen