//-*-c++-*-
/**
 Author: David Auber
 Email : auber@labri.fr
 Last modification : 26/09/2001
 This program is free software; you can redistribute it and/or modify  *
 it under the terms of the GNU General Public License as published by  
 the Free Software Foundation; either version 2 of the License, or     
 (at your option) any later version.
*/

#include "../tulipconf.h"

template <class Tnode, class Tedge>
PropertyProxy<Tnode,Tedge>::PropertyProxy(const PropertyContext *context):
  nodeDefaultValue(Tnode::defaultValue()),
  edgeDefaultValue(Tedge::defaultValue()),
  currentProperty(0),
  superGraph(context->superGraph),
  edgeValueSetup(false),
  nodeValueSetup(false),
  context(*context)
{}
//=============================================================
template <class Tnode, class Tedge>
PropertyProxy<Tnode,Tedge>::~PropertyProxy() {
  if (currentProperty!=0) delete currentProperty;
  nodeProperties.clear();
  edgeProperties.clear();
}
//=============================================================
template <class Tnode, class Tedge>
void PropertyProxy<Tnode,Tedge>::reset() {
  Observable::holdObservers();
  reset_handler();
  nodeValueSetup=false;
  edgeValueSetup=false;
  nodeProperties.clear();
  edgeProperties.clear();
  notifyObservers();
  Observable::unholdObservers();
}
//=============================================================
template <class Tnode, class Tedge>
void PropertyProxy<Tnode,Tedge>::changeCurrentProperty(Property< Tnode ,Tedge > *c, const std::string &s) {
  name = s;
  currentProperty=c;
}
//================================================================
template <class Tnode, class Tedge>
std::string PropertyProxy<Tnode,Tedge>::getName() {
  if (currentProperty!=NULL) return name;
  else return std::string("none");
}
//=============================================================
template <class Tnode, class Tedge>
typename Tnode::RealType PropertyProxy<Tnode,Tedge>::getNodeDefaultValue()
{ return nodeDefaultValue; }
//=============================================================
template <class Tnode, class Tedge>
typename Tedge::RealType PropertyProxy<Tnode,Tedge>::getEdgeDefaultValue()
{ return edgeDefaultValue; }
//=============================================================
template <class Tnode, class Tedge>
typename Tnode::RealType & PropertyProxy<Tnode,Tedge>::getNodeValue(const node n ) {
  typename NodeProperties::iterator it;
  if ((it=nodeProperties.find(n))==nodeProperties.end()) {
    if ((currentProperty!=NULL) && (!nodeValueSetup))
      return nodeProperties[n]=currentProperty->getNodeValue(n);
    else
      return nodeDefaultValue;
  }
  else
    return (*it).second;
}
//=============================================================
template <class Tnode, class Tedge>
typename Tedge::RealType & PropertyProxy<Tnode,Tedge>::getEdgeValue(const edge e) {
  typename EdgeProperties::iterator it;
  if ((it=edgeProperties.find(e))==edgeProperties.end()) {
    if ((currentProperty!=NULL) && (!edgeValueSetup))
      return edgeProperties[e]=currentProperty->getEdgeValue(e);
    else
      return edgeDefaultValue;
  }
  else
    return (*it).second;
}
//=============================================================
template <class Tnode, class Tedge>
void PropertyProxy<Tnode,Tedge>::setNodeValue(const node n,const typename Tnode::RealType v) {
  nodeProperties[n]=v;
  setNodeValue_handler(n);
  notifyObservers();
}
//=============================================================
template <class Tnode, class Tedge>
void PropertyProxy<Tnode,Tedge>::setEdgeValue(const edge e,const typename Tedge::RealType v) {
  edgeProperties[e]=v;
  setEdgeValue_handler(e);
  notifyObservers();
}
//=============================================================
template <class Tnode, class Tedge>
void PropertyProxy<Tnode,Tedge>::setAllNodeValue(const typename Tnode::RealType v) {
  nodeDefaultValue=v;
  nodeProperties.clear();
  nodeValueSetup=true;
  setAllNodeValue_handler();
  notifyObservers();
}
//============================================================
template <class Tnode, class Tedge>
void PropertyProxy<Tnode,Tedge>::setAllEdgeValue(const typename Tedge::RealType v) {
  edgeDefaultValue=v;
  edgeProperties.clear();
  edgeValueSetup=true;
  setAllEdgeValue_handler();
  notifyObservers();
}

