#include <cmath>
#include <sstream>
#include <algorithm>
#include <memory>

#include "hurricane/DebugSession.h"
#include "hurricane/Warning.h"
#include "hurricane/Error.h"
#include "hurricane/Name.h"
#include "hurricane/Horizontal.h"
#include "hurricane/Vertical.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/Component.h"
#include "hurricane/Net.h"
#include "hurricane/DeepNet.h"
#include "hurricane/Cell.h"
#include "hurricane/Technology.h"
#include "hurricane/DataBase.h"
#include "hurricane/UpdateSession.h"
#include "hurricane/Breakpoint.h"

#include "crlcore/Utilities.h"
#include "crlcore/AllianceFramework.h"
#include "crlcore/RoutingGauge.h"
#include "crlcore/RoutingLayerGauge.h"

#include "knik/Configuration.h"
#include "knik/Graph.h"
#include "knik/Vertex.h"
#include "knik/Edge.h"
#include "knik/HEdge.h"
#include "knik/VEdge.h"
#include "knik/KnikEngine.h"

#include "knik/flute.h"

//#define __USE_SLICINGTREE__
#define __USE_MATRIXVERTEX__

#define EPSILON 10e-4
#define FLUTE_LIMIT 150
#define HISTORIC_INC 1.5 // define the increment of historic cost for ripup & reroute

namespace Knik {

  using Hurricane::inltrace;
  using Hurricane::ltracein;
  using Hurricane::ltraceout;
  using Hurricane::tab;
  using Hurricane::ForEachIterator;

int  depthMaterialize;
unsigned countDijkstra    = 0;
unsigned countMonotonic   = 0;
unsigned countMaterialize = 0;
bool debugging;
Name debugName = Name("");

bool __ripupMode__;

extern float __edge_capacity_percent__;
extern unsigned __congestion__;
extern unsigned __precongestion__;

using namespace CRL;

STuple::STuplePQIter STuple::_stuplePQEnd;
Name STuple::CostProperty::_name = "Knik::CostProperty";

struct segmentStat {
    unsigned nbDep;
    unsigned nbTot;
    unsigned sumOv;

    segmentStat(unsigned dep, unsigned tot, unsigned ov) { nbDep=dep; nbTot=tot; sumOv=ov; };
    segmentStat() {};
    ~segmentStat() {};

    void incNbDep() { nbDep++; };
    void incNbTot() { nbTot++; };
    void incSumOv ( unsigned inc ) { sumOv+=inc; };

    unsigned getNbDep() const { return nbDep; };
    unsigned getNbTot() const { return nbTot; };
    unsigned getSumOv() const { return sumOv; };
};

Graph::Graph ( KnikEngine* engine, RoutingGrid* routingGrid, bool benchMode, bool useSegments )
// ********************************************************************************************
    : _cell ( engine->getCell() )
    , _engine ( engine )
    , _benchMode ( benchMode )
    , _useSegments ( useSegments )
    , _slicingTree ( NULL )
    , _matrixVertex ( NULL )
    , _routingGrid ( routingGrid )
    , _working_net ( NULL )
    , _vertexes_to_route()
    , _lowerLeftVertex ( NULL )
    , _all_vertexes()
    , _all_edges()
    , _nbSplitters ( 0 )
    , _vtuplePriorityQueue()
    , _stuplePriorityQueue()
    , _searchingArea()
    , _xSize ( 0 )
    , _ySize ( 0 )
    //, _estimateOccupancyWindow ( NULL )
    //, _occupancyWindow ( NULL )
    , _maxEstimateOccupancy ( 0.0 )
    , _maxXEstimateOccupancy ( 0.0 )
    , _maxYEstimateOccupancy ( 0.0 )
    , _maxOccupancy ( 0 )
    , _maxXOccupancy ( 0 )
    , _maxYOccupancy ( 0 )
    , _hEdgeNormalisedLength ( 1.0 ) // au cas ou
    , _vEdgeNormalisedLength ( 1.0 ) // au cas ou
{
    __ripupMode__ = false;
}

Graph* Graph::create ( KnikEngine* engine, RoutingGrid* routingGrid, bool benchMode, bool useSegments )
// ****************************************************************************************************
{
    Graph* _graph = new Graph ( engine, routingGrid, benchMode, useSegments );

    _graph->_postCreate();

    return _graph;
}

void Graph::_postCreate()
// **********************
{
    _netStamp = 1; // initializing netStamp here instead of in Knik::Route function (for reroute, it seems good)

  //Cell* cell = _nimbus->getCell();
  //DisplaySlot* vertexDS = DisplaySlot::create( cell, Name("KnikVertexDS"),192, 0 ,192,"FFFFFFFFFFFFFFFF",1,192, 0 ,192,"FFFFFFFFFFFFFFFF",1 );
  //DisplaySlot* edgeDS   = DisplaySlot::create( cell, Name("KnikEdgeDS")  ,153,100, 17,"55AA55AA55AA55AA",1,153,100, 17,"55AA55AA55AA55AA",1 );

  // XXX On supprime tout ce qui concerne NIMBUS et on considère qu'il existe toujours une _routingGrid XXX
    if ( !_routingGrid ) {
#ifdef __USE_MATRIXVERTEX__
      _matrixVertex = MatrixVertex::create(this);
      if( !_matrixVertex )
        throw Error ("Graph::_postCreate(): cannot create MatrixVertex");
      _lowerLeftVertex = _matrixVertex->createRegularMatrix ();
      cmess2 << "     - Created vertex matrix (without RoutingGrid)" << endl;
#else
      throw Error ("Graph::_postCreate(): cannot use another method than MatrixVertex");
#endif
    // il faut définir les normalisedLength, pour l'instant on le fait pas
    } else {
      cmess2 << "     - RoutingGrid size [" << _routingGrid->getNbXTiles() << "x" << _routingGrid->getNbYTiles() << "]." << endl;
#ifdef __USE_MATRIXVERTEX__
      _matrixVertex = MatrixVertex::create(this);
      if( !_matrixVertex )
        throw Error ("Graph::_postCreate(): cannot create MatrixVertex");

      _lowerLeftVertex = _matrixVertex->createRegularMatrix ( _routingGrid );
    // initialisation des normalisedLength
      float hEdgeLength = _routingGrid->getTileWidth();
      float vEdgeLength = _routingGrid->getTileHeight();
      _hEdgeNormalisedLength = hEdgeLength <= vEdgeLength ? 1.0 : hEdgeLength / vEdgeLength;
      _vEdgeNormalisedLength = hEdgeLength <= vEdgeLength ? vEdgeLength / hEdgeLength : 1.0;
      cmess2 << "     - Created vertex matrix (from RoutingGrid)." << endl;
#else
      throw Error ("Graph::_postCreate(): cannot use another method than MatrixVertex");
#endif
    }

    cout << Dots::asUInt ("     - Global router H edges capacity"     ,_lowerLeftVertex->getHEdgeOut()->getCapacity()) << endl;
    cout << Dots::asUInt ("     - Global router V edges capacity"     ,_lowerLeftVertex->getVEdgeOut()->getCapacity()) << endl;
    
//    #ifdef __USE_MATRIXVERTEX__
//        _matrixVertex = MatrixVertex::create(this);
//        if ( _routingGrid ) {  
//            _matrixVertex->createXRegular ( _routingGrid );
//            _matrixVertex->createYRegular ( _routingGrid );
//        }
//        else { 
//            _matrixVertex->createXIrregular ( _nimbus );
//            _matrixVertex->createYIrregular ( _nimbus );
//        }
//    #endif
//    #ifdef __USE_SLICINGTREE__
//        _slicingTree = SlicingTree::create ( _nimbus );
//    #endif
//
//    unsigned compteur = 0;
//    for_each_gcell ( gcell, _nimbus->getRoutingLeaves() )
//    {
//        compteur++;
//        Vertex* vertex = Vertex::create ( gcell, this );
//        if ( !_lowerLeftVertex )
//            _lowerLeftVertex = vertex;
//        else {
//            if ( vertex->getX() <= _lowerLeftVertex->getX() ) {
//                if ( vertex->getY() <= _lowerLeftVertex->getY() )
//                    _lowerLeftVertex = vertex;
//            }
//        }
//        _all_vertexes.push_back ( vertex );
//        #ifdef __USE_MATRIXVERTEX__
//            _matrixVertex->setVertex ( gcell->getCenter(), vertex );
//        #endif
//        #ifdef __USE_SLICINGTREE__
//            SlicingTreeNode* terminalNode = _slicingTree->getTerminalNode ( gcell->getCenter() );
//            terminalNode->setVertex ( vertex );
//        #endif
//        end_for;
//    }
//    cmess2 << "           - Parcours des gcells pour créer les vertex terminé : " << compteur << " vertex" << endl;
//
//    Vertex* currentVertex = _lowerLeftVertex;
//    while ( currentVertex ) {
//        Vertex* firstLineVertex = currentVertex;
//        while ( currentVertex ) {
//            GCell* source   = currentVertex->getGCell();
//            Fence* fenceUP  = source->getUpFence();
//            GCell* targetUP = source->getUpOfMe();
//            if ( targetUP )
//                createVEdge ( currentVertex, getVertex ( targetUP->getCenter() ), fenceUP );
//            Fence* fenceRIGHT  = source->getRightFence();
//            GCell* targetRIGHT = source->getRightOfMe();
//            if ( targetRIGHT ) {
//                Vertex* rightVertex = getVertex ( targetRIGHT->getCenter() );
//                createHEdge ( currentVertex, rightVertex, fenceRIGHT );
//                currentVertex = rightVertex;
//            }
//            else
//                break;
//        }
//        Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
//        if ( vEdgeOut )
//            currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
//        else
//            break;
//    }
//    cmess2 << "           - Parcours des gcells puis des fences pour créer les edges terminé" << endl;

    for ( unsigned i = 0 ; i < _all_vertexes.size() ; i++ ) {
        _all_vertexes[i]->sortEdges();
    }
    cmess2 << "     - Edge sorting completed." << endl;

    STuple::setSTuplePQEnd ( _stuplePriorityQueue.end() );

//    cmess2 << "Petites stats :" << endl
//         << "    gcell : " << sizeof(GCell) << endl
//         << "    fence : " << sizeof(Fence) << endl
//         << "    vertex : " << sizeof(Vertex) << endl
//         << "    edge : " << sizeof (Edge) << endl
//         << "    net : " << sizeof(Net) << endl
//         << "    pin : " << sizeof(Pin) << endl
//         << "    splitter : " << sizeof(Splitter) << endl
//         << "    splitterContact : " << sizeof(SplitterContact) << endl;

}

void Graph::destroy()
// *****************
{
    _preDestroy();
    delete this;
}

void Graph::_preDestroy()
// *********************
{
    // Destruction of all VTuples
    for ( VTuplePQIter pqit = _vtuplePriorityQueue.begin() ; pqit != _vtuplePriorityQueue.end() ; pqit++ ) {
        (*pqit)->destroy();
    }

    // Destrucion of all Edges and Vertexes
    Vertex* currentVertex = _lowerLeftVertex;
    while ( currentVertex ) {
        Vertex* nextVVertex;
        if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() )
            nextVVertex = vEdgeOut->getOpposite ( currentVertex );
        else
            nextVVertex = NULL;

        while ( currentVertex ) {
            if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() )
                vEdgeOut->destroy();

            Vertex* nextHVertex;
            if ( Edge* hEdgeOut = currentVertex->getHEdgeOut() ) {
                nextHVertex = hEdgeOut->getOpposite ( currentVertex );
                hEdgeOut->destroy();
            }
            else
                nextHVertex = NULL;
            currentVertex->destroy();
            currentVertex = nextHVertex;
        }
        currentVertex = nextVVertex;
    }

    //// Destruction of all Edges
    //for ( unsigned i = 0 ; i < _all_edges.size() ; i++ ) {
    //    _all_edges[i]->destroy();
    //}

    //// Destruction of all Vertexes
    //for ( unsigned i = 0 ; i < _all_vertexes.size() ; i++ ) {
    //    _all_vertexes[i]->destroy();
    //}

    #ifdef __USE_MATRIXVERTEX__
        _matrixVertex->destroy();
    #endif
    #ifdef __USE_SLICINGTREE__
        _slicingTree->destroy();
    #endif
}

Vertex* Graph::getPredecessor ( const Vertex* vertex )
// ***************************************************
{
    assert( vertex->getPredecessor() );
    return vertex->getPredecessor()->getOpposite ( vertex );
}


Vertex* Graph::getCentralVertex()
// ******************************
{
    assert ( _vertexes_to_route.begin() != _vertexes_to_route.end() );
    // This function skims the _vertexes_to_route set and returns the most centered vertex.
    //
    // first pass : builds the bounding box of all vertexes
    Box vertexesBBox;
    VertexSetIter vsit = _vertexes_to_route.begin();
    while ( vsit != _vertexes_to_route.end() ) {
        vertexesBBox.merge((*vsit)->getPosition());
        vsit++;
    }
    // second pass : finds the most centered vertex
    Point   boxCenter    = vertexesBBox.getCenter();
    vsit = _vertexes_to_route.begin();
    Vertex* mostCentered = (*vsit);
    DbU::Unit    minDistance  = boxCenter.manhattanDistance ( mostCentered->getPosition() );
    vsit++;
    while ( vsit != _vertexes_to_route.end() ) {
        Vertex* currentVertex   = (*vsit);
        DbU::Unit    currentDistance = boxCenter.manhattanDistance( currentVertex->getPosition() );
        if ( currentDistance < minDistance ) {
            mostCentered = currentVertex;
            minDistance  = currentDistance;
        }
        vsit++;
    }

    return mostCentered;
}

