/*******************************************************************************
 * Copyright (c) 2015-2017 ONERA and IRT AESE (IRT Saint Exupéry).
 * Ce logiciel est la propriété de l’ONERA (the French Aerospace Lab) et de
 * l'IRT AESE (IRT Saint Exupéry).
 * Tous droits réservés.
 *
 * Ce programme et les éléments qui l'accompagnent sont mis à disposition
 * aux conditions définies par le contrat de licence logiciel CeCILL-C soumise
 * au droit français et respectant les principes de diffusion des logiciels libres.
 * Vous pouvez utiliser, modifier et/ou redistribuer ce programme
 * sous les conditions de la licence CeCILL-C (http://www.cecill.info).

 * This software is property of ONERA (the French Aerospace Lab) and of
 * the IRT AESE (IRT Saint Exupéry).
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under
 * the terms of the CeCILL-C license under French law and
 * abiding by the rules of distribution of free software.
 * You can  use, modify and/ or redistribute the software under the terms of
 * the CeCILL-C license (http://www.cecill.info).
 *
 * Contributeurs/contributors:
 *     Guillaume Infantes (ONERA - Centre de Toulouse) - initial API and implementation
 *     Alexandre Albore (IRT Saint-Exupéry) - Altarica/Fiacre translation
 *
 *******************************************************************************/

#include <iostream>
#include <sstream>

#include "Node.hh"
#include "MemberAccess.hh"
#include "Parameter.hh"
#include "Variable.hh"
#include "Event.hh"
#include "Transition.hh"
#include "Assertion.hh"
#include "Synchronisation.hh"
#include "EventLaw.hh"
#include "Assignment.hh"
#include "domains/EnumDomain.hh"

namespace epoch {
  namespace altarica {

    Node::Node() {
      // name_ = NULL;
      ma_ = NULL;
      typeName_  =NULL;
      events_by_prio_ = NULL;
      parent_ = NULL;
    }

    Node * Node::clone() const {
      Node * n = new Node();
      n->setMA(ma_->clone());
      n->setTypeName(typeName_->clone());
      n->setParent(parent_);
      for(std::vector<std::string>::const_iterator it = attributes_.begin();
          it != attributes_.end(); ++it)
        n->addAttribute(*it);
      for(std::vector<Parameter*>::const_iterator it = params_.begin();
          it != params_.end(); ++it)
        n->addParam((*it)->clone());
      for (std::map<std::string, Variable*, ltstr>::const_iterator it = stateVars_.begin();
           it != stateVars_.end(); ++it) {
        Variable * v = it->second->clone();
        n->addVariable(v);
      }
      for (std::map<std::string, Variable*, ltstr>::const_iterator it = flowVars_.begin();
           it != flowVars_.end(); ++it) {
        Variable * v = it->second->clone();
        n->addVariable(v);
      }
      for(std::map<std::string,Event*,ltstr>::const_iterator it = events_.begin();
          it != events_.end(); ++it) {
        n->addEvent(it->second->clone());
      }
      for(std::vector<Transition*>::const_iterator it = trans_.begin();
          it != trans_.end(); ++it) {
        n->addTransition((*it)->clone());
      }
      for(std::vector<Assertion*>::const_iterator it = asserts_.begin();
          it != asserts_.end(); ++it)
        n->addAssertion((*it)->clone());
      for(std::map<std::string, Node*, ltstr>::const_iterator it =   subNodes_.begin();
          it != subNodes_.end(); ++it)
        n->addSubNode(it->second->clone());
      for(std::vector<Synchronisation*>::const_iterator it = syncs_.begin();
          it != syncs_.end(); ++it)
          n->addSync((*it)->clone());
      for(std::vector<Assignment*>::const_iterator it = inits_.begin();
          it != inits_.end(); ++it)
        n->addInit((*it)->clone());
      for(std::vector<Assignment*>::const_iterator it = paramSets_.begin();
          it != paramSets_.end(); ++it)
        n->addParamsSet((*it)->clone());
      for(std::vector<std::string>::const_iterator it = externals_.begin();
          it != externals_.end(); ++it)
        n->addExternal(*it);
      //      n->finalize(am);
      return n;
    }

