// -*-mode: c++; -*-
#ifndef GRAPH_WRAPPER_H
#define GRAPH_WRAPPER_H

namespace hugo {

  template<typename Graph>
  class TrivGraphWrapper {
    Graph* graph;
  
  public:
    typedef Graph BaseGraph;

    typedef typename Graph::NodeIt NodeIt;
    typedef typename Graph::EdgeIt EdgeIt;
  
    typedef typename Graph::EachNodeIt EachNodeIt;

    typedef typename Graph::OutEdgeIt OutEdgeIt;
    typedef typename Graph::InEdgeIt InEdgeIt;
    typedef typename Graph::SymEdgeIt SymEdgeIt;
    typedef typename Graph::EachEdgeIt EachEdgeIt;

    int nodeNum() const { return graph->nodeNum(); }
    int edgeNum() const { return graph->edgeNum(); }
    
    template<typename I> I& getFirst(I& i) const { return graph->getFirst(i); }
    template<typename I, typename P> I& getFirst(I& i, const P& p) const { 
      return graph->getFirst(i, p); }
    //template<typename I> I next(const I i); { return graph->goNext(i); }
    //template<typename I> I &goNext(I &i); { return graph->goNext(i); }

    template< typename It > It first() const { 
      It e; getFirst(e); return e; }

    template< typename It > It first(NodeIt v) const { 
      It e; getFirst(e, v); return e; }

    NodeIt head(const EdgeIt& e) const { return graph->head(e); }
    NodeIt tail(const EdgeIt& e) const { return graph->tail(e); }
  
    template<typename I> NodeIt aNode(const I& e) const { 
      return graph->aNode(e); }
    template<typename I> NodeIt bNode(const I& e) const { 
      return graph->bNode(e); }
  
    //template<typename I> bool valid(const I& i) 
    //{ return graph->valid(i); }
  
    //template<typename I> void setInvalid(const I &i);
    //{ return graph->setInvalid(i); }
  
    NodeIt addNode() const { return graph->addNode(); }
    EdgeIt addEdge(const NodeIt& tail, const NodeIt& head) const { 
      return graph->addEdge(tail, head); }
  
    template<typename I> void erase(const I& i) const { graph->erase(i); }
  
    void clear() const { graph->clear(); }
  
    template<typename T> class NodeMap : public Graph::NodeMap<T> { 
    public:
      NodeMap(const Graph& _G) : Graph::NodeMap<T>(_G) { }
      NodeMap(const Graph& _G, T a) : Graph::NodeMap<T>(_G, a) { }
    };
    template<typename T> class EdgeMap : public Graph::EdgeMap<T> { };
  
    void setGraph(Graph& _graph) { graph = &_graph; }
    Graph& getGraph() { return (*graph); }
  
    //TrivGraphWrapper() : graph(0) { }
    TrivGraphWrapper(Graph& _graph) : graph(&_graph) { }
  };

  template<typename Graph>
  class ConstTrivGraphWrapper {
    const Graph* graph;
  
  public:
    typedef Graph BaseGraph;

    typedef typename Graph::NodeIt NodeIt;
    typedef typename Graph::EdgeIt EdgeIt;
  
    typedef typename Graph::EachNodeIt EachNodeIt;

    typedef typename Graph::OutEdgeIt OutEdgeIt;
    typedef typename Graph::InEdgeIt InEdgeIt;
    typedef typename Graph::SymEdgeIt SymEdgeIt;
    typedef typename Graph::EachEdgeIt EachEdgeIt;

    int nodeNum() const { return graph->nodeNum(); }
    int edgeNum() const { return graph->edgeNum(); }
    
    template<typename I> I& getFirst(I& i) const { return graph->getFirst(i); }
    template<typename I, typename P> I& getFirst(I& i, const P& p) const { 
      return graph->getFirst(i, p); }
    //template<typename I> I next(const I i); { return graph->goNext(i); }
    //template<typename I> I &goNext(I &i); { return graph->goNext(i); }