Vertex* Graph::getVertex ( Point p )
// *********************************
{
    Vertex* vertex;
    #ifdef __USE_MATRIXVERTEX__
        vertex = _matrixVertex->getVertex(p);
        assert(vertex);
    #endif
    #ifdef __USE_SLICINGTREE__
        vertex = _slicingTree->getVertex ( p );
        assert ( vertex );
    //#else   // Ce n'est plus une option !
    //    GCell* gcell =  _nimbus->getRoutingLeafContaining ( p );
    //    assert ( gcell );
    //    vertex = getVertexOfGCell ( gcell );
    //    assert ( vertex );
    #endif

    return vertex;
}

Vertex* Graph::getVertex ( DbU::Unit x, DbU::Unit y )
// **************************************************
{
  return getVertex ( Point(x,y) );
}

unsigned Graph::getGridLength ( Segment* segment )
// ***********************************************
{
    // new time-optimized version 02/02/09
    unsigned sourceColId = _matrixVertex->getColumnIndex ( segment->getSourceX() );
    unsigned targetColId = _matrixVertex->getColumnIndex ( segment->getTargetX() );
    unsigned sourceRowId = _matrixVertex->getLineIndex ( segment->getSourceY() );
    unsigned targetRowId = _matrixVertex->getLineIndex ( segment->getTargetY() );
    if ( sourceColId == targetColId )
        return targetRowId - sourceRowId;
    else
        return targetColId - sourceColId;
    //if ( isAGlobalRoutingSegment(segment) ) {
    //    if ( Horizontal* horiz = dynamic_cast<Horizontal*>(segment) ) {
    //        unsigned sourceId = _matrixVertex->getColumnIndex ( horiz->getSourceX() );
    //        unsigned targetId = _matrixVertex->getColumnIndex ( horiz->getTargetX() );
    //        assert ( sourceId != targetId );
    //        return targetId - sourceId; // On considere que les segments sont bien orientes !!!!
    //    }
    //    else if ( Vertical* verti = dynamic_cast<Vertical*>(segment) ) {
    //        unsigned sourceId = _matrixVertex->getLineIndex ( verti->getSourceY() );
    //        unsigned targetId = _matrixVertex->getLineIndex ( verti->getTargetY() );
    //        assert ( sourceId != targetId );
    //        return targetId - sourceId; // meme hypothese !!!
    //    }
    //    else
    //        throw Error ( "Graph::getGridLength(): segment is neither horizontal nor vertical." );
    //}
    return 0;
}

unsigned Graph::getCongestEdgeNb ( Segment* segment )
// **************************************************
{
    if ( !isAGlobalRoutingSegment(segment) ) {
        string message = "getCongestEdgeNb only treats global routing segment for now : ";
        message += getString(segment);
        throw Warning ( message );
    }
    unsigned nbEdge = 0;
    if ( dynamic_cast<Horizontal*>(segment) ) {
        Vertex* current = getVertex ( segment->getSource()->getCenter() );
        Vertex* target  = getVertex ( segment->getTarget()->getCenter() );
        while ( current != target ) {
            Edge* edge = current->getHEdgeOut();
            if ( !edge ) throw Error ("Graph::getCongestEdgeNb(): Wow! NULL horizontal Edge.");
            if ( edge->isCongested() )
                nbEdge++;
            current = edge->getTo();
        }
    }
    else if ( dynamic_cast<Vertical*>(segment) ) {
        Vertex* current = getVertex ( segment->getSource()->getCenter() );
        Vertex* target  = getVertex ( segment->getTarget()->getCenter() );
        while ( current != target ) {
            Edge* edge = current->getVEdgeOut();
            if ( !edge ) throw Error ("Graph::getCongestEdgeNb(): Wow! NULL vertical Edge.");
            if ( edge->isCongested() )
                nbEdge++;
            current = edge->getTo();
        }
    }
    else
            throw Error ( "Graph::getCongestEdgeNb(): segment is neither horizontal nor vertical." );
    
    return nbEdge++;
    
}

Segment* Graph::createSegment ( Contact* initialContact, Contact* reachedContact )
// *******************************************************************************
{
    //cerr << "Graph::createSegment: " << initialContact << " -- " << reachedContact << endl;
    if ( initialContact->getX() == reachedContact->getX() ) {
      const Layer* layer  = Configuration::getGMetalV();
      DbU::Unit   xCoord = initialContact->getX();
      DbU::Unit   width  = DbU::lambda(2);

      if ( initialContact->getY() <= reachedContact->getY() )
        return Vertical::create ( initialContact, reachedContact, layer, xCoord, width );
      else
        return Vertical::create ( reachedContact, initialContact, layer, xCoord, width );
    }
    else if ( initialContact->getY() == reachedContact->getY() ) {
      const Layer* layer  = Configuration::getGMetalH();
      DbU::Unit   yCoord = initialContact->getY();
      DbU::Unit   height = DbU::lambda(2);
      
      if ( initialContact->getX() <= reachedContact->getX() )
        return Horizontal::create ( initialContact, reachedContact, layer, yCoord, height );
      else
        return Horizontal::create ( reachedContact, initialContact, layer, yCoord, height );
    }
    else
      throw Error ( "Graph::createSegment(): Contacts are not aligneds." );
}

void Graph::sortHVertexes ( Vertex*& from, Vertex*& to )
// *****************************************************
{
    // This function sorts 2 vertexes horizontally:
    //   from will be the leftest one
    assert (from);
    assert (to);
    if ( from->getX() > to->getX() ) {
        Vertex* temp = from;
        from = to;
        to   = temp;
    }
}

void Graph::sortVVertexes ( Vertex*& from, Vertex*& to )
// *****************************************************
{
    // This function sorts 2 vertexes vertically:
    //   from will be the downest one
    assert (from);
    assert (to);
    if ( from->getY() > to->getY() ) {
        Vertex* temp = from;
        from = to;
        to   = temp;
    }
}

Vertex* Graph::createVertex ( Point position, DbU::Unit halfWidth, DbU::Unit halfHeight )
// **************************************************************************************
{
    Vertex* vertex = Vertex::create ( this, position, halfWidth, halfHeight );
    assert ( vertex );
    _all_vertexes.push_back ( vertex );
    return vertex;
}

  void Graph::createHEdge ( Vertex* from, Vertex* to, size_t reserved )
// ********************************************************************
{
    size_t capacity = 0;
    if ( _routingGrid ) {
        capacity = _routingGrid->getHCapacity();
      //cerr << "createHEdge capacity:" << capacity << " reserved:" << reserved << endl;
    } else {
        vector<RoutingLayerGauge*> rtLGauges = _engine->getRoutingGauge()->getLayerGauges();
        for ( vector<RoutingLayerGauge*>::iterator it = rtLGauges.begin() ; it != rtLGauges.end() ; it++ ) {
            RoutingLayerGauge* routingLayerGauge = (*it);
            if (routingLayerGauge->getType() != Constant::Default) continue;
            if (routingLayerGauge->getDepth() > _engine->getAllowedDepth()) continue;

            if (routingLayerGauge->getDirection() != Constant::Horizontal)
                continue;

            capacity += routingLayerGauge->getTrackNumber ( from->getYMin(), from->getYMax() ) - 1;
        }
      //cerr << "createHEdge capacity:" << capacity << " reserved:" << reserved << endl;
    }
    Edge* newEdge = HEdge::create ( from, to, capacity-reserved );

    _all_edges.push_back ( newEdge );

    newEdge->setCost(1);

    Edge* previousEdge = from->getHEdgeOut();
    if ( previousEdge )
        newEdge->setNextFrom ( previousEdge );
    from->setHEdgeOut ( newEdge );

    previousEdge = to->getHEdgeIn();
    if ( previousEdge )
        newEdge->setNextTo ( previousEdge );
    to->setHEdgeIn ( newEdge );
}

void Graph::createVEdge ( Vertex* from, Vertex* to, size_t reserved )
// ******************************************************************
{
    size_t capacity = 0;
    if ( _routingGrid )
        capacity = _routingGrid->getVCapacity();
    else {
        vector<RoutingLayerGauge*> rtLGauges = AllianceFramework::get()->getRoutingGauge()->getLayerGauges();
        for ( vector<RoutingLayerGauge*>::iterator it = rtLGauges.begin() ; it != rtLGauges.end() ; it++ ) {
            RoutingLayerGauge* routingLayerGauge = (*it);
            if (routingLayerGauge->getType() != Constant::Default) continue;
            if (routingLayerGauge->getDepth() > _engine->getAllowedDepth()) continue;

            if (routingLayerGauge->getDirection() != Constant::Vertical)
                continue;

            capacity += routingLayerGauge->getTrackNumber ( from->getXMin(), from->getXMax() ) - 1;
        }
      //cerr << "createVEdge capacity:" << capacity << " reserved:" << reserved << endl;
    }
    Edge* newEdge = VEdge::create ( from, to, capacity-reserved );

    _all_edges.push_back ( newEdge );

    newEdge->setCost(1);

    Edge* previousEdge = from->getVEdgeOut();
    if ( previousEdge )
        newEdge->setNextFrom ( previousEdge );
    from->setVEdgeOut ( newEdge );

    previousEdge = to->getVEdgeIn();
    if ( previousEdge )
        newEdge->setNextTo ( previousEdge );
    to->setVEdgeIn ( newEdge );
}

void Graph::initConnexComp ( Vertex* vertex, int newConnexID )
// ***********************************************************
{
    initConnexComp ( vertex, NULL, newConnexID );
}

void Graph::initConnexComp ( Vertex* vertex, Edge* arrivalEdge, int newConnexID )
// ******************************************************************************
{
    // This recursive function initializes all vertexes of same connexID and connected through edges of same connexID,
    //  which means that the vertex's distance is set to 0 and the vertex is inserted in the VTuplePriorityQueue
    //  If newConnexID is different from -1, then the connexID is set to newConnexID
    int vertexConnex = vertex->getConnexID();
    assert ( vertexConnex != -1 );
    for_each_edge ( edge, vertex->getAdjacentEdges() ) {
        if ( edge == arrivalEdge ) {
            continue;
        }
        if ( (edge->getNetStamp() == _netStamp) && (edge->getConnexID() == vertexConnex) ) {
            initConnexComp ( edge->getOpposite(vertex), edge, newConnexID );
            if ( newConnexID != -1 ) {
                edge->setConnexID(newConnexID);
            }
        }
        end_for;
    }
    
    vertex->setDistance(0);
    if ( newConnexID != -1 ) {
        vertex->setConnexID ( newConnexID );
    }

    VTuple* vtuple = vertex->getVTuple();
    if ( vtuple ) {
        //cerr << "    Vertex " << vertex << " already has a vtuple : " << vtuple << endl;
        assert ( vtuple->getVertex() == vertex );
        increaseVTuplePriority ( vtuple, 0 );
    }
    else {
        vtuple = VTuple::create ( vertex, 0 );
        //cerr << "    Vertex " << vertex << " has now a new vtuple : " << vtuple << endl;
        addVTupleToPriorityQueue ( vtuple );
    }
}

void Graph::UpdateConnexComp ( VertexList reachedVertexes, Vertex* firstVertex )
// *****************************************************************************
{
    // XXX PLUTOT QUE DE PASSER UNE LISTE DE VERTEX EN ARG, ON DEVRAIT PASSER SEULEMENT UN VERTEX XXX
    // XXX proviens du fait qu'au depart on voulait reellement passer une liste mais du fait de la possiblité de chemins paralleles on evite XXX
    int firstConnexID = firstVertex->getConnexID();

    VertexListIter lvit = reachedVertexes.begin();
    // Pour essayer d'éviter le bug des chemins parallèles si 2 vertex sont atteints avec la meme distance, on ne va updater que le premier
    //while ( lvit != reachedVertexes.end() ) {
    Vertex* currentVertex = (*lvit);
    int     currentConnexID = currentVertex->getConnexID(); 

    //cerr << "Gonna updateConnexComp : first: " << firstVertex << ", reached: " << currentVertex << endl;

    //cerr << "  vertexes_to_route :" << endl;
    //for ( VertexSetIter vsit = _vertexes_to_route.begin() ; vsit != _vertexes_to_route.end() ; vsit++ )
    //     cerr << "     " << (*vsit) << endl;

    // the vertex must be removed from the _vertexes_to_route
    // XXX Woowoo il ne faut pas faire un erase du vertex atteint, mais rechercher le représentant de la composante connexe atteinte dans les _vertexes_to_route et faire un erase dessus !
    Vertex* toErase = NULL;
    for ( VertexSetIter vsit = _vertexes_to_route.begin() ; vsit != _vertexes_to_route.end() ; vsit++ ) {
        if ( (*vsit)->getConnexID() == currentConnexID )
            toErase = (*vsit);
    }

    //cerr << "  gonna erase : " << toErase << endl;
    // on veut updater toute la composante connexe représenter par le currentVertex
#ifndef NDEBUG
    unsigned deleteVertex = _vertexes_to_route.erase ( toErase );
    assert ( deleteVertex == 1 );
#else
    _vertexes_to_route.erase ( toErase );
#endif
    // the connexe component corresponding to the vertex must be initialize with the firstConnexID
    initConnexComp ( currentVertex, firstConnexID );
    
    // create the new connex component and initializes it :
    while ( Edge* predecessor = currentVertex->getPredecessor() ) {
        currentVertex->setPredecessor ( NULL );
        predecessor->setConnexID ( firstConnexID );
        currentVertex = predecessor->getOpposite ( currentVertex );

        // si jamais on réatteint un vertex dejà mis à jour.
        if ( currentVertex->getConnexID() == firstConnexID )
            break;

        currentVertex->setDistance(0);
        currentVertex->setConnexID(firstConnexID);

        VTuple* vtuple = currentVertex->getVTuple();
        if ( vtuple  ) {
            increaseVTuplePriority ( vtuple, 0);
        }
        else {
            vtuple = VTuple::create ( currentVertex, 0 );
            addVTupleToPriorityQueue ( vtuple );
        }
    }
    //}
}