    void Node::setMA(std::string name, std::vector<int> * idxs) {
      if (ma_ != NULL)
        delete ma_;
      ma_ = new MemberAccess();
      ma_->addIdBack(name,*idxs);
    }

    void Node::setMA(std::string  name) {
      if (ma_ != NULL)
        delete ma_;
      ma_ = new MemberAccess(name);
      //      ma_->addIdBack(name);
    }

    void Node::setMA(MemberAccess* ma) {
      if (ma_ != NULL)
        delete ma_;
      ma_ = ma;
    }


    void Node::setParent(Node *n) {
      parent_ = n;
    }

    const Node * Node::getParent() const{
      return parent_;
    }

    std::vector<const Node*>* Node::getPath() const {
      if(parent_ == NULL)
        return new std::vector<const Node*>();
      auto ret = parent_->getPath();
      ret->push_back(parent_);
      return ret;
    }
    
    std::string Node::getFullName() const {
      if(parent_ == NULL)
        return this->getMA()->toString();
      std::ostringstream oss;
      oss << parent_->getFullName()
          << "."
          << this->getMA()->toString();
      return oss.str();
    }

    void Node::addAttribute(const std::string a) {
      attributes_.push_back(std::string(a));
    }

    void Node::addAttributes(const std::vector<std::string>* va) {
      for (std::vector<std::string>::const_iterator si = va->begin(); si != va->end(); ++si) {
        addAttribute(*si);
      }
    }


    void Node::addParam(Parameter* p) {
      params_.push_back(p);
    }

    void Node::addParams(std::vector<Parameter*>* p) {
      for (std::vector<Parameter*>::iterator pit = p->begin();
           pit != p->end(); ++pit)
        addParam(*pit);
    }


    void Node::addVariable(Variable* v) {
      v->setNode(this);
      EnumDomain * ed = dynamic_cast<EnumDomain*>(v->getDomain());
      if (ed != NULL) {
        const std::vector<std::string> * sed = ed->getSymbols();
        for (std::vector<std::string>::const_iterator i = sed->begin(); i!= sed->end(); ++i)
          symbolCache_.insert(*i);
      }

      std::vector<Variable*> *vars = v->flattenDomain();
      for (std::vector<Variable*>::iterator vi = vars->begin(); vi != vars->end(); ++vi)
        //    vars_.push_back(*vi);
        if (v->isState())
          stateVars_[(*vi)->getMA()->toString()] = *vi;
        else
          flowVars_[(*vi)->getMA()->toString()] = *vi;
      delete(vars);
    }

    void Node::addVariables(std::vector<Variable*>* v) {
      for (std::vector<Variable*>::iterator vit = v->begin();
           vit != v->end(); ++vit)
        addVariable(*vit);
    }


    void Node::addEvent(Event* e) {
      e->setNode(this);
      //      events_.push_back(e);
      events_[e->getMA()->toString()] = e;
    }

    void Node::addEvents(std::vector<Event*>* e) {
      for (std::vector<Event*>::iterator eit = e->begin();
           eit != e->end(); ++eit)
        addEvent(*eit);
    }


    void Node::addTransition(Transition* t) {
      t->setNode(this);
      trans_.push_back(t);
    }

    void Node::addTransitions(std::vector<Transition*>* t) {
      for (std::vector<Transition*>::iterator tit = t->begin();
           tit != t->end(); ++tit)
        addTransition(*tit);
    }


    void Node::addAssertion(Assertion *a) {
      a->setNode(this);
      asserts_.push_back(a);
    }

    void Node::addAssertions(std::vector<Assertion*> *a) {
      for (std::vector<Assertion*>::iterator ait = a->begin();
           ait != a->end(); ++ait)
        addAssertion(*ait);
    }


