Marsyas  0.5.0-beta1
/Users/jleben/code/marsyas/src/marsyas/system/MarSystem.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2010 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include <marsyas/system/MarSystem.h>
00020 #include <marsyas/system/MarControlManager.h>
00021 #include <marsyas/sched/EvValUpd.h>
00022 #include <marsyas/sched/TmVirtualTime.h>
00023 #include "../common_source.h"
00024 
00025 #include <algorithm>
00026 #include <stack>
00027 
00028 using std::ostringstream;
00029 using std::cout;
00030 using std::endl;
00031 using std::vector;
00032 using std::pair;
00033 using std::map;
00034 using std::istream;
00035 using std::ostream;
00036 using std::string;
00037 
00038 
00039 using namespace Marsyas;
00040 
00041 MarSystem::MarSystem(mrs_string type, mrs_string name):
00042   parent_scope_(0)
00043 {
00044   parent_ = NULL;
00045   name_ = name;
00046   type_ = type;
00047   active_ = true;
00048   prefix_ = "/" + type_ + "/" + name_ + "/";
00049   absPath_ = prefix_;
00050 
00051   inObservations_ = 0;
00052   inSamples_ = 0;
00053   onObservations_ = 0;
00054   onSamples_ = 0;
00055   osrate_ = 0.0;
00056   israte_ = 0.0;
00057 
00058   inStabilizingDelay_ = 0;
00059   onStabilizingDelay_ = 0;
00060 
00061   tonSamples_ = 0;
00062   tonObservations_ = 0;
00063   tinSamples_ = 0;
00064   tinObservations_ = 0;
00065   tosrate_ = 0.0;
00066   tisrate_ = 0.0;
00067   tinStabilizingDelay_ = 0;
00068   tonStabilizingDelay_ = 0;
00069   tonObsNames_ = "";
00070   onObsNames_ = "";
00071 
00072   addToStabilizingDelay_ = 0;
00073 
00074 
00075   isComposite_ = false;
00076 
00077   MATLABscript_ = "";
00078 
00079   isUpdating_ = false;
00080 
00081   //add default controls that
00082   //all MarSystems should have
00083   addControls();
00084 
00085   scheduler_.removeAll();
00086   TmTimer* t = new TmVirtualTime("Virtual",this);
00087   scheduler_.addTimer(t);
00088 }
00089 
00090 // copy constructor
00091 MarSystem::MarSystem(const MarSystem& a):
00092   parent_scope_(0)
00093 {
00094   parent_ = NULL;
00095   type_ = a.type_;
00096   name_ = a.name_;
00097   prefix_ = a.prefix_;
00098   absPath_ = a.absPath_;
00099   active_ = true;
00100 
00101   osrate_ = 0.0;
00102   inObservations_ = 0;
00103   onObservations_ = 0;
00104   inSamples_ = 0;
00105   israte_ = 0.0;
00106   inStabilizingDelay_ = 0;
00107   onStabilizingDelay_ = 0;
00108 
00109   onSamples_ = 0;
00110   tonObsNames_ = "";
00111   onObsNames_ = "";
00112 
00113   tonSamples_ = 0;
00114   tonObservations_ = 0;
00115   tinSamples_ = 0;
00116   tinObservations_ = 0;
00117   tosrate_ = 0.0;
00118   tisrate_ = 0.0;
00119   tinStabilizingDelay_ = 0;
00120   tonStabilizingDelay_ = 0;
00121 
00122   addToStabilizingDelay_ = 0;
00123 
00124 
00125   MATLABscript_ = a.MATLABscript_;
00126 
00127   isUpdating_ = false;
00128 
00129   //clone controls (cloned controls will have no links! - they have to be relinked as done below)
00130   {
00131     controls_.clear();
00132     for (ControlItr ctrlIter_ = a.controls_.begin(); ctrlIter_ != a.controls_.end(); ++ctrlIter_)
00133     {
00134       //clone all controls
00135       controls_[ctrlIter_->first] = ctrlIter_->second->clone();
00136       //set new MarSystem parent
00137       controls_[ctrlIter_->first]->setMarSystem(this);
00138     }
00139   }
00140 
00141   //update the "references" to the controls
00142   ctrl_inSamples_ = getctrl("mrs_natural/inSamples");
00143   ctrl_inObservations_ = getctrl("mrs_natural/inObservations");
00144   ctrl_israte_ = getctrl("mrs_real/israte");
00145   ctrl_inObsNames_ = getctrl("mrs_string/inObsNames");
00146   ctrl_onSamples_ = getctrl("mrs_natural/onSamples");
00147   ctrl_onObservations_ = getctrl("mrs_natural/onObservations");
00148   ctrl_osrate_ = getctrl("mrs_real/osrate");
00149   ctrl_onObsNames_ = getctrl("mrs_string/onObsNames");
00150   ctrl_debug_ = getctrl("mrs_bool/debug");
00151   ctrl_verbose_ = getctrl("mrs_bool/verbose");
00152   ctrl_mute_ = getctrl("mrs_bool/mute");
00153   ctrl_active_ = getctrl("mrs_bool/active");
00154   ctrl_processedData_ = getctrl("mrs_realvec/processedData");
00155   ctrl_inStabilizingDelay_ = getctrl("mrs_natural/inStabilizingDelay");
00156   ctrl_onStabilizingDelay_ = getctrl("mrs_natural/onStabilizingDelay");
00157 
00158   //clone children (if any) => mutexes [?]
00159   isComposite_ = a.isComposite_;
00160   if (isComposite_)
00161   {
00162     child_count_t child_count = a.marsystems_.size();
00163     for (child_count_t i=0; i< child_count; ++i)
00164     {
00165       MarSystem* clonedChild = (*a.marsystems_[i]).clone();
00166       addMarSystem(clonedChild);
00167       clonedChild->relinkControls((*a.marsystems_[i]));
00168     }
00169   }
00170 
00171   this->relinkControls(a);
00172 
00173 //  // "re-link" controls  => mutexes [?]
00174 //  for(ControlItr ctrlIter_ = a.controls_.begin(); ctrlIter_ != a.controls_.end(); ++ctrlIter_)
00175 //  {
00176 //      // get original links...
00177 //      vector<pair<MarControlPtr, MarControlPtr> > originalLinks = ctrlIter_->second->getLinks();
00178 //
00179 //      // ...clear clone's links...
00180 //      //controls_[ctrlIter_->first]->unlinkFromAll(); //[?] is this really necessary?
00181 //
00182 //      //... and re-establish links between the new cloned controls
00183 //      vector<pair<MarControlPtr, MarControlPtr> >::const_iterator linksIter;
00184 //      for (linksIter = originalLinks.begin(); linksIter != originalLinks.end(); ++linksIter)
00185 //      {
00186 //          //ignore the root link (not important for relinking)
00187 //          if(linksIter->first() == linksIter->second())
00188 //              continue;
00189 //
00190 //          //check if this control links to someone, and link them accordingly...
00191 //          if(linksIter->first() == ctrlIter_->second())
00192 //          {
00193 //              MarControlPtr ctrl2Link2 = this->getControl(linksIter->second->getMarSystem()->getAbsPath() + linksIter->second->getName(), true);
00194 //              //controls from siblings may not exist yet at this time, so we must not try to link
00195 //              //to their yet invalid controls. Just link with controls from
00196 //              //the parent or already existing siblings and children. The remaining ones will be linked
00197 //              //by the siblings when they get created.
00198 //              if (!ctrl2Link2.isInvalid())
00199 //              {
00200 //                  controls_[ctrlIter_->first]->linkTo(ctrl2Link2);
00201 //              }
00202 //          }
00203 //          //...or check if someone links to this control, and link them accordingly
00204 //          else if(linksIter->second() == ctrlIter_->second())
00205 //          {
00206 //              MarControlPtr linkedCtrl = this->getControl(linksIter->first->getMarSystem()->getAbsPath() + linksIter->first->getName(), true);
00207 //              //controls from siblings may not exist yet at this time, so we must not try to link
00208 //              //to their yet invalid controls. Just link with controls from
00209 //              //the parent or already existing siblings and children. The remaining ones will be linked
00210 //              //by the siblings when they get created.
00211 //              if (!linkedCtrl.isInvalid())
00212 //              {
00213 //                  linkedCtrl->linkTo(controls_[ctrlIter_->first]);
00214 //              }
00215 //          }
00216 //      }
00217 //  }
00218 
00219   //recreate schedule objects  => mutexes [?]
00220 
00221   scheduler_.removeAll();
00222   TmTimer* t = new TmVirtualTime("Virtual",this);
00223   scheduler_.addTimer(t);
00224 }
00225 
00226 void
00227 MarSystem::relinkControls(const MarSystem& a)
00228 {
00229   // "re-link" controls  => mutexes [?]
00230   for (ControlItr ctrlIter_ = a.controls_.begin(); ctrlIter_ != a.controls_.end(); ++ctrlIter_)
00231   {
00232     // get original links...
00233     vector<pair<MarControlPtr, MarControlPtr> > originalLinks = ctrlIter_->second->getLinks();
00234 
00235     // ...clear clone's links...
00236     //controls_[ctrlIter_->first]->unlinkFromAll(); //[?] is this really necessary?
00237 
00238     //... and re-establish links between the new cloned controls
00239     vector<pair<MarControlPtr, MarControlPtr> >::const_iterator linksIter;
00240     for (linksIter = originalLinks.begin(); linksIter != originalLinks.end(); ++linksIter)
00241     {
00242       //ignore the root link (not important for relinking)
00243       if (linksIter->first() == linksIter->second())
00244         continue;
00245 
00246       //check if this control links to someone, and link them accordingly...
00247       if (linksIter->first() == ctrlIter_->second())
00248       {
00249         MarControlPtr ctrl2Link2 = this->getControl(linksIter->second->getMarSystem()->getAbsPath() + linksIter->second->getName(), true);
00250         //controls from siblings may not exist yet at this time, so we must not try to link
00251         //to their yet invalid controls. Just link with controls from
00252         //the parent or already existing siblings and children. The remaining ones will be linked
00253         //by the siblings when they get created.
00254         if (!ctrl2Link2.isInvalid())
00255         {
00256           controls_[ctrlIter_->first]->linkTo(ctrl2Link2);
00257         }
00258       }
00259       //...or check if someone links to this control, and link them accordingly
00260       else if (linksIter->second() == ctrlIter_->second())
00261       {
00262         MarControlPtr linkedCtrl = this->getControl(linksIter->first->getMarSystem()->getAbsPath() + linksIter->first->getName(), true);
00263         //controls from siblings may not exist yet at this time, so we must not try to link
00264         //to their yet invalid controls. Just link with controls from
00265         //the parent or already existing siblings and children. The remaining ones will be linked
00266         //by the siblings when they get created.
00267         if (!linkedCtrl.isInvalid())
00268         {
00269           linkedCtrl->linkTo(controls_[ctrlIter_->first]);
00270         }
00271       }
00272     }
00273   }
00274 }
00275 
00276 MarSystem::~MarSystem()
00277 {
00278   //delete children (if any)
00279   child_count_t child_count = marsystems_.size();
00280   for (child_count_t i=0; i< child_count; ++i)
00281   {
00282     delete marsystems_[i];
00283   }
00284 
00285   child_count_t attached_count = attached_marsystems_.size();
00286   for (child_count_t i=0; i < attached_count; ++i)
00287   {
00288     delete attached_marsystems_[i];
00289   }
00290 
00291   removeFromScope();
00292 }
00293 
00294 void
00295 MarSystem::addControls()
00296 {
00297   //input pin controls (with state)
00298   addctrl("mrs_natural/inSamples", MRS_DEFAULT_SLICE_NSAMPLES, ctrl_inSamples_);
00299   setctrlState(ctrl_inSamples_, true);
00300   addctrl("mrs_natural/inObservations", MRS_DEFAULT_SLICE_NOBSERVATIONS, ctrl_inObservations_);
00301   setctrlState(ctrl_inObservations_, true);
00302   addctrl("mrs_real/israte", MRS_DEFAULT_SLICE_SRATE, ctrl_israte_);
00303   setctrlState(ctrl_israte_, true);
00304   addctrl("mrs_string/inObsNames", ",", ctrl_inObsNames_);
00305   setctrlState(ctrl_inObsNames_, true);
00306   addctrl("mrs_natural/inStabilizingDelay", 0, ctrl_inStabilizingDelay_);
00307   setctrlState(ctrl_inStabilizingDelay_, true);
00308 
00309   //output pin controls (stateless)
00310   addctrl("mrs_natural/onSamples", MRS_DEFAULT_SLICE_NSAMPLES, ctrl_onSamples_);
00311   addctrl("mrs_natural/onObservations", MRS_DEFAULT_SLICE_NOBSERVATIONS, ctrl_onObservations_);
00312   addctrl("mrs_real/osrate", MRS_DEFAULT_SLICE_SRATE, ctrl_osrate_);
00313   addctrl("mrs_string/onObsNames", ",", ctrl_onObsNames_);
00314   addctrl("mrs_natural/onStabilizingDelay", 0, ctrl_onStabilizingDelay_);
00315   setctrlState(ctrl_onStabilizingDelay_, true);
00316 
00317   inObservations_ = ctrl_inObservations_->to<mrs_natural>();
00318   inSamples_ = ctrl_inSamples_->to<mrs_natural>();
00319   inStabilizingDelay_ = ctrl_inStabilizingDelay_->to<mrs_natural>();
00320   onObservations_ = ctrl_onObservations_->to<mrs_natural>();
00321   onSamples_ = ctrl_onSamples_->to<mrs_natural>();
00322   onStabilizingDelay_ = ctrl_onStabilizingDelay_->to<mrs_natural>();
00323 
00324   //other controls:
00325   addctrl("mrs_bool/debug", false, ctrl_debug_);        //no debug by default
00326   addctrl("mrs_bool/verbose", false, ctrl_verbose_);
00327   addctrl("mrs_bool/mute", false, ctrl_mute_);          //unmuted by default
00328   addctrl("mrs_bool/active",true, ctrl_active_);        //active by default
00329 
00330   inTick_.create(inObservations_, inSamples_);
00331   outTick_.create(onObservations_, onSamples_);
00332 
00333   addctrl("mrs_realvec/processedData", outTick_, ctrl_processedData_);
00334 
00335   ctrl_active_->setState(true);
00336 
00337   active_ = ctrl_active_->to<bool>();
00338 }
00339 
00340 bool
00341 MarSystem::addMarSystem(MarSystem *marsystem)
00342 {
00343   //idiot proof 1
00344   if (this == marsystem)
00345   {
00346     MRSWARN("MarSystem::addMarSystem - Trying to add MarSystem to itself - failing...");
00347     return false;
00348   }
00349 
00350   if (marsystem == NULL)
00351   {
00352     MRSWARN("MarSystem::addMarSystem - Adding a NULL MarSystem - failing...");
00353     return false;
00354   }
00355 
00356   //idiot proof 2
00357   MarSystem* msys = parent_;
00358   while (msys)
00359   {
00360     if (msys == marsystem)
00361     {
00362       MRSWARN("MarSystem::addMarSystem - Trying to add an ancestor MarSystem as a child - failing...");
00363       return false;
00364     }
00365     msys = msys->parent_;
00366   }
00367 
00368   //it's only possible to add MarSystems to Composites
00369   if (isComposite_)
00370   {
00371     vector<MarSystem*>::iterator it;
00372     bool replaced = false;
00373     //check if a child MarSystem with the same type/name
00374     //exists. If it does, replace it with the new one.
00375     for (it = marsystems_.begin(); it != marsystems_.end(); ++it)
00376     {
00377       if ((*it)->getName() == marsystem->getName() &&
00378           (*it)->getType() == marsystem->getType())
00379       {
00380         //delete current child MarSystem
00381         delete (*it);
00382         //and replace it with the new one
00383         (*it) = marsystem;
00384         replaced = true;
00385         break;
00386       }
00387     }
00388     //if no replacement took place, then add the
00389     //new MarSystem as a new child
00390     if (!replaced)
00391     {
00392       marsystems_.push_back(marsystem);
00393     }
00394     //set parent for the new child MarSystem
00395     marsystem->setParent(this);
00396 
00397     //update child MarSystem
00398     //marsystem->update(); //superfluous update call! It will be called by this->update() [!]
00399     //update parent MarSystem
00400     update();
00401     return true;
00402   }
00403   else
00404   {
00405     MRSWARN("MarSystem::addMarSystem - Trying to add MarSystem to a non-Composite - failing...");
00406     return false;
00407   }
00408 }
00409 
00410 bool MarSystem::isDescendentOf(MarSystem *ancestor)
00411 {
00412   MarSystem *system = parent_;
00413   while(system)
00414   {
00415     if (system == ancestor)
00416       return true;
00417     system = system->parent_;
00418   }
00419   return false;
00420 }
00421 
00422 void MarSystem::addToScope( MarSystem * ancestor )
00423 {
00424   //MRSMSG("MarSystem::addToScope: " << getPrefix() << " >> " << ancestor->getAbsPath());
00425 
00426   if (ancestor == this)
00427     throw std::runtime_error("MarSystem can not have itself in scope.");
00428 
00429   if (parent_scope_)
00430     throw std::runtime_error("MarSystem already in another scope.");
00431 
00432   //if (!isDescendentOf(ancestor))
00433     //throw std::runtime_error("MarSystem must be descendent to be in scope.");
00434 
00435   const string  & name = getName();
00436   if (name.empty())
00437     throw std::runtime_error("MarSystem has no name.");
00438 
00439   std::map<string, MarSystem*>::iterator it;
00440   it = ancestor->scope_.find(name);
00441   if (it != ancestor->scope_.end())
00442   {
00443     std::ostringstream msg;
00444     msg << "MarSystem with same name already in this scope.";
00445     throw std::runtime_error(msg.str());
00446   }
00447 
00448   ancestor->scope_[name] = this;
00449 
00450   parent_scope_ = ancestor;
00451 }
00452 
00453 void MarSystem::removeFromScope()
00454 {
00455   MarSystem *ancestor = parent_scope_;
00456   if (!ancestor)
00457     return;
00458 
00459   parent_scope_ = 0;
00460 
00461   std::map<string, MarSystem*>::iterator it;
00462   it = ancestor->scope_.find(getName());
00463   if (it == ancestor->scope_.end())
00464     return;
00465 
00466   ancestor->scope_.erase(it);
00467 }
00468 
00469 MarSystem*
00470 MarSystem::getChildMarSystem(std::string childPath)
00471 {
00472   //check for an absolute path, and if necessary convert it
00473   //to a relative path
00474   if (childPath[0] == '/')
00475   {
00476     //is this absolute path pointing to this MarSystem?  => mutexes [?]
00477     if (childPath.substr(0, absPath_.length()) == absPath_)
00478     {
00479       //return control path without the absolute path
00480       //(i.e. return the relative path)
00481       childPath = childPath.substr(absPath_.length(), childPath.length());
00482     }
00483     else
00484     {
00485       //this absolute path does not point to this MarSystem or any of its
00486       //children...
00487       MRSWARN("MarSystem::getChildMarSystem: " + childPath + " is an invalid path @ " + absPath_);
00488       return NULL;
00489     }
00490   }
00491   //from this point, childPath is for sure a relative path.
00492 
00493   //start by checking if childPath is not empty (or resulted from an absolute
00494   //path pointing to this MarSystem itself and not to any of its children)
00495   if (childPath == "")
00496   {
00497     MRSWARN("MarSystem::getChildMarSystem: path does not point to a child MarSystem");
00498     return NULL;
00499   }
00500   //...otherwise, search among its children... => mutexes [?]
00501   else if (isComposite_)
00502   {
00503     vector<MarSystem*>::const_iterator msysIter;
00504     for (msysIter = marsystems_.begin(); msysIter != marsystems_.end(); ++msysIter)
00505     {
00506       mrs_string prefix = (*msysIter)->getPrefix();
00507       prefix = prefix.substr(1, prefix.length()-2); //ignore leading and trailing "/"
00508       if (childPath.substr(0, prefix.length()) == prefix)
00509       {
00510         //a matching child was found!
00511         if (childPath.length() == prefix.length())
00512           return (*msysIter);
00513         //The prefix may be the same, but we still need to check that the next char is a /
00514         // Otherwise in the case of system Sys1, and Sys10, it will appear that Sys10 is the child Sys1
00515         else if (childPath.length() > prefix.length() && childPath.substr(prefix.length() , 1) == "/")
00516         {
00517           //remove parent prefix from childPath, and continue searching recursively in children
00518           childPath = childPath.substr(prefix.length()+1,childPath.length());
00519           return (*msysIter)->getChildMarSystem(childPath);
00520         }
00521       }
00522     }
00523     MRSWARN("MarSystem::getChildMarsystem(): " + childPath + " not found!");
00524     return NULL;
00525   }
00526   else
00527   {
00528     MRSWARN("MarSystem::getChildMarsystem(): " + childPath + " not found!");
00529     return NULL;
00530   }
00531 }
00532 
00533 void
00534 MarSystem::setParent(const MarSystem* parent) // => mutexes [?]
00535 {
00536   parent_ = const_cast<MarSystem*>(parent);
00537 
00538   // Update our path, and propogate changes to children (if applicable)
00539   updatePath();
00540 }
00541 
00542 void
00543 MarSystem::setName(mrs_string name) // => mutexes [?]
00544 {
00545   if (name == name_)
00546     return;
00547 
00548   mrs_string oldPrefix = prefix_;
00549   prefix_ = "/" + type_ + "/" + name + "/";
00550   name_ = name;
00551 
00552   //update path accordingly
00553   mrs_string::size_type pos = absPath_.find(oldPrefix, 0);
00554   mrs_string uppath = absPath_.substr(0, pos);
00555   mrs_string downpath = absPath_.substr(oldPrefix.length()+pos, absPath_.length()-(oldPrefix.length()+pos));
00556   absPath_ = uppath + prefix_ + downpath;
00557 
00558   if (isComposite_)
00559   {
00560     child_count_t child_count = marsystems_.size();
00561     for (child_count_t i=0; i<child_count; ++i)
00562     {
00563       marsystems_[i]->updatePath();
00564     }
00565   }
00566 }
00567 
00568 void
00569 MarSystem::setType(mrs_string type) // => mutexes [?]
00570 {
00571   if (type == type_)
00572     return;
00573 
00574   mrs_string oldPrefix = prefix_;
00575   prefix_ = "/" + type + "/" + name_ + "/";
00576   type_ = type;
00577 
00578   //update path accordingly
00579   mrs_string::size_type pos = absPath_.find_last_of(oldPrefix, 0);
00580   mrs_string uppath = absPath_.substr(0, pos);
00581   mrs_string downpath = absPath_.substr(oldPrefix.length()+pos, absPath_.length()-(oldPrefix.length()+pos));
00582   absPath_ = uppath + prefix_ + downpath;
00583 
00584   if (isComposite_)
00585   {
00586     child_count_t child_count = marsystems_.size();
00587     for (child_count_t i=0; i<child_count; ++i)
00588     {
00589       marsystems_[i]->updatePath();
00590     }
00591   }
00592 }
00593 
00594 const std::string &
00595 MarSystem::getType() const // => mutexes [?]
00596 {
00597   return type_;
00598 }
00599 
00600 const std::string &
00601 MarSystem::getName() const // => mutexes [?]
00602 {
00603   return name_;
00604 }
00605 
00606 const std::string &
00607 MarSystem::getPrefix() const // => mutexes [?]
00608 {
00609   return prefix_;
00610 }
00611 
00612 const std::string &
00613 MarSystem::getAbsPath() const // => mutexes [?]
00614 {
00615   return absPath_;
00616 }
00617 
00618 void
00619 MarSystem::updatePath() // => mutexes [?]
00620 {
00621   if (parent_)
00622   {
00623     absPath_ = parent_->getAbsPath() + type_ + '/' + name_ + '/';
00624   }
00625   else
00626   {
00627     absPath_ = prefix_;
00628   }
00629 
00630   //propagate new path to all children (if any)
00631   if (isComposite_) {
00632     child_count_t child_count = marsystems_.size();
00633     for (child_count_t i=0; i< child_count; ++i)
00634       marsystems_[i]->updatePath();
00635   }
00636 }
00637 
00638 void
00639 MarSystem::checkFlow(realvec& in, realvec& out)
00640 {
00641   irows_ = in.getRows();
00642   icols_ = in.getCols();
00643   orows_ = out.getRows();
00644   ocols_ = out.getCols();
00645 
00646   if (ctrl_debug_->isTrue())
00647   {
00648     MRSWARN("Debug CheckFlow Information");
00649     MRSWARN("MarSystem Type    = " << type_);
00650     MRSWARN("MarSystem Name    = " << name_);
00651     MRSWARN("inObservAtions_ = " << inObservations_);
00652     MRSWARN("inSamples_ = " << inSamples_);
00653     MRSWARN("onObservations_ = " << onObservations_);
00654     MRSWARN("onSamples_ = " << onSamples_);
00655     MRSWARN("inStabilizingDelay_ = " << inStabilizingDelay_);
00656     MRSWARN("onStabilizingDelay_ = " << onStabilizingDelay_);
00657     MRSWARN("Input  Slice Rows = " << irows_ );
00658     MRSWARN("Input  Slice Cols = " << icols_ );
00659     MRSWARN("Output Slice Rows = " << orows_ );
00660     MRSWARN("Output Slice Cols = " << ocols_ );
00661   }
00662 
00663 
00664   MRSASSERT(irows_ == inObservations_);
00665   MRSASSERT(icols_ == inSamples_);
00666   MRSASSERT(orows_ == onObservations_);
00667   MRSASSERT(ocols_ == onSamples_);
00668 }
00669 
00670 void
00671 MarSystem::process(realvec& in, realvec& out)
00672 {
00673   MRSDIAG(type_ << "/" << name_ << "::process");
00674 #ifdef MARSYAS_FLOWCHECK
00675   checkFlow(in, out);
00676 #endif
00677 
00678 #ifndef MARSYAS_NO_MARSYSTEM_OBSERVERS
00679   observer_count_t observer_count = observers_.size();
00680   if (observer_count)
00681   {
00682     for (observer_count_t idx = 0; idx < observer_count; ++idx)
00683     {
00684       observers_[idx]->preProcess(in);
00685     }
00686 
00687     myProcess(in, out);
00688 
00689     for (observer_count_t idx = 0; idx < observer_count; ++idx)
00690     {
00691       observers_[idx]->postProcess(out);
00692     }
00693   }
00694   else
00695 #endif
00696   {
00697     myProcess(in, out);
00698   }
00699 
00700 #ifdef MARSYAS_MATLAB
00701   if (!MATLABscript_.empty())
00702   {
00703     MATLAB_PUT(in, name_ + "_in");
00704     MATLAB_PUT(out, name_ + "_out");
00705     MATLAB_EVAL(MATLABscript_);
00706     MATLAB_GET(name_+"_out", out);
00707 
00708     //check if out realvec was shortened by MATLAB script... //[!]
00709     if ((out.getRows() < onObservations_)||(out.getCols() < onSamples_))
00710       out.stretch(onObservations_, onSamples_);
00711   }
00712 #endif
00713 }
00714 
00715 void
00716 MarSystem::tick()
00717 {
00718   //if MarSystem is not active, ignore ticks
00719   if (ctrl_active_->isTrue())
00720   {
00721     scheduler_.tick();
00722     {
00723       MarControlAccessor acc(ctrl_processedData_);
00724       realvec& processedData = acc.to<mrs_realvec>();
00725       process(inTick_, processedData);
00726     }
00727   }
00728   else
00729   {
00730     MRSDIAG("MarSystem::tick() : MarSystem is not active! Ignoring tick command.");
00731     (void)42;
00732   }
00733 }
00734 
00735 void
00736 MarSystem::myUpdate(MarControlPtr sender)
00737 {
00738   (void) sender;  //suppress warning of unused parameter(s)
00739   MRSDIAG("MarSystem.cpp - MarSystem:myUpdate");
00740 
00741   //lmartins:
00742   //By default, a MarSystem does not modify the input data stream format.
00743   //Override this method on a derived MarSystem if data format changes
00744   //should take place...
00745 
00746   //forward flow propagation
00747   ctrl_onSamples_->setValue(ctrl_inSamples_, NOUPDATE);
00748   ctrl_onObservations_->setValue(ctrl_inObservations_, NOUPDATE);
00749   ctrl_osrate_->setValue(ctrl_israte_, NOUPDATE);
00750   ctrl_onObsNames_->setValue(ctrl_inObsNames_, NOUPDATE);
00751 }
00752 
00753 bool
00754 MarSystem::isUpdating()
00755 {
00756   return isUpdating_;
00757 }
00758 
00759 void
00760 MarSystem::update(MarControlPtr sender)
00761 {
00762   MRSDIAG(type_ << "/" << name_ << "::update");
00763 
00764   isUpdating_ = true;
00765 
00766   //store current flow variables
00767   tinObservations_ = inObservations_;
00768   tinSamples_ = inSamples_;
00769   tisrate_ = israte_;
00770   tinObsNames_ = inObsNames_;
00771   tonObservations_ = onObservations_;
00772   tonSamples_ = onSamples_;
00773   tosrate_ = osrate_;
00774   tonObsNames_ = onObsNames_;
00775   tinStabilizingDelay_ = inStabilizingDelay_;
00776   tonStabilizingDelay_ = onStabilizingDelay_;
00777 
00778   //sync input member variables
00779   inObservations_ = ctrl_inObservations_->to<mrs_natural>();
00780   inSamples_ = ctrl_inSamples_->to<mrs_natural>();
00781   israte_ = ctrl_israte_->to<mrs_real>();
00782   inObsNames_ = ctrl_inObsNames_->to<mrs_string>();
00783   inStabilizingDelay_ = ctrl_inStabilizingDelay_->to<mrs_natural>();
00784   //sync output member variables
00785   onObservations_ = ctrl_onObservations_->to<mrs_natural>();
00786   onSamples_ = ctrl_onSamples_->to<mrs_natural>();
00787   osrate_ = ctrl_osrate_->to<mrs_real>();
00788   onObsNames_ = ctrl_onObsNames_->to<mrs_string>();
00789   onStabilizingDelay_ = ctrl_onStabilizingDelay_->to<mrs_natural>();
00790 
00791   // do this before myUpdate() in case it needs to be
00792   // overridden, i.e. for a Composite
00793   ctrl_onStabilizingDelay_->setValue(
00794     ctrl_inStabilizingDelay_->to<mrs_natural>()
00795     + addToStabilizingDelay_, NOUPDATE);
00796 
00797   //call derived class specific update
00798   myUpdate(sender);
00799 
00800   //sync input member variables
00801   inObservations_ = ctrl_inObservations_->to<mrs_natural>();
00802   inSamples_ = ctrl_inSamples_->to<mrs_natural>();
00803   israte_ = ctrl_israte_->to<mrs_real>();
00804   inObsNames_ = ctrl_inObsNames_->to<mrs_string>();
00805   inStabilizingDelay_ = ctrl_inStabilizingDelay_->to<mrs_natural>();
00806   //sync output member variables
00807   onObservations_ = ctrl_onObservations_->to<mrs_natural>();
00808   onSamples_ = ctrl_onSamples_->to<mrs_natural>();
00809   osrate_ = ctrl_osrate_->to<mrs_real>();
00810   onObsNames_ = ctrl_onObsNames_->to<mrs_string>();
00811   onStabilizingDelay_ = ctrl_onStabilizingDelay_->to<mrs_natural>();
00812 
00813   //check active status
00814   bool active = ctrl_active_->isTrue();
00815   //if active status changed...
00816   if (active_ !=  active)
00817   {
00818     active_ = active;
00819     activate(active);
00820   }
00821 
00822   //resize input and output realvec if necessary
00823   if ((inObservations_ != inTick_.getRows()) ||
00824       (inSamples_ != inTick_.getCols())      ||
00825       (onObservations_ != outTick_.getRows()) ||
00826       (onSamples_ != outTick_.getCols()))
00827   {
00828 
00829 
00830     inTick_.create(inObservations_, inSamples_);
00831     {
00832       MarControlAccessor acc(ctrl_processedData_);
00833       realvec& processedData = acc.to<mrs_realvec>();
00834       processedData.create(onObservations_, onSamples_);
00835 
00836     }
00837 
00838 
00839   }
00840 
00841   //check for OUT-FLOW modifications without parent knowledge!!
00842   if (parent_)
00843   {
00844     if (tonObservations_ != onObservations_ ||
00845         tonSamples_ != onSamples_ ||
00846         tosrate_ != osrate_ ||
00847         tonObsNames_ != onObsNames_)
00848       if (!parent_->isUpdating())
00849         parent_->update(sender);
00850   }
00851 
00852   isUpdating_ = false;
00853 }
00854 
00855 void
00856 MarSystem::activate(bool state) //non-thread-safe, but this method is only supposed to be called from update(), which is thread-safe
00857 {
00858   //since this method must be public (so it can be called in Composite::activate())
00859   //we must guarantee that the "mrs_bool/active" control is in sync with any eventual
00860   //direct calls to MarSystem::activate() from client code
00861   if (ctrl_active_->to<bool>() != state)
00862   {
00863     ctrl_active_->setValue(state, NOUPDATE);
00864     active_ = state;
00865   }
00866 
00867   //execute any code needed to run when activating/deactivating
00868   //the derived MarSystem
00869   localActivate(state);
00870 }
00871 
00872 void
00873 MarSystem::localActivate(bool state)
00874 {
00875   //call activate for all Composite's components
00876   if (isComposite_)
00877   {
00878     child_count_t child_count = marsystems_.size();
00879     for (child_count_t i=0; i<child_count; ++i)
00880     {
00881       //marsystems_[i]->activate(state);
00882       marsystems_[i]->updControl("mrs_bool/active", state); //thread-safe
00883     }
00884   }
00885 }
00886 
00887 mrs_string
00888 MarSystem::getControlRelativePath(mrs_string cname) const
00889 {
00890   // If the cname starts with an '/', it is an absolute path
00891   // that has to be made relative.
00892   if (cname[0] == '/')
00893   {
00894     //is this absolute path pointing to this MarSystem? // => mutexes [?]
00895     if (cname.substr(0, absPath_.length()) == absPath_)
00896     {
00897       //return control path without the absolute path
00898       //(i.e. return the relative path)
00899       return cname.substr(absPath_.length(), cname.length());
00900     }
00901     else
00902     {
00903       return "";
00904     }
00905   }
00906   else
00907   {
00908     // cname is already a relative path, so we can return that.
00909     return cname;
00910   }
00911 }
00912 
00913 mrs_string
00914 MarSystem::getControlLocalPath(mrs_string cname) const
00915 {
00916   // Convert cname to the canonical relative format.
00917   cname = getControlRelativePath(cname);
00918   if (cname == "")
00919   {
00920     // Not a control from this MarSystem or its children.
00921     return "";
00922   }
00923 
00924   // A local path should have only one '/' (e.g. "mrs_xxx/nnnn"),
00925   // otherwise it's probably a control from a child MarSystem.
00926   if (cname.find_first_of('/') == cname.find_last_of('/') &&
00927       cname.find_first_of('/') != mrs_string::npos)
00928   {
00929     // This is a relative and local path, so just return it
00930     return cname;
00931   }
00932   else
00933   {
00934     // This is not a local control => return invalid name
00935     return "";
00936   }
00937 }
00938 
00939 bool
00940 MarSystem::linkControl(mrs_string cname1, mrs_string cname2, bool update)
00941 {
00942   //Links the control cname1 with the control cname 2.
00943   //
00944   //Link fails case both cname1 and cname2 point to non-existing controls.
00945   //
00946   //cname1 should point to a local or child control (using an absolute control pathname,
00947   //a local control pathname or a relative pathname).
00948   //If control corresponding to cname1 does not exist locally or in any child,
00949   //a proxy control is created and added to the corresponding MarSystem.
00950   //In all these cases, cname1 control will assume the current value of the cname2 control.
00951   //
00952   //cname2 should point to an existing control, anywhere in the network (i.e. not necessarily a
00953   //local or a child's control).
00954   //cname 2 can be a absolute, local or relative pathname.
00955   //In case cname2 points to a non-existing control, if its pathname corresponds to a local or
00956   //a child's control, a proxy control will be created in the corresponding MarSystem.
00957   //In this case, the value of the cname2 control will be set to the current value of the cname1 control.
00958 
00959   //try to get the controls
00960   MarControlPtr ctrl1 = getControl(cname1, false, true);//search local and child controls
00961   MarControlPtr ctrl2 = getControl(cname2, true, true);//search everywhere in the network (including locally, at parent and among children)
00962 
00963   //a control is inherently connected to itself!
00964   if (ctrl1() == ctrl2())
00965   {
00966     if (ctrl1() == NULL)
00967     {
00968       MRSWARN("MarSystem::linkControl - Impossible to link two non-existing controls: " + cname1+" --> "+cname2);
00969       return false;
00970     }
00971     else
00972       return true;
00973   }
00974 
00975   //if  2nd control does not exist somewhere in the network,
00976   //try to create one locally or in children (and assign it the value of the 1st control)
00977   if (ctrl2.isInvalid())
00978   {
00979     //MRSWARN("MarSystem::linkControl - 2nd control does not exist anywhere: " + cname2 + " -> THIS MAY BE NORMAL WHEN LOADING A MARSYSTEM NETWORK FROM A .mpl FILE!");
00980     //return false;
00981 
00982     mrs_string relativecname = getControlRelativePath(cname2);
00983     mrs_string localcname = getControlLocalPath(cname2);
00984 
00985     //if cname2 is a local control path, add it to this MarSystem
00986     if (localcname != "")
00987     {
00988       if (!addControl(cname2, ctrl1->clone(), ctrl2))
00989       {
00990         MRSWARN("MarSystem::linkControl - Error creating new proxy control " + cname2 + " @ " + getAbsPath());
00991         return false;
00992       }
00993       MRSDIAG("MarSystem::linkControl - Added new proxy control " + cname2 + " @ " + getAbsPath());
00994       ctrl2->setState(false); //proxy controls never need to have state!
00995     }
00996     //if cname2 is a relative path, check among children for a matching MarSystem
00997     //where to add the new link control
00998     else if (relativecname != "")
00999     {
01000       //get the MarSystem path from relativecname
01001       mrs_string::size_type pos = relativecname.find("/mrs_", 0);
01002       mrs_string relativepath = relativecname.substr(0, pos);
01003 
01004       MarSystem* msys = getChildMarSystem(relativepath);
01005       if (msys)
01006       {
01007         mrs_string cname = relativecname.substr(pos+1, relativecname.length());
01008         if (!msys->addControl(cname, ctrl1->clone(), ctrl2))
01009         {
01010           MRSWARN("MarSystem::linkControl - Error creating new link control " + cname2 + " @ " + msys->getAbsPath());
01011           return false;
01012         }
01013         MRSDIAG("MarSystem::linkControl - Added new proxy control " + cname2 + " @ " + msys->getAbsPath());
01014         ctrl2->setState(false); //proxy controls never need to have state!
01015       }
01016       else
01017       {
01018         MRSWARN("MarSystem::linkControl - Error creating new link control: " + cname2 + " is an invalid path");
01019         return false;
01020       }
01021     }
01022     //if cname1 path is not a valid path, nor a path pointing to any of the children
01023     //it is not possible to add the new link control...
01024     else
01025     {
01026       MRSWARN("MarSystem::linkControl - Error creating new link control: " + cname2 + " is an invalid path");
01027       return false;
01028     }
01029   }
01030 
01031   //check if the first control already exists or if we have
01032   // to create and add it to the corresponding MarSystem
01033   if (ctrl1.isInvalid())
01034   {
01035     mrs_string relativecname = getControlRelativePath(cname1);
01036     mrs_string localcname = getControlLocalPath(cname1);
01037 
01038     //if cname1 is a local control path, add it to this MarSystem
01039     if (localcname != "")
01040     {
01041       if (!addControl(cname1, ctrl2->clone(), ctrl1))
01042       {
01043         MRSWARN("MarSystem::linkControl - Error creating new link control " + cname1 + " @ " + getAbsPath());
01044         return false;
01045       }
01046       MRSDIAG("MarSystem::linkControl - Added new proxy control " + cname1 + " @ " + getAbsPath());
01047       ctrl1->setState(false); //proxy controls never need to have state!
01048     }
01049     //if cname1 is a relative path, check among children for a matching MarSystem
01050     //where to add the new link control
01051     else if (relativecname != "")
01052     {
01053       //get the MarSystem path from relativecname
01054       mrs_string::size_type pos = relativecname.find("/mrs_", 0);
01055       mrs_string relativepath = relativecname.substr(0, pos);
01056 
01057       MarSystem* msys = getChildMarSystem(relativepath);
01058       if (msys)
01059       {
01060         mrs_string cname = relativecname.substr(pos+1, relativecname.length());
01061         if (!msys->addControl(cname, ctrl2->clone(), ctrl1))
01062         {
01063           MRSWARN("MarSystem::linkControl - Error creating new link control " + cname1 + " @ " + msys->getAbsPath());
01064           return false;
01065         }
01066         MRSDIAG("MarSystem::linkControl - Added new proxy control " + cname1 + " @ " + msys->getAbsPath());
01067         ctrl1->setState(false); //proxy controls never need to have state!
01068       }
01069       else
01070       {
01071         MRSWARN("MarSystem::linkControl - Error creating new link control: " + cname1 + "is an invalid path");
01072         return false;
01073       }
01074     }
01075     //if cname1 path is not a valid path, nor a path pointing to any of the children
01076     //it is not possible to add the new link control...
01077     else
01078     {
01079       MRSWARN("MarSystem::linkControl - Error creating new link control: " + cname1 + "is an invalid path");
01080       return false;
01081     }
01082   }
01083 
01084   //now both controls exist
01085   //just link them
01086   return ctrl1->linkTo(ctrl2, update);
01087 }
01088 
01089 MarControlPtr
01090 MarSystem::getControl(mrs_string cname, bool searchParent, bool searchChildren)
01091 {
01092   //USE A CACHE FOR MORE EFFICIENT LOOK-UP?? [!]
01093 
01094   //convert cname to the canonical relative format
01095   mrs_string relativecname = getControlRelativePath(cname);
01096 
01097   //if this is not a control from this MarSystem or its children
01098   //ask parent (if allowed) to search for it on the remaining of the network
01099   if (relativecname == "")
01100   {
01101     if (searchParent && parent_)
01102     {
01103       return parent_->getControl(cname, true, true);//parent will also ask its parent if necessary // => mutexes [?]
01104     }
01105     else //parent search not allowed, so the control was not found => return invalid control
01106     {
01107       //MRSWARN("MarSystem::getControl - Unsupported control name: " + cname + " @ " + absPath_ + " -> THIS MAY BE NORMAL DURING CLONING!");
01108       return MarControlPtr();
01109     }
01110   }
01111   //check if this relative control path points to a possible local control
01112   mrs_string localcname = getControlLocalPath(relativecname);
01113   if (localcname != "")
01114   {
01115     //This may be a local control, so look for it
01116     if (controls_.find(localcname) != controls_.end())
01117     {
01118       return controls_[localcname]; //control found
01119     }
01120     else
01121     {
01122       return MarControlPtr(); //no control found with this name => return invalid control
01123     }
01124   }
01125   //definitely not a local control pathname. It can only be a relative control path.
01126   //So search in children (if allowed).
01127   else
01128   {
01129     if (searchChildren)
01130     {
01131       //search for a child that has a corresponding prefix
01132       vector<MarSystem*>::const_iterator msysIter;
01133       for (msysIter = marsystems_.begin(); msysIter != marsystems_.end(); ++msysIter) // => mutexes [?]
01134       {
01135         mrs_string prefix = (*msysIter)->getPrefix();
01136         prefix = prefix.substr(1, prefix.length()); //ignore leading "/"
01137         if (relativecname.substr(0, prefix.length()) == prefix)
01138         {
01139           //a matching child was found!
01140           //check if the control exists in the child
01141           mrs_string childcname = relativecname.substr(prefix.length(),relativecname.length());
01142           return (*msysIter)->getControl(childcname);
01143         }
01144       }
01145       return MarControlPtr();//no child found with corresponding prefix...
01146     }
01147     else
01148     {
01149       return MarControlPtr();
01150     }
01151   }
01152 }
01153 
01154 bool
01155 MarSystem::hasControlState(mrs_string cname)
01156 {
01157   MarControlPtr control = getControl(cname);
01158   if (control.isInvalid())
01159   {
01160     MRSWARN("MarSystem::hasControlState Unsupported control name = " + cname);
01161     return false;
01162   }
01163   else
01164     return control->hasState();
01165 }
01166 
01167 void
01168 MarSystem::setControlState(mrs_string cname, bool state)
01169 {
01170   MarControlPtr control = getControl(cname);
01171   if (control.isInvalid())
01172   {
01173     MRSWARN("MarControls::setState Unsupported control name = " + cname);
01174   }
01175   else
01176     control->setState(state);
01177 }
01178 
01179 bool
01180 MarSystem::hasControl(mrs_string cname, bool searchChildren)
01181 {
01182   //look for local and (optionally) children controls
01183   MarControlPtr control = this->getControl(cname, false, searchChildren);
01184   return !control.isInvalid();
01185 }
01186 
01187 bool
01188 MarSystem::hasControl(MarControlPtr control, bool searchChildren)
01189 {
01190   //search local controls
01191   for (ControlItr ctrlIter_=controls_.begin(); ctrlIter_!=controls_.end(); ++ctrlIter_)
01192   {
01193     if ((ctrlIter_->second)() == control())
01194       return true;
01195   }
01196   //search control among children (if allowed)
01197   if (searchChildren)
01198   {
01199     vector<MarSystem*>::const_iterator msysIter;
01200     for (msysIter=marsystems_.begin(); msysIter!=marsystems_.end(); ++msysIter)
01201     {
01202       if ((*msysIter)->hasControl(control, true))
01203         return true;
01204     }
01205   }
01206   return false;
01207 }
01208 
01209 
01210 
01211 bool MarSystem::updControl(const char* cname, MarControlPtr newcontrol, bool upd)
01212 {
01213   MarControlPtr control = getControl(cname);
01214   if (control.isInvalid())
01215   {
01216     MRSWARN("MarSystem::updControl - " + std::string(cname) + " is an invalid control @ " + getAbsPath());
01217     return false;
01218   }
01219   return updControl(control, newcontrol, upd);
01220 }
01221 
01222 bool MarSystem::updControl(std::string cname, MarControlPtr newcontrol, bool upd)
01223 {
01224   MarControlPtr control = getControl(cname);
01225   if (control.isInvalid())
01226   {
01227     MRSWARN("MarSystem::updControl - " + cname + " is an invalid control @ " + getAbsPath());
01228     return false;
01229   }
01230   return updControl(control, newcontrol, upd);
01231 }
01232 
01233 
01234 bool
01235 MarSystem::updControl(MarControlPtr control, MarControlPtr newcontrol, bool upd)
01236 {
01237   // check if the control is valid
01238   if (control.isInvalid())
01239   {
01240     MRSWARN("MarSystem::updControl - Invalid control ptr @ " + getAbsPath());
01241     return false;
01242   }
01243 
01244   if (newcontrol.isInvalid())
01245   {
01246     MRSWARN("MarSystem::updControl - Invalid control ptr given for assignment");
01247     return false;
01248   }
01249   //    //check if control exists locally or among children
01250   //    if(!hasControl(control))
01251   //    {
01252   //        MRSWARN("MarSystem::updControl - " + control->getName() +" @ "+getAbsPath()+ " does not exist locally or in children!");
01253   //        return false;
01254   //    }
01255 
01256   return control->setValue(newcontrol, upd);
01257 }
01258 
01259 
01260 void
01261 MarSystem::updControl(EvEvent* me)
01262 {
01263   if (me != NULL)
01264   {
01265     me->dispatch();
01266     delete(me);
01267   }
01268 }
01269 
01270 void
01271 MarSystem::updControl(TmTime t, EvEvent* ev)
01272 {
01273   scheduler_.post(t,Repeat(),ev);
01274 }
01275 
01276 void
01277 MarSystem::updControl(TmTime t, Repeat r, EvEvent* ev)
01278 {
01279   scheduler_.post(t,r,ev);
01280 }
01281 
01282 void
01283 MarSystem::updControl(TmTime t, mrs_string cname, MarControlPtr control)
01284 {
01285   scheduler_.post(t,Repeat(),new EvValUpd(this,cname,control));
01286 }
01287 
01288 void
01289 MarSystem::updControl(TmTime t, Repeat r, mrs_string cname, MarControlPtr control)
01290 {
01291   scheduler_.post(t,r,new EvValUpd(this,cname,control));
01292 }
01293 
01294 
01295 
01296 //get local controls only (i.e. no child controls included)
01297 const map<mrs_string, MarControlPtr>&
01298 MarSystem::getLocalControls()
01299 {
01300   return controls_;
01301 }
01302 
01303 // get all the controls (including controls of children)
01304 // for a particular MarSystem
01305 map<mrs_string, MarControlPtr>
01306 MarSystem::getControls(map<mrs_string, MarControlPtr>* cmap)
01307 {
01308   if (!cmap)
01309   {
01310     map<mrs_string, MarControlPtr> controlsmap;
01311 
01312     cmap = &controlsmap;
01313 
01314     //fill list with local controls
01315     for (ControlItr ctrlIter_=controls_.begin(); ctrlIter_ != controls_.end(); ++ctrlIter_)
01316     {
01317       (*cmap)[absPath_+ctrlIter_->first] = ctrlIter_->second;
01318     }
01319 
01320     //iterate over children, recursively,
01321     //and fill the list with their controls
01322     vector<MarSystem*>::const_iterator msysIter;
01323     for (msysIter = marsystems_.begin(); msysIter != marsystems_.end(); ++msysIter)
01324     {
01325       (*msysIter)->getControls(cmap);
01326     }
01327 
01328     return (*cmap);
01329   }
01330   else
01331   {
01332     //fill list with local controls
01333     for (ControlItr ctrlIter_=controls_.begin(); ctrlIter_ != controls_.end(); ++ctrlIter_)
01334     {
01335       (*cmap)[absPath_+ctrlIter_->first] = ctrlIter_->second;
01336     }
01337 
01338     //iterate over children, recursively,
01339     //and fill the list with their controls
01340     vector<MarSystem*>::const_iterator msysIter;
01341     for (msysIter = marsystems_.begin(); msysIter != marsystems_.end(); ++msysIter)
01342     {
01343       (*msysIter)->getControls(cmap);
01344     }
01345 
01346     return (*cmap);
01347   }
01348 }
01349 
01350 vector<MarSystem*>
01351 MarSystem::getChildren()
01352 {
01353   return marsystems_;
01354 }
01355 
01356 std::string MarSystem::splitPathEnd( const std::string & path, std::string & remaining )
01357 {
01358   string::size_type last_separator = path.rfind('/');
01359   if (last_separator != string::npos)
01360   {
01361     string ending = path.substr(last_separator + 1);
01362     if (last_separator > 0)
01363       remaining = path.substr(0, last_separator);
01364     else
01365       remaining = '/';
01366     return ending;
01367   }
01368   else
01369   {
01370     return path;
01371   }
01372 }
01373 
01374 std::string MarSystem::path() const
01375 {
01376   std::stack<const MarSystem*> hierarchy;
01377   const MarSystem *system = this;
01378   while(system->getParent())
01379   {
01380     hierarchy.push(system);
01381     system = system->getParent();
01382   }
01383   string path("/");
01384   while(!hierarchy.empty())
01385   {
01386     path += hierarchy.top()->getName();
01387     path += '/';
01388     hierarchy.pop();
01389   }
01390   return path;
01391 }
01392 
01393 // Name without type:
01394 MarSystem * MarSystem::child( const string & name )
01395 {
01396   std::vector<MarSystem*>::iterator it;
01397   for (it = marsystems_.begin(); it != marsystems_.end(); ++it)
01398   {
01399     if ((*it)->getName() == name)
01400       return *it;
01401   }
01402 
01403   return 0;
01404 }
01405 
01406 // Name without type:
01407 MarControlPtr MarSystem::control( const string & name )
01408 {
01409   //MRSMSG("MarSystem::control: " << getAbsPath() << " -> " << name);
01410 
01411   ControlItr it;
01412   for (it = controls_.begin(); it != controls_.end(); ++it)
01413   {
01414     if (it->second->id() == name)
01415       return it->second;
01416   }
01417 
01418   return MarControlPtr();
01419 }
01420 
01421 MarSystem *MarSystem::subSystem( const std::string & name )
01422 {
01423   //MRSMSG("MarSystem::subSystem: " << getAbsPath() << " -> " << name);
01424 
01425   std::map<std::string, MarSystem*>::iterator it;
01426   it = scope_.find(name);
01427   if (it != scope_.end())
01428     return it->second;
01429   else
01430     return 0;
01431 }
01432 
01433 class path_stream
01434 {
01435 public:
01436   path_stream( const string & path ):
01437     m_path(path),
01438     m_pos(0)
01439   {}
01440 
01441   path_stream & operator>>(string & element)
01442   {
01443     if (at_end()) {
01444       element = string();
01445       return *this;
01446     }
01447 
01448     string::size_type separator = m_path.find('/', m_pos);
01449     if (separator != string::npos)
01450     {
01451       element = m_path.substr(m_pos, separator - m_pos);
01452       m_pos = separator + 1;
01453     }
01454     else
01455     {
01456       element = m_path.substr(m_pos);
01457       m_pos = string::npos;
01458     }
01459 
01460     return *this;
01461   }
01462 
01463   void skip()
01464   {
01465     string::size_type separator = m_path.find('/', m_pos);
01466     if (separator != string::npos)
01467       m_pos = separator + 1;
01468     else
01469       m_pos = string::npos;
01470   }
01471 
01472   bool at_end()
01473   {
01474     return m_pos >= m_path.length();
01475   }
01476 
01477 private:
01478   string m_path;
01479   string::size_type m_pos;
01480 };
01481 
01482 // Path in form of "system-name/system-name/..." without types:
01483 MarSystem *MarSystem::remoteSystem( const string & path )
01484 {
01485   //MRSMSG("MarSystem::remoteSystem: " << this << " " << path);
01486 
01487   if (path.empty())
01488     return 0;
01489 
01490   path_stream elements(path);
01491   MarSystem * system = this;
01492 
01493   if (path[0] == '/')
01494   {
01495     // Absolute path. Go find root system:
01496 
01497     elements.skip();
01498 
01499     while(system->getParent())
01500       system = system->getParent();
01501   }
01502   else
01503   {
01504     // Relative path.
01505     // Go find first ancestor which has the first element in scope.
01506     // TODO: Could speed up if all systems had parent_scope_,
01507     // even if not named in any scope
01508     // - then we could jump up scope instead of system hierarchy.
01509 
01510     string elem;
01511     elements >> elem;
01512     assert(!elem.empty());
01513 
01514     while (system)
01515     {
01516       MarSystem *subsystem = system->subSystem(elem);
01517       if (subsystem)
01518       {
01519         system = subsystem;
01520         break;
01521       }
01522       system = system->getParent();
01523     }
01524   }
01525 
01526   while(system && !elements.at_end())
01527   {
01528     string elem;
01529     elements >> elem;
01530     system = system->subSystem(elem);
01531   }
01532 
01533   return system;
01534 }
01535 
01536 // Path in form of "system-name/system-name/.../control-name" without types:
01537 MarControlPtr MarSystem::remoteControl( const string & path )
01538 {
01539   //MRSMSG("MarSystem::remoteControl: " << getAbsPath() << " -> " << path);
01540   if (path.empty())
01541     return MarControlPtr();
01542 
01543   MarSystem * system = this;
01544   string system_path;
01545   string control_name = splitPathEnd(path, system_path);
01546   if (!system_path.empty())
01547   {
01548     system = remoteSystem(system_path);
01549   }
01550   if (system)
01551     return system->control( control_name );
01552   else
01553     return MarControlPtr();
01554 }
01555 
01556 bool
01557 MarSystem::addControl(mrs_string cname, MarControlPtr v, MarControlPtr& ptr)
01558 {
01559   if (addControl(cname, v))
01560   {
01561     ptr = controls_[cname]; // => mutexes [?]
01562     return true;
01563   }
01564   else
01565   {
01566     ptr = MarControlPtr();//return invalid control
01567     return false;
01568   }
01569 }
01570 
01571 bool
01572 MarSystem::addControl(mrs_string cname, MarControlPtr v)
01573 {
01574   //convert cname to the canonical local control pathname format
01575   mrs_string pcname = cname;
01576   cname = getControlLocalPath(cname);
01577   if (cname == "")
01578   {
01579     //cname is an invalid control pathname!
01580     MRSWARN("MarSystem::addControl - invalid control pathname: " + pcname);
01581     MRSWARN("MarSystem::addControl - absolute path: " + absPath_); // => mutexes [?]
01582     return false;
01583   }
01584 
01585   //check for type mismatch between cname string (which include type information)
01586   //and the actual control type passed as an argument
01587   mrs_string::size_type pos = cname.find("/", 0);
01588   mrs_string ctype = cname.substr(0,pos);
01589   if (ctype!= v->getType())
01590   {
01591     MRSWARN("MarSystem::addControl control type mismatch (" + ctype + "!=" + v->getType() + ", in " + type_ + ")");
01592     return false;
01593   }
01594   controls_[cname] = v;
01595   controls_[cname]->setMarSystem(this);
01596   controls_[cname]->setName(cname);
01597 
01598   //success!
01599   MRSDIAG("MarSystem::addControl - control added successfully: " + cname + " @ " + absPath_);
01600   return true;
01601 }
01602 
01603 void
01604 MarSystem::updctrl(EvEvent* me)
01605 {
01606   if (me != NULL)
01607   {
01608     me->dispatch();
01609     delete(me);
01610   }
01611 }
01612 
01613 void
01614 MarSystem::updctrl(TmTime t, EvEvent* ev)
01615 {
01616   scheduler_.post(t,Repeat(),ev);
01617 }
01618 
01619 void
01620 MarSystem::updctrl(TmTime t, Repeat r, EvEvent* ev)
01621 {
01622   scheduler_.post(t,r,ev);
01623 }
01624 
01625 void
01626 MarSystem::updctrl(TmTime t, mrs_string cname, MarControlPtr control)
01627 {
01628   scheduler_.post(t,Repeat(),new EvValUpd(this,cname,control));
01629 }
01630 
01631 void
01632 MarSystem::updctrl(TmTime t, Repeat r, mrs_string cname, MarControlPtr control)
01633 {
01634   scheduler_.post(t,r,new EvValUpd(this,cname,control));
01635 }
01636 
01637 void
01638 MarSystem::removeTimer(mrs_string name)
01639 {
01640   scheduler_.removeTimer(name);
01641 }
01642 
01643 void
01644 MarSystem::addTimer(std::string tmr_class, std::string tmr_ident)
01645 {
01646   scheduler_.addTimer(tmr_class,tmr_ident);
01647 }
01648 void
01649 MarSystem::addTimer(std::string tmr_class, std::string tmr_ident, std::vector<TmParam> params)
01650 {
01651   scheduler_.addTimer(tmr_class,tmr_ident,params);
01652 }
01653 
01654 void
01655 MarSystem::updtimer(std::string tmr_ctrl_path, TmControlValue value)
01656 {
01657   scheduler_.updtimer(tmr_ctrl_path,value);
01658 }
01659 void
01660 MarSystem::updtimer(std::string tmr_path, TmParam param)
01661 {
01662   scheduler_.updtimer(tmr_path,param);
01663 }
01664 void
01665 MarSystem::updtimer(std::string tmr_path, std::vector<TmParam> params)
01666 {
01667   scheduler_.updtimer(tmr_path,params);
01668 }
01669 
01670 
01671 
01672 mrs_natural
01673 MarSystem::getTime(mrs_string timer_name)
01674 {
01675   return scheduler_.getTime(timer_name);
01676 }
01677 
01678 void
01679 MarSystem::setMATLABscript(std::string script)
01680 {
01681   MATLABscript_ = script;
01682 }
01683 
01684 mrs_string
01685 MarSystem::getMATLABscript()
01686 {
01687   return MATLABscript_;
01688 }
01689 
01690 mrs_string
01691 MarSystem::toStringShort()
01692 {
01693   ostringstream oss;
01694   put(oss, false);
01695   return oss.str();
01696 
01697 }
01698 
01699 
01700 
01701 mrs_string
01702 MarSystem::toString()
01703 {
01704   ostringstream oss;
01705   put(oss,true);
01706   return oss.str();
01707 }
01708 
01709 
01710 mrs_string
01711 MarSystem::toStringGraphViz()
01712 {
01713   ostringstream oss;
01714   ostringstream oss_defs;
01715   ostringstream oss_links;
01716   toStringGraphViz(oss_defs, oss_links);
01717 
01718   //oss << oss_defs.str() << endl;
01719 
01720   oss << "digraph G {" << endl;
01721   oss << oss_links.str();
01722 
01723   oss << "}" << endl;
01724   return oss.str();
01725 }
01726 
01727 void
01728 MarSystem::toStringGraphViz(ostringstream& oss_defs, ostringstream& oss_links)
01729 {
01730   // Print the node def.
01731   //oss_defs << "Node=" << prefix_ << endl;
01732   static int a=0;
01733 
01734   // Print the links
01735   child_count_t sz = marsystems_.size();
01736   if (sz>0)
01737   {
01738     // Make a cluster.
01739     oss_links << "\tsubgraph cluster_" << a++ << " {" << endl;
01740     oss_links << "\t\tlabel = \"" << prefix_  << "\"" << endl;
01741     oss_links << "\t\t";
01742 
01743     for (child_count_t i=0; i<sz-1; ++i)
01744     {
01745       // TODO are there other composite types to handle?
01746       if (type_ == "Fanout" || type_ == "Parallel") {
01747         if ( marsystems_[i]->isComposite_) {
01748           // TODO: handle links to composites better.
01749           oss_links << "\"" << marsystems_[i]->prefix_ << "\";" << endl;
01750         } else {
01751           oss_links << "\"" << marsystems_[i]->prefix_ << "\";" << endl;
01752         }
01753       } else {
01754         if ( marsystems_[i]->isComposite_) {
01755           // TODO: handle links to composites better.
01756           oss_links << "\"" << marsystems_[i]->prefix_ << "\" -> ";
01757         } else {
01758           oss_links << "\"" << marsystems_[i]->prefix_ << "\" -> ";
01759         }
01760       }
01761     }
01762     oss_links << "\"" << marsystems_[sz-1]->prefix_ << "\";" << endl;
01763     oss_links << "\t}" << endl << endl;
01764 
01765     // Link to start.
01766     // TODO are there other composite types to handle?
01767     if (type_ == "Fanout" || type_ == "Parallel") {
01768       // Link to all first items for parallel types of composites.
01769       for (child_count_t j=0; j<sz; ++j)
01770         oss_links << "\t\"" << prefix_ << "\" -> \"" << marsystems_[j]->prefix_ << "\";" << endl;
01771     } else {
01772       // Only link to first item in series.
01773       oss_links << "\t\"" << prefix_ << "\" -> \"" << marsystems_[0]->prefix_ << "\";" << endl;
01774     }
01775 
01776     // Link the end of series back to parent's next item... tricky.
01777     // TODO
01778   }
01779 
01780 
01781 
01782   // Children.
01783   if (sz>0)
01784   {
01785     for (child_count_t i=0; i<sz; ++i)
01786       marsystems_[i]->toStringGraphViz(oss_defs, oss_links);
01787   }
01788 }
01789 
01790 
01791 
01792 
01793 
01794 marostring&
01795 MarSystem::toString(marostring& m)
01796 {
01797   m.begin_marsystem(isComposite_, getType(), getName());
01798 
01799   m.begin_controls((int)controls_.size());
01800   for (ControlItr ctrlIter_ = controls_.begin(); ctrlIter_ != controls_.end(); ++ctrlIter_)
01801   {
01802     MarControlPtr c = ctrlIter_->second;
01803     std::ostringstream cv;
01804     cv << c;
01805     std::string ct = c->getType();
01806     std::string cn = c->getName();
01807     // get the trailing bit after / Don't know why name is now type/name
01808     int lp = (int)cn.find_last_of('/');
01809     if (lp >= 0 && (lp+1) < (int)cn.size())
01810       cn = cn.substr(lp+1);
01811 
01812     bool cs = c->hasState();
01813     m.begin_control(ct, cn, cv.str(), cs);
01814 
01815     std::vector<std::pair<MarControlPtr, MarControlPtr> > links = c->getLinks();
01816     int j=0;
01817     for (mrs_natural i=0; i< (mrs_natural)links.size(); ++i)
01818     {
01819       //check who is linking to this control, but avoid outputting root link info
01820       if (c == links[i].second() && links[i].first() != c)
01821       {
01822         j++;
01823       }
01824     }
01825     m.begin_control_links_in(j);
01826     for (mrs_natural i=0; i<(mrs_natural)links.size(); ++i)
01827     {
01828       // check who is linking to this control, but avoid outputting root link info
01829       if (c == links[i].second() && links[i].first() != c)
01830       {
01831         m.put_control_link_in(links[i].first->getMarSystem()->getAbsPath(),links[i].first->getType(),links[i].first->getName());
01832       }
01833     }
01834     m.end_control_links_in(j);
01835 
01836     for (mrs_natural i=0; i<(mrs_natural)links.size(); ++i)
01837     {
01838       //check where to this control is linking, but avoid outputting root link info
01839       if (c == links[i].first() && c != links[i].second())
01840       {
01841         j++;
01842       }
01843     }
01844     m.begin_control_links_out(j);
01845     for (mrs_natural i=0; i<(mrs_natural)links.size(); ++i)
01846     {
01847       //check where to this control is linking, but avoid outputting root link info
01848       if (c == links[i].first() && c != links[i].second())
01849       {
01850         m.put_control_link_out(links[i].second->getMarSystem()->getAbsPath(),links[i].second->getType(),links[i].second->getName());
01851       }
01852     }
01853     m.end_control_links_out(j);
01854     m.end_control(ct, cn, cv.str(), cs);
01855   }
01856   m.end_controls((int)controls_.size());
01857 
01858   child_count_t sz = marsystems_.size();
01859   if (sz>0)
01860   {
01861     m.begin_children((int)sz);
01862     for (child_count_t i=0; i<sz; ++i)
01863     {
01864       marsystems_[i]->toString(m);
01865     }
01866     m.end_children((int)sz);
01867   }
01868   m.end_marsystem(isComposite_, getType(), getName());
01869   return m;
01870 }
01871 
01872 // write *this to s
01873 ostream&
01874 MarSystem::put(ostream &o, bool verbose)
01875 {
01876 
01877   if (isComposite_)
01878   {
01879     o << "# MarSystemComposite" << endl;
01880   }
01881   else
01882   {
01883     o << "# MarSystem" << endl;
01884   }
01885   o << "# Type = " << type_ << endl;
01886   o << "# Name = " << name_ << endl;
01887 
01888   o << endl;
01889 
01890   if (verbose)
01891   {
01892     o << "# MarControls = " << controls_.size() << endl;
01893     for (ControlItr ctrlIter_=controls_.begin(); ctrlIter_ != controls_.end(); ++ctrlIter_)
01894     {
01895       ostringstream toss;
01896       toss << ctrlIter_->second;
01897       if (toss.str() != "")
01898         o << "# " << ctrlIter_->first << " = " << ctrlIter_->second << endl;
01899       else
01900         o << "# " << ctrlIter_->first << " = " << "MARSYAS_EMPTYSTRING" << endl;
01901       //serialize links
01902       ostringstream oss;
01903       std::vector<std::pair<MarControlPtr, MarControlPtr> > links = ctrlIter_->second->getLinks();
01904       mrs_natural numLinks = 0;
01905       //links to:
01906       for (mrs_natural i=0; i<(mrs_natural)links.size(); ++i)
01907       {
01908         //check where to this control is linking, but avoid outputting root link info
01909         if (ctrlIter_->second() == links[i].first() && links[i].first() != links[i].second())
01910         {
01911           oss << "# " << links[i].second->getMarSystem()->getAbsPath() << links[i].second->getName() << endl;
01912           numLinks++;
01913         }
01914       }
01915       o << "# LinksTo = " << numLinks << endl << oss.str();
01916       //linked from:
01917       numLinks = 0;
01918       oss.str(""); //clear the stringstream
01919       for (mrs_natural i=0; i<(mrs_natural)links.size(); ++i)
01920       {
01921         //check who is linking to this control, but avoid outputting root link info
01922         if (ctrlIter_->second() == links[i].second() && links[i].first() != links[i].second())
01923         {
01924           oss << "# " << links[i].first->getMarSystem()->getAbsPath() << links[i].first->getName() << endl;
01925           numLinks++;
01926         }
01927       }
01928       o << "# LinkedFrom = " << numLinks << endl << oss.str();
01929     }
01930   }
01931 
01932   if (isComposite_)
01933   {
01934     child_count_t child_count = marsystems_.size();
01935 
01936     o << endl;
01937     o << "# nComponents = " << child_count << endl;
01938     o << endl;
01939 
01940     for (child_count_t i=0; i < child_count; ++i)
01941       marsystems_[i]->put(o,verbose);
01942   }
01943 
01944   return o;
01945 }
01946 
01947 //
01948 // Output the MarSystem to stdout as a HTML document, with
01949 // collapsible elements provided by a Javascript function
01950 //
01951 ostream&
01952 MarSystem::put_html(ostream &o)
01953 {
01954   //
01955   // Output the HTML header
01956   //
01957   // sness - Add proper DOCTYPE later
01958   o << "<script type=\"text/javascript\" src=\"http://assets.sness.net/simpletreemenu.js\">" << endl;
01959   o << "</script>" << endl;
01960   o << "<link rel=\"stylesheet\" type=\"text/css\" href=\"http://assets.sness.net/simpletree.css\" />" << endl;
01961   o << "<a href=\"javascript:ddtreemenu.flatten(\'treemenu1\', \'expand\')\">Expand All</a>" << endl;
01962   o << "<a href=\"javascript:ddtreemenu.flatten(\'treemenu1\', \'contact\')\">Contact All</a>" << endl;
01963   o << "<ul id=\"treemenu1\" class=\"treeview\">" << endl;
01964 
01965   put_html_worker(o);
01966 
01967   //
01968   // Output the HTML footer
01969   //
01970   o << "<script type=\"text/javascript\">" << endl;
01971   o << "ddtreemenu.createTree(\"treemenu1\", true)" << endl;
01972   o << "</script>" << endl;
01973 
01974   return o;
01975 }
01976 
01977 //
01978 // Output a single MarSystem to &o, without HTML headers and footers
01979 //
01980 ostream&
01981 MarSystem::put_html_worker(ostream &o)
01982 {
01983 
01984   if (isComposite_)
01985   {
01986     o << "<li>MarSystemComposite" << endl;
01987   }
01988   else
01989   {
01990     o << "<li>MarSystem" << endl;
01991   }
01992   o << "Type = " << type_ << endl;
01993   o << "Name = " << name_ << endl;
01994 
01995   o << endl;
01996   o << "<li>MarControls" << controls_.size() << endl;
01997   o << "<ul>" << endl;
01998   for (ControlItr ctrlIter_=controls_.begin(); ctrlIter_ != controls_.end(); ++ctrlIter_)
01999   {
02000     ostringstream toss;
02001     toss << ctrlIter_->second;
02002     if (toss.str() != "")
02003       o << "<li>" << ctrlIter_->first << " = " << ctrlIter_->second << "</li>" << endl;
02004     else
02005       o << "<li>" << ctrlIter_->first << " = " << "MARSYAS_EMPTYSTRING" << "</li>" << endl;
02006 
02007     //serialize links
02008     ostringstream oss;
02009     std::vector<std::pair<MarControlPtr, MarControlPtr> > links = ctrlIter_->second->getLinks();
02010     mrs_natural numLinks = 0;
02011 
02012     //
02013     // Links To:
02014     //
02015     for (mrs_natural i=0; i<(mrs_natural)links.size(); ++i)
02016     {
02017       //check where to this control is linking, but avoid outputting root link info
02018       if (ctrlIter_->second() == links[i].first() && links[i].first() != links[i].second())
02019       {
02020         oss << "<li>" << links[i].second->getMarSystem()->getAbsPath() << links[i].second->getName() << "</li>" << endl;
02021         numLinks++;
02022       }
02023     }
02024     if (numLinks > 0)
02025       o << "<li>LinksTo = " << numLinks << endl << "<ul>" << oss.str() << "</ul></li>";
02026 
02027     //
02028     // Linked From:
02029     //
02030     numLinks = 0;
02031     oss.str(""); //clear the stringstream
02032     for (mrs_natural i=0; i<(mrs_natural)links.size(); ++i)
02033     {
02034       //check who is linking to this control, but avoid outputting root link info
02035       if (ctrlIter_->second() == links[i].second() && links[i].first() != links[i].second())
02036       {
02037         oss << "<li>" << links[i].first->getMarSystem()->getAbsPath() << links[i].first->getName() << "</li>" << endl;
02038         numLinks++;
02039       }
02040     }
02041     if (numLinks > 0)
02042       o << "<li>LinkedFrom = " << numLinks << endl << "<ul>" << oss.str() << "</ul></li>";
02043   }
02044   o << "</ul>" << endl;
02045   o << "</li>" << endl;
02046 
02047   if (isComposite_)
02048   {
02049     child_count_t child_count = marsystems_.size();
02050 
02051     o << endl;
02052     o << "<li>Components = " << child_count << endl;
02053     o << "<ul>" << endl;
02054 
02055     for (child_count_t i=0; i < child_count; ++i)
02056       (marsystems_[i])->put_html_worker(o);
02057 
02058     o << "</ul>" << endl;
02059     o << "</li>" << endl;
02060   }
02061 
02062   o << "</li>" << endl;
02063 
02064 
02065   return o;
02066 }
02067 
02068 istream&
02069 MarSystem::put(istream& is)
02070 {
02071   /* This method assumes that the input stream is in the format
02072    * generated by MarSystem::put(ostream& o).
02073    * This is also known as ".mpl file format".
02074    *
02075    * This method also assumes that it is being called by
02076    * MarSystemManager::getMarSystem(std::istream& is, MarSystem *parent)
02077    * and thus the input has its header data (first 4 lines) stripped off already
02078    */
02079 
02080   mrs_string skipstr;
02081   mrs_natural i;
02082   mrs_string type;
02083   mrs_string rstr = "mrs_real";
02084   mrs_string nstr = "mrs_natural";
02085   mrs_string bstr = "mrs_bool";
02086   mrs_string sstr = "mrs_string";
02087   mrs_string vstr = "mrs_realvec";
02088   mrs_real   rcvalue;
02089   mrs_string scvalue;
02090   mrs_natural ncvalue;
02091   bool bcvalue;
02092   mrs_string cname;
02093   map<mrs_string, MarControlPtr>::iterator iter;
02094 
02095   // if composite, clear all children to avoid bad links to prototype children
02096   if (isComposite_)
02097   {
02098     child_count_t child_count = marsystems_.size();
02099     for (child_count_t i=0; i< child_count; ++i)
02100     {
02101       delete marsystems_[i];
02102     }
02103     marsystems_.clear();
02104   }
02105 
02106   // Start reading!
02107 
02108   /* The first line should look something like:
02109    * # MarControls = 19
02110    * we want to skip everything up to the 19 (or whatever number it is)
02111    */
02112   is >> skipstr >> skipstr >> skipstr;
02113 
02114   mrs_natural nControls;
02115   is >> nControls;
02116 
02117   for (i=0; i < nControls; ++i)
02118   {
02119     /* For each control there are at least three lines:
02120      * # ctrlname = ctrlvalue
02121      * # LinksTo = nLinks
02122      * # LinkedFrom = nLinks
02123      * First, we get the cname and, from it, extract the type:
02124      */
02125     is >> skipstr;
02126     is >> cname;
02127 
02128     mrs_string ctype;
02129     ctype = cname.substr(0, cname.rfind("/", cname.length()));
02130 
02131     iter = controls_.find(cname);
02132 
02133     is >> skipstr;
02134     // Now, based on the type, we extract the value
02135     if (ctype == rstr)
02136     {
02137       is >> rcvalue;
02138       if (iter == controls_.end())
02139         addControl(cname, rcvalue);
02140       else
02141         updControl(cname, rcvalue);
02142     }
02143     else if (ctype == sstr)
02144     {
02145       getline(is, scvalue);  // getline is used to include spaces in strings
02146       scvalue = scvalue.substr(1, scvalue.length()); // strip leading space
02147 
02148       if (scvalue == "MARSYAS_EMPTYSTRING")
02149         scvalue = "";
02150       if (iter == controls_.end())
02151         addControl(cname, scvalue);
02152       else
02153         updControl(cname, scvalue);
02154     }
02155     else if (ctype == nstr)
02156     {
02157       is >> ncvalue;
02158       if (iter == controls_.end())
02159         addControl(cname, ncvalue);
02160       else
02161         updControl(cname, ncvalue);
02162     }
02163     else if (ctype == bstr)
02164     {
02165       is >> bcvalue;
02166       if (iter == controls_.end())
02167         addControl(cname, bcvalue);
02168       else
02169         updControl(cname, bcvalue);
02170     }
02171     else if (ctype == vstr)
02172     {
02173       realvec vcvalue;
02174       is >> vcvalue;
02175       if (iter == controls_.end())
02176         addControl(cname, vcvalue);
02177       else
02178         updControl(cname, vcvalue);
02179     }
02180     else
02181     {
02182       // if the ctype wasn't recognized as a base type
02183       // it's a control type. add a new control pointer
02184       MarControlPtr ctrl = MarControlManager::getManager()->createFromStream(ctype, is);
02185       if (iter == controls_.end())
02186         addControl(cname, ctrl);
02187       else
02188         updControl(cname, ctrl);
02189     }
02190 
02191     /*
02192      * Now we read in the LinksTo and LinksFrom lines
02193      */
02194 
02195     //clean all links for current control (if any)
02196     MarControlPtr curCtrl = getControlLocal(cname);
02197     curCtrl->unlinkFromAll();
02198 
02199     // read links
02200     int nLinks;
02201     mrs_string linkto;
02202     mrs_string linkedfrom;
02203 
02204     // Next line looks like:
02205     //# LinksTo = nlinks
02206     is >> skipstr >> skipstr >> skipstr;
02207     is >> nLinks;
02208 
02209     //relink
02210     if (nLinks > 0)
02211     {
02212       //read link absolute path
02213       is >> skipstr >> linkto;
02214       linkControl(cname, linkto);
02215     }
02216 
02217     // Next line looks like:
02218     //# LinksFrom = nlinks
02219     is >> skipstr >> skipstr >> skipstr;
02220     is >> nLinks;
02221 
02222     //relink
02223     /* If there are any LinksFrom, there will be one line for each.
02224      * those lines look like:
02225      * # /Series/net/Classifier/cl/ZeroRClassifier/zerorcl/mrs_natural/nClasses
02226      * ie. hash sign, followed by a path
02227      */
02228     for (mrs_natural link=0; link < nLinks; ++link)
02229     {
02230       //read link absolute path
02231       is >> skipstr;
02232       is >> linkedfrom;
02233 
02234       //look for control in the entire network
02235       MarControlPtr ctrl = getControl(linkedfrom, true, true);
02236       //if found, just link it to this control.
02237       //if not, this link will be done when the sibling or child MarSystem
02238       //owning the missing control is created
02239       if (!ctrl.isInvalid())
02240       {
02241         //ctrl->getMarSystem()->linkControl(linkedfrom, cname);
02242         ctrl->linkTo(curCtrl);
02243       }
02244     }
02245   }
02246   return is;
02247 }
02248 
02249 bool MarSystem::hasObserver( MarSystemObserver * observer ) const
02250 {
02251   std::vector<MarSystemObserver*>::const_iterator it =
02252       std::find( observers_.begin(), observers_.end(), observer );
02253 
02254   return it != observers_.end();
02255 }
02256 
02257 void MarSystem::addObserver( MarSystemObserver * observer )
02258 {
02259   if (hasObserver(observer))
02260     return;
02261 
02262   observers_.push_back(observer);
02263 }
02264 
02265 void MarSystem::removeObserver( MarSystemObserver * observer )
02266 {
02267   std::vector<MarSystemObserver*>::iterator it =
02268       std::find( observers_.begin(), observers_.end(), observer );
02269 
02270   if (it != observers_.end())
02271     observers_.erase(it);
02272 }
02273 
02274 void MarSystem::attachMarSystem( MarSystem * system )
02275 {
02276   if (find(attached_marsystems_.begin(), attached_marsystems_.end(), system)
02277       != attached_marsystems_.end())
02278     return;
02279 
02280   if (system->getParent())
02281   {
02282     MRSERR("MarSystem: can not attach a MarSystem with parent.");
02283     return;
02284   }
02285 
02286   attached_marsystems_.push_back(system);
02287 }
02288 
02289 void MarSystem::detachMarSystem( MarSystem * system )
02290 {
02291   std::vector<MarSystem*>::iterator iter = std::find(attached_marsystems_.begin(), attached_marsystems_.end(), system);
02292   if (iter != attached_marsystems_.end())
02293     attached_marsystems_.erase(iter);
02294 }
02295 
02296 namespace Marsyas {
02297 
02298 ostream&
02299 operator<< (ostream& o, MarSystem& sys)
02300 {
02301   sys.put(o, true);
02302   return o;
02303 }
02304 
02305 istream&
02306 operator>> (istream& is, MarSystem& sys)
02307 {
02308   sys.put(is);
02309   return is;
02310 }
02311 
02312 ostream&
02313 operator<< (ostream& o, const map<mrs_string,MarControlPtr>& c)
02314 {
02315   //lock map<mrs_string,MarControlPtr>& c for read? [?]
02316   o << "# MarControls = " << c.size() << endl;
02317   map<mrs_string, MarControlPtr>::const_iterator iter;
02318   for (iter=c.begin(); iter != c.end(); ++iter)
02319   {
02320     o << "# " << iter->first << " = " << iter->second << endl;
02321   }
02322   return o;
02323 }
02324 
02325 } // namespace Marsyas
02326 
02327 
02343 mrs_string
02344 Marsyas::obsNamesAddPrefix(mrs_string observationNames, mrs_string prefix)
02345 {
02346   ostringstream oss;
02347   mrs_string::size_type startPos = 0, endPos=0;
02348   while ((endPos = observationNames.find(",", startPos)) != mrs_string::npos)
02349   {
02350     // Extract the observation name.
02351     mrs_string name = observationNames.substr(startPos, endPos-startPos);
02352     oss << prefix << name << ",";
02353     // Update the start position for the next name.
02354     startPos = endPos + 1;
02355   }
02356   return oss.str();
02357 }
02358 
02359 
02377 vector<mrs_string>
02378 Marsyas::stringSplit(mrs_string input, mrs_string delimiter)
02379 {
02380   vector<mrs_string> itemList;
02381   mrs_string::size_type startPos = 0, endPos=0;
02382   // Keep searching for the delimiter.
02383   while ((endPos = input.find(delimiter, startPos)) != mrs_string::npos)
02384   {
02385     // Get the current item.
02386     mrs_string item = input.substr(startPos, endPos - startPos);
02387     // Store it
02388     itemList.push_back(item);
02389     // Update the start position for the next name.
02390     startPos = endPos + delimiter.size();
02391   }
02392   // And the last item
02393   itemList.push_back(input.substr(startPos, input.size() - startPos));
02394   return itemList;
02395 }
02396 
02397 
02413 vector<mrs_string>
02414 Marsyas::obsNamesSplit(mrs_string observationNames)
02415 {
02416   vector<mrs_string> obsNames = stringSplit(observationNames, ",");
02417   obsNames.pop_back();
02418   return obsNames;
02419 }