// VTuplePriorityQueue Utility Methods
// ***********************************
Vertex* Graph::extractMinFromPriorityQueue()
// *****************************************
{
    if ( _vtuplePriorityQueue.begin() == _vtuplePriorityQueue.end() )
        return NULL;
    
    VTuple*  vtuple  = *(_vtuplePriorityQueue.begin());
    Vertex* vertex = vtuple->getVertex();

    _vtuplePriorityQueue.erase ( _vtuplePriorityQueue.begin() );
    vtuple->destroy();
    vertex->setVTuple ( NULL );

    return vertex;
}

Vertex* Graph::getMinFromPriorityQueue()
// *************************************
{
    if ( _vtuplePriorityQueue.begin() == _vtuplePriorityQueue.end() )
        return NULL;

    VTuple*  vtuple  = *(_vtuplePriorityQueue.begin());
    Vertex* vertex = vtuple->getVertex();

    return vertex;
}

void Graph::PopMinFromPriorityQueue()
// **********************************
{
    if ( _vtuplePriorityQueue.begin() != _vtuplePriorityQueue.end() ) {
        VTuple*  vtuple  = *(_vtuplePriorityQueue.begin());
        Vertex* vertex = vtuple->getVertex();

        _vtuplePriorityQueue.erase ( _vtuplePriorityQueue.begin() );
        vtuple->destroy();
        vertex->setVTuple ( NULL );
    }
}

void Graph::addVTupleToPriorityQueue ( VTuple* vtuple )
// *************************************************
{
//cerr << "addVTupleToPriorityQueue: "
//     << (void*)vtuple << " " << (void*)vtuple->getVertex() << ":" << vtuple->getVertex() << endl;

  assert ( vtuple );
  assert ( vtuple->getVertex()->getVTuple() == vtuple );
  assert ( _vtuplePriorityQueue.find ( vtuple ) == _vtuplePriorityQueue.end() );
  if (debugging)
    cerr << "    ADDING vtuple to priority queue : " << vtuple->_getString() << endl;
  _vtuplePriorityQueue.insert ( vtuple );
//pair<VTuplePQIter,bool> p = _vtuplePriorityQueue.insert ( vtuple );
//assert ( p.second );
}

void Graph::increaseVTuplePriority ( VTuple* vtuple, float distance )
// ***************************************************************
{
    assert ( vtuple );
    //if ( debugging ) 
    //    cerr << "    " << vtuple->getVertex() << " : " << vtuple->getDistance() << " > " << distance << endl;
    assert ( vtuple->getDistance() > distance );
    // Copy removeVTupleFromPriorityQueue without vtuple->destroy()
    VTuplePQIter pqit = _vtuplePriorityQueue.find ( vtuple );
    if ( pqit != _vtuplePriorityQueue.end() ) {
        assert ( vtuple->getVertex() == (*pqit)->getVertex() );
        _vtuplePriorityQueue.erase ( pqit );
    }
    // end copy
    vtuple->setDistance ( distance );
    _vtuplePriorityQueue.insert ( vtuple );
}

void Graph::printVTuplePriorityQueue()
// ***********************************
{
  ltracein(600);
  ltrace(600) << "VTuplePriorityQueue:" << endl;
  unsigned int i=0;
  for ( auto iv : _vtuplePriorityQueue ) {
    ltrace(600) << setw(3) << i << "| " << iv->getVertex() << " : " << iv->getDistance() << endl;
    ++i;
  }
  ltraceout(600);
}

void Graph::clearPriorityQueue()
// *****************************
{
    for ( VTuplePQIter pqit = _vtuplePriorityQueue.begin() ; pqit != _vtuplePriorityQueue.end() ; pqit++ ) {
        (*pqit)->destroy();
    }
    _vtuplePriorityQueue.clear();
}

// STuplePriorityQueue Utility Methods
// ***********************************
Segment* Graph::extractMaxFromSTuplePQ()
// *************************************
{
    if ( _stuplePriorityQueue.begin() == STuple::_stuplePQEnd )
        return NULL;
    
    STuple*  stuple = *(_stuplePriorityQueue.begin());
    Segment* segment = stuple->getSegment();

    _stuplePriorityQueue.erase ( _stuplePriorityQueue.begin() );
    stuple->destroy();

    return segment;
}

STuple* Graph::getMaxFromSTuplePQ()
// ********************************
{
    if ( _stuplePriorityQueue.begin() == STuple::_stuplePQEnd )
        return NULL;

    STuple* stuple  = *(_stuplePriorityQueue.begin());

    return stuple;
}

void Graph::popMaxFromSTuplePQ()
// *********************************
{
    if ( _stuplePriorityQueue.begin() != STuple::_stuplePQEnd ) {
        STuple* stuple = *(_stuplePriorityQueue.begin());
#ifndef NDEBUG
        STuple::CostProperty* costProperty = stuple->getCostProperty();
        assert ( costProperty );
        assert ( (*costProperty->getPQIter()) == stuple );
#endif
        stuple->destroy();
        _stuplePriorityQueue.erase ( _stuplePriorityQueue.begin());
    }
}

void Graph::addToSTuplePQ ( STuple* stuple )
// *****************************************
{
  assert( stuple );
  STuple::CostProperty* costProperty = stuple->getCostProperty();
  assert( costProperty );
  costProperty->setPQIter ( _stuplePriorityQueue.insert( stuple ) );
  STuple::STuplePQIter pqit = costProperty->getPQIter();
  assert( (*pqit) == stuple );
}

void Graph::updateSTupleCost ( STuple* stuple, unsigned cost )
// ***********************************************************
{
    assert ( stuple );
    STuple::CostProperty* costProperty = stuple->getCostProperty();
    assert ( costProperty );
    STuple::STuplePQIter pqit = costProperty->getPQIter();
    assert ( (*pqit) == stuple );
    _stuplePriorityQueue.erase ( pqit );
    stuple->setCost ( cost );
    costProperty->setPQIter ( _stuplePriorityQueue.insert ( stuple ) );
}

void Graph::printSTuplePQ()
// ************************
{
    cmess1 << "*** printing STuplePriorityQueue ***" << endl;
    STuple::STuplePQIter pqit = _stuplePriorityQueue.begin();
    while ( pqit != STuple::_stuplePQEnd ) {
        cmess1 << getString(*pqit) << endl;
        pqit++;
    }
    cmess1 << "***********************************" << endl;
}

void Graph::clearSTuplePQ()
// ************************
{
    for ( STuple::STuplePQIter pqit = _stuplePriorityQueue.begin() ; pqit != STuple::_stuplePQEnd ; pqit++ ) {
        (*pqit)->destroy();
    }
    _stuplePriorityQueue.clear();
}

void Graph::testSTuplePQ()
// ***********************
{
//    unsigned count = 0;
//    Component* compo1 = NULL;
//    Component* compo2 = NULL;
//    for_each_component ( component, _nimbus->getCell()->getComponents() ) {
//        if ( dynamic_cast<Segment*>(component) ) {
//            STuple::CostProperty* costProperty = STuple::CostProperty::create (count );
//            component->put ( costProperty );
//            STuple* stuple = STuple::create ( costProperty );
//            addToSTuplePQ ( stuple );
//            if ( count == 4 ) compo1 = component;
//            if ( count == 8 ) compo2 = component;
//            count++;
//            if ( count >= 10 )   
//                break;
//        }
//        end_for;
//    }
//    printSTuplePQ();
//    STuple::CostProperty* costProperty = dynamic_cast<STuple::CostProperty*>(compo1->getProperty ( "Knik::CostProperty" ));
//    updateSTupleCost ( (*costProperty->getPQIter()), 18 );
//    cmess2 << "updateSTupleCost ( (*costProperty->getPQIter()), 18 )" << endl;
//    printSTuplePQ();
//    costProperty = dynamic_cast<STuple::CostProperty*>(compo2->getProperty ( "Knik::CostProperty"));
//    updateSTupleCost ( (*costProperty->getPQIter()), 2 );
//    cmess2 << "updateSTupleCost ( (*costProperty->getPQIter()), 2 )" << endl;
//    printSTuplePQ();
//    popMaxFromSTuplePQ();
//    cmess2 << "popMaxFromSTuplePQ()" << endl;
//    printSTuplePQ();
//    cmess2 << "getString ( getMaxFromSTuplePQ() )" << endl;
//    cmess2 << getString ( getMaxFromSTuplePQ() ) << endl;
//    printSTuplePQ();
//    cmess2 << "getString ( extractMaxFromSTuplePQ() )" << endl;
//    cmess2 << getString ( extractMaxFromSTuplePQ() ) << endl;
//    printSTuplePQ();
//    clearSTuplePQ();
//    cmess2 << "clearSTuplePQ()" << endl;
//    printSTuplePQ();
}

int Graph::countVertexes ( Net* net )
// **********************************
{
    assert ( net );
    
    _working_net = net;
    forEach ( Component*, component, net->getComponents() ) {
        if ( RoutingPad* routingPad = dynamic_cast<RoutingPad*>(*component) ) {
            //if ( routingPad->getCenter().getY() < 0 ) {

            //    CEditor* editor = getCEditor ( getCell() );
            //    editor->Select ( routingPad );
            //    editor->Refresh();
            //    editor->Stop ( "RoutingPad" );
            //    editor->Unselect( routingPad );
            //}


            Vertex* vertex = getVertex ( routingPad->getCenter() );
            assert(vertex);
            if ( _vertexes_to_route.find ( vertex ) == _vertexes_to_route.end() ) {
                _vertexes_to_route.insert ( vertex );
            }
        }
    }
    return _vertexes_to_route.size();
}