    void Node::addSubNode(Node* n) {
      n->setParent(this);
      subNodes_[n->getMA()->toString()] = n;
      //subNodes_.push_back(n);
    }

    void Node::addSubNodes(std::vector<Node*>* n) {
      for (std::vector<Node*>::iterator nit = n->begin();
           nit != n->end(); ++nit)
        addSubNode(*nit);
    }


    // void Node::addSubNode(Node* n, std::vector<int> *tab) {
    //     if (tab == NULL)
    //    subNodes_[n] = new std::vector<int>();
    //     else
    //    subNodes_[n] = new std::vector<int>(*tab);
    // }

    // void Node::addSubNodes(std::vector<Node*>* n, std::vector<std::vector<int>*> *tab) {
    //     std::vector<std::vector<int> * >::iterator tabit = tab->begin();
    //     for (std::vector<Node*>::iterator nit = n->begin() ;
    //     nit != n->end(); ++nit, ++tabit)
    //    addSubNode(*nit, *tabit);
    // }


    void Node::addInit(Assignment* i) {
      Variable* var = findStateVariableByName(i->getMA());
      if(var == NULL) {
        std::cerr << "\nInit failed, variable not found : "
                  << i->getMA()->toString()
                  << std::endl;
      } else {
        var->setInit(i);
      i->setNode(this);
      inits_.push_back(i);
      }
    }

    void Node::addInits(std::vector<Assignment*>* i) {
      for (std::vector<Assignment*>::iterator iit = i->begin();
           iit != i->end(); ++iit)
        addInit(*iit);

    }


    void Node::addParamsSet(Assignment* p) {
      paramSets_.push_back(p);
    }

    void Node::addParamsSets(std::vector<Assignment*>* p) {
      for (std::vector<Assignment*>::iterator pit = p->begin();
           pit != p->end(); ++pit)
        addParamsSet(*pit);
    }


    void Node::addExternal(std::string e) {
      externals_.push_back(e);
    }

    void Node::addExternals(std::vector<std::string>* e) {
      for (std::vector<std::string>::iterator eit = e->begin();
           eit != e->end(); ++eit)
        addExternal(*eit);
    }

    void Node::addSync(Synchronisation* s) {
      s->setNode(this);
      syncs_.push_back(s);
    }

    void Node::addSyncs(std::vector<Synchronisation*> *s) {
      for (std::vector<Synchronisation*>::iterator sit = s->begin();
           sit != s->end(); ++sit)
        addSync(*sit);
    }

    void Node::addEventLaw(EventLaw* el) {
      Event * ev = findEventByName(el->getMA());
      el->setNode(this);
      if (ev != NULL)
        ev->setLaw(el);
    }

    void Node::addEventLaws(std::vector<EventLaw*>* e) {
      for (std::vector<EventLaw*>::iterator eli = e->begin();
           eli != e->end(); ++eli)
        addEventLaw(*eli);
    }



    bool Node::hasName(std::string n) {
      MemberAccess * ma = new MemberAccess(n);

      if (ma_->equals(ma)) {
        delete(ma);
        return true;
      } else {
        delete(ma);
        return false;
      }
      return false;
    }


    Event * Node::findEventByName(const MemberAccess * eName) const {
      const MemberAccess * suffix = NULL;
      if (eName->isGlobal()) {
        suffix = eName->buildSuffix(ma_);
        if (suffix == NULL)
          return NULL;
      } else {
        suffix = eName;
      }

      std::map<std::string, Event*, ltstr>::const_iterator i = events_.find(suffix->toString());
      if (i != events_.end())
        return i->second;



      std::string head = suffix->headToString();
      std::map<std::string, Node*, ltstr>::const_iterator j = subNodes_.find(head);
      if (j == subNodes_.end())
        return NULL;
      MemberAccess * ma = suffix->buildSuffix(j->second->getMA());
      Event * e = j->second->findEventByName(ma);
      delete ma;
      return e;
    }


    Variable * Node::findStateVariableByName(const std::string& s) const {
      MemberAccess ma(s);
      Variable * v = findStateVariableByName(&ma);
      return v;
    }