    template< typename It > It first() const { 
      It e; getFirst(e); return e; }

    template< typename It > It first(NodeIt v) const { 
      It e; getFirst(e, v); return e; }

    NodeIt head(const EdgeIt& e) const { return graph->head(e); }
    NodeIt tail(const EdgeIt& e) const { return graph->tail(e); }
  
    template<typename I> NodeIt aNode(const I& e) const { 
      return graph->aNode(e); }
    template<typename I> NodeIt bNode(const I& e) const { 
      return graph->bNode(e); }
  
    //template<typename I> bool valid(const I& i) 
    //{ return graph->valid(i); }
  
    //template<typename I> void setInvalid(const I &i);
    //{ return graph->setInvalid(i); }
  
    NodeIt addNode() const { return graph->addNode(); }
    EdgeIt addEdge(const NodeIt& tail, const NodeIt& head) const { 
      return graph->addEdge(tail, head); }
  
    template<typename I> void erase(const I& i) const { graph->erase(i); }
  
    void clear() const { graph->clear(); }
  
    template<typename T> class NodeMap : public Graph::NodeMap<T> { 
    public:
      NodeMap(const Graph& _G) : Graph::NodeMap<T>(_G) { }
      NodeMap(const Graph& _G, T a) : Graph::NodeMap<T>(_G, a) { }
    };
    template<typename T> class EdgeMap : public Graph::EdgeMap<T> { };
  
    void setGraph(const Graph& _graph) { graph = &_graph; }
    const Graph& getGraph() { return (*graph); }
  
    //ConstTrivGraphWrapper() : graph(0) { }
    ConstTrivGraphWrapper(const Graph& _graph) : graph(&_graph) { }
  };


  template<typename Graph>
  class RevGraphWrapper
  {
    Graph* graph;
  
  public:
    typedef Graph BaseGraph;

    typedef typename Graph::NodeIt NodeIt;
    typedef typename Graph::EdgeIt EdgeIt;
  
    typedef typename Graph::EachNodeIt EachNodeIt;
  
    typedef typename Graph::OutEdgeIt InEdgeIt;
    typedef typename Graph::InEdgeIt OutEdgeIt;
    typedef typename Graph::SymEdgeIt SymEdgeIt;
    typedef typename Graph::EachEdgeIt EachEdgeIt;

    int nodeNum() const { return graph->nodeNum(); }
    int edgeNum() const { return graph->edgeNum(); }
    
    template<typename I> I& getFirst(I& i) const { return graph->getFirst(i); }
    template<typename I, typename P> I& getFirst(I& i, const P& p) const { 
      return graph->getFirst(i, p); }
    //template<typename I> I next(const I i); { return graph->goNext(i); }
    //template<typename I> I &goNext(I &i); { return graph->goNext(i); }

    template< typename It > It first() const { 
      It e; getFirst(e); return e; }

    template< typename It > It first(NodeIt v) const { 
      It e; getFirst(e, v); return e; }

    NodeIt head(const EdgeIt& e) const { return graph->tail(e); }
    NodeIt tail(const EdgeIt& e) const { return graph->head(e); }
  
    template<typename I> NodeIt aNode(const I& e) const { 
      return graph->aNode(e); }
    template<typename I> NodeIt bNode(const I& e) const { 
      return graph->bNode(e); }
  
    //template<typename I> bool valid(const I i);
    //{ return graph->valid(i); }
  
    //template<typename I> void setInvalid(const I &i);
    //{ return graph->setInvalid(i); }
  
    NodeIt addNode() { return graph->addNode(); }
    EdgeIt addEdge(const NodeIt& tail, const NodeIt& head) { 
      return graph->addEdge(tail, head); }
  
    template<typename I> void erase(const I& i) { graph->erase(i); }
  
    void clear() { graph->clear(); }
  
