text: // g2o - General Graph Optimization
  // Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  // * Redistributions of source code must retain the above copyright notice,
  //   this list of conditions and the following disclaimer.
  // * Redistributions in binary form must reproduce the above copyright
  //   notice, this list of conditions and the following disclaimer in the
  //   documentation and/or other materials provided with the distribution.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  #include "hyper_graph_action.h"
  
  #include <iostream>
  #include <list>
  
  #include "cache.h"
  #include "g2o/stuff/macros.h"
  #include "optimizable_graph.h"
  
  namespace g2o {
  using namespace std;
  
  std::unique_ptr<HyperGraphActionLibrary>
      HyperGraphActionLibrary::actionLibInstance;
  
  HyperGraphAction::Parameters::~Parameters() {}
  
  HyperGraphAction::ParametersIteration::ParametersIteration(int iter)
      : HyperGraphAction::Parameters(), iteration(iter) {}
  
  HyperGraphAction::~HyperGraphAction() {}
  
  HyperGraphAction* HyperGraphAction::operator()(const HyperGraph*, Parameters*) {
    return nullptr;
  }
  
  HyperGraphElementAction::Parameters::~Parameters() {}
  
  HyperGraphElementAction::HyperGraphElementAction(const std::string& typeName_)
      : _typeName(typeName_) {}
  
  void HyperGraphElementAction::setTypeName(const std::string& typeName_) {
    _typeName = typeName_;
  }
  
  HyperGraphElementAction* HyperGraphElementAction::operator()(
      HyperGraph::HyperGraphElement*, HyperGraphElementAction::Parameters*) {
    return nullptr;
  }
  
  HyperGraphElementAction* HyperGraphElementAction::operator()(
      const HyperGraph::HyperGraphElement*,
      HyperGraphElementAction::Parameters*) {
    return nullptr;
  }
  
  HyperGraphElementAction::~HyperGraphElementAction() {}
  
  HyperGraphElementActionCollection::HyperGraphElementActionCollection(
      const std::string& name_) {
    _name = name_;
  }
  
  HyperGraphElementAction* HyperGraphElementActionCollection::operator()(
      HyperGraph::HyperGraphElement* element,
      HyperGraphElementAction::Parameters* params) {
    ActionMap::iterator it = _actionMap.find(typeid(*element).name());
    // cerr << typeid(*element).name() << endl;
    if (it == _actionMap.end()) return nullptr;
    HyperGraphElementAction* action = it->second.get();
    return (*action)(element, params);
  }
  
  HyperGraphElementAction* HyperGraphElementActionCollection::operator()(
      const HyperGraph::HyperGraphElement* element,
      HyperGraphElementAction::Parameters* params) {
    ActionMap::iterator it = _actionMap.find(typeid(*element).name());
    if (it == _actionMap.end()) return nullptr;
    HyperGraphElementAction* action = it->second.get();
    return (*action)(element, params);
  }
  
  bool HyperGraphElementActionCollection::registerAction(
      const HyperGraphElementAction::HyperGraphElementActionPtr& action) {
  #ifdef G2O_DEBUG_ACTIONLIB
    cerr << __PRETTY_FUNCTION__ << " " << action->name() << " "
         << action->typeName() << endl;
  #endif
    if (action->name() != name()) {
      cerr << __PRETTY_FUNCTION__
           << ": invalid attempt to register an action in a collection with a "
              "different name "
           << name() << " " << action->name() << endl;
    }
    _actionMap.insert(make_pair(action->typeName(), action));
    return true;
  }
  
  bool HyperGraphElementActionCollection::unregisterAction(
      const HyperGraphElementAction::HyperGraphElementActionPtr& action) {
    for (HyperGraphElementAction::ActionMap::iterator it = _actionMap.begin();
         it != _actionMap.end(); ++it) {
      if (it->second == action) {
        _actionMap.erase(it);
        return true;
      }
    }
    return false;
  }
  
  HyperGraphActionLibrary* HyperGraphActionLibrary::instance() {
    if (actionLibInstance == 0) {
      actionLibInstance =
          std::unique_ptr<HyperGraphActionLibrary>(new HyperGraphActionLibrary);
    }
    return actionLibInstance.get();
  }
  
  void HyperGraphActionLibrary::destroy() {
    std::unique_ptr<HyperGraphActionLibrary> aux;
    actionLibInstance.swap(aux);
  }
  
  HyperGraphElementAction* HyperGraphActionLibrary::actionByName(
      const std::string& name) {
    HyperGraphElementAction::ActionMap::iterator it = _actionMap.find(name);
    if (it != _actionMap.end()) return it->second.get();
    return nullptr;
  }
  
  bool HyperGraphActionLibrary::registerAction(
      const HyperGraphElementAction::HyperGraphElementActionPtr& action) {
    HyperGraphElementAction* oldAction = actionByName(action->name());
    HyperGraphElementActionCollection* collection = nullptr;
    if (oldAction) {
      collection = dynamic_cast<HyperGraphElementActionCollection*>(oldAction);
      if (!collection) {
        cerr << __PRETTY_FUNCTION__
             << ": fatal error, a collection is not at the first level in the "
                "library"
             << endl;
        return false;
      }
    }
    if (collection) {
      return collection->registerAction(action);
    }
  #ifdef G2O_DEBUG_ACTIONLIB
    cerr << __PRETTY_FUNCTION__ << ": creating collection for \""
         << action->name() << "\"" << endl;
  #endif
    collection = new HyperGraphElementActionCollection(action->name());
    _actionMap.insert(make_pair(
        action->name(),
        HyperGraphElementAction::HyperGraphElementActionPtr(collection)));
    return collection->registerAction(action);
  }
  
  bool HyperGraphActionLibrary::unregisterAction(
      const HyperGraphElementAction::HyperGraphElementActionPtr& action) {
    list<HyperGraphElementActionCollection*> collectionDeleteList;
  
    // Search all the collections and delete the registered actions; if a
    // collection becomes empty, schedule it for deletion; note that we can't
    // delete the collections as we go because this will screw up the state of the
    // iterators
    for (HyperGraphElementAction::ActionMap::iterator it = _actionMap.begin();
         it != _actionMap.end(); ++it) {
      HyperGraphElementActionCollection* collection =
          dynamic_cast<HyperGraphElementActionCollection*>(it->second.get());
      if (collection != nullptr) {
        collection->unregisterAction(action);
        if (collection->actionMap().size() == 0) {
          collectionDeleteList.push_back(collection);
        }
      }
    }
  
    // Delete any empty action collections
    for (list<HyperGraphElementActionCollection*>::iterator itc =
             collectionDeleteList.begin();
         itc != collectionDeleteList.end(); ++itc) {
      // cout << "Deleting collection " << (*itc)->name() << endl;
      _actionMap.erase((*itc)->name());
    }
  
    return true;
  }
  
  WriteGnuplotAction::WriteGnuplotAction(const std::string& typeName_)
      : HyperGraphElementAction(typeName_) {
    _name = "writeGnuplot";
  }
  
  DrawAction::Parameters::Parameters() {}
  
  DrawAction::DrawAction(const std::string& typeName_)
      : HyperGraphElementAction(typeName_) {
    _name = "draw";
    _previousParams = (Parameters*)0x42;
    refreshPropertyPtrs(0);
    _cacheDrawActions = 0;
  }
  
  bool DrawAction::refreshPropertyPtrs(
      HyperGraphElementAction::Parameters* params_) {
    if (_previousParams == params_) return false;
    DrawAction::Parameters* p = dynamic_cast<DrawAction::Parameters*>(params_);
    if (!p) {
      _previousParams = 0;
      _show = 0;
      _showId = 0;
    } else {
      _previousParams = p;
      _show = p->makeProperty<BoolProperty>(_typeName + "::SHOW", true);
      _showId = p->makeProperty<BoolProperty>(_typeName + "::SHOW_ID", false);
    }
    return true;
  }
  
  void DrawAction::initializeDrawActionsCache() {
    if (!_cacheDrawActions) {
      _cacheDrawActions =
          HyperGraphActionLibrary::instance()->actionByName("draw");
    }
  }
  
  void DrawAction::drawCache(CacheContainer* caches,
                             HyperGraphElementAction::Parameters* params_) {
    if (caches) {
      for (CacheContainer::iterator it = caches->begin(); it != caches->end();
           ++it) {
        Cache* c = it->second;
        (*_cacheDrawActions)(c, params_);
      }
    }
  }
  
  void DrawAction::drawUserData(HyperGraph::Data* data,
                                HyperGraphElementAction::Parameters* params_) {
    while (data && _cacheDrawActions) {
      (*_cacheDrawActions)(data, params_);
      data = data->next();
    }
  }
  
  void applyAction(HyperGraph* graph, HyperGraphElementAction* action,
                   HyperGraphElementAction::Parameters* params,
                   const std::string& typeName) {
    for (HyperGraph::VertexIDMap::iterator it = graph->vertices().begin();
         it != graph->vertices().end(); ++it) {
      auto& aux = *it->second;
      if (typeName.empty() || typeid(aux).name() == typeName) {
        (*action)(it->second, params);
      }
    }
    for (HyperGraph::EdgeSet::iterator it = graph->edges().begin();
         it != graph->edges().end(); ++it) {
      auto& aux = **it;
      if (typeName.empty() || typeid(aux).name() == typeName)
        (*action)(*it, params);
    }
  }
  
  }  // namespace g2o
  