    Variable * Node::findFlowVariableByName(const std::string& s) const {
      MemberAccess ma(s);
      Variable * v = findFlowVariableByName(&ma);
      return v;
    }

    Variable * Node::findVariableByName(const std::string& s) const {
      MemberAccess ma(s);
      Variable * v = findVariableByName(&ma);
      return v;
    }

    bool Node::isSymbol(const MemberAccess *ma) const {
      std::set<std::string>::iterator si = symbolCache_.find(ma->toString());
      if (si != symbolCache_.end())
        return true;
      return false;
    }


    bool Node::isSymbol(std::string s) const {
      std::set<std::string>::iterator si = symbolCache_.find(s);
      if (si != symbolCache_.end())
        return true;
      return false;
    }

    Variable * Node::findStateVariableByName(const MemberAccess * eName) const {


      const MemberAccess * suffix = NULL;
      if (eName->isGlobal()) {
        suffix = eName->buildSuffix(ma_);
        if (suffix == NULL)
          return NULL;
      } else
        suffix = eName;


      std::map<std::string, Variable*, ltstr>::const_iterator i = stateVars_.find(suffix->toString());
      if (i != stateVars_.end())
        return i->second;

      if (stateVarsCache_.size() != 0) {
        i = stateVarsCache_.find(suffix->toString());
        if (i != stateVarsCache_.end())
          return i->second;
        return NULL;
      }



      std::map<std::string, Node*, ltstr>::const_iterator j = subNodes_.find(suffix->headToString());
      if (j == subNodes_.end()) {
        return NULL;
      }
      MemberAccess * ma = suffix->buildSuffix(j->second->getMA());
      Variable * v = j->second->findStateVariableByName(ma);
      delete ma;
      return v;

    }


    Variable * Node::findFlowVariableByName(const MemberAccess * eName) const {

      bool delSuffix = false;

      const MemberAccess * suffix = NULL;
      if (eName->isGlobal()) {
        suffix = eName->buildSuffix(ma_);
        delSuffix = true;
        if (suffix == NULL)
          return NULL;
      } else
        suffix = eName;


      std::map<std::string, Variable*, ltstr>::const_iterator i = flowVars_.find(suffix->toString());
      if (i != flowVars_.end()) {
        if (delSuffix)
          delete suffix;
        return i->second;
      }


      if (flowVarsCache_.size() != 0) {
        i = flowVarsCache_.find(suffix->toString());
        if (i != flowVarsCache_.end()) {
          if (delSuffix)
            delete suffix;
          return i->second;
        }
        return NULL;
      }


      std::map<std::string, Node*, ltstr>::const_iterator j = subNodes_.find(suffix->headToString());
      if (j == subNodes_.end()) {
        if (delSuffix)
          delete suffix;
        return NULL;
      }
      MemberAccess * ma = suffix->buildSuffix(j->second->getMA());
      Variable * v = j->second->findFlowVariableByName(ma);
      if (delSuffix)
        delete suffix;
      delete ma;
      return v;

    }


    Variable * Node::findVariableByName(const MemberAccess * eName) const {
      Variable *v = findFlowVariableByName(eName);
      if (v == NULL)
        return findStateVariableByName(eName);
      return v;
    }


    // const std::vector<Variable*>* Node::getVariables() {
    const std::map<std::string, Variable*, Node::ltstr> *
    Node::getStateVariables() const {
      return &stateVars_;
    }


    const std::map<std::string, Variable*, Node::ltstr> * 
    Node::getFlowVariables() const {
      return &flowVars_;
    }


    //  const std::vector<Event*>* Node::getEvents() {
    const std::map<std::string, Event*, Node::ltstr> *
    Node::getEvents() const {
      return &events_;
    }

    const std::vector<Synchronisation*>* Node::getSyncs() const {
      return &syncs_;
    }
    const std::vector<Assertion*> *Node::getAsserts() const {
      return &asserts_;
    }