int Graph::initRouting ( Net* net )
// ********************************
{
    assert ( net );
    _working_net = net;

    //cerr  << "[DEBUG]: Net: " << _working_net << endl;
    //cerr  << "[DEBUG]: vertexes_to_route size: " << _vertexes_to_route.size() << endl;

    //CEditor* editor = getCEditor( _nimbus->getCell() );
    //editor->Refresh();
    //editor->Stop ("Going to init");

    int currentConnexID = 0;
    vector<Contact*> vContacts;
    vector<RoutingPad*> vRoutingPads;
    unsigned compoSize = net->getComponents().getSize();
    vContacts.reserve ( compoSize );
    vRoutingPads.reserve ( compoSize );
    for_each_component ( component, net->getComponents() ) {
        if ( dynamic_cast<RoutingPad*>(component) )
            vRoutingPads.push_back ( static_cast<RoutingPad*>(component) );
        if ( dynamic_cast<Contact*>(component) ) {
            Contact* contact = static_cast<Contact*>(component);
            if ( isAGlobalRoutingContact ( contact ) )
                vContacts.push_back ( contact );
        }
        end_for;
    }
    //cerr << "   vContacts size :    " << vContacts.size() << endl;
    //cerr << "   vRoutingPads size : " << vRoutingPads.size() << endl;
    UpdateSession::open();
    for ( unsigned index = 0; index < vContacts.size() ; index++ ) {
        Contact* contact = vContacts[index];
        //cerr << "        contact : " << contact << "" << endl;
        Vertex* contactVertex = getVertex ( contact->getCenter() );
        Contact* vContact = contactVertex->getContact();
        if ( (vContact == contact) && (contactVertex->getNetStamp() == _netStamp) ) {
            //cerr << "        on a deja un contact associe avec le meme netStamp !" << endl;
            continue; // on la déjà traité à travers le parcourt de composante connexe
        }
        else {
            //cerr << "            rebuild connexe component " << contact << "" << endl;
            rebuildConnexComponent ( contact, currentConnexID, NULL );
            //cerr << "            done" << endl;
            if ( _vertexes_to_route.find ( contactVertex ) == _vertexes_to_route.end() ) {
                //cerr << "            Adding vertex to _vertexes_to_route: continue" << endl;
                _vertexes_to_route.insert ( contactVertex );
                _searchingArea.merge ( contactVertex->getBox() );
                contactVertex->setDistance((float)(HUGE_VAL));
                contactVertex->setPredecessor(NULL);
                currentConnexID++;
            }
        }
    }
    //cerr << "   traitement pour les contacts : OK" << endl;
    //OoOoooOoooOoO A QUOI SERT CE BOOLEEN OoOoooOoooOoO  ==>> pour le //5 le connexID ne doit pas avoir été augmenté ! ou alors connexID-1 !!
    //bool useConnexID = false;
    for ( unsigned index = 0 ; index < vRoutingPads.size() ; index ++ ) {
        RoutingPad* routingPad = vRoutingPads[index];
        //cerr << "        RoutingPad :" << routingPad << endl;
        Vertex*  rpVertex = getVertex ( routingPad->getCenter() );
        //cerr << "            Vertex :" << rpVertex << endl;
        Contact* rpContact = rpVertex->getContact();
        if ( rpContact && (rpContact->getNet() == routingPad->getNet()) ) {
            // s'il existe deja un contact pour ce vertex pour ce net, on s'y attache
            //cerr << "            Contact already exists: attaching hooks" << endl;
            // le contact a deja ete cree, il suffit d'ajouter le routingPad à la ronde du contact.
            routingPad->getBodyHook()->detach();
            routingPad->getBodyHook()->attach ( rpVertex->getContact()->getBodyHook() );
        }
        else {
            // sinon on crée un contact et on s'y attache
            Contact* contact = Contact::create ( _working_net
                                               , DataBase::getDB()->getTechnology()->getLayer("metal2")
                                               , rpVertex->getPosition().getX()
                                               , rpVertex->getPosition().getY()
                                               , rpVertex->getHalfWidth()/5
                                               , rpVertex->getHalfHeight()/5
                                               );
            rpVertex->setContact ( contact );
            routingPad->getBodyHook()->detach();
            routingPad->getBodyHook()->attach ( contact->getBodyHook() );
            if ( _vertexes_to_route.find ( rpVertex ) == _vertexes_to_route.end() ) {
                //cerr << "            Adding vertex to _vertexes_to_route: continue" << endl;
                _vertexes_to_route.insert ( rpVertex );
                _searchingArea.merge ( rpVertex->getBox() );
                rpVertex->setConnexID ( currentConnexID );
                rpVertex->setNetStamp ( _netStamp );
                rpVertex->setDistance((float)(HUGE_VAL));
                rpVertex->setPredecessor(NULL);
                currentConnexID++;
            }
        }
    }
    // for ripup & reroute purpose
    if ( __ripupMode__ )
        _searchingArea = _cell->getAbutmentBox(); // recherche sur toute la surface : trop long pour gros circuits
        //_searchingArea.inflate((_searchingArea.getWidth()*10)/100, (_searchingArea.getHeight()*10)/100); // raté ça ne marche pas avec les nets plats

    //cerr << "   traitement pour les routingPads : OK" << endl;
    UpdateSession::close();
    //cerr  << "[DEBUG]: vertexes_to_route size (after init): " << _vertexes_to_route.size() << endl;
    //editor->Refresh();
    //editor->Stop("initDone");
    // 8/10/2007
    // {
    // Expand seaching area
    //int bottomLineIdx  = (int)_matrixVertex->getLineIndex   ( _searchingArea.getYMin() +1 );
    //int topLineIdx     = (int)_matrixVertex->getLineIndex   ( _searchingArea.getYMax() -1 );
    //int leftColumnIdx  = (int)_matrixVertex->getColumnIndex ( _searchingArea.getXMin() +1 );
    //int rightColumnIdx = (int)_matrixVertex->getColumnIndex ( _searchingArea.getXMax() -1 );
    //if ( _matrixVertex->isLineIndexValid ( bottomLineIdx - 2 ) )
    //    bottomLineIdx -= 2;
    //else if ( _matrixVertex->isLineIndexValid ( bottomLineIdx - 1 ) )
    //    bottomLineIdx -= 1;

    //if ( _matrixVertex->isLineIndexValid ( topLineIdx + 2 ) )
    //    topLineIdx += 2;
    //else if ( _matrixVertex->isLineIndexValid ( topLineIdx + 1 ) )
    //    topLineIdx += 1;

    //if ( _matrixVertex->isColumnIndexValid ( leftColumnIdx - 2 ) )
    //    leftColumnIdx -= 2;
    //else if ( _matrixVertex->isColumnIndexValid ( leftColumnIdx - 1 ) )
    //    leftColumnIdx -= 1;

    //if ( _matrixVertex->isColumnIndexValid ( rightColumnIdx + 2 ) )
    //    rightColumnIdx += 2;
    //else if ( _matrixVertex->isColumnIndexValid ( rightColumnIdx + 1 ) )
    //    rightColumnIdx += 1;

    //_searchingArea.merge ( _matrixVertex->getVertexFromIndexes(bottomLineIdx, leftColumnIdx)->getGCell()->getBox() );
    //_searchingArea.merge ( _matrixVertex->getVertexFromIndexes(topLineIdx, rightColumnIdx)->getGCell()->getBox() );
    
    //cerr << "net " << net << " has " << _vertexes_to_route.size() << " vertexes to route." << endl;
    //}
    return _vertexes_to_route.size();
}

void Graph::Dijkstra()
// *******************
{
//checkEmptyPriorityQueue();

  countDijkstra++;

// first we need to choose the closest to center vertex in _vertexes_to_route
  Vertex* centralVertex = getCentralVertex();
//ltrace(435) << "  most centered vertex is " << centralVertex << endl;
// we want to prepare all vertexes of the 'composante connexe'
//      set the distance to 0
//      insert each vertex in the vtuplePriorityQueue
  initConnexComp( centralVertex );
    
// create a copy of _vertexes_to_route vector fo method UpdateEstimateCongestion
//set<Vertex*,VertexPositionComp> copy_vertex = _vertexes_to_route; // This is no more useful

//#if defined ( __USE_DYNAMIC_PRECONGESTION__ )
  if ( !__ripupMode__ &&  (__precongestion__ == 2) )
    UpdateEstimateCongestion();
//#endif

  DebugSession::open( _working_net, 600 );
  ltrace(600) << "Dijkstra for net: " << _working_net << endl;
  ltracein(600);
  ltrace(600) << "Stamp:" << _netStamp << endl;
  ltrace(600) << "Central vertex : " << centralVertex << endl;
  ltrace(600) << "_vertexes_to_route.size(): " << _vertexes_to_route.size() << endl;
  ltracein(600);
//Breakpoint::stop(1, "<center><b>Dijkstra</b><br>initialized</center>");

  while ( _vertexes_to_route.size() > 1 ) {
  // Now, let's expanse the top of the queue
    VertexList reachedVertexes;
    float      reachedDistance = (float)(HUGE_VAL);

  //checkGraphConsistency();
    if (ltracelevel() >= 600) {
      ltrace(600) << "_vertexes_to_route:" << endl;
      for ( auto iv : _vertexes_to_route )
        ltrace(600) << "| " << iv << endl;
    }

    ltrace(600) << "Source component" << endl;
    printVTuplePriorityQueue();
  //Breakpoint::stop(1, "<center><b>Dijkstra</b><br>source connexe component</center>");

    Vertex* firstVertex = getMinFromPriorityQueue();
    assert( firstVertex );
    Vertex* currentVertex     = firstVertex;
    int     firstVertexConnex = firstVertex->getConnexID();

    while ( currentVertex and (currentVertex->getDistance() < reachedDistance) ) {
      PopMinFromPriorityQueue();
      assert( not currentVertex->getVTuple() );

    // IMPORTANT : each currentVertex considered here has been getFromPriorityQueue() 
    // which means its NetStamp and ConnexID are set for the current _working_net :
    // no need to check netStamp
      int currentVertexConnex = currentVertex->getConnexID() ;
      if ( (currentVertexConnex != -1) and (currentVertexConnex != firstVertexConnex) ) {
        reachedDistance = currentVertex->getDistance();
        reachedVertexes.clear();
        reachedVertexes.push_back ( currentVertex );
        ltrace(600) << "Re-init reachedVertexes with " << currentVertex << endl;
        break;
      }

      Edge* arrivalEdgeCurrentVertex = currentVertex->getPredecessor();
      forEach ( Edge*, iedge, currentVertex->getAdjacentEdges() ) {
        if ( (iedge->getNetStamp() == _netStamp) && (iedge->getConnexID() == firstVertexConnex) ) {
        // already visited iedge
        //   ok because to reach a connex component the algorithm first reach a vertex !!
          continue;
        }
        iedge->setConnexID(-1);  // reinitialize connexID for edge (was done by CleanRoutingState)
        iedge->setNetStamp(_netStamp);
        
        Vertex* oppositeVertex = iedge->getOpposite ( currentVertex );
        assert( oppositeVertex );
        if (not _searchingArea.contains(oppositeVertex->getPosition()))
          continue;

        float newDistance          = currentVertex->getDistance()
                                   + iedge->getCost( arrivalEdgeCurrentVertex );
        bool  updateOppositeVertex = false;
      // reinitialize the oppositeVertex if its netStamp is < _netStamp
        if (oppositeVertex->getNetStamp() < _netStamp) {
        //oppositeVertex->setLocalRingHook(NULL);
          oppositeVertex->setContact(NULL);
          oppositeVertex->setConnexID(-1);
          updateOppositeVertex = true;
        }

        int   oppositeConnex       = oppositeVertex->getConnexID();
        float oppositeDistance     = oppositeVertex->getDistance();
        if ( updateOppositeVertex or (newDistance + EPSILON < oppositeDistance) ) {
          assert( oppositeConnex != firstVertexConnex );
          oppositeVertex->setPredecessor( *iedge );
          oppositeVertex->setDistance   ( newDistance );
          oppositeVertex->setNetStamp   ( _netStamp );

          VTuple* oppositeVTuple = oppositeVertex->getVTuple();
          if (oppositeVTuple) {
            ltrace(600) << "Increasing priority for:" << endl;
            ltrace(600) << "* " << oppositeVertex << endl;
            ltrace(600) << "* " << oppositeVTuple << endl;
            increaseVTuplePriority( oppositeVTuple, newDistance );
          // Du fait de la reinit ce n'est plus seulement un increase!
          // Non, c'est bon si on garde le CleanRoutingState (avec clearPriorityQueue)
          } else {
            VTuple* newOppositeVTuple = VTuple::create ( oppositeVertex, newDistance );
            ltrace(600) << "Creating New VTuple for Vertex:" << endl;
            ltrace(600) << "* " << oppositeVertex    << ":" << newDistance << endl;
            ltrace(600) << "* " << newOppositeVTuple << endl;
            addVTupleToPriorityQueue( newOppositeVTuple );
          }

          ltrace(600) << "Updated distance " << newDistance << " on: " << (*iedge) << endl;
          printVTuplePriorityQueue();
        //Breakpoint::stop(1, "<center><b>Dijkstra</b><br>distance has been updated</center>");
        }

        if ( (oppositeConnex != -1) and (oppositeConnex != firstVertexConnex) ) {
        // verifier si la newDistance est inférieure a la reachedDistance,
        // si oui vider la liste des reachedVertex et ajouter l'oppositeVertex
        // si == ajouter l'oppositeVertex a la liste (a condition qu'il n'y soit pas déjà)
        // si > rien a faire (a verifier que la pile de priorité se comporte bien)
          if (newDistance < reachedDistance) {
            reachedDistance = newDistance;
            reachedVertexes.clear();
            reachedVertexes.push_back( oppositeVertex );
            ltrace(600) << "Re-init (< distance) reachedVertexes with " << oppositeVertex << endl;
          } else if (newDistance == reachedDistance) {
          // on pourrait simplifier grandement tout ca : 1 seul vertex atteint sauvergardé!
          // Conclusion qu'il ait le meme connexID ou pas, on ne fait rien, on en a deja atteint
          // un avec la meme distance ...
            bool  foundVertex = false;
            for ( auto iv : reachedVertexes ) {
            // the following test depends on the fact we authorize multiple representant (vertex)
            // of the same connexe component in reachedVertexes list
            //if (iv->getConnexID() == oppositeConnex) 
              if (iv == oppositeVertex) {
                foundVertex = true;
                break;
              }
            }
            if (not foundVertex) {
              reachedVertexes.push_back( oppositeVertex );
              ltrace(600) << "Re-init (== distance) reachedVertexes with " << oppositeVertex << endl;
            }
          } else {
          // Nothing to do?
          }
        }
      }

      currentVertex = getMinFromPriorityQueue();
    }

    if (reachedVertexes.empty()) {
      ostringstream message;
      message << "In Graph::Dijkstra():\n";
      message << "        Unable to reach target on net " << _working_net->getName() << ".";
      throw Error( message.str() );
    }
    assert( reachedDistance < (float)(HUGE_VAL) );

    ltrace(600) << "Updating two connex components:" << endl;
    ltrace(600) << "1. " << (*(reachedVertexes.begin())) << endl;
    ltrace(600) << "2. " << firstVertex << endl;
    UpdateConnexComp( reachedVertexes, firstVertex );
  }

//cerr << "check before materialize _vertexes_to_route.size = " << _vertexes_to_route.size() << endl;
//checkGraphConsistency();
  MaterializeRouting ( *(_vertexes_to_route.begin()) );

//_vertexes_to_route.clear();   // no more useful
//_vertexes_to_route = copy_vertex ;

  ltraceout(600);
  ltraceout(600);
  DebugSession::close();
}