    template<typename T> class NodeMap : public Graph::NodeMap<T> { };
    template<typename T> class EdgeMap : public Graph::EdgeMap<T> { };
  
    void setGraph(Graph& _graph) { graph = &_graph; }
    Graph& getGraph() { return (*graph); }

    //RevGraphWrapper() : graph(0) { }
    RevGraphWrapper(Graph& _graph) : graph(&_graph) { }
  };

  template<typename Graph>
  class SymGraphWrapper
  {
    Graph* graph;
  
  public:
    typedef Graph BaseGraph;

    typedef typename Graph::NodeIt NodeIt;
    typedef typename Graph::EdgeIt EdgeIt;
  
    typedef typename Graph::EachNodeIt EachNodeIt;
    
    //FIXME tag-ekkel megcsinalni, hogy abbol csinaljon
    //iranyitatlant, ami van
    //mert csak 1 dolgot lehet be typedef-elni
    typedef typename Graph::OutEdgeIt SymEdgeIt;
    //typedef typename Graph::InEdgeIt SymEdgeIt;
    //typedef typename Graph::SymEdgeIt SymEdgeIt;
    typedef typename Graph::EachEdgeIt EachEdgeIt;

    int nodeNum() const { return graph->nodeNum(); }
    int edgeNum() const { return graph->edgeNum(); }
    
    template<typename I> I& getFirst(I& i) const { return graph->getFirst(i); }
    template<typename I, typename P> I& getFirst(I& i, const P& p) const { 
      return graph->getFirst(i, p); }
    //template<typename I> I next(const I i); { return graph->goNext(i); }
    //template<typename I> I &goNext(I &i); { return graph->goNext(i); }

    template< typename It > It first() const { 
      It e; getFirst(e); return e; }

    template< typename It > It first(NodeIt v) const { 
      It e; getFirst(e, v); return e; }

    NodeIt head(const EdgeIt& e) const { return graph->head(e); }
    NodeIt tail(const EdgeIt& e) const { return graph->tail(e); }
  
    template<typename I> NodeIt aNode(const I& e) const { 
      return graph->aNode(e); }
    template<typename I> NodeIt bNode(const I& e) const { 
      return graph->bNode(e); }
  
    //template<typename I> bool valid(const I i);
    //{ return graph->valid(i); }
  
    //template<typename I> void setInvalid(const I &i);
    //{ return graph->setInvalid(i); }
  
    NodeIt addNode() { return graph->addNode(); }
    EdgeIt addEdge(const NodeIt& tail, const NodeIt& head) { 
      return graph->addEdge(tail, head); }
  
    template<typename I> void erase(const I& i) { graph->erase(i); }
  
    void clear() { graph->clear(); }
  
    template<typename T> class NodeMap : public Graph::NodeMap<T> { };
    template<typename T> class EdgeMap : public Graph::EdgeMap<T> { };
  
    void setGraph(Graph& _graph) { graph = &_graph; }
    Graph& getGraph() { return (*graph); }

    //SymGraphWrapper() : graph(0) { }
    SymGraphWrapper(Graph& _graph) : graph(&_graph) { }
  };


// FIXME: comparison should be made better!!!
  template<typename Graph, typename T, typename LowerMap, typename FlowMap, typename UpperMap>
  class ResGraphWrapper
  {
    Graph* graph;
  
  public:
    typedef Graph BaseGraph;

    typedef typename Graph::NodeIt NodeIt;
    typedef typename Graph::EdgeIt EdgeIt;
  
    typedef typename Graph::EachNodeIt EachNodeIt;
   
    class OutEdgeIt {
    public:
      //Graph::NodeIt n;
      bool out_or_in;
      typename Graph::OutEdgeIt o;
      typename Graph::InEdgeIt i;   
    };
    class InEdgeIt {
    public:
      //Graph::NodeIt n;
      bool out_or_in;
      typename Graph::OutEdgeIt o;
      typename Graph::InEdgeIt i;   
    };
    typedef typename Graph::SymEdgeIt SymEdgeIt;
    typedef typename Graph::EachEdgeIt EachEdgeIt;