    const std::vector<Transition*>* Node::getTransitions() const {
      return &trans_;
    }

    const std::map<std::string,Node*,Node::ltstr>* Node::getSubNodes() const {
      return &subNodes_;
    }

    const MemberAccess * Node::getMA() const {
      return ma_;
    }


    void Node::buildEventsByPrio() {
      if (events_.size() == 0)
        return;
      std::vector<Event*> ev;
      if (events_by_prio_ == NULL)
        events_by_prio_ = new std::vector<std::vector<Event*>* >();
      for (std::map<std::string, Event*,ltstr>::iterator i = events_.begin(); i!=events_.end(); ++i)
        ev.push_back(i->second);
      //      ev.insert(ev.begin(), events_.begin(), events_.end());

      std::vector<Event*> *p0 = new std::vector<Event*>();
      std::vector<Event*>::iterator i = ev.begin();

      while (i!= ev.end()) {
        if ((*i)->getUppers()->size() == 0) {
          p0->push_back(*i);
          i = ev.erase(i);
        } else
          ++i;
      }
      events_by_prio_->push_back(p0);

      while (ev.size() > 0) {
        std::vector<Event*> *pi = new std::vector<Event*>();
        i = ev.begin();
        while (i!=ev.end()) {
          if (notInEv((*i)->getUppers(),&events_)) {
            pi->push_back(*i);
            i = ev.erase(i);
          } else
            ++i;
        }
        events_by_prio_->push_back(pi);
      }


    }

    //  bool Node::notInEv(std::set<Event*>const *up, std::vector<Event*> * ev) {
    bool Node::notInEv(std::set<Event*>const *up, std::map<std::string, Event*, Node::ltstr> * ev) {
      for (std::set<Event*>::iterator upi = up->begin(); upi != up->end(); ++upi) {
        //    for (std::vector<Event*>::iterator evi = ev->begin(); evi != ev->end(); evi++)
        for (std::map<std::string, Event*, Node::ltstr>::iterator evi = ev->begin(); evi != ev->end(); evi++)
          if (*upi == evi->second)
            return false;
      }
      return true;
    }

    void Node::matchEventsInTransitions() {
      for (std::vector<Transition*>::iterator i = trans_.begin(); i!= trans_.end(); ++i) {
        (*i)->matchEvents();
      }
    }


    void Node::matchEventsInSynchros() {
      for (std::vector<Synchronisation*>::iterator i = syncs_.begin(); i!= syncs_.end(); ++i) {
        (*i)->matchEvents();
      }
    }

    // void Node::matchVariablesInInits() {
    // for (std::vector<Variable*>::iterator i = vars_.begin(); i!= vars_.end(); ++i) {
    // std::cerr << "var: " << *((*i)->getMA()->toString()) << std::endl;
    // }
    // for (std::vector<Assignment*>::iterator i = inits_.begin(); i!= inits_.end(); ++i) {
    //    (*i)->matchVariable(true);
    // }
    // }


    // To each variable is added the vector of the asserts that update its value
    void Node::matchVariablesInAsserts(const AltaricaModel* am) {
      for (std::vector<Assertion*>::iterator i = asserts_.begin(); i!= asserts_.end(); ++i) {
        std::vector<Variable*> * fv = (*i)->infoVars(am, true, true);
        for (std::vector<Variable*>::iterator j = fv->begin(); j!= fv->end(); ++j) {
      	  std::cerr << "adding one assertion for node "<< toString() << " var: " << (*j)->getFullName() <<std::endl;
      	  (*j)->addAssert(*i);
        }
        delete fv;
      }
    }

    std::string Node::toString(bool withTypes) const {
      std::string s;
      if (parent_ != NULL)
        s += parent_->toString(withTypes) + ".";
      if (typeName_ != NULL && withTypes)
        s+= "(";
      s+= ma_->toString();
      if (typeName_!=NULL && withTypes)
        s+= ":" + typeName_->toString() + ")";

      return s;
    }