void Graph::Monotonic()
// ********************
{
    // This function execute an algorithm of monotonic routing
    //   it assumes that _vertexes_to_route.sze is 2 (only 2 pin nets can be route with monotonic routing)
    assert ( _vertexes_to_route.size() == 2 );

    countMonotonic++;

    //cerr << "Monotonic for net " << _working_net << " : " << _netStamp << endl;
    //cerr << "    check start monotonic" << endl;
    //checkGraphConsistency();

    Vertex* source = (*_vertexes_to_route.begin());
    Vertex* target = (*_vertexes_to_route.rbegin());
    assert ( source != target );
    DbU::Unit sourceX = source->getPosition().getX();
    DbU::Unit targetX = target->getPosition().getX();

    if ( sourceX > targetX ) {
        Vertex* temp = source;
        source = target;
        target = temp;
    }
    else if ( sourceX == targetX ) {
        if ( source->getPosition().getY() > target->getPosition().getY() ) {
            Vertex* temp = source;
            source = target;
            target = temp;
        }
    }

    // POUR SIMPLIFIER : PAS DE TRAITEMENT D'UN GRAPHE DE ROUTAGE IRREGULIER POUR L'INSTANT
    sourceX = source->getPosition().getX();
    targetX = target->getPosition().getX();
    DbU::Unit sourceY = source->getPosition().getY();
    DbU::Unit targetY = target->getPosition().getY();
    source->setDistance ( 0 );
    if ( sourceY <= targetY ) {
        // 1st case : monotonic directions : top and right
        // marquing all vertexes which y-coordinates are equal to sourceY
        Vertex* predecessor = source;
        Edge* rightEdge = predecessor->getHEdgeOut();
        while ( rightEdge ) {
            Vertex* currentVertex = rightEdge->getOpposite ( predecessor );
            if ( currentVertex->getPosition().getX() <= targetX ) {
                currentVertex->setDistance ( predecessor->getDistance() + rightEdge->getCost( predecessor->getPredecessor() ) );
                currentVertex->setPredecessor ( rightEdge );
                predecessor = currentVertex;
                rightEdge = predecessor->getHEdgeOut();
            }
            else
                break;
        }
        // marquing all vertexes which x-coordinates are equal to sourceX
        predecessor = source;
        Edge* topEdge = predecessor->getVEdgeOut();
        while ( topEdge ) {
            //while ( topEdge->getNextFrom() != NULL )
            //    topEdge = topEdge->getNextFrom();
            Vertex* currentVertex = topEdge->getOpposite ( predecessor );
            if ( currentVertex->getPosition().getY() <= targetY ) {
                currentVertex->setDistance ( predecessor->getDistance() + topEdge->getCost( predecessor->getPredecessor() ) );
                currentVertex->setPredecessor ( topEdge );
                predecessor = currentVertex;
                topEdge = predecessor->getVEdgeOut();
            }
            else
                break;
        }
        // marquing all others vertexes by column
        predecessor = source;
        rightEdge = predecessor->getHEdgeOut();
        while ( rightEdge ) {
            Vertex* baseColumn = rightEdge->getOpposite ( predecessor );
            if ( baseColumn->getPosition().getX() <= targetX ) {
                Vertex* vertPred = baseColumn;
                Edge* topEdge = vertPred->getVEdgeOut();
                while ( topEdge ) {
                    Vertex* currentVertex = topEdge->getOpposite ( vertPred );
                    if ( currentVertex->getPosition().getY() <= targetY ) {
                        float vertDistance = (float)(HUGE_VAL);
                        float horzDistance = (float)(HUGE_VAL);

                        vertDistance = vertPred->getDistance() + topEdge->getCost ( vertPred->getPredecessor() );
                        Edge* leftEdge = currentVertex->getHEdgeIn();
                        if ( leftEdge ) {
                            Vertex* horzPred = leftEdge->getOpposite ( currentVertex );
                            horzDistance = horzPred->getDistance() + leftEdge->getCost ( horzPred->getPredecessor() );
                        }

                        if ( vertDistance < horzDistance ) {
                            currentVertex->setDistance ( vertDistance );
                            currentVertex->setPredecessor ( topEdge );
                        }
                        else {
                            currentVertex->setDistance ( horzDistance );
                            currentVertex->setPredecessor ( leftEdge );
                        }

                        vertPred = currentVertex;
                        topEdge = vertPred->getVEdgeOut();
                    }
                    else
                        break;
                }
                predecessor = baseColumn;
                rightEdge = predecessor->getHEdgeOut();
            }
            else
                break;
        }
    }
    else {
        // 2nd case : monotonic directions : down and right
        // marquing all vertexes which y-coordinates are equal to sourceY
        Vertex* predecessor = source;
        Edge* rightEdge = predecessor->getHEdgeOut();
        while ( rightEdge ) {
            Vertex* currentVertex = rightEdge->getOpposite ( predecessor );
            if ( currentVertex->getPosition().getX() <= targetX ) {
                currentVertex->setDistance ( predecessor->getDistance() + rightEdge->getCost ( predecessor->getPredecessor() ) );
                currentVertex->setPredecessor ( rightEdge );
                predecessor = currentVertex;
                rightEdge = predecessor->getHEdgeOut();
            }
            else
                break;
        }
        // marquing all vertexes which x-coordinates are equal to sourceX
        predecessor = source;
        Edge* bottomEdge = predecessor->getVEdgeIn();
        while ( bottomEdge ) {
            //while ( topEdge->getNextFrom() != NULL )
            //    topEdge = topEdge->getNextFrom();
            Vertex* currentVertex = bottomEdge->getOpposite ( predecessor );
            if ( currentVertex->getPosition().getY() >= targetY ) {
                currentVertex->setDistance ( predecessor->getDistance() + bottomEdge->getCost ( predecessor->getPredecessor() ) );
                currentVertex->setPredecessor ( bottomEdge );
                predecessor = currentVertex;
                bottomEdge = predecessor->getVEdgeIn();
            }
            else
                break;
        }
        // marquing all others vertexes by column
        predecessor = source;
        rightEdge = predecessor->getHEdgeOut();
        while ( rightEdge ) {
            Vertex* baseColumn = rightEdge->getOpposite ( predecessor );
            if ( baseColumn->getPosition().getX() <= targetX ) {
                Vertex* vertPred = baseColumn;
                Edge* bottomEdge = vertPred->getVEdgeIn();
                while ( bottomEdge ) {
                    Vertex* currentVertex = bottomEdge->getOpposite ( vertPred );
                    if ( currentVertex->getPosition().getY() >= targetY ) {
                        float vertDistance = (float)(HUGE_VAL);
                        float horzDistance = (float)(HUGE_VAL);

                        vertDistance = vertPred->getDistance() + bottomEdge->getCost ( vertPred->getPredecessor() );
                        Edge* leftEdge = currentVertex->getHEdgeIn();
                        if ( leftEdge ) {
                            Vertex* horzPred = leftEdge->getOpposite ( currentVertex );
                            horzDistance = horzPred->getDistance() + leftEdge->getCost (horzPred->getPredecessor() );
                        }

                        if ( vertDistance < horzDistance ) {
                            currentVertex->setDistance ( vertDistance );
                            currentVertex->setPredecessor ( bottomEdge );
                        }
                        else {
                            currentVertex->setDistance ( horzDistance );
                            currentVertex->setPredecessor ( leftEdge );
                        }

                        vertPred = currentVertex;
                        bottomEdge = vertPred->getVEdgeIn();
                        if (!bottomEdge)
                            break;
                        currentVertex = bottomEdge->getOpposite ( vertPred );
                    }
                    else
                        break;
                }
                predecessor = baseColumn;
                rightEdge = predecessor->getHEdgeOut();
            }
            else
                break;
        }
    }

    // On crée la nouvelle composante connexe à partir du chemin monotone trouvé :
    int sourceID = source->getConnexID();
    Vertex* currentVertex = target;

    while ( Edge* predecessor = currentVertex->getPredecessor() ) {
        currentVertex->setConnexID ( sourceID );
        currentVertex->setNetStamp ( _netStamp );
        predecessor->setConnexID ( sourceID );
        predecessor->setNetStamp ( _netStamp );
        currentVertex = predecessor->getOpposite ( currentVertex );
    }
    source->setNetStamp ( _netStamp );

    assert ( currentVertex == source );

    MaterializeRouting ( source );
    //#if defined ( __USE_DYNAMIC_PRECONGESTION__ )
    if ( __precongestion__ == 2 )
        UpdateEstimateCongestion();
    //#endif
}

FTree* Graph::createFluteTree()
// ****************************
{ 
    int  accuracy = 3;                         // accuracy for flute (by default 3)
    int  d        = _vertexes_to_route.size(); // degre du net, ie nombre de routingPads
    int *x = new int [d];                      // x coordinates of the vertexes
    int *y = new int [d];                      // y coordinates of the vertexes
    FTree* flutetree = new FTree;              // the flute Steiner Tree

    //cout << "Net : " << _working_net << endl;
    // scans _working_net to find x,y coordinates and fill x, y and d
    // parcours des _vertexes_to_route
    VertexSetIter vsit = _vertexes_to_route.begin();
    int cpt = 0;
    while ( vsit != _vertexes_to_route.end() ) {
        Point position = (*vsit)->getPosition();
        x[cpt] = position.getX();
        y[cpt] = position.getY();
        vsit++;
        cpt++;
    }

    assert ( d == cpt );

    *flutetree = flute ( d, x, y, accuracy );
    //printtree ( flutetree );
    //plottree ( flutetree );
    //cout << endl;
    return flutetree;
}

void Graph::UpdateEstimateCongestion ( bool create )
// *************************************************
{
    if ( _vertexes_to_route.size() < 2 )
       return;
    if ( _vertexes_to_route.size() >= FLUTE_LIMIT ) {
      if ( create )
        cerr << Warning( "Graph::UpdateEstimateCongestion(): %s\n"
                        "          has more than %d vertex/terminals and cannot be handled by FLUTE."
                       , getString(_working_net).c_str(), FLUTE_LIMIT ) << endl;
      return;
    }
    //cerr << "Running FLUTE for net : " << _working_net << endl;
    auto_ptr<FTree> flutetree ( createFluteTree() );

    //parcours des branches du FTree pour créer la congestion estimée
    for ( int i = 0 ; i < 2*flutetree->deg-2 ; i++ ) {
//        int sourceX = flutetree->branch[i].x;
//        int sourceY = flutetree->branch[i].y;
//        int targetX = flutetree->branch[flutetree->branch[i].n].x;
//        int targetY = flutetree->branch[flutetree->branch[i].n].y;
        Vertex* source = getVertex ( flutetree->branch[i].x                     , flutetree->branch[i].y );
        Vertex* target = getVertex ( flutetree->branch[flutetree->branch[i].n].x, flutetree->branch[flutetree->branch[i].n].y );
        assert ( source );
        assert ( target );
        //Si source et target alignée -> ajoute 1 a toutes les edges sur le chemin
        if ( source->isVerticallyAligned ( target ) ) {
            sortVVertexes ( source, target );
            Vertex* currentVertex = source;
            while ( currentVertex != target ) {
                Edge* edge = currentVertex->getVEdgeOut();
                assert ( edge );
                edge->addSubEstimateOccupancy ( 1.0, create );
                currentVertex = edge->getOpposite ( currentVertex );
                assert ( currentVertex );
            }
        }
        else if ( source->isHorizontallyAligned ( target ) ) {
            sortHVertexes ( source, target );
            Vertex* currentVertex = source;
            while( currentVertex != target ) {
                Edge* edge = currentVertex->getHEdgeOut();
                assert ( edge );
                edge->addSubEstimateOccupancy ( 1.0, create );
                currentVertex = edge->getOpposite ( currentVertex );
                assert ( currentVertex );
            }
        }
        else {
            sortHVertexes ( source, target );
            if ( source->getY() < target->getY() ) {
                // 1st case :
                //  +-------T       +-------T               T
                //  |       |       |                       |
                //  |       |   =   |  0.5      +      0.5  |
                //  |       |       |                       |
                //  S-------+       S               S-------+
                Vertex* currentVertex = source;
                while ( currentVertex->getY() < target->getY() ) {
                    Edge* edge = currentVertex->getVEdgeOut();
//                    assert ( edge );
                    edge->addSubEstimateOccupancy ( 0.5, create );
                    currentVertex = edge->getOpposite ( currentVertex );
//                    assert ( currentVertex );
                }
                while ( currentVertex != target ) {
                    Edge* edge = currentVertex->getHEdgeOut();
//                    assert ( edge );
                    edge->addSubEstimateOccupancy ( 0.5, create );
                    currentVertex = edge->getOpposite ( currentVertex );
//                    assert ( currentVertex );
                }
                currentVertex = source;
                while ( currentVertex->getX() < target->getX() ) {
                    Edge* edge = currentVertex->getHEdgeOut();
//                    assert ( edge );
                    edge->addSubEstimateOccupancy ( 0.5, create );
                    currentVertex = edge->getOpposite ( currentVertex );
//                    assert ( currentVertex );
                }
                while ( currentVertex != target ) {
                    Edge* edge = currentVertex->getVEdgeOut();
//                    assert ( edge );
                    edge->addSubEstimateOccupancy ( 0.5, create );
                    currentVertex = edge->getOpposite ( currentVertex );
//                    assert ( edge );
                }
            }
            else {
                // 2nd case :
                //  S-------+       S               S-------+
                //  |       |       |                       |
                //  |       |   =   |  0.5      +      0.5  |
                //  |       |       |                       |
                //  +-------T       +-------T               T
                Vertex* currentVertex = source;
                while ( currentVertex->getY() > target->getY() ) {
                    Edge* edge = currentVertex->getVEdgeIn();
//                    assert ( edge );
                    edge->addSubEstimateOccupancy ( 0.5, create );
                    currentVertex = edge->getOpposite ( currentVertex );
//                    assert ( currentVertex );
                }
                while ( currentVertex != target ) {
                    Edge* edge = currentVertex->getHEdgeOut();
//                    assert ( edge );
                    edge->addSubEstimateOccupancy ( 0.5, create );
                    currentVertex = edge->getOpposite ( currentVertex );
//                    assert ( currentVertex );
                }
                currentVertex = source;
                while ( currentVertex->getX() < target->getX() ) {
                    Edge* edge = currentVertex->getHEdgeOut();
//                    assert ( edge );
                    edge->addSubEstimateOccupancy ( 0.5, create );
                    currentVertex = edge->getOpposite ( currentVertex );
//                    assert ( currentVertex );
                }
                while ( currentVertex != target ) {
                    Edge* edge = currentVertex->getVEdgeIn();
//                    assert ( edge );
                    edge->addSubEstimateOccupancy ( 0.5, create );
                    currentVertex = edge->getOpposite ( currentVertex );
//                    assert ( edge );
                }
            }
        }
    }
}