    int nodeNum() const { return graph->nodeNum(); }
    int edgeNum() const { return graph->edgeNum(); }

    NodeIt& getFirst(NodeIt& n) const { return graph->getFirst(n); }

    // EachEdge and SymEdge  is missing!!!!
    // EdgeIt <-> In/OutEdgeIt conversion is missing!!!!

    //FIXME
    OutEdgeIt& getFirst(OutEdgeIt& e, const NodeIt& n) const 
      {
	e.n=n;
	graph->getFirst(e.o,n);
	while(graph->valid(e.o) && fmap.get(e.o)>=himap.get(e.o))
	  graph->goNext(e.o);
	if(!graph->valid(e.o)) {
	  graph->getFirst(e.i,n);
	  while(graph->valid(e.i) && fmap.get(e.i)<=lomap.get(e.i))
	    graph->goNext(e.i);
	}
	return e;
      }
/*
  OutEdgeIt &goNext(OutEdgeIt &e)
  {
  if(graph->valid(e.o)) {
  while(graph->valid(e.o) && fmap.get(e.o)>=himap.get(e.o))
  graph->goNext(e.o);
  if(graph->valid(e.o)) return e;
  else graph->getFirst(e.i,e.n);
  }
  else {
  while(graph->valid(e.i) && fmap.get(e.i)<=lomap.get(e.i))
  graph->goNext(e.i);
  return e;
  }
  }
  OutEdgeIt Next(const OutEdgeIt &e) {OutEdgeIt t(e); return goNext(t);}
*/
    //bool valid(const OutEdgeIt e) { return graph->valid(e.o)||graph->valid(e.i);}

    //FIXME
    InEdgeIt& getFirst(InEdgeIt& e, const NodeIt& n) const 
      {
	e.n=n;
	graph->getFirst(e.i,n);
	while(graph->valid(e.i) && fmap.get(e.i)>=himap.get(e.i))
	  graph->goNext(e.i);
	if(!graph->valid(e.i)) {
	  graph->getFirst(e.o,n);
	  while(graph->valid(e.o) && fmap.get(e.o)<=lomap.get(e.o))
	    graph->goNext(e.o);
	}
	return e;
      }
/*
  InEdgeIt &goNext(InEdgeIt &e)
  {
  if(graph->valid(e.i)) {
  while(graph->valid(e.i) && fmap.get(e.i)>=himap.get(e.i))
  graph->goNext(e.i);
  if(graph->valid(e.i)) return e;
  else graph->getFirst(e.o,e.n);
  }
  else {
  while(graph->valid(e.o) && fmap.get(e.o)<=lomap.get(e.o))
  graph->goNext(e.o);
  return e;
  }
  }
  InEdgeIt Next(const InEdgeIt &e) {InEdgeIt t(e); return goNext(t);}
*/
    //bool valid(const InEdgeIt e) { return graph->valid(e.i)||graph->valid(e.o);}

    //template<typename I> I &goNext(I &i); { return graph->goNext(i); }
    //template<typename I> I next(const I i); { return graph->goNext(i); }

    template< typename It > It first() const { 
      It e; getFirst(e); return e; }

    template< typename It > It first(NodeIt v) const { 
      It e; getFirst(e, v); return e; }

    NodeIt head(const EdgeIt& e) const { return graph->head(e); }
    NodeIt tail(const EdgeIt& e) const { return graph->tail(e); }
  
    template<typename I> NodeIt aNode(const I& e) const { 
      return graph->aNode(e); }
    template<typename I> NodeIt bNode(const I& e) const { 
      return graph->bNode(e); }
  
    //template<typename I> bool valid(const I i);
    //{ return graph->valid(i); }
  
    //template<typename I> void setInvalid(const I &i);
    //{ return graph->setInvalid(i); }
  