    std::string Node::toFiacre() const {
    	std::string s;
    	if (parent_ != NULL)
    		s += parent_->toFiacre() + "_";
    	s+= ma_->toString();

    	return s;
    }

    std::string Node::printTrans() const {
      std::string s;
      s += "TRANSITIONS:\n";
      for (std::vector<Transition*>::const_iterator i = trans_.begin(); i!= trans_.end(); ++i) {
        s+= (*i)->toString() + "\n";
      }
      return s;
    }


    void Node::finalize(const AltaricaModel *am) {
      buildEventsByPrio();
      matchEventsInTransitions();
      matchEventsInSynchros();
      //      matchVariablesInInits();
      matchVariablesInAsserts(am);

    }

    void Node::compactSimpleAsserts(const AltaricaModel *am) {
      for (std::vector<Assertion*>::iterator i = asserts_.begin(); i!=asserts_.end();++i) {
        std::pair<Variable*,Variable*> * aff = (*i)->isSimpleAffect(am);
        if (aff != NULL)  {
          //     ++i;
          // else {
          // in this case, this assert is aff->first = aff->second
          // both being flow vars
          //   std::cerr << "REMOVING ASSERTION:::: " <<aff->first->toString() << " = " << aff->second->toString()<< std::endl;
          aff->first->removeAssert(*i);
          //        i = asserts_.erase(i);
          // ++i;
          std::vector<Node *> *n = (std::vector<Node *>*)aff->first->getNodes();
          aff->second->mergeVariable(aff->first);
          //        Node * n = (Node*)aff->first->getNode();
          for (std::vector<Node*>::iterator j = n->begin(); j!=n->end(); ++j)
            (*j)->aliasVar(aff->first,aff->second);
          delete n;
          delete(aff->first);
          delete aff;
        }
      }
    }

    void Node::aliasVar(Variable* toRemove, Variable *mergedVar)  {
      //std::vector<Variable*>::iterator i;
      std::map<std::string, Variable*, ltstr>::iterator i;

      for (i = flowVars_.begin();  i!=flowVars_.end() && i->second != toRemove; ++i) ;
      if (i == flowVars_.end())
        BOOST_THROW_EXCEPTION(std::runtime_error(std::string("unable to find var toremove!!!!!!!")));
      //      *i = mergedVar;
      flowVars_[i->first] = mergedVar;
      // std::cerr << "AFTER: node var of node:" << this->toString() << std::endl;
      // for (std::vector<Variable*>::iterator j = vars_.begin();  j!=vars_.end(); ++j) {
      //    std::cerr<< (*j)->toString() << std::endl;
      // }
    }

    void Node::deleteExprs() {
      for (std::vector<Transition*>::iterator i = trans_.begin(); i!= trans_.end(); ++i)
        (*i)->deleteExprs();
      for (std::vector<Assertion*>::iterator i = asserts_.begin(); i!= asserts_.end(); ++i)
        (*i)->deleteExpr();
      for (std::vector<Assignment*>::iterator i = inits_.begin(); i!= inits_.end(); ++i)
        (*i)->deleteExprs();
      for (std::vector<Assignment*>::iterator i = paramSets_.begin(); i!= paramSets_.end(); ++i)
        (*i)->deleteExprs();
      for (std::map<std::string, Event*, ltstr>::iterator i = events_.begin(); i!= events_.end(); ++i)
        (*i).second->deleteExprs();      
    }

