00001 /*************************************************************************** 00002 file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/src/model/problems_operationplan.cpp $ 00003 version : $LastChangedRevision: 899 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2009-01-18 13:28:21 +0100 (Sun, 18 Jan 2009) $ 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 namespace frepple 00030 { 00031 00032 00033 DECLARE_EXPORT void Operation::updateProblems() 00034 { 00035 // Find all operationplans, and delegate the problem detection to them 00036 for (OperationPlan *o = first_opplan; o; o = o->next) o->updateProblems(); 00037 } 00038 00039 00040 // 00041 // BEFORECURRENT, BEFOREFENCE, PLANNEDEARLY, PLANNEDLATE 00042 // 00043 00044 00045 void OperationPlan::updateProblems() 00046 { 00047 // A flag for each problem type that may need to be created 00048 bool needsBeforeCurrent(false); 00049 bool needsBeforeFence(false); 00050 bool needsEarly(false); 00051 bool needsLate(false); 00052 00053 // The following categories of operation plans can't have problems: 00054 // - locked opplans 00055 // - opplans having an owner 00056 // - opplans of hidden operations 00057 if (!getOwner() && !getLocked() && getOperation()->getDetectProblems()) 00058 { 00059 // Check if a BeforeCurrent problem is required. 00060 if (dates.getStart() < Plan::instance().getCurrent()) 00061 needsBeforeCurrent = true; 00062 00063 // Check if a BeforeFence problem is required. 00064 // Note that we either detect of beforeCurrent or a beforeFence problem, 00065 // never both simultaneously. 00066 else if 00067 (dates.getStart() < Plan::instance().getCurrent() + oper->getFence()) 00068 needsBeforeFence = true; 00069 00070 // Check if a PlannedEarly problem is required 00071 if (getEpst() 00072 && getDates().getStart() 00073 < getEpst() - ProblemPlannedEarly::getAllowedEarly()) 00074 needsEarly = true; 00075 00076 // Check if a PlannedLate problem is required 00077 if (getLpst() 00078 && getDates().getStart() 00079 > getLpst() + ProblemPlannedLate::getAllowedLate()) 00080 needsLate = true; 00081 } 00082 00083 // Loop through the existing problems 00084 for (Problem::const_iterator j = Problem::begin(this, false); 00085 j!=Problem::end(); ++j) 00086 { 00087 // Need to increment now and define a pointer to the problem, since the 00088 // problem can be deleted soon (which invalidates the iterator). 00089 Problem& curprob = *j; 00090 ++j; 00091 // The if-statement keeps the problem detection code concise and 00092 // concentrated. However, a drawback of this design is that a new problem 00093 // subclass will also require a new demand subclass. I think such a link 00094 // is acceptable. 00095 if (typeid(curprob) == typeid(ProblemBeforeCurrent)) 00096 { 00097 // if: problem needed and it exists already 00098 if (needsBeforeCurrent) needsBeforeCurrent = false; 00099 // else: problem not needed but it exists already 00100 else delete &curprob; 00101 } 00102 else if (typeid(curprob) == typeid(ProblemBeforeFence)) 00103 { 00104 if (needsBeforeFence) needsBeforeFence = false; 00105 else delete &curprob; 00106 } 00107 else if (typeid(curprob) == typeid(ProblemPlannedEarly)) 00108 { 00109 if (needsEarly) needsEarly = false; 00110 else delete &curprob; 00111 } 00112 else if (typeid(curprob) == typeid(ProblemPlannedLate)) 00113 { 00114 if (needsLate) needsLate = false; 00115 else delete &curprob; 00116 } 00117 } 00118 00119 // Create the problems that are required but aren't existing yet. 00120 // There is a little trick involved here... Normally problems are owned 00121 // by objects of the Plannable class. OperationPlan isn't a subclass of 00122 // Plannable, so we need a dirty cast. 00123 if (needsBeforeCurrent) new ProblemBeforeCurrent(this); 00124 if (needsBeforeFence) new ProblemBeforeFence(this); 00125 if (needsEarly) new ProblemPlannedEarly(this); 00126 if (needsLate) new ProblemPlannedLate(this); 00127 } 00128 00129 00130 DECLARE_EXPORT TimePeriod ProblemPlannedEarly::allowedEarly; 00131 DECLARE_EXPORT TimePeriod ProblemPlannedLate::allowedLate; 00132 00133 00134 void ProblemPlannedEarly::setAllowedEarly(TimePeriod p) 00135 { 00136 allowedEarly = p; 00137 00138 // Let all operationplans check for new problems 00139 // Note that ProblemPlannedEarly problems are subscribing to their 00140 // operationplan and the update() method is notifying them. 00141 for (OperationPlan::iterator i = OperationPlan::begin(); 00142 i != OperationPlan::end(); ++i) 00143 i->getOperation()->setChanged(); 00144 } 00145 00146 00147 void ProblemPlannedLate::setAllowedLate(TimePeriod p) 00148 { 00149 allowedLate = p; 00150 00151 // Let all operationplans check for new problems 00152 // Note that ProblemPlannedLate problems are subscribing to their 00153 // operationplan and the update() method is notifying them. 00154 for (OperationPlan::iterator i = OperationPlan::begin(); 00155 i != OperationPlan::end(); ++i) 00156 i->getOperation()->setChanged(); 00157 } 00158 00159 00160 // 00161 // PRECEDENCE 00162 // 00163 00164 00165 void OperationPlanRouting::updateProblems() // @todo test! may well be broken 00166 { 00167 // Make a list of all existing precedence problems 00168 list<ProblemPrecedence*> currentproblems; 00169 for (Problem::const_iterator j = Problem::begin(this, false); 00170 j!=Problem::end(); ++j) 00171 if (typeid(*j) == typeid(ProblemPrecedence)) 00172 currentproblems.push_front(static_cast<ProblemPrecedence*>(&*j)); 00173 00174 // Problem detection: Check for new precedence_before problem 00175 OperationPlan* prev = NULL; 00176 for (list<OperationPlan*>::const_iterator i = step_opplans.begin(); 00177 i != step_opplans.end(); ++i) 00178 { 00179 if (prev && prev->getDates().getEnd() > (*i)->getDates().getStart()) 00180 { 00181 // We need a precedence problem. It could already exist or we need a 00182 // new one... 00183 list<ProblemPrecedence*>::iterator l; 00184 for (l = currentproblems.begin(); l != currentproblems.end(); ++l) 00185 if ((*l)->getFirstOperationPlan() == prev) 00186 { 00187 // It already exists 00188 currentproblems.erase(l); 00189 break; 00190 } 00191 if (l == currentproblems.end()) 00192 // It is a new problem 00193 new ProblemPrecedence (getOperation(), prev, *i); 00194 } 00195 prev = *i; 00196 } 00197 00198 // Erase old problems that have now become obsolete 00199 while (!currentproblems.empty()) 00200 { 00201 delete currentproblems.front(); 00202 currentproblems.pop_front(); 00203 } 00204 00205 // Continue with the normal problem detection 00206 OperationPlan::updateProblems(); 00207 } 00208 00209 }