    NodeIt addNode() { return graph->addNode(); }
    EdgeIt addEdge(const NodeIt& tail, const NodeIt& head) { 
      return graph->addEdge(tail, head); }
  
    template<typename I> void erase(const I& i) { graph->erase(i); }
  
    void clear() { graph->clear(); }
  
    template<typename S> class NodeMap : public Graph::NodeMap<S> { };
    template<typename S> class EdgeMap : public Graph::EdgeMap<S> { };
  
    void setGraph(Graph& _graph) { graph = &_graph; }
    Graph& getGraph() { return (*graph); }

    //ResGraphWrapper() : graph(0) { }
    ResGraphWrapper(Graph& _graph) : graph(&_graph) { }
  };


// FIXME: comparison should be made better!!!
  template<typename Graph, typename T, typename LowerMap, typename FlowMap, typename UpperMap>
  class ConstResGraphWrapper
  {
    const Graph* graph;
    const LowerMap* low;
    FlowMap* flow;
    const UpperMap* up;
  public:
    typedef Graph BaseGraph;

    typedef typename Graph::NodeIt NodeIt;
    typedef typename Graph::EdgeIt EdgeIt;
  
    typedef typename Graph::EachNodeIt EachNodeIt;
   
    class OutEdgeIt {
    public:
      //Graph::NodeIt n;
      bool out_or_in;
      typename Graph::SymEdgeIt sym;
    };
    class InEdgeIt {
    public:
      //Graph::NodeIt n;
      bool out_or_in;
      typename Graph::OutEdgeIt sym;
    };
    //typedef typename Graph::SymEdgeIt SymEdgeIt;
    //typedef typename Graph::EachEdgeIt EachEdgeIt;

    int nodeNum() const { return graph->nodeNum(); }
    //int edgeNum() const { return graph->edgeNum(); }

    NodeIt& getFirst(NodeIt& n) const { return graph->getFirst(n); }

    // EachEdge and SymEdge  is missing!!!!
    // EdgeIt <-> In/OutEdgeIt conversion is missing!!!!

    
    //FIXME
    OutEdgeIt& getFirst(OutEdgeIt& e, const NodeIt& n) const 
      {
	e.n=n;
	graph->getFirst(e.o,n);
	while(graph->valid(e.o) && fmap.get(e.o)>=himap.get(e.o))
	  graph->goNext(e.o);
	if(!graph->valid(e.o)) {
	  graph->getFirst(e.i,n);
	  while(graph->valid(e.i) && fmap.get(e.i)<=lomap.get(e.i))
	    graph->goNext(e.i);
	}
	return e;
      }
/*
  OutEdgeIt &goNext(OutEdgeIt &e)
  {
  if(graph->valid(e.o)) {
  while(graph->valid(e.o) && fmap.get(e.o)>=himap.get(e.o))
  graph->goNext(e.o);
  if(graph->valid(e.o)) return e;
  else graph->getFirst(e.i,e.n);
  }
  else {
  while(graph->valid(e.i) && fmap.get(e.i)<=lomap.get(e.i))
  graph->goNext(e.i);
  return e;
  }
  }
  OutEdgeIt Next(const OutEdgeIt &e) {OutEdgeIt t(e); return goNext(t);}
*/
    //bool valid(const OutEdgeIt e) { return graph->valid(e.o)||graph->valid(e.i);}