    Node::~Node() {
      //      std::cerr << "\ndeleting node " << ma_->toString() << std::endl;
      for (std::map<std::string, Node*, ltstr>::iterator i = subNodes_.begin();
           i!= subNodes_.end(); ++i)
        delete i->second;
      delete  ma_;
      delete typeName_;



      for (std::map<std::string,Variable*,ltstr*>::iterator i = flowVars_.begin(); i!= flowVars_.end(); ++i) {
         if (i->second->removeOwner(this)) {
             delete i->second;
         }
      }


      for (std::map<std::string,Variable*,ltstr>::iterator i = stateVars_.begin(); i!= stateVars_.end(); ++i) {
         delete i->second;
      }



      // for (std::vector<Event*>::iterator i = events_.begin(); i!= events_.end(); ++i)
      //    delete *i;
      for (std::map<std::string,Event*,ltstr>::iterator i = events_.begin(); i!= events_.end(); ++i)
          delete i->second;
      for (std::vector<Transition*>::iterator i = trans_.begin(); i!= trans_.end(); ++i)
        delete *i;
      for (std::vector<Assertion*>::iterator i = asserts_.begin(); i!= asserts_.end(); ++i)
        delete *i;
      for (std::vector<Assignment*>::iterator i = inits_.begin();
           i!= inits_.end(); ++i)
        delete *i;
      for (std::vector<Assignment*>::iterator i = paramSets_.begin();
           i!= paramSets_.end(); ++i)
        delete *i;

      for (std::vector<Synchronisation*>::iterator i = syncs_.begin();
           i!= syncs_.end(); ++i)
        delete *i;

      attributes_.clear();
      externals_.clear();
      for (std::vector<Parameter*>::iterator i = params_.begin();
           i!= params_.end(); ++i)
        delete *i;

      if (events_by_prio_ != NULL)
        for (std::vector<std::vector<Event*>* >::iterator i = events_by_prio_->begin();
             i!= events_by_prio_->end(); ++i)
          delete (*i);

      delete(events_by_prio_);
    }

    void Node::addFlowVarToCache(Variable * v, MemberAccess *subMA, std::string vName) const {
      std::string s = subMA->toString() + "." + vName;
      //      std::cout << "adding var " << s << " to node " << ma_->toString() << std::endl;
      flowVarsCache_[s] = v;
      if (parent_ != NULL) {
        subMA->addMemberAccessFront(ma_);
        parent_->addFlowVarToCache(v,subMA,vName);
      }
    }

    void Node::addStateVarToCache(Variable * v, MemberAccess *subMA, std::string vName) const {
      std::string s = subMA->toString() + "." + vName;
      //      std::cout << "adding var " << s << " to node " << ma_->toString() << std::endl;
      stateVarsCache_[s] = v;
      if (parent_ != NULL) {
        subMA->addMemberAccessFront(ma_);
        parent_->addStateVarToCache(v,subMA,vName);
      }
    }


    void Node::populateVarCache() const {
      for (std::map<std::string, Variable*, ltstr>::const_iterator i = stateVars_.begin(); i!= stateVars_.end(); ++i) {
        if (parent_ != NULL) {
          MemberAccess *ma = ma_->clone();
          parent_->addStateVarToCache(i->second, ma, i->first);
          delete ma;
        }
        const  std::vector<std::pair<const Node*, const MemberAccess*>*> * aliases =
          i->second->getAliases();
        for (std::vector<std::pair<const Node*, const MemberAccess*>*>::const_iterator j = aliases->begin();
             j!= aliases->end(); ++j) {
          MemberAccess * ma = (*j)->first->getMA()->clone();
          const Node * p = (*j)->first->getParent();
          p->addStateVarToCache(i->second,ma,(*j)->second->toString());
        }
      }


      for (std::map<std::string, Variable*, ltstr>::const_iterator i = flowVars_.begin(); i!= flowVars_.end(); ++i) {
        if (parent_ != NULL) {
          MemberAccess *ma = ma_->clone();
          parent_->addFlowVarToCache(i->second, ma, i->first);
          delete ma;
        }
        const  std::vector<std::pair<const Node*, const MemberAccess*>*> * aliases =
          i->second->getAliases();
        for (std::vector<std::pair<const Node*, const MemberAccess*>*>::const_iterator j = aliases->begin();
             j!= aliases->end(); ++j) {
          MemberAccess * ma = (*j)->first->getMA()->clone();
          const Node * p = (*j)->first->getParent();
          if (p!=NULL)
            p->addFlowVarToCache(i->second,ma,(*j)->second->toString());
          delete ma;
        }

      }


    }
  }
}