void Graph::UpdateMaxEstimateCongestion()
// **************************************
{
    Vertex* currentVertex = _lowerLeftVertex;
    while ( currentVertex ) {
        Vertex* firstLineVertex = currentVertex;
        while ( currentVertex ) {
            Edge* hEdgeOut = currentVertex->getHEdgeOut();
            unsigned max     = 0;
            float    maxEsti = 0.0;
            if ( hEdgeOut ) {
                unsigned maxX     = hEdgeOut->getRealOccupancy();
                float    maxXEsti = hEdgeOut->getEstimateOccupancy();
                max     += maxX;
                maxEsti += maxXEsti;
                if ( maxX > _maxXOccupancy )
                    _maxXOccupancy = maxX;
                if ( maxXEsti > _maxXEstimateOccupancy )
                    _maxXEstimateOccupancy = maxXEsti;
            }
            Edge* vEdgeOut = currentVertex->getVEdgeOut();
            if ( vEdgeOut ) {
                unsigned maxY     = vEdgeOut->getRealOccupancy();
                float    maxYEsti = vEdgeOut->getEstimateOccupancy();
                max     += maxY;
                maxEsti += maxYEsti;
                if ( maxY > _maxYOccupancy )
                    _maxYOccupancy = maxY;
                if ( maxYEsti > _maxYEstimateOccupancy )
                    _maxYEstimateOccupancy = maxYEsti;
            }
            if ( max > _maxOccupancy )
                _maxOccupancy = max;
            if ( maxEsti > _maxEstimateOccupancy )
                _maxEstimateOccupancy = maxEsti;

            if ( hEdgeOut )
                currentVertex = hEdgeOut->getOpposite ( currentVertex );
            else
                break;
        }
        Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
        if ( vEdgeOut )
            currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
        else
            break;
    }
}


Edge* Graph::getEdge ( unsigned col1, unsigned row1, unsigned col2, unsigned row2 )
// ********************************************************************************
{
  Edge* edge = NULL;

  if ( col1 == col2 ) {
    if ( row1 == row2 ) 
      throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be different." );

    Vertex* bottomVertex = NULL;
    Vertex* topVertex    = NULL;

    if ( ( row1 < row2 ) && ( row2 == row1 + 1 ) ) {
      bottomVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
      topVertex    = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row2) );
    } else if ( row1 == row2 + 1 ) {
      bottomVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row2) );
      topVertex    = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
    } else
      throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be contiguous." );

    edge = bottomVertex->getVEdgeOut();
    assert ( edge->getOpposite(bottomVertex) == topVertex );
  } else if ( row1 == row2 ) {
    Vertex* leftVertex  = NULL;
    Vertex* rightVertex = NULL;

    if ( ( col1 < col2 ) && ( col2 == col1 + 1 ) ) {
      leftVertex  = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
      rightVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col2, row1) );
    } else if ( col1 == col2 + 1 ) {
      leftVertex  = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col2, row1) );
      rightVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
    } else
      throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be contiguous." );

    edge = leftVertex->getHEdgeOut();
    assert ( edge->getOpposite(leftVertex) == rightVertex );
  } else
    throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be vertically or horizontally aligned." );

  return edge;
}


void Graph::UpdateEdgeCapacity ( unsigned col1, unsigned row1, unsigned col2, unsigned row2, unsigned cap )
// ********************************************************************************************************
{
  getEdge ( col1, row1, col2, row2 )->setCapacity ( cap );
}


void Graph::increaseEdgeCapacity ( unsigned col1, unsigned row1, unsigned col2, unsigned row2, int cap )
// *****************************************************************************************************
{
  getEdge ( col1, row1, col2, row2 )->increaseCapacity ( cap );
}


void Graph::updateEdgesOccupancy ( Segment* segment, bool add )
// ************************************************************
{
    if ( Horizontal* horiz = dynamic_cast<Horizontal*>(segment) ) {
        Vertex* currentVertex = _matrixVertex->getVertex ( Point ( horiz->getSourceX(), horiz->getY() ) );
        Vertex* targetVertex  = _matrixVertex->getVertex ( Point ( horiz->getTargetX(), horiz->getY() ) );
        while ( currentVertex != targetVertex ) {
            Edge* edge = currentVertex->getHEdgeOut();
            assert ( edge );
            if ( add )
                edge->insertSegment ( segment );
            else
                edge->removeSegment ( segment );
            currentVertex = edge->getOpposite ( currentVertex );
            assert ( currentVertex );
        }
    }
    else if ( Vertical* verti = dynamic_cast<Vertical*>(segment) ) {
        Vertex* currentVertex = _matrixVertex->getVertex ( Point ( verti->getX(), verti->getSourceY() ) );
        Vertex* targetVertex  = _matrixVertex->getVertex ( Point ( verti->getX(), verti->getTargetY() ) );
        while ( currentVertex != targetVertex ) {
            Edge* edge = currentVertex->getVEdgeOut();
            assert ( edge );
            if ( add )
                edge->insertSegment ( segment );
            else
                edge->removeSegment ( segment );
            currentVertex = edge->getOpposite ( currentVertex );
            assert ( currentVertex );
        }
    }
}

void Graph::rebuildConnexComponent ( Contact* contact, int connexID, Segment* arrivalSegment )
// *******************************************************************************************
{
    //CEditor* editor = getCEditor ( _nimbus->getCell() );
    Vertex* contactVertex = getVertex ( contact->getCenter() );
    contactVertex->setContact  ( contact );
    contactVertex->setConnexID ( connexID );
    contactVertex->setNetStamp ( _netStamp );
    contactVertex->setDistance((float)(HUGE_VAL));
    contactVertex->setPredecessor(NULL);
    //cerr << "from :" << contact << endl;
    //cerr << "arrivalSegment: " << arrivalSegment << endl;
    for_each_component ( component, contact->getSlaveComponents() ) {
        if ( dynamic_cast<Segment*>(component) ) {
            Segment* segment = static_cast<Segment*>(component);
            //cerr << " a segment " << segment << endl;
            //editor->Stop("Guess what to do");
            if ( segment == arrivalSegment ) continue;
            //cerr << "    not arrivalSegment -> setNetStampConnexID" << endl;
            setNetStampConnexID ( segment, connexID );
            //cerr << "    done" << endl;
            if ( !dynamic_cast<Contact*>( segment->getOppositeAnchor(contact) ) )
              throw Error ("Graph::rebuildConnexComponent(): For the moment we do not consider Segments that anchors on something else than a Contact.");
            Contact* oppositeContact = static_cast<Contact*>(segment->getOppositeAnchor(contact));
            //cerr << "    now recursive call on oppositeContact: " << oppositeContact << endl;
            //editor->Stop("See what has been done");
            rebuildConnexComponent ( oppositeContact, connexID, segment );
            //cerr << "    done" << endl;
        }
        end_for;
    }
}

void Graph::setNetStampConnexID ( Segment* segment, int connexID ) 
// ***************************************************************
{
    unsigned int sourceColumnIdx = _matrixVertex->getColumnIndex ( segment->getSourceX() );
    unsigned int sourceLineIdx   = _matrixVertex->getLineIndex   ( segment->getSourceY() );
    unsigned int targetColumnIdx = _matrixVertex->getColumnIndex ( segment->getTargetX() );
    unsigned int targetLineIdx   = _matrixVertex->getLineIndex   ( segment->getTargetY() );

    if ( sourceColumnIdx == targetColumnIdx ) { // vertical segment
        for ( unsigned line = sourceLineIdx ; line < targetLineIdx ; line++ ) {
            Vertex* vertex = _matrixVertex->getVertexFromIndexes ( line, sourceColumnIdx );
            assert(vertex);
            vertex->setNetStamp ( _netStamp );
            vertex->setConnexID ( connexID );
            vertex->setDistance((float)(HUGE_VAL));
            Edge* edge = vertex->getVEdgeOut();
            assert(edge);
            edge->setNetStamp ( _netStamp );
            edge->setConnexID ( connexID );
        }
        Vertex* vertex = _matrixVertex->getVertexFromIndexes ( targetLineIdx, targetColumnIdx );
        assert(vertex);
        vertex->setNetStamp ( _netStamp );
        vertex->setConnexID ( connexID );
        vertex->setDistance((float)(HUGE_VAL));
        return;
    }
    if ( sourceLineIdx == targetLineIdx ) { // horizontal segment
        for ( unsigned column = sourceColumnIdx ; column < targetColumnIdx ; column++ ) {
            Vertex* vertex = _matrixVertex->getVertexFromIndexes ( sourceLineIdx, column );
            assert(vertex);
            vertex->setNetStamp ( _netStamp );
            vertex->setConnexID ( connexID );
            vertex->setDistance((float)(HUGE_VAL));
            Edge* edge = vertex->getHEdgeOut();
            assert(edge);
            edge->setNetStamp ( _netStamp );
            edge->setConnexID ( connexID );
        }
        Vertex* vertex = _matrixVertex->getVertexFromIndexes ( targetLineIdx, targetColumnIdx );
        assert(vertex);
        vertex->setNetStamp ( _netStamp );
        vertex->setConnexID ( connexID );
        vertex->setDistance((float)(HUGE_VAL));
        return;
    }
    throw Error ( "Graph::setNetStampConnexId(): what sort of segment is that, a diagonal one?" );
}

void Graph::insertSegment ( Segment* segment )
// *******************************************
{
    updateEdgesOccupancy ( segment, true );
}

void Graph::removeSegment ( Segment* segment )
// *******************************************
{
    updateEdgesOccupancy ( segment, false );
}

float Graph::getSegmentCost ( Segment* segment )
// *********************************************
{
    unsigned nbDep = 0;
    unsigned nbTot = 0;
    unsigned sumDep = 0;
    Vertex* currentVertex = getVertex ( segment->getSourcePosition() );
    Vertex* targetVertex = getVertex ( segment->getTargetPosition() );
    if ( segment->getSourceY() == segment->getTargetY() ) { // which means : if it's a horizontal segment
        while ( currentVertex != targetVertex ) { // attention pour faire simple on code pour un grpahe regulier
            Edge* edge = currentVertex->getHEdgeOut(); // il faudrait choisir la bonne HEdgeOut pour un graphe irregulier
            unsigned ov = edge->getOverflow();
            if ( ov ) {
                nbDep++;
                sumDep += ov;
            }
            nbTot++;
            currentVertex = edge->getOpposite ( currentVertex );
        }
    }
    else {
        while ( currentVertex != targetVertex ) {
            Edge* edge = currentVertex->getVEdgeOut();
            unsigned ov = edge->getOverflow();
            if ( ov ) {
                nbDep++;
                sumDep += ov;
            }
            nbTot++;
            currentVertex = edge->getOpposite ( currentVertex );
        }
    }
    if ( !nbTot )
        return 0;
    return (float(nbDep)/float(nbTot))*sumDep;
}