    //FIXME
    InEdgeIt& getFirst(InEdgeIt& e, const NodeIt& n) const 
      {
	e.n=n;
	graph->getFirst(e.i,n);
	while(graph->valid(e.i) && fmap.get(e.i)>=himap.get(e.i))
	  graph->goNext(e.i);
	if(!graph->valid(e.i)) {
	  graph->getFirst(e.o,n);
	  while(graph->valid(e.o) && fmap.get(e.o)<=lomap.get(e.o))
	    graph->goNext(e.o);
	}
	return e;
      }
/*
  InEdgeIt &goNext(InEdgeIt &e)
  {
  if(graph->valid(e.i)) {
  while(graph->valid(e.i) && fmap.get(e.i)>=himap.get(e.i))
  graph->goNext(e.i);
  if(graph->valid(e.i)) return e;
  else graph->getFirst(e.o,e.n);
  }
  else {
  while(graph->valid(e.o) && fmap.get(e.o)<=lomap.get(e.o))
  graph->goNext(e.o);
  return e;
  }
  }
  InEdgeIt Next(const InEdgeIt &e) {InEdgeIt t(e); return goNext(t);}
*/
    //bool valid(const InEdgeIt e) { return graph->valid(e.i)||graph->valid(e.o);}

    //template<typename I> I &goNext(I &i); { return graph->goNext(i); }
    //template<typename I> I next(const I i); { return graph->goNext(i); }

    template< typename It > It first() const { 
      It e; getFirst(e); return e; }

    template< typename It > It first(NodeIt v) const { 
      It e; getFirst(e, v); return e; }

    NodeIt head(const EdgeIt& e) const { return graph->head(e); }
    NodeIt tail(const EdgeIt& e) const { return graph->tail(e); }
  
    template<typename I> NodeIt aNode(const I& e) const { 
      return graph->aNode(e); }
    template<typename I> NodeIt bNode(const I& e) const { 
      return graph->bNode(e); }
  
    //template<typename I> bool valid(const I i);
    //{ return graph->valid(i); }
  
    //template<typename I> void setInvalid(const I &i);
    //{ return graph->setInvalid(i); }
  
    NodeIt addNode() { return graph->addNode(); }
    EdgeIt addEdge(const NodeIt& tail, const NodeIt& head) { 
      return graph->addEdge(tail, head); }
  
    template<typename I> void erase(const I& i) { graph->erase(i); }
  
    void clear() { graph->clear(); }
  
    template<typename S> class NodeMap : public Graph::NodeMap<S> { };
    template<typename S> class EdgeMap : public Graph::EdgeMap<S> { };
  
    void setGraph(const Graph& _graph) { graph = &_graph; }
    const Graph& getGraph() { return (*graph); }

    //ConstResGraphWrapper() : graph(0) { }
    ConstResGraphWrapper(const Graph& _graph) : graph(&_graph) { }
  };





} //namespace hugo

#endif //GRAPH_WRAPPER_H


//   NodeIt &getFirst(NodeIt &n) { return graph->getFirst(n); }
//   InEdgeIt &getFirst(InEdgeIt &e,const NodeIt &n);
//   { return graph->getFirst(e,n); }
//   OutEdgeIt &getFirst(OutEdgeIt &e,const NodeIt &n);
//   { return graph->getFirst(e,n); }
//   SymEdgeIt &getFirst(SymEdgeIt &e,const NodeIt &n);
//   { return graph->getFirst(e,n); }
//   EachEdgeIt &getFirst(EachEdgeIt &e);
//   { return graph->getFirst(e); }
   
//   NodeIt next(const NodeIt &n);
//   { return graph->next(n); }
//   InEdgeIt next(const InEdgeIt &e);
//   { return graph->next(e); }
//   OutEdgeIt next(const OutEdgeIt &e);
//   { return graph->next(e); }
//   SymEdgeIt next(const SymEdgeIt &e);
//   { return graph->next(e); }
//   EachEdgeIt next(const EachEdgeIt &e);
//   { return graph->next(e); }
 
//   NodeIt &goNext(NodeIt &n);
//   { return graph->goNext(n); }
//   InEdgeIt &goNext(InEdgeIt &e);
//   { return graph->goNext(e); }
//   OutEdgeIt &goNext(OutEdgeIt &e);
//   { return graph->goNext(e); }
//   SymEdgeIt &goNext(SymEdgeIt &e);
//   { return graph->goNext(e); }
//   EachEdgeIt &goNext(EachEdgeIt &e);
//   { return graph->goNext(e); }
 