//==============================================================
template <class Tnode, class Tedge>
bool PropertyProxy<Tnode,Tedge>::recompute(std::string &erreurMsg) {
#ifndef NDEBUG
  cerr << "PropertyProxy::reCompute" << endl;
#endif

  recompute_handler();
  reset();
  if (this->currentProperty!=NULL) {
    Observable::holdObservers();
    currentProperty->reset();
    if (!currentProperty->check(erreurMsg)) {
      Observable::unholdObservers();
      return false;
    }
    currentProperty->run();
    Observable::unholdObservers();
    return true;
  }
  else  {
    erreurMsg="PropertyProxy::reCompute error Current property is NULL cannot reCompute";
    return false;
  }
}
//==============================================================
template <class Tnode, class Tedge>
void PropertyProxy<Tnode,Tedge>::erase(const node n) {
  typename NodeProperties::iterator it;
  if ((it=nodeProperties.find(n))!=nodeProperties.end())
    nodeProperties.erase(it);
}
//=================================================================================
template <class Tnode, class Tedge>
void PropertyProxy<Tnode,Tedge>::erase(const edge e)
{
  typename EdgeProperties::iterator it;
  if ((it=edgeProperties.find(e))!=edgeProperties.end())
    edgeProperties.erase(it);
}

//=================================================================================
template <class Tnode, class Tedge>
PropertyProxy<Tnode,Tedge>& PropertyProxy<Tnode,Tedge>::operator =(PropertyProxy<Tnode,Tedge> &proxy)
{
  if (this!= &proxy) {
    //=============================================================*
    //The backup is necessary, if a property is a function which use the value of "*this"
    //Future implementation should take into account : Buffered or not recursive or not
    //It will enable to presserve the backup cost in a lot of case.
    //=============================================================*
    STL_EXT_NS::hash_map<node,typename Tnode::RealType> backupNode(superGraph->numberOfNodes());
    STL_EXT_NS::hash_map<edge,typename Tedge::RealType> backupEdge(superGraph->numberOfEdges());
    //--*
    Iterator<node> *itN=superGraph->getNodes();
    for (;itN->hasNext();) {
      node itn=itN->next();
      backupNode[itn]=proxy.getNodeValue(itn);
    }delete itN;
    //--*
    Iterator<edge> *itE=superGraph->getEdges();
    for (;itE->hasNext();) {
      edge ite=itE->next();
      backupEdge[ite]=proxy.getEdgeValue(ite);
    }delete itE;
    //==============================================================*
    reset();
    currentProperty=0;
    superGraph=proxy.superGraph;
    nodeDefaultValue=proxy.nodeDefaultValue;
    edgeDefaultValue=proxy.edgeDefaultValue;
    edgeValueSetup=proxy.edgeValueSetup;
    nodeValueSetup=proxy.nodeValueSetup;
    if (proxy.currentProperty==0) {
      nodeProperties=proxy.nodeProperties;
      edgeProperties=proxy.edgeProperties;
    }
    else {
      Iterator<node> *itN=superGraph->getNodes();
      for (;itN->hasNext();) {
	node itn=itN->next();
	typename Tnode::RealType tmpValNode=backupNode[itn];
	if (tmpValNode!=nodeDefaultValue)
	  nodeProperties[itn]=tmpValNode;
      }delete itN;
      Iterator<edge> *itE=superGraph->getEdges();
      for (;itE->hasNext();) {
	edge ite=itE->next();
	typename Tedge::RealType tmpValEdge=backupEdge[ite];
	if (tmpValEdge!=edgeDefaultValue)
	  edgeProperties[ite]=tmpValEdge;
      }delete itE;
    }
    clone_handler(proxy);
  }
  return *this;
}
//==============================================================