unsigned Graph::analyseRouting ( set<Segment*>& segmentsToUnroute )
// ****************************************************************
{
    // This function construct the list of segments that participate to congestion
    // empty Priority queue : easier than update each semgent when removing a semgent ...
    clearSTuplePQ();
    // 30/01/09 on  remplace le parcours  des nets/segments par un  parcours des
    // edges avec un map trié sur pointeur de segments et définissant un record:
    // nbDep nBTot + sumOv pour chaque segment.
    unsigned nbEdgesTot = 0;
    unsigned nbEdgesOv = 0;
    unsigned overflow = 0;
    unsigned maxOv = 0;
    unsigned wirelength = 0;
    unsigned viaWirelength = 0;
    map<Segment*, segmentStat> segmentsMap;
    for ( unsigned i = 0 ; i < _all_edges.size() ; i++ ) 
    {
        Edge* edge = _all_edges[i];
        nbEdgesTot++;
        if ( edge->isCongested() ) {
            nbEdgesOv++;
            unsigned edgeOv = 2*edge->getOverflow();
            overflow += edgeOv;
            maxOv = edgeOv > maxOv ? edgeOv : maxOv;
            edge->addSubEstimateOccupancy ( HISTORIC_INC, true ); // add historic cost for each overflowed edge
        }
        forEach ( Segment*, segment, edge->getSegments() ) {
            map<Segment*, segmentStat>::iterator it = segmentsMap.find(*segment);
            if ( it != segmentsMap.end() ) {
                (*it).second.incNbTot();
                if ( edge->isCongested() ) {
                    (*it).second.incNbDep();
                    (*it).second.incSumOv(edge->getOverflow());
                }
            }
            else {
                if ( edge->isCongested() )
                    segmentsMap[*segment]=segmentStat(1,1,edge->getOverflow());
                else
                    segmentsMap[*segment]=segmentStat(0,1,0);
            }
        }
    }

    unsigned nbDep = 0;
    unsigned nbTot = 0;
    float minimalCost = 0;
    float maximalCost = 0;
    for ( map<Segment*, segmentStat>::iterator it = segmentsMap.begin() ; it != segmentsMap.end() ; it++ ) {
      assert( (*it).second.getNbTot() != 0 );

      nbTot++;
      wirelength += getGridLength( (*it).first );
      float segmentCost = (float((*it).second.getNbDep()) / float((*it).second.getNbTot())) * (*it).second.getSumOv();
      if ( segmentCost ) {
        if (minimalCost == 0)
          minimalCost = segmentCost;
        minimalCost = segmentCost < minimalCost ? segmentCost : minimalCost;
        maximalCost = segmentCost > maximalCost ? segmentCost : maximalCost;

        STuple* stuple = STuple::create((*it).first, segmentCost);
        addToSTuplePQ(stuple);
        nbDep++;
      }
    }

    forEach ( Net*, net, _cell->getNets() ) {
        forEach ( Contact*, contact, net->getContacts() ) {
            const Layer* cLayer = contact->getLayer();
            if ( cLayer == Configuration::getGContact() || cLayer == Configuration::getGMetalV()  )
                viaWirelength += 3;
        }
    }
    //forEach ( Net*, net, _cell->getNets() ) {
    //    forEach ( Segment*, segment, net->getSegments() ) {
    //        if ( isAGlobalRoutingSegment ( *segment ) ) {
    //            float segmentCost = getSegmentCost ( *segment );
    //            if ( segmentCost ) {
    //                nbDep++;
    //                STuple* stuple = NULL;
    //                // si une CostProperty est attaché au segment et que son iterateur est différent de _stuplePQEnd
    //                //    on recupere le STuple
    //                // sinon on cree un stuple
    //                Hurricane::Property* property = segment->getProperty ( STuple::CostProperty::_name );
    //                if ( STuple::CostProperty* cprop = dynamic_cast<STuple::CostProperty*>(property) ) {
    //                    STuple::STuplePQIter pqit = cprop->getPQIter();
    //                    if ( pqit != STuple::_stuplePQEnd )
    //                        stuple = (*pqit);
    //                }
    //                if ( !stuple )
    //                    stuple = STuple::create ( *segment, segmentCost );
    //                addToSTuplePQ ( stuple );
    //            }
    //            nbTot++;
    //        }
    //    }
    //}

    cmess2 << "                     # of Overcapacity edges:" << nbEdgesOv
           <<                    "  (tot.:" << nbEdgesTot << ")" << endl;
    cmess2 << "                     # of Overflow:" << overflow
           <<                    "  Max. overflow:" << maxOv
           <<                    "  Avg. overflow:" << (float)overflow / (float)nbEdgesTot << endl;
    cmess2 << "                     # of Overflowed edges: " << nbDep << " (tot.:" << nbTot << ")" << endl; 
    cmess2 << "                     gHPWL:" << wirelength
           <<                    "  # of VIAs:" << viaWirelength/3
           <<                    "  Tot. wirelength:" << wirelength + viaWirelength << endl;


    // cmess1 << "     o  Analyse routing :" << endl
    //        << "        - Number of overcapacity edges : " << nbEdgesOv << " / " << nbEdgesTot << endl
    //        << "        - # of overflow : " << overflow << endl
    //        << "        - max of overflow : " << maxOv << endl
    //        << "        - avg overflow : " << (float)overflow / (float)nbEdgesTot << endl
    //        << "        - grid wirelength : " << wirelength << endl
    //        << "        - # of via : " << viaWirelength/3 << endl
    //        << "        - total wirelength : " << wirelength + viaWirelength << endl
    //        << "        - Overflowed segments : " << nbDep << " / " << nbTot << endl;
    // construct the list on segments to unroute
    if ( _stuplePriorityQueue.empty() ) {
    //cmess1 << "        - Nothing to reroute !" << endl;
    //cmess1 << "        - Maximum segment cost : 0" << endl;
    }
    else {
        STuple* topSTuple = getMaxFromSTuplePQ();
        float maxCost = topSTuple->getCost();
      //cmess1 << "        - Maximum segment cost : " << maxCost << endl;
        float minCost = 0.20;
        if (_stuplePriorityQueue.size() <= 100)
            minCost = 0.0;
        //if ( maxCost > 1 )
        //    minCost = maxCost * 0.20;
        
        //cmess1 << "        - Minimum segment cost considered : " << minCost << endl;
        //cmess1 << "        - Minimal computed segment cost : " << minimalCost << endl
        //       << "        - Maximal computed segment cost : " << maximalCost << endl;
        segmentsToUnroute.insert ( topSTuple->getSegment() );
        //debugName = topSTuple->getSegment()->getNet()->getName();
        popMaxFromSTuplePQ();
        topSTuple = getMaxFromSTuplePQ();
        //bool fullSkim = true;
        //printSTuplePQ();
        while ( topSTuple != NULL ) {
            if ( topSTuple->getCost() >= minCost ) {
                segmentsToUnroute.insert ( topSTuple->getSegment() );
                popMaxFromSTuplePQ();
                topSTuple = getMaxFromSTuplePQ();
            }
            else {
                //fullSkim = false;
                break;
            }
        }
        //cerr << "        - fullSkim : " << fullSkim << endl;
        //printSTuplePQ();
    }
    return overflow;
}

void Graph::getHorizontalCutLines ( vector<DbU::Unit>& horizontalCutLines )
// ************************************************************************
{
    horizontalCutLines.clear();
    Vertex* currentVertex = _lowerLeftVertex;
    horizontalCutLines.push_back ( currentVertex->getYMin() );
    while ( currentVertex ) {
        horizontalCutLines.push_back ( currentVertex->getYMax() );
        Edge* edge = currentVertex->getVEdgeOut();
        if ( edge )
            currentVertex = edge->getTo();
        else
            break;
    }
}

void Graph::getVerticalCutLines ( vector<DbU::Unit>& verticalCutLines )
// ********************************************************************
{
    verticalCutLines.clear();
    Vertex* currentVertex = _lowerLeftVertex;
    verticalCutLines.push_back ( currentVertex->getXMin() );
    while ( currentVertex ) {
        verticalCutLines.push_back ( currentVertex->getXMax() );
        Edge* edge = currentVertex->getHEdgeOut();
        if ( edge)
            currentVertex = edge->getTo();
        else
            break;
    }
}

bool Graph::hasGlobalRouting ( RoutingPad* routingPad )
// ****************************************************
{
    Hook* rpHook = routingPad->getBodyHook();
    Vertex* rpVertex = _matrixVertex->getVertex ( routingPad->getX(), routingPad->getY() );
    Hook* currentHook = rpHook->getNextHook();
    while ( currentHook != rpHook ) {
        if ( dynamic_cast<Segment::TargetHook*>(currentHook) ) {
            Segment* seg = dynamic_cast<Segment*>(currentHook->getComponent());
            if ( getVertex ( seg->getTargetX(), seg->getTargetY() ) == rpVertex )
                return true;
        }
        if ( dynamic_cast<Segment::SourceHook*>(currentHook) ) {
            Segment* seg = dynamic_cast<Segment*>(currentHook->getComponent());
            if ( getVertex ( seg->getSourceX(), seg->getSourceY() ) == rpVertex )
                return true;
        }
        currentHook = currentHook->getNextHook();
    }
    return false;
}

bool Graph::isAGlobalRoutingContact ( Contact* contact )
// *****************************************************
{
    if ( contact->getLayer() == Configuration::getGMetalH () ) return true;
    if ( contact->getLayer() == Configuration::getGMetalV () ) return true;
    if ( contact->getLayer() == Configuration::getGContact() ) return true;
    return false;
}

bool Graph::isAGlobalRoutingSegment ( Segment* segment )
// *****************************************************
{
    if ( segment->getLayer() == Configuration::getGMetalH () ) return true;
    if ( segment->getLayer() == Configuration::getGMetalV () ) return true;
    return false;
}

static void setContactLayer(Contact* contact)
// ******************************************
{
	bool alu2Used = false;
	bool alu3Used = false;

	for_each_hook(hook, contact->getBodyHook()->getHooks()) {
		Component* component = hook->getComponent();
		if (dynamic_cast<Segment*>(component) || dynamic_cast<RoutingPad*>(component)) {
			const Layer* layer = component->getLayer();
            if      (layer == Configuration::getGMetalH() || layer == Configuration::getPinMetal() ) alu2Used = true;
            else if (layer == Configuration::getGMetalV() )   alu3Used = true;
            //else    assert(false);   // makes non ispd07 benchs failed....
		}
		end_for;
	}

	const Layer* layer = NULL;
    if ( alu2Used ) {
        if ( alu3Used )
          layer = Configuration::getGContact();
        else
            layer = Configuration::getGMetalH();
    }
    else if ( alu3Used ) {
      layer = Configuration::getGMetalV();
    }
    else
        assert ( false );

    contact->setLayer(layer);
}

void Graph::MaterializeRouting ( Vertex* vertex )
// **********************************************
{
    // This function materializes the routing of the connexe component passed as argument
    
    countMaterialize++;

    //if ( debugging ) {
    //    cerr << "    Materialize routing" << endl;
    //    CEditor* editor = getCEditor( _nimbus->getCell() );
    //    editor->Refresh();
    //    string stopMessage = "MaterializeRouting, starting vertex: ";
    //    stopMessage += getString ( vertex );
    //    editor->Stop(stopMessage);
    //}
    
    depthMaterialize = 0;
    //cerr << "INITIAL CALL of materialize routing for net : " << _working_net << endl;
    Edge*    arrivalEdge = NULL;
    Contact* initContact = NULL;
    if ( _useSegments ) {
        initContact = vertex->getContact ( arrivalEdge );
        assert ( initContact ); // must be != NULL because the source vertex must have a routingPad !
    }

    MaterializeRouting ( vertex, arrivalEdge, initContact );
}

void Graph::MaterializeRouting ( Vertex* vertex, Edge* arrivalEdge, Contact* initialContact )
// ******************************************************************************************
{
    depthMaterialize++;
    int vertexConnex = vertex->getConnexID();
    assert ( vertexConnex != -1 );
    //cerr << "--> check in MaterializeRouting " << endl;
    //checkGraphConsistency();
    //cerr << "    MR:" << depthMaterialize << ": vertex " << vertex << endl;
    
    //add for test ofnew MaterializeRouting 03/09/2997 d2
    if ( _useSegments ) {
        for ( unsigned i = 0 ; i < 4 ; i++ ) {
            if ( Edge* edge = vertex->getFirstEdges ( i ) ) {
                if ( edge == arrivalEdge )
                    continue;
                if ( (edge->getNetStamp() == _netStamp) && (edge->getConnexID() == vertexConnex) ) {
                    Vertex* oppositeVertex = edge->getOpposite ( vertex );
                    Contact* reachedContact = oppositeVertex->getContact(edge);
                    Edge* straightArrivalEdge = edge;
                    vector<Edge*> crossedEdges; 
                    crossedEdges.push_back(edge);
                    while ( reachedContact == NULL ) {
                        straightArrivalEdge = oppositeVertex->getFirstEdges(i);
                        if ( straightArrivalEdge == NULL )
                            throw Error ( "Graph:MaterializeRouting(): Cannot continue straight on." );
                        oppositeVertex = straightArrivalEdge->getOpposite ( oppositeVertex );
                        reachedContact = oppositeVertex->getContact ( straightArrivalEdge );
                        //straightArrivalEdge->incOccupancy(); // put the incOccupancy in insertSegment function
                        crossedEdges.push_back(straightArrivalEdge);
                    }
                    // test pour ne pas recreer le routage preexistant en cas de reroutage
                    bool alreadyExist = false;
                    for_each_component ( component, initialContact->getSlaveComponents() ) {
                        if ( dynamic_cast<Segment*>(component) ) {
                            Segment* seg = static_cast<Segment*>(component);
                            if ( seg->getOppositeAnchor(initialContact) == (Component*)(reachedContact) ) {
                                //cerr << "    segment already exists" << endl;
                                alreadyExist = true;
                            }
                        }
                        end_for;
                    }
                    if ( !alreadyExist ) {
                        Segment* segment = createSegment ( initialContact, reachedContact );
                        assert ( segment );
                        for ( unsigned j = 0 ; j < crossedEdges.size(); j++ )
                            crossedEdges[j]->insertSegment(segment);
                    }
                    MaterializeRouting ( oppositeVertex, straightArrivalEdge, reachedContact );
                }
            }
        }
        setContactLayer(initialContact);
    }
    //else {
    //    for_each_edge ( edge, vertex->getAdjacentEdges() ) {
    //        //if ( edge == arrivalEdge)
    //        //    continue;
    //        //cerr << "    MR:" << depthMaterialize<< ":     edge " << edge << endl;
    //        if ( (edge->getNetStamp() == _netStamp) && (edge->getConnexID() == vertexConnex) ) {
    //            edge->createSplitter ( _working_net );
    //            _nbSplitters++;
    //            Hook* hook = edge->getSplitterHook ( vertex );
    //            assert (hook);
    //            if ( Hook* previousHook = vertex->getLocalRingHook() ) // XXX Attention puisqu'on vire le systeme le localRingHook au profit du contact
    //                hook->attach ( previousHook );
    //            vertex->setLocalRingHook ( hook );
    //            if ( edge != arrivalEdge ) {
    //                MaterializeRouting ( edge->getOpposite(vertex), edge);
    //                // cleaning for next routing
    //                edge->setSplitter(NULL);
    //            }
    //        end_for;
    //        }
    //    }
    //}
    // cleaning for next routing
    
    //vertex->setLocalRingHook(NULL);
    vertex->setContact(NULL);
    depthMaterialize--;
}

void Graph::CleanRoutingState()
// ****************************
{
    // Vide la pile
    clearPriorityQueue();

    //// Pour chacun des vertex, on efface le pointeur sur la ronde locale et on reinitialise le connexID, la distance et le predecessor
    //// le vtuple est aussi mis a NULL, c'est pourquoi il faut que la pile ait été vidée avant ( sinon assert )
    //// (XXX mieux vaudrait le faire uniquement pour les vertex touchés par le routage XXX)
    //for ( unsigned i = 0 ; i < _all_vertexes.size() ; i++ ) {
    //    Vertex* vertex = _all_vertexes[i];
    //    assert (vertex);
    //    vertex->setLocalRingHook(NULL);
    //    vertex->setConnexID(-1);
    //    vertex->setDistance((float)(HUGE_VAL));
    //    vertex->setPredecessor(NULL);
    //    assert ( vertex->getVTuple() == NULL );
    //}

    //// Pour chacune des edges, on efface le pointeur sur le splitter (potentiel) et on reinitialise le connexID
    //for ( unsigned i = 0 ; i < _all_edges.size() ; i++ ) {
    //    Edge* edge = _all_edges[i];
    //    assert ( edge );
    //    edge->setSplitter(NULL);
    //    edge->setConnexID(-1);
    //}

    // On vide le set des _vertexes_to_route
    _vertexes_to_route.clear();
    _working_net = NULL;
    _searchingArea.makeEmpty();
}

void Graph::checkGraphConsistency()
// ********************************
{
    bool checkFailed = false;
    unsigned nbEdges= 0;
    for_each_edge ( edge, VectorCollection<Edge*>(_all_edges) ) {
        nbEdges++;
        if ( edge->getNetStamp() > _netStamp ) {
            cerr << "    - " << edge << " netStamp mismatch" << endl;
            checkFailed = true;
        }
        if ( edge->getNetStamp() == _netStamp ) {
            int edgeID = edge->getConnexID();
            if ( edgeID != -1 ) {
                if ( edge->getFrom()->getConnexID() == -1 ) {
                    cerr << "    - from : " << edge->getFrom() << " of " << edge << " : connexID mismatch" << endl;
                    checkFailed = true;
                }
                if ( edge->getTo()->getConnexID() == -1 ) {
                    cerr << "    - to : " << edge->getTo() << " of " << edge << " : connexID mismatch" << endl;
                    checkFailed = true;
                }
                if ( (edge->getFrom()->getConnexID() != edgeID) && (edge->getTo()->getConnexID() != edgeID) ) {
                    cerr << "    - " << edge << " : connexID mismatch" << endl;
                    checkFailed = true;
                }
            }
        }
        end_for
    }
    if ( checkFailed ) {
        cerr << " ************************************" << endl
             << " *  GRAPH CHECK CONSISTENCY FAILED  *" << endl
             << " ************************************" << endl;
    }
}

void Graph::checkEmptyPriorityQueue()
// **********************************
{
    bool checkFailed = false;
    // check empty priority queue
    if ( !_vtuplePriorityQueue.empty() ) {
        checkFailed = true;
        cerr << "    Priority Queue is not empty !!!!" << endl
             << "      stil in queue :" << endl;

        VTuplePQIter pqit = _vtuplePriorityQueue.begin();
        while ( pqit != _vtuplePriorityQueue.end() ) {
            cerr << "      " << (*pqit)->getVertex() << " : " << (*pqit)->getDistance() << endl;
            pqit++;
        }
    }
    //check null vtuple foreach vertex
    unsigned nbVertexes= 0;
    for_each_vertex ( vertex, VectorCollection<Vertex*>(_all_vertexes) ) {
        nbVertexes++;
        if ( vertex->getNetStamp() > _netStamp ) {
            cerr << "    - " << vertex << " netStamp mismatch" << endl;
            checkFailed = true;
        }
        if ( vertex->getVTuple() ) {
            cerr << "    - " << vertex << " still have a vtuple : " << vertex->getVTuple() << endl;
            checkFailed = true;
        }
        end_for
    }
    if ( checkFailed ) {
        cerr << " *********************************************" << endl
             << " *  GRAPH CHECK EMPTY PRIORITY QUEUE FAILED  *" << endl
             << " *********************************************" << endl;
    }

}

// DensityWindow* Graph::createEstimateOccupancyWindow()
// // **************************************************
// {
//     if ( _estimateOccupancyWindow )    return _estimateOccupancyWindow;

//     unsigned int max   = _ySize > _xSize ? _ySize : _xSize;
//     unsigned int scale = (unsigned) ceil(500.0/(double)max);

//     _estimateOccupancyWindow = new DensityWindow ( _xSize, _ySize, 3, "fire", scale );
//     _estimateOccupancyWindow->setName ( 0, "Global Estimate Occupancy" );
//     _estimateOccupancyWindow->setName ( 1, "Horizontal Estimate Occupancy" );
//     _estimateOccupancyWindow->setName ( 2, "Vertical Estimate Occupancy" );

//     return _estimateOccupancyWindow;
// }

// void Graph::UpdateEstimateOccupancyWindow()
// // ****************************************
// {
//     if ( !_estimateOccupancyWindow )
//         createEstimateOccupancyWindow();

//     _estimateOccupancyWindow->setSlice(0);
//     Vertex* currentVertex = _lowerLeftVertex;
//     int i = 0;
//     int j = 0;
//     while ( currentVertex ) {
//         Vertex* firstLineVertex = currentVertex;
//         i = 0;
//         while ( currentVertex ) {
//             float xEstimateOccupancy = 0.0;
//             Edge* hEdgeOut = currentVertex->getHEdgeOut();
//             if ( hEdgeOut )
//                 xEstimateOccupancy += hEdgeOut->getEstimateOccupancy();
//             float yEstimateOccupancy = 0.0;
//             if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() )
//                 yEstimateOccupancy += vEdgeOut->getEstimateOccupancy();

//             int colorValue  = _maxEstimateOccupancy  != 0 ? (int)(255 * (xEstimateOccupancy + yEstimateOccupancy) / _maxEstimateOccupancy) : 0;
//             int colorXValue = _maxXEstimateOccupancy != 0 ? (int)(255 * xEstimateOccupancy / _maxXEstimateOccupancy) : 0;
//             int colorYValue = _maxYEstimateOccupancy != 0 ? (int)(255 * yEstimateOccupancy / _maxYEstimateOccupancy) : 0;
//             _estimateOccupancyWindow->DrawRectangle(i, j, i, j, colorValue , 0);
//             _estimateOccupancyWindow->DrawRectangle(i, j, i, j, colorXValue, 1);
//             _estimateOccupancyWindow->DrawRectangle(i, j, i, j, colorYValue, 2);
//             i++;
//             if ( hEdgeOut )
//                 currentVertex = hEdgeOut->getOpposite ( currentVertex );
//             else
//                 break;
//         }
//         j++;
//         Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
//         if ( vEdgeOut )
//             currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
//         else
//             break;
//     }
//     _estimateOccupancyWindow->getWindow()->show();
//     return;
// }

//void Graph::printStats()
//// *********************
//{
//    Vertex* currentVertex = _lowerLeftVertex;
//    int   i = 0;
//    int   j = 0;
//    int   nbEdgesTotal = 0;
//    int   nbEdgesOver  = 0;
//
//    unsigned overflow  = 0;
//    unsigned maxOver   = 0;
//    //float maxOver      = 0;
//    //float averageOver  = 0;
//    while ( currentVertex ) {
//        Vertex* firstLineVertex = currentVertex;
//        i = 0;
//        while ( currentVertex ) {
//            Edge* hEdgeOut = currentVertex->getHEdgeOut();
//            if ( hEdgeOut ) {
//                nbEdgesTotal++;
//                int ov = 2*(hEdgeOut->getRealOccupancy() - hEdgeOut->getCapacity()); // 2 = minimum sapcing + minimum width
//                if ( ov > 0 ) {
//                    nbEdgesOver++;
//                    overflow += ov;
//                    maxOver = ov > maxOver ? ov : maxOver;
//                    for_each_segment ( segment, hEdgeOut->getSegments() ) {
//                        Net* net = segment->getNet();
//                        map<Net*, unsigned>::iterator nuit = _netNbOverEdges.find ( net );
//                        if ( nuit != _netNbOverEdges.end() )
//                            (*nuit).second = (*nuit).second + 1;
//                        else
//                            _netNbOverEdges[net] = 1;
//                        end_for;
//                    }
//                }
//                //float tempOver = (float)hEdgeOut->getRealOccupancy() / (float)hEdgeOut->getCapacity();
//                //if ( tempOver > 0.8 ) {
//                //    nbEdgesOver++;
//                //    averageOver += tempOver;
//                //    if ( tempOver > maxOver )    maxOver = tempOver;
//                //}
//            }
//            if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() ) {
//                nbEdgesTotal++;
//                int ov = 2*(vEdgeOut->getRealOccupancy() - vEdgeOut->getCapacity());
//                if ( ov > 0 ) {
//                    nbEdgesOver++;
//                    overflow += ov;
//                    maxOver = ov > maxOver ? ov : maxOver;
//                    for_each_segment ( segment, vEdgeOut->getSegments() ) {
//                        Net* net = segment->getNet();
//                        map<Net*, unsigned>::iterator nuit = _netNbOverEdges.find ( net );
//                        if ( nuit != _netNbOverEdges.end() )
//                            (*nuit).second = (*nuit).second + 1;
//                        else
//                            _netNbOverEdges[net] = 1;
//                        end_for;
//                    }
//                }
//                //float tempOver = (float)vEdgeOut->getRealOccupancy() / (float)vEdgeOut->getCapacity();
//                //if ( tempOver > 0.8 ) {
//                //    nbEdgesOver++;
//                //    averageOver += tempOver;
//                //    if ( tempOver > maxOver )    maxOver = tempOver;
//                //}
//            }
//
//            i++;
//            if ( hEdgeOut )
//                currentVertex = hEdgeOut->getOpposite ( currentVertex );
//            else
//                break;
//        }
//        j++;
//        Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
//        if ( vEdgeOut )
//            currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
//        else
//            break;
//    }
//    //averageOver = nbEdgesOver == 0 ? 0 : averageOver / (float)nbEdgesOver;
//    //
//
//    cerr << "        - Total number of edges : " << nbEdgesTotal << endl
//         << "        - Number of overcapacity edges : " << nbEdgesOver << endl
//         << "        - Total calls to Dijkstra : " << countDijkstra << endl
//         << "        - Total calls to Monotonic : " << countMonotonic << endl
//         << "        - Total calls to Materialize : " << countMaterialize << endl
//         << "        - Taille du Graphe de routage : " << _xSize << " x " << _ySize << endl
//         << endl
//         << "        - # of overflow : " << overflow << endl
//         << "        - max of overflow : " << maxOver << endl
//         << "        - # of net with overflow : " << _netNbOverEdges.size() << endl;
//    return;
//}

// DensityWindow* Graph::createOccupancyWindow()
// // ******************************************
// {
//     if ( _occupancyWindow )    return _occupancyWindow;

//     unsigned int max   = _ySize > _xSize ? _ySize : _xSize;
//     unsigned int scale = (unsigned) ceil(500.0/(double)max);

//     _occupancyWindow = new DensityWindow ( _xSize, _ySize, 3, "fire", scale );
//     _occupancyWindow->setName ( 0, "Global Occupancy" );
//     _occupancyWindow->setName ( 1, "Horizontal Occupancy" );
//     _occupancyWindow->setName ( 2, "Vertical Occupancy" );

//     return _occupancyWindow;
// }

// void Graph::UpdateOccupancyWindow()
// // ********************************
// {
//     if ( !_occupancyWindow )
//         createOccupancyWindow();

//     _occupancyWindow->setSlice(0);
//     Vertex* currentVertex = _lowerLeftVertex;
//     int i = 0;
//     int j = 0;
//     while ( currentVertex ) {
//         Vertex* firstLineVertex = currentVertex;
//         i = 0;
//         while ( currentVertex ) {
//             unsigned xOccupancy = 0;
//             Edge* hEdgeOut = currentVertex->getHEdgeOut();
//             if ( hEdgeOut )
//                 xOccupancy += hEdgeOut->getRealOccupancy();
//             unsigned yOccupancy = 0;
//             if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() )
//                 yOccupancy += vEdgeOut->getRealOccupancy();
//             assert(_maxOccupancy);
//             assert(_maxXOccupancy);
//             assert(_maxYOccupancy);
//             _occupancyWindow->DrawRectangle(i, j, i, j, (255 * (xOccupancy + yOccupancy) / _maxOccupancy), 0);
//             _occupancyWindow->DrawRectangle(i, j, i, j, (255 * xOccupancy / _maxXOccupancy), 1);
//             _occupancyWindow->DrawRectangle(i, j, i, j, (255 * yOccupancy / _maxYOccupancy), 2);
//             i++;
//             if ( hEdgeOut )
//                 currentVertex = hEdgeOut->getOpposite ( currentVertex );
//             else
//                 break;
//         }
//         j++;
//         Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
//         if ( vEdgeOut )
//             currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
//         else
//             break;
//     }
//     _occupancyWindow->getWindow()->show();
//     return;
// }

Record* Graph::_getRecord() const
// ************************
{
    Record* record = new Record ( getString ( this ) );

    record->add ( getSlot ( "LowerLeftVertex", _lowerLeftVertex ) );
//    record->add ( getSlot ( "SlicingTree"    , _slicingTree ) );
    record->add ( getSlot ( "WorkingNet"     , _working_net ) );
    record->add ( getSlot ( "SearchingArea"  , _searchingArea ) );
    record->add ( getSlot ( "xSize"          , _xSize ) );
    record->add ( getSlot ( "ySize"          , _ySize ) );
    record->add ( getSlot ( "maxEstimateOccupancy", _maxEstimateOccupancy ) );
    record->add ( getSlot ( "maxXEstimateOccupancy", _maxXEstimateOccupancy ) );
    record->add ( getSlot ( "maxYEstimateOccupancy", _maxYEstimateOccupancy ) );

    return record;
}

string Graph::_getString() const
// *****************************
{
    return   "<" + _TName ( "RoutingGraph" )
           //+ ":" + getString ( _slicingTree )
           + "," + getString ( _xSize )
           + "," + getString ( _ySize )
           + ">";
}

} // namespace Knik