// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2008-2016, All Rights Reserved
//
// +-----------------------------------------------------------------+
// |                   C O R I O L I S                               |
// |      K i t e  -  D e t a i l e d   R o u t e r                  |
// |                                                                 |
// |  Author      :                    Jean-Paul CHAPUT              |
// |  E-mail      :       Jean-Paul.Chaput@asim.lip6.fr              |
// | =============================================================== |
// |  C++ Module  :       "./Manipulator.cpp"                        |
// +-----------------------------------------------------------------+


#include "hurricane/DebugSession.h"
#include "hurricane/Bug.h"
#include "kite/TrackSegment.h"
#include "kite/Track.h"
#include "kite/Tracks.h"
#include "kite/DataNegociate.h"
#include "kite/RoutingPlane.h"
#include "kite/RoutingEvent.h"
#include "kite/SegmentFsm.h"
#include "kite/Manipulator.h"
#include "kite/KiteEngine.h"


namespace {

  using namespace std;
  using namespace Hurricane;
  using namespace Kite;
  using Katabatic::GCell;


// -------------------------------------------------------------------
// Class  :  "LvGCandidate".

  class LvGCandidate {
    public:
      struct Compare : public binary_function<LvGCandidate&,LvGCandidate&,bool> {
          inline bool  operator() ( const LvGCandidate& lhs, const LvGCandidate& rhs ) const;
      };
    public:
      inline                  LvGCandidate ( TrackElement* segment=NULL, Interval overlap=Interval(), size_t terminals=0 );
      inline  TrackElement*   getSegment   () const;
      inline  const Interval& getOverlap   () const;
      inline  size_t          getTerminals () const;
    private:
      TrackElement* _segment;
      Interval      _overlap;
      size_t        _terminals;
  };

  inline  LvGCandidate::LvGCandidate ( TrackElement* segment, Interval overlap, size_t terminals )
    : _segment  (segment)
    , _overlap  (overlap)
    , _terminals(terminals)
  { }

  inline  TrackElement*   LvGCandidate::getSegment   () const { return _segment; }
  inline  const Interval& LvGCandidate::getOverlap   () const { return _overlap; }
  inline  size_t          LvGCandidate::getTerminals () const { return _terminals; }

  inline bool  LvGCandidate::Compare::operator() ( const LvGCandidate& lhs, const LvGCandidate& rhs ) const
  {
    if ( lhs.getTerminals() != rhs.getTerminals() )
      return lhs.getTerminals() < rhs.getTerminals();

    if ( lhs.getOverlap() != rhs.getOverlap() )
      return lhs.getOverlap().getSize() > rhs.getOverlap().getSize();

    return lhs.getSegment()->getAxis() < rhs.getSegment()->getAxis();
  }


}  // Anonymous namespace.


namespace Kite {

  using Hurricane::Bug;

// -------------------------------------------------------------------
// Class  :  "Manipulator".

  Manipulator::Manipulator ( TrackElement* segment, SegmentFsm& S )
    : _segment(segment)
    , _data   (NULL)
    , _event  (NULL)
    , _fsm    (S)
  {
    if (not _segment)
      throw Error( "Manipulator::Manipulator(): cannot build upon a NULL TrackElement." );

    DebugSession::open( _segment->getNet(), 150, 160 );

    _data = _segment->getDataNegociate();
    if (_data) _event = _data->getRoutingEvent();
  }


  Manipulator::~Manipulator ()
  { DebugSession::close(); }


  bool  Manipulator::canRipup ( unsigned int flags ) const
  {
    if (_data) {
      if (not _event or _event->isUnimplemented()) return false;

      unsigned int limit = Session::getKiteEngine()->getRipupLimit(_segment);
      unsigned int count = _data->getRipupCount() + ((flags & NotOnLastRipup) ? 1 : 0);

      return (count < limit);
    }
    return false;
  }


  bool  Manipulator::isCaged ( DbU::Unit axis ) const
  {
    Track* track = _segment->getTrack();
    if ( not track ) return false;

    TrackElement* neighbor = _segment->getPrevious();
    if (neighbor and (neighbor->isFixed() or neighbor->isBlockage())) {
      if (abs(axis - neighbor->getTargetU()) < getPPitch()*2)
        return true;
    }

    neighbor = _segment->getNext();
    if (neighbor and (neighbor->isFixed() or neighbor->isBlockage())) {
      if (abs(axis - neighbor->getSourceU()) < getPPitch()*2)
        return true;
    }

    return false;
  }


  bool  Manipulator::ripup ( unsigned int type, DbU::Unit axisHint )
  {
    cdebug_log(159,0) << "Manipulator::ripup() " << endl;

    if (not canRipup()) return false;

    if (_segment->isFixed()) return false;
    if (_data == NULL) return true;

    _fsm.addAction( _segment, type, axisHint );
    return true;
  }


  bool  Manipulator::ripupPerpandiculars ( unsigned int flags )
  {
    cdebug_log(159,0) << "Manipulator::ripupPerpandiculars() - " << flags << endl;

    bool          success                  = true;
    bool          cagedPerpandiculars      = false;
    Interval      constraints              ( _event->getConstraints() );
    Interval      perpandicularConstraints ( constraints );
    size_t        placedPerpandiculars     = 0;
    unsigned int  parallelActionFlags      = SegmentAction::SelfRipup|SegmentAction::EventLevel4;
    unsigned int  perpandicularActionFlags = SegmentAction::SelfRipupPerpand;

    if (flags & Manipulator::PerpandicularsFirst) {
      parallelActionFlags      &= ~SegmentAction::EventLevel4;
      perpandicularActionFlags |=  SegmentAction::EventLevel4;
      if (flags & Manipulator::ToRipupLimit)
        perpandicularActionFlags |=  SegmentAction::ToRipupLimit;
    } else {
      if (flags & Manipulator::ToRipupLimit)
        parallelActionFlags |=  SegmentAction::ToRipupLimit;
    }

    cdebug_log(159,0) << "Pure constraints: " << constraints << endl;

    Track* track = NULL;
    const vector<TrackElement*>& perpandiculars = _event->getPerpandiculars();

    for ( size_t i=0 ; i < perpandiculars.size() ; i++ ) {
      track = perpandiculars[i]->getTrack();
      if (not track) {
      // The perpandicular is not placed yet.
        if (flags & Manipulator::PerpandicularsFirst) {
          _fsm.addAction( perpandiculars[i], perpandicularActionFlags );
        }
        continue;
      }

      bool dislodgeCaged = false;
      if (Manipulator(perpandiculars[i],_fsm).isCaged(_event->getSegment()->getAxis())) {
        cagedPerpandiculars = true;
        dislodgeCaged       = true;
      }

      placedPerpandiculars++;

    // Try to ripup the perpandicular.
      DataNegociate* data2 = perpandiculars[i]->getDataNegociate();
      cdebug_log(159,0) << "| " << perpandiculars[i] << endl;

      if ( (flags & Manipulator::ToMoveUp) and (data2->getState() < DataNegociate::MoveUp) )
        data2->setState( DataNegociate::MoveUp );
        
      if (Manipulator(perpandiculars[i],_fsm).ripup(perpandicularActionFlags)) {
        if (dislodgeCaged) {
          _event->setAxisHint( _event->getSegment()->getAxis() + _event->getSegment()->getPitch() );
        }
        continue;
      }

    // Cannot ripup the perpandicular, try to ripup it's neigbors.
      size_t begin;
      size_t end;
      track->getOverlapBounds( constraints, begin, end );

      for ( ; (begin < end) ; begin++ ) {
        TrackElement* other = track->getSegment(begin);

        if (other->getNet() == _event->getSegment()->getNet()) continue;

        Interval otherCanonical ( other->getCanonicalInterval() );
        if (not otherCanonical.intersect(constraints)) continue;

      // Try to ripup conflicting neighbor.
        if (Manipulator(other,_fsm).canRipup()) {
          cdebug_log(159,0) << "  | Ripup: " << begin << " " << other << endl;
          _fsm.addAction( other, SegmentAction::OtherRipup );
        } else {
          cdebug_log(159,0) << "Aborted ripup of perpandiculars, fixed or blocked." << endl;
          return false;
        }
      }
    }

    if (cagedPerpandiculars and not placedPerpandiculars) {
      cdebug_log(159,0) << "Aborted ripup of perpandiculars, constraints are due to fixed/blockage." << endl;
      _fsm.addAction( _segment, SegmentAction::SelfRipup );
      return true;
    }

    if (_segment->isLocal() and not placedPerpandiculars) {
      cdebug_log(159,0) << "No placed perpandiculars, tight native constraints, place perpandiculars FIRST." << endl;
      for ( size_t i=0 ; i < perpandiculars.size() ; i++ ) {
        _fsm.addAction( perpandiculars[i], perpandicularActionFlags|SegmentAction::EventLevel4 );
      }
      _fsm.addAction( _segment, parallelActionFlags );
      return true;
    }

    RoutingPlane* plane    = Session::getKiteEngine()->getRoutingPlaneByLayer(_segment->getLayer());
    size_t        tracksNb = 0;

    track = plane->getTrackByPosition(constraints.getVMin());

    if (track and (track->getAxis() < constraints.getVMin())) track = track->getNextTrack();
    for ( ; track && (track->getAxis() <= constraints.getVMax())
          ; track = track->getNextTrack(), tracksNb++ );

    if (_segment->isLocal() and (tracksNb < 2)) success = ripple();

    _fsm.addAction( _segment, parallelActionFlags );
    return success;
  }


  bool  Manipulator::relax ( Interval interval, unsigned int flags )
  {
    interval.inflate( - Session::getExtensionCap(getLayer()) );
    cdebug_log(159,0) << "Manipulator::relax() of: " << _segment << " " << interval << endl; 

    if (_segment->isFixed()) return false;
    if (not interval.intersect(_segment->getCanonicalInterval())) return false;
    if (not _data) return false;

    if (    _segment->isTerminal()
       and (_segment->getLayer() == Session::getRoutingGauge()->getRoutingLayer(1)) ) {
      if (interval.contains(_segment->base()->getAutoSource()->getX())) return false;
      if (interval.contains(_segment->base()->getAutoTarget()->getX())) return false;
    }

    cdebug_tabw(159,1);
    bool success = true;
    bool expand = _segment->isGlobal() and (flags&AllowExpand);
    cdebug_log(159,0) << "Expand:" << expand << endl;

    Katabatic::GCellVector gcells;
    _segment->getGCells( gcells );

    if (gcells.size() < 2 ){
      cerr << Bug( "relax() Cannot break %s,\n      only in %s."
                 , getString(_segment).c_str()
                 , getString(gcells[0]).c_str()
                 ) << endl;
      cdebug_tabw(159,-1);
      return false;
    }

    unsigned int  depth = Session::getRoutingGauge()->getLayerDepth(_segment->getLayer());
    Interval      uside;
    size_t        dogLegCount  = 0;
    size_t        iminconflict = gcells.size();
    size_t        imaxconflict = gcells.size();
    size_t        igcell;

  // Look for closest enclosing min & max GCells indexes.
    for ( igcell=0 ; igcell<gcells.size() ; igcell++ ) {
      uside = gcells[igcell]->getSide(_segment->getDirection());
      cdebug_log(159,0) << "| " << setw(3) << igcell << " " << gcells[igcell] << " uside: " << uside << endl;

      if (uside.contains(interval.getVMin())) {
        iminconflict = igcell;
        cdebug_log(159,0) << "> Min conflict: " << iminconflict << endl;
      }
      if (uside.contains(interval.getVMax())) {
        imaxconflict = igcell;
        cdebug_log(159,0) << "> Max conflict: " << imaxconflict << endl;
      }
    }

  // Expand min & max to enclose GCells of greatest or equal order
  // (i.e. less saturateds)
    bool minExpanded = false;
    bool maxExpanded = false;
    if (expand) {
      if (iminconflict < gcells.size()) {
      //cdebug_log(159,0) << "Expand min" << endl;

        size_t imindensity = 0;
        for ( size_t iexpand=1 ; iexpand<iminconflict ; ++iexpand ) {
          if (not _segment->canDogleg(gcells[iexpand],KtAllowDoglegReuse)) continue;

          // cdebug_log(159,0) << "<GCell [" << iexpand << "]> Density "
          //             << "Density " << Session::getRoutingGauge()->getRoutingLayer(depth)->getName()
          //             << " min. dens.:" << gcells[imindensity]->getDensity(depth)
          //             << " exp. dens.:" << gcells[iexpand    ]->getDensity(depth)
          //             << endl;

          if (gcells[imindensity]->getDensity(depth) - gcells[iexpand]->getDensity(depth) > 1e-3) {
            imindensity = iexpand;
          //cdebug_log(159,0) << "Accepted expand " << imindensity << endl;
          }
        }

        if (iminconflict != imindensity) minExpanded = true;
        iminconflict = (imindensity>0) ? imindensity : gcells.size();
      }

      if (imaxconflict < gcells.size()) {
      //cdebug_log(159,0) << "Expand max" << endl;

        size_t imindensity = imaxconflict;
        for ( size_t iexpand=imaxconflict+1 ; iexpand<gcells.size() ; ++iexpand ) {
          if (not _segment->canDogleg(gcells[iexpand],KtAllowDoglegReuse)) continue;

          // cdebug_log(159,0) << "<GCell [" << iexpand << "]> Density "
          //             << Session::getRoutingGauge()->getRoutingLayer(depth)->getName()
          //             << " min. dens.:" << gcells[imindensity]->getDensity(depth)
          //             << " exp. dens.:" << gcells[iexpand    ]->getDensity(depth)
          //             << endl;

          if (gcells[imindensity]->getDensity(depth) - gcells[iexpand]->getDensity(depth) > 1e-3) {
            imindensity = iexpand;
          //cdebug_log(159,0) << "Accepted expand " << imindensity << endl;
          }
        }
        
        if (imindensity != imaxconflict) maxExpanded = true;
        imaxconflict = (imindensity < gcells.size()) ? imindensity : gcells.size();
      }
    }
    cdebug_log(159,0) <<   "minExpanded:" << minExpanded << " (" << iminconflict
                << ") maxExpanded:" << maxExpanded << " (" << imaxconflict << ")" << endl;

  // Check for full enclosure.
    if (  ( (iminconflict == gcells.size()) and (imaxconflict == gcells.size()  ) )
       or ( (iminconflict == 0)             and (imaxconflict == gcells.size()-1) )) {
      cinfo << "[INFO] Manipulator::relax(): Segment fully enclosed in interval." << endl;
      cdebug_tabw(159,-1);
      return false;
    }

  // Suppress min/max if it's the first/last.
    if ((iminconflict < gcells.size()) and (imaxconflict == gcells.size()-1)) imaxconflict = gcells.size();
    if ((imaxconflict < gcells.size()) and (iminconflict == 0))               iminconflict = gcells.size();

  // Compute number of doglegs and nature of the *first* dogleg.
  // (first can be min or max, second can only be max)
    bool firstDoglegIsMin = false;
    if (iminconflict < gcells.size()) { dogLegCount++; firstDoglegIsMin = true; }
    if (imaxconflict < gcells.size())   dogLegCount++;
    
    switch ( dogLegCount ) {
      case 2:
      // Compact only if the double dogleg is at beginning or end.
        if (iminconflict == imaxconflict) {
          if (iminconflict == 0) {
          // First dogleg is max.
            dogLegCount--;
          } else if (iminconflict == gcells.size()-1) {
            dogLegCount--;
            firstDoglegIsMin = true;
          }
        }
        break;
      case 1: break;
      case 0:
        cerr << Bug( "Manipulator::relax() Can't find a GCell suitable for making dogleg."
                   , getString(interval).c_str() ) << endl;
        cdebug_tabw(159,-1);
        return false;
    }

    cdebug_log(159,0) << "| Has to do " << dogLegCount << " doglegs." << endl;

  // Check of "min is less than one track close the edge" (while not expanded).
  // AND we are on the first GCell AND there's one dogleg only.
    if (not minExpanded and (iminconflict == 0) and (imaxconflict == gcells.size())) {
      cdebug_log(159,0) << "Cannot break in first GCell only." << endl;
      cdebug_tabw(159,-1);
      return false;
    }

  // Check of "min is less than one track close the edge" (while not expanded).
    if ( /*not minExpanded and*/ (iminconflict > 0) and (iminconflict < gcells.size()) ) {
      uside = gcells[iminconflict-1]->getSide(_segment->getDirection());
      cdebug_log(159,0) << "GCell Edge Comparison (min): " << uside
                  << " vs. " << DbU::getValueString(interval.getVMin()) << endl;
    // Ugly: One lambda shrink.
      if (interval.getVMin()-DbU::lambda(1.0) <= uside.getVMax()) {
        cdebug_log(159,0) << "Using previous GCell." << endl;
        iminconflict--;
      }
    }

  // Check if there is only one dogleg AND it's the last one.
    if (not maxExpanded and (iminconflict == gcells.size()) and (imaxconflict == gcells.size()-1)) {
      cdebug_log(159,0) << "Cannot break in last GCell only." << endl;
      cdebug_tabw(159,-1);
      return false;
    }

  // Check of "max is less than one track close the edge" (while not expanded).
    if ((imaxconflict < gcells.size()-1)) {
      uside = gcells[imaxconflict+1]->getSide( _segment->getDirection() );
      cdebug_log(159,0) << "GCell Edge Comparison (max): " << uside
                  << " vs. " << DbU::getValueString(interval.getVMax()) << endl;
      if (interval.getVMax()+getPPitch() >= uside.getVMin()) {
        interval.inflate( 0, getPPitch() );
        cdebug_log(159,0) << "Using next GCell " << interval << endl;
        imaxconflict++;
      }
    }

    size_t ifirstDogleg  = gcells.size();
    size_t isecondDogleg = gcells.size();
    if (not firstDoglegIsMin) {
      ifirstDogleg = imaxconflict;
    } else {
      ifirstDogleg  = iminconflict;
      isecondDogleg = imaxconflict;
    }

  // Making first dogleg.
    cdebug_log(159,0) << "Making FIRST dogleg at " << ifirstDogleg << endl;
    TrackElement*     segment1     = NULL;
    TrackElement*     segment2     = NULL;
    Track*            track        = _segment->getTrack();
    Katabatic::GCell* dogLegGCell  = gcells[ifirstDogleg];
    TrackElement*     dogleg       = NULL;
    DbU::Unit         doglegAxis;
    bool              doglegReuse1 = false;
    bool              doglegReuse2 = false;

  // Try to reuse existing dogleg if broken at either end.
    if (ifirstDogleg == 0)               dogleg = _segment->getSourceDogleg();
    if (ifirstDogleg == gcells.size()-1) dogleg = _segment->getTargetDogleg();
    if (dogleg) {
      cdebug_log(159,0) << "Reusing dogleg." << endl;
      doglegReuse1 = true;
      segment1     = _segment;
    } else {
    // Try to create a new dogleg.
      if (not _segment->canDogleg(dogLegGCell)) {
        cdebug_log(159,0) << "Cannot create FIRST dogleg." << endl;
        cdebug_tabw(159,-1);
        return false;
      }
      _segment->makeDogleg( dogLegGCell, dogleg, segment1 );
    }

    if (firstDoglegIsMin) {
      if (minExpanded) {
        doglegAxis = dogLegGCell->getSide( _segment->getDirection() ).getCenter();
      //cdebug_log(159,0) << "MARK 1 doglegAxis: " << DbU::getValueString(doglegAxis) << endl;
      } else {
        doglegAxis = interval.getVMin() - getPPitch();
      //cdebug_log(159,0) << "MARK 2 doglegAxis: " << DbU::getValueString(doglegAxis) << endl;
      }
    } else {
      if (maxExpanded) {
        doglegAxis = dogLegGCell->getSide( _segment->getDirection() ).getVMin();
      //cdebug_log(159,0) << "MARK 3 doglegAxis: " << DbU::getValueString(doglegAxis) << endl;
      } else {
        doglegAxis = interval.getVMax() + getPPitch() - DbU::fromLambda(1.0);
      //cdebug_log(159,0) << "MARK 4 doglegAxis: " << DbU::getValueString(doglegAxis) << endl;
      }
    }
    if (doglegReuse1) _fsm.addAction( dogleg, SegmentAction::OtherRipup );
    else              dogleg->setAxis( doglegAxis );

  // If event is present, the dogleg is in the current RoutingSet.
    RoutingEvent* event = dogleg->getDataNegociate()->getRoutingEvent();
    if (event) {
      cdebug_log(159,0) << "Set Axis Hint: @" << DbU::getValueString(doglegAxis) << " " << dogleg << endl;
      event->setAxisHint( doglegAxis );
    } else {
      cdebug_log(159,0) << "Dogleg has no RoutingEvent yet." << endl;
    }

  // Making second dogleg.
    if (dogLegCount > 1) {
      cdebug_log(159,0) << "Making SECOND dogleg at " << isecondDogleg
                  << " on " << segment1 << endl;
      
      dogleg      = NULL;
      dogLegGCell = gcells[isecondDogleg];

      if (ifirstDogleg == isecondDogleg) {
        cdebug_log(159,0) << "Double break in same GCell." << endl;
        segment1->setFlags( TElemSourceDogleg );
      }

      if (isecondDogleg == gcells.size()-1) dogleg = segment1->getTargetDogleg();
      if (dogleg) {
        cdebug_log(159,0) << "Reusing dogleg." << endl;
        doglegReuse2 = true;
        segment2     = segment1;
      } else {
      // Try to create a new dogleg.
        if (not segment1->canDogleg(dogLegGCell)) {
          cdebug_log(159,0) << "Cannot create SECOND dogleg." << endl;
          cdebug_tabw(159,-1);
          return false;
        }
        segment1->makeDogleg( dogLegGCell, dogleg, segment2 );
      }
      
      if (maxExpanded) {
        doglegAxis = dogLegGCell->getSide(segment1->getDirection()/*,false*/).getCenter();
      } else {
        doglegAxis = interval.getVMax() + getPPitch();
      }
      if (doglegReuse2) _fsm.addAction( dogleg, SegmentAction::OtherRipup );
      else              dogleg->setAxis( doglegAxis );

    // If event is present, the dogleg is in the current RoutingSet.
      RoutingEvent* event = dogleg->getDataNegociate()->getRoutingEvent();
      if (event) {
        cdebug_log(159,0) << "Set Axis Hint: @" << DbU::getValueString(doglegAxis) << " " << dogleg << endl;
        event->setAxisHint( doglegAxis );
      } else {
        cdebug_log(159,0) << "Dogleg has no RoutingEvent yet." << endl;
      }

    // This cases seems never to occurs.
      const vector<AutoSegment*>& doglegs = Session::getDoglegs();
      for ( size_t i=0 ; i<doglegs.size() ; i++ ) { 
        TrackElement* segment = Session::lookup(doglegs[i]);
        if (not segment->getTrack() and track) {
          cdebug_log(159,0) << "Direct Track insert of: " << segment << endl;
          Session::addInsertEvent( segment, track );
        }
      }
    }

    switch ( dogLegCount ) {
      case 1:
        if (not doglegReuse1) {
          if (firstDoglegIsMin)
            _segment->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true );
          else
            segment1->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true );
        }
        if ((flags & NoDoglegReuse) and (doglegReuse1 or doglegReuse2 ))
          success = false;
        break;
      case 2:
        if (not doglegReuse1)
          _segment->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true );
        if ( not doglegReuse2 )
          segment2->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true );
        break;
    }

    if (_segment->isLocal()) {
      cdebug_log(159,0) << "Reset state of: " << _segment << endl;
      _segment->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true );
    } else {
      cdebug_log(159,0) << "No state reset: " << _segment << endl;
    }

    if ((not doglegReuse1) and segment1 and segment1->isLocal()) {
      cdebug_log(159,0) << "Reset state of: " << segment1 << endl;
      segment1->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true );
    }

    if ((not doglegReuse2) and segment2 and segment2->isLocal()) {
      cdebug_log(159,0) << "Reset state of: " << segment2 << endl;
      segment2->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true );
    }

    cdebug_tabw(159,-1);
    return success;
  }


  bool  Manipulator::insertInTrack ( size_t itrack )
  {
    Track*              track            = _fsm.getTrack(itrack);
    size_t              begin            = _fsm.getBegin(itrack);
    size_t              end              = _fsm.getEnd  (itrack);
    Net*                ownerNet         = _segment->getNet();
    Interval            toFree            (_segment->getCanonicalInterval());
  //Net*                ripupNet         = NULL;
    set<TrackElement*>  canonicals;
    DbU::Unit           rightAxisHint    = 0;
    DbU::Unit           leftAxisHint     = 0;
    bool                leftIntrication  = false;
    bool                rightIntrication = false;
    bool                success          = true;

    cdebug_log(159,0) << "Manipulator::insertInTrack() - " << toFree << endl;

    for ( size_t i = begin ; success && (i < end) ; i++ ) {
      TrackElement* segment2 = track->getSegment(i);

      cdebug_log(159,0) << "* Looking // " << segment2 << endl;

      if ( segment2->getNet() == ownerNet  ) continue;
      if ( not toFree.intersect(segment2->getCanonicalInterval()) ) {
        cdebug_log(159,0) << "No intersection with: " << segment2->getCanonicalInterval() << endl;
        continue;
      }
      if ( segment2->isBlockage() or segment2->isFixed() ) {
        cdebug_log(159,0) << "Ovelap is blockage or fixed." << endl;
        success = false;
        continue;
      }
      // if ( segment2->getId() >= maxId ) {
      //   cdebug_log(159,0) << "Ovelap has an Id superior to AutoSegment::maxId:" << maxId << "." << endl;
      //   continue;
      // }
      // ripupNet = segment2->getNet();

      DataNegociate* data2 = segment2->getDataNegociate();
      if ( !data2 ) {
        cdebug_log(159,0) << "No DataNegociate, ignoring." << endl;
        continue;
      }

      if ( data2->getState() == DataNegociate::MaximumSlack ) {
        cdebug_log(159,0) << "At " << DataNegociate::getStateString(data2)
                    << " for " << segment2 << endl;
        success = false;
        continue;
      }

      bool shrinkLeft  = false;
      bool shrinkRight = false;

      if ( data2->getRightMinExtend() < toFree.getVMin() ) {
        cdebug_log(159,0) << "- Shrink right edge (push left) " << segment2 << endl;
        shrinkRight = true;
        TrackElement* rightNeighbor2 = track->getSegment(i+1);
        if ( rightNeighbor2 && (rightNeighbor2->getNet() == segment2->getNet()) ) {
          Interval interval1 = segment2->getCanonicalInterval();
          Interval interval2 = rightNeighbor2->getCanonicalInterval();

          if ( interval1.intersect(interval2) && (interval2.getVMax() > interval1.getVMax()) )
            shrinkLeft = true;
        }
      }

      if ( data2->getLeftMinExtend() > toFree.getVMax() ) {
        cdebug_log(159,0) << "- Shrink left edge (push right) " << segment2 << endl;
        shrinkLeft = true;
        if ( i > 0 ) {
          TrackElement* leftNeighbor2 = track->getSegment(i-1);
          if ( leftNeighbor2 && (leftNeighbor2->getNet() == segment2->getNet()) ) {
            Interval interval1 = segment2->getCanonicalInterval();
            Interval interval2 = leftNeighbor2->getCanonicalInterval();

            if ( interval1.intersect(interval2) && (interval2.getVMin() < interval1.getVMin()) )
              shrinkRight = true;
          }
        }
      }

      if ( _segment->isLocal() and segment2->isLocal() ) {
        if ( shrinkLeft and shrinkRight ) {
          Interval interval1 = segment2->getCanonicalInterval();
          if ( toFree.getCenter() < interval1.getCenter() ) shrinkRight = false;
          else shrinkLeft = false;
        }
      }

      cdebug_log(159,0) << "- Hard overlap/enclosure/shrink " << segment2 << endl;
      if ( _segment->isStrap() and segment2->isGlobal() ) continue;
      if ( not (success = Manipulator(segment2,_fsm).ripup(SegmentAction::OtherRipup)) )
        continue;

      canonicals.clear ();
      for( TrackElement* segment3
              : segment2->getPerpandiculars().getSubSet(TrackElements_UniqCanonical(canonicals)) ) {
        DataNegociate* data3 = segment3->getDataNegociate();
        if ( not data3 ) continue;

        RoutingEvent* event3 = data3->getRoutingEvent();
        if ( not event3 ) continue;

        if ( not toFree.intersect(event3->getConstraints()) ) {
          cdebug_log(159,0) << "  . " << segment3 << endl;
          continue;
        }

        cdebug_log(159,0) << "  | " << segment3 << endl;

        if ( shrinkRight xor shrinkLeft ) {
          if ( shrinkRight ) {
            if ( not (success=Manipulator(segment3,_fsm)
                     .ripup( SegmentAction::OtherRipupPerpandAndPushAside
                           , toFree.getVMin() - getPPitch()/2
                           )) )
              break;

            if ( event3->getTracksFree() == 1 ) {
              cdebug_log(159,0) << "Potential left intrication with other perpandicular." << endl;
              if ( segment3->getAxis() == segment2->getTargetU() - Session::getExtensionCap(getLayer()) ) {
                leftIntrication = true;
                leftAxisHint    = segment3->getAxis();
              }
            }
          }
          if ( shrinkLeft  ) {
            if ( not (success=Manipulator(segment3,_fsm)
                     .ripup( SegmentAction::OtherRipupPerpandAndPushAside
                           , toFree.getVMax() + getPPitch()/2
                           )) )
              break;
            if ( event3->getTracksFree() == 1 ) {
              cdebug_log(159,0) << "Potential right intrication with other perpandicular." << endl;
              if ( segment3->getAxis() == segment2->getSourceU() + Session::getExtensionCap(getLayer()) ) {
                rightIntrication = true;
                rightAxisHint    = segment3->getAxis();
              }
            }
          }
        } else {
          if ( not (success=Manipulator(segment3,_fsm).ripup( SegmentAction::OtherRipup
                                                              | SegmentAction::EventLevel3
                                                              )) )
            break;
        }
      }
      if ( not success ) break;
    }

    if ( success ) {
      cdebug_log(159,0) << "Manipulator::insertInTrack() success" << endl;

      _fsm.setState  ( SegmentFsm::OtherRipup );
      _fsm.addAction ( _segment
                     , SegmentAction::SelfInsert|SegmentAction::MoveToAxis|SegmentAction::EventLevel4 
                     , _fsm.getCost(itrack).getTrack()->getAxis() );

      unsigned int flags = 0;
      if ( rightIntrication ) flags |= RightAxisHint;
      if ( leftIntrication  ) flags |= LeftAxisHint;
      if ( flags )
        Manipulator(_segment,_fsm).shrinkToTrack(itrack,flags,leftAxisHint,rightAxisHint);
    } else
      _fsm.clearActions ();

    return success;
  }


  bool  Manipulator::forceToTrack ( size_t itrack )
  {
    Track*              track      = _fsm.getTrack(itrack);
    size_t              begin      = _fsm.getBegin(itrack);
    size_t              end        = _fsm.getEnd  (itrack);
    Net*                ownerNet   = _segment->getNet();
    Interval            toFree      (_segment->getCanonicalInterval());
  //Net*                ripupNet   = NULL;
    set<TrackElement*>  canonicals;
    bool                success    = true;

    cdebug_log(159,0) << "Manipulator::forceToTrack() - " << toFree << endl;

    for ( size_t i=begin ; success and (i < end) ; ++i ) {
      TrackElement* segment2 = track->getSegment(i);

      cdebug_log(159,0) << "* Looking // " << segment2 << endl;

      if (segment2->getNet() == ownerNet) continue;
      if (not toFree.intersect(segment2->getCanonicalInterval())) continue;
      if (segment2->isFixed()) {
        success = false;
        continue;
      }
    //ripupNet = segment2->getNet();

      DataNegociate* data2 = segment2->getDataNegociate();
      if (not data2 ) {
        cdebug_log(159,0) << "No DataNegociate, ignoring." << endl;
        continue;
      }

      cdebug_log(159,0) << "- Forced ripup " << segment2 << endl;
      if (not (success=Manipulator(segment2,_fsm).ripup(SegmentAction::OtherRipup)))
        continue;

      canonicals.clear();
      for( TrackElement* segment3
              : segment2->getPerpandiculars().getSubSet(TrackElements_UniqCanonical(canonicals)) ) {
        DataNegociate* data3 = segment3->getDataNegociate();
        if (not data3) continue;

        RoutingEvent* event3 = data3->getRoutingEvent();
        if (not event3) continue;

        if (Manipulator(segment3,_fsm).canRipup())
          _fsm.addAction( segment3, SegmentAction::OtherRipup );
      }
    }

    if (success) {
      _fsm.setState ( SegmentFsm::OtherRipup );
      _fsm.addAction( _segment
                    , SegmentAction::SelfInsert|SegmentAction::MoveToAxis
                    , _fsm.getCost(itrack).getTrack()->getAxis() );
    }

    return success;
  }


  bool  Manipulator::shrinkToTrack ( size_t i, unsigned int flags, DbU::Unit leftAxisHint, DbU::Unit rightAxisHint )
  {
#if THIS_IS_DISABLED
    Track*              track       = _fsm.getTrack(i);
    size_t              begin       = _fsm.getBegin(i);
    size_t              end         = _fsm.getEnd  (i);
    Net*                ownerNet    = _segment->getNet();
    set<TrackElement*>  canonicals;
    bool                success     = true;
    DbU::Unit           leftExtend  = _segment->getSourceU() + Session::getExtensionCap(getLayer());
    DbU::Unit           rightExtend = _segment->getSourceU() - Session::getExtensionCap(getLayer());

    cdebug_log(159,0) << "Manipulator::shrinkToTrack()" << endl;

    if (_segment->isLocal()) return false;
    Interval  shrunkFree = _segment->base()->getMinSpanU();

    cdebug_log(159,0) << "* " << shrunkFree << endl;

    for ( size_t i = begin ; success and (i < end) ; ++i ) {
      TrackElement* segment2 = track->getSegment(i);

      cdebug_log(159,0) << "* Looking // " << segment2 << endl;

      if (segment2->getNet() == ownerNet) continue;
      if (segment2->isFixed()) { success = false; continue; }
      if (not shrunkFree.intersect(segment2->getCanonicalInterval())) continue;

      success = false;
    }

    if (success) {
      set<TrackElement*>           perpandiculars;
      set<TrackElement*>::iterator iperpand;

      DbU::Unit axisHint;
      if (not (flags & LeftAxisHint )) leftAxisHint  = shrunkFree.getCenter();
      if (not (flags & RightAxisHint)) rightAxisHint = shrunkFree.getCenter();

      _segment->getPerpandicularsBound( perpandiculars );
      for ( iperpand = perpandiculars.begin() ; iperpand != perpandiculars.end() ; ++iperpand ) {
        DataNegociate* data2 = (*iperpand)->getDataNegociate();
        if (data2) {
          cdebug_log(159,0) << "| perpandicular bound:" << *iperpand << endl;
          success = Manipulator(*iperpand,_fsm).ripup( SegmentAction::SelfRipupPerpandWithAxisHint );
          if (success) {
            if      ((*iperpand)->getAxis() == leftExtend ) axisHint = leftAxisHint;
            else if ((*iperpand)->getAxis() == rightExtend) axisHint = rightAxisHint;
            else {
              cinfo << "[INFO] Bound Axis is neither left nor right\n      " << (*iperpand) << endl;
              axisHint = shrunkFree.getCenter();
            }

            _fsm.getActions()[_fsm.getActions().size()-1].setAxisHint( axisHint );
          }
        }
      }

      _fsm.addAction( _segment, SegmentAction::SelfInsert );
      _fsm.setState ( SegmentFsm::OtherRipup );

      cdebug_log(159,0) << "Successful shrinkToTrack." << endl;
      return true;
    }
#endif

    return false;
  }


  bool  Manipulator::forceOverLocals ()
  {
    cdebug_log(159,1) << "Manipulator::forceOverLocals()" << endl;

    vector<TrackCost>& costs = _fsm.getCosts();
    size_t itrack = 0;
    for ( ; itrack<costs.size() ; ++itrack ) {
      cdebug_log(159,0) << "Trying itrack:" << itrack << endl;

      if (  costs[itrack].isFixed()
         or costs[itrack].isBlockage()
         or costs[itrack].isInfinite()
         or costs[itrack].isOverlapGlobal() )
        continue;

      bool      success    = true;
      Track*    track      = _fsm.getTrack(itrack);
      size_t    begin      = _fsm.getBegin(itrack);
      size_t    end        = _fsm.getEnd  (itrack);
      Net*      ownerNet   = _segment->getNet();
      Interval  toFree      (_segment->getCanonicalInterval());
      
      for ( size_t i = begin ; success and (i < end) ; i++ ) {
        TrackElement* segment2 = track->getSegment(i);

        cdebug_log(159,0) << "* Looking // " << segment2 << endl;

        if ( segment2->getNet() == ownerNet  ) continue;
        if ( not toFree.intersect(segment2->getCanonicalInterval()) ) continue;
        if ( segment2->isFixed() ) {
          success = false;
          continue;
        }

        DataNegociate* data2 = segment2->getDataNegociate();
        if ( not data2 ) {
          cdebug_log(159,0) << "No DataNegociate, ignoring." << endl;
          success = false;
          continue;
        }

        cdebug_log(159,0) << "- Forced ripup " << segment2 << endl;
        if ( not (success=Manipulator(segment2,_fsm).ripup(SegmentAction::OtherRipup)) ) {
          continue;
        }
      }

      if (success) {
        _fsm.setState ( SegmentFsm::OtherRipup );
        _fsm.addAction( _segment
                      , SegmentAction::SelfInsert|SegmentAction::MoveToAxis
                      , _fsm.getCost(itrack).getTrack()->getAxis()
                      );
        break;
      }
    }

    cdebug_tabw(159,-1);
    return (itrack < costs.size());
  }


  bool  Manipulator::slacken ( unsigned int flags )
  {
    cdebug_log(159,0) << "Manipulator::slacken() " << _segment << endl; 

    if (    _segment->isFixed   ()) return false;
    if (not _segment->canSlacken()) return false;

    return _segment->slacken( flags );
  }


  bool  Manipulator::ripple ()
  {
    cdebug_log(159,0) << "Manipulator::ripple() from " << _segment << endl; 

  //if (not _segment->canRipple()) return false;
    if (not _segment->isLocal()) return false;

    Net*          net   = _segment->getNet();
    Interval      uside = _segment->base()->getAutoSource()->getGCell()->getSide ( Katabatic::perpandicularTo(_segment->getDirection())/*, false*/ );
    RoutingPlane* plane = Session::getKiteEngine()->getRoutingPlaneByLayer(_segment->getLayer());

    cdebug_tabw(159,1);
    for( Track* track : Tracks_Range::get(plane,uside)) {
      size_t begin;
      size_t end;

      track->getOverlapBounds( _segment->getCanonicalInterval(), begin, end );
      for ( ; begin < end ; begin++ ) {
        TrackElement* other = track->getSegment(begin);
        cdebug_log(159,0) << "| " << other << endl;

        if (other->getNet() == net) continue;
        if (not other->canRipple()) continue;

        DataNegociate* otherData = other->getDataNegociate();
        if (not otherData) continue;

        DbU::Unit     shiftedAxisHint;
        RoutingEvent* otherEvent = otherData->getRoutingEvent();

        if (other->getAxis() < _segment->getAxis()) {
        // Ugly: routing pitch.
          shiftedAxisHint = otherEvent->getAxisHint() - getPitch();
          if (shiftedAxisHint < uside.getVMin())
            shiftedAxisHint = uside.getVMin();
        } else {
        // Ugly: routing pitch.
          shiftedAxisHint = otherEvent->getAxisHint() + getPitch();
          if (shiftedAxisHint > uside.getVMax())
            shiftedAxisHint = uside.getVMax();
        }

        otherEvent->setAxisHint( shiftedAxisHint );
        _fsm.addAction( other, SegmentAction::OtherRipup );
      }
    }
    cdebug_tabw(159,-1);

    return true;
  }


  bool  Manipulator::pivotUp ()
  {
    cdebug_log(159,0) << "Manipulator::pivotUp() " << _segment << endl; 
    return false;

    if (_segment->isFixed()) return false;
    if (_segment->isStrap()) return false;

    float reserve = (_segment->isLocal()) ? 0.5 : 1.0;
    if (not _segment->canMoveUp(reserve)) return false;

    return _segment->moveUp( Katabatic::KbNoFlags );
  }


  bool  Manipulator::pivotDown ()
  {
    cdebug_log(159,0) << "Manipulator::pivotDown() " << _segment << endl; 
    return false;

    if (    _segment->isFixed ()       ) return false;
    if (    _segment->isStrap ()       ) return false;
    if (not _segment->canPivotDown(2.0)) return false;

    return _segment->moveDown( Katabatic::KbNoFlags );
  }


  bool  Manipulator::moveUp ( unsigned int flags )
  {
    cdebug_log(159,0) << "Manipulator::moveUp() " << _segment << endl; 

    unsigned int kflags = Katabatic::KbWithNeighbors;
  //kflags |= (flags & AllowLocalMoveUp   ) ? Katabatic::AutoSegment::AllowLocal    : 0;
    kflags |= (flags & AllowTerminalMoveUp) ? Katabatic::KbAllowTerminal : 0;

    if (_segment->isFixed()) return false;
    if (not (flags & AllowLocalMoveUp)) {
      if (_segment->isLocal()) {
        if (not _segment->canPivotUp(0.5)) return false;
      } else {
        if (_segment->getLength() < 20*getPitch()) {
          if (not (flags & AllowShortPivotUp)) return false;
          if (not _segment->canPivotUp(1.0)) return false;
        }
        if (not _segment->canMoveUp(0.5,kflags)) return false;
      }
    } else {
      if (not _segment->canMoveUp(0.5,kflags)) return false;
    }
    return _segment->moveUp( kflags );
  }


  bool  Manipulator::makeDogleg ()
  {
    cdebug_log(159,0) << "Manipulator::makeDogleg() " << _segment << endl; 

    if (    _segment->isFixed()) return false;
    if (not _segment->isLocal()) return false;
    if (_segment->getLength() < 5*getPitch()) return false;

    if (_fsm.getCosts().size()) {
      Track*    track    = _fsm.getTrack(0);
      size_t    begin    = _fsm.getBegin(0);
      size_t    end      = _fsm.getEnd  (0);
      Net*      ownerNet = _segment->getNet();
      Interval  toFree    (_segment->getCanonicalInterval());
      Interval  overlap;

      for ( size_t i=begin ; i<end ; ++i ) {
        TrackElement* segment2 = track->getSegment(i);

        cdebug_log(159,0) << "* Looking // " << segment2 << endl;

        if (    segment2->getNet() == ownerNet) continue;
        if (not toFree.intersect(segment2->getCanonicalInterval())) continue;

        if (overlap.isEmpty())
          overlap = segment2->getCanonicalInterval();
        else
          overlap.merge( segment2->getCanonicalInterval() );
      }

      if (not overlap.isEmpty() and makeDogleg(overlap)) return true;
    }

    if (not _segment->canDogleg()) return false;
    _segment->makeDogleg();

    return true;
  }


  bool  Manipulator::makeDogleg ( Interval overlap )
  {
    cdebug_log(159,0) << "Manipulator::makeDogleg(Interval) " << _segment << endl; 
    cdebug_log(159,0) << overlap << endl;

    if (    _segment->isFixed  ()       ) return false;
    if (not _segment->canDogleg(overlap)) return false;

    unsigned int  flags      = 0;
    TrackElement* dogleg     = _segment->makeDogleg(overlap,flags);
    if (dogleg) {
      cdebug_log(159,0) << "Manipulator::makeDogleg(Interval) - Push dogleg to the "
                  << ((flags&Katabatic::KbDoglegOnLeft)?"left":"right") << endl;
      if (_segment->isTerminal()) {
        Katabatic::AutoContact* contact =
          (flags&Katabatic::KbDoglegOnLeft) ? _segment->base()->getAutoSource()
                                            : _segment->base()->getAutoTarget();
        DbU::Unit     axisHint = (_segment->isHorizontal()) ? contact->getX() : contact->getY();
        RoutingEvent* event    = dogleg->getDataNegociate()->getRoutingEvent();
        if (event) {
          event->setAxisHint    ( axisHint );
          event->setForcedToHint( true );
          cdebug_log(159,0) << "Forced to axis hint @" << DbU::getValueString(axisHint) << endl;
        }
      }
      return true;
    }

    return false;
  }


  bool  Manipulator::makeDogleg ( DbU::Unit position )
  {
    cdebug_log(159,0) << "Manipulator::makeDogleg(position) " << _segment << endl; 
    cdebug_log(159,0) << "Breaking position: " << DbU::getValueString(position) << endl;

    if (_segment->isFixed()) return false;

    Katabatic::GCellVector gcells;
    _segment->getGCells( gcells );

    size_t igcell = 0;
    for ( ; igcell<gcells.size() ; igcell++ ) {
      if (gcells[igcell]->getSide(_segment->getDirection()).contains(position))
        break;
    }
    if (igcell == gcells.size()) return false;
    if (not _segment->canDogleg(gcells[igcell])) return false;

    TrackElement* dogleg   = NULL;
    TrackElement* parallel = NULL;
    _segment->makeDogleg( gcells[igcell], dogleg, parallel );
    return (dogleg != NULL);
  }


  bool  Manipulator::minimize ()
  {
    cdebug_log(159,0) << "Manipulator::minimize() " << _segment << endl; 

    if (_segment->isFixed()) return false;
    if (not _event->canMinimize()) return false;

    DbU::Unit  minSpan = DbU::Max;
    DbU::Unit  maxSpan = DbU::Min;
    Interval   punctualSpan ( false );

    if (_segment->base()->getAutoSource()->getAnchor()) {
      cdebug_log(159,0) << "  | " << _segment->base()->getAutoSource() << endl;
      Interval constraints ( _segment->base()->getAutoSource()->getUConstraints
                             (perpandicularTo(_segment->getDirection())) );
      cdebug_log(159,0) << "  | Constraints: " << constraints << endl;

      minSpan = min( minSpan, constraints.getVMax() );
      maxSpan = max( maxSpan, constraints.getVMin() );
      punctualSpan.intersection( constraints );
    }

    if (_segment->base()->getAutoTarget()->getAnchor()) {
      cdebug_log(159,0) << "  | " << _segment->base()->getAutoTarget() << endl;
      Interval constraints ( _segment->base()->getAutoTarget()->getUConstraints
                             (perpandicularTo(_segment->getDirection())) );
      cdebug_log(159,0) << "  | Constraints: " << constraints << endl;

      minSpan = min( minSpan, constraints.getVMax() );
      maxSpan = max( maxSpan, constraints.getVMin() );
      punctualSpan.intersection( constraints );
    }

    const vector<TrackElement*>& perpandiculars = _event->getPerpandiculars();
    for ( size_t i=0 ; i<perpandiculars.size() ; i++ ) {
      DataNegociate* data2 = perpandiculars[i]->getDataNegociate();
      if (not data2) continue;

      cdebug_log(159,0) << "  | " << perpandiculars[i] << endl;

      RoutingEvent* event2 = data2->getRoutingEvent();
      if (not event2) continue;

      cdebug_log(159,0) << "  | Constraints: " << event2->getConstraints() << endl;

      minSpan = min( minSpan, event2->getConstraints().getVMax() );
      maxSpan = max( maxSpan, event2->getConstraints().getVMin() );
      punctualSpan.intersection( event2->getConstraints() );
    }
    if (minSpan > maxSpan) swap( minSpan, maxSpan );

    cdebug_log(159,0) << "punctualSpan: " << punctualSpan
                << " min/max span: [" << DbU::getValueString(minSpan)
                <<                ":" << DbU::getValueString(maxSpan) << "]"
                << " long: ["         << minSpan
                <<                ":" << maxSpan << "]" << endl;

    vector<Interval> holes;
    for ( size_t itrack=0 ; itrack<_fsm.getCosts().size() ; itrack++ ) {
      size_t  begin = _fsm.getBegin(itrack);
      size_t  end   = _fsm.getEnd  (itrack);
      Track*  track = _fsm.getTrack(itrack);

      if (end < track->getSize()) end++;

      cdebug_log(159,0) << "Looking for holes in " << _fsm.getCost(itrack) << endl;

      TrackElement* otherPrevious = NULL;
    // ToDo: Manage disjoint but subsequent segment of a Net.
    //       (currently, that hole will not be found).
      for ( ; begin < end ; begin++ ) {
        TrackElement* otherSegment = track->getSegment(begin);
        if (otherSegment->getNet() == _segment->getNet()) continue;
        if (not otherPrevious) {
          holes.push_back( Interval(track->getMin()
                                   ,otherSegment->getSourceU()) );
          cdebug_log(159,0) << "| First hole: " << holes.back() << " " << otherSegment << endl;
        } else {
          if (otherSegment->getNet() == otherPrevious->getNet()) continue;

          holes.push_back( Interval(otherPrevious->getTargetU()
                                   ,otherSegment ->getSourceU()) );
          cdebug_log(159,0) << "| Found hole: " << holes.back()
                      << " " << otherPrevious << " <-> " << " " << otherSegment << endl;
        }
        otherPrevious = otherSegment;
      }
    }

    if (holes.empty()) {
      cdebug_log(159,0) << "No holes found to minimize into." << endl;
      return false;
    }

    Interval  currentSpan = _segment->getCanonicalInterval();
    Interval  biggestHole;
    for ( size_t i=0 ; i<holes.size() ; i++ ) {
      if ( currentSpan.getIntersection(holes[i]   ).getSize()
         > currentSpan.getIntersection(biggestHole).getSize() )
        biggestHole = holes[i];
    }

    DbU::Unit axisHint = 0;
    if (not punctualSpan.isEmpty()) {
      bool success = false;

      if (biggestHole.intersect(punctualSpan)) {
        cdebug_log(159,0) << "Go as punctual into biggest hole: " << biggestHole << endl;
        axisHint = biggestHole.intersection(punctualSpan).getCenter();
        success = true;
      } else {
        for ( size_t i=0 ; i<holes.size() ; i++ ) {
          cdebug_log(159,0) << "Trying secondary hole: " << holes[i] << endl;
          if (holes[i].intersect(punctualSpan)) {
            biggestHole = holes[i];
            axisHint = biggestHole.intersection(punctualSpan).getCenter();
            cdebug_log(159,0) << "Go as punctual into secondary hole: " << biggestHole << endl;
            success = true;
          }
        }
      }

      if (not success) {
        cdebug_log(159,0) << "No suitable hole found." << endl;
        return false;
      }
    } else {
      biggestHole.intersection( Interval(minSpan,maxSpan) );
      if (biggestHole.isEmpty()) {
        cdebug_log(159,0) << "Biggest hole is empty (under span ["
                    << DbU::getValueString(minSpan) << " "
                    << DbU::getValueString(maxSpan) << "])" << endl;
        return false;
      } else {
        cdebug_log(159,0) << "Go into biggest hole: " << biggestHole << endl;
        axisHint = biggestHole.getCenter();
      }
    }

    cdebug_log(159,0) << "Axis Hint: " << DbU::getValueString(axisHint) << endl;

    for ( size_t i=0 ; i<perpandiculars.size() ; i++ ) {
      DataNegociate* data2 = perpandiculars[i]->getDataNegociate();
      if (not data2) continue;

      cdebug_log(159,0) << "  | " << perpandiculars[i] << endl;

      RoutingEvent* event2 = data2->getRoutingEvent();
      if (not event2) continue;

      _fsm.addAction( perpandiculars[i], SegmentAction::SelfRipupPerpandWithAxisHint, axisHint );
    }

    _event->setMinimized();

    return true;
  }


  void  Manipulator::reprocessPerpandiculars ()
  {
    if ( _event->getAxisHistory() == _event->getAxisHint() ) return;

    bool moveLeft = (_event->getAxisHistory() > _event->getAxisHint());

    const vector<TrackElement*>& perpandiculars = _event->getPerpandiculars();
    for ( size_t iperpand=0 ; iperpand<perpandiculars.size() ; iperpand++ ) {
      TrackElement*  perpandicular = perpandiculars[iperpand];
      DataNegociate* data          = perpandicular->getDataNegociate();

      if ( perpandicular->isFixed() ) continue;
      if ( not data ) continue;
      if ( not perpandicular->getTrack() ) continue;
      if ( not Manipulator(perpandicular,_fsm).canRipup()
         or (data->getState() >= DataNegociate::MaximumSlack) ) continue;

    // Ugly: ExtensionCap usage.
      if ( moveLeft ) {
        if ( perpandicular->getTargetU()-Session::getExtensionCap(getLayer()) == _event->getAxisHistory() )
          _fsm.addAction ( perpandicular, SegmentAction::OtherRipupPerpandAndPacking );
      } else {
        if ( perpandicular->getSourceU()+Session::getExtensionCap(getLayer()) == _event->getAxisHistory() )
          _fsm.addAction ( perpandicular, SegmentAction::OtherRipupPerpandAndPacking );
      }
    }
  }


  void  Manipulator::repackPerpandiculars ()
  {
    cdebug_log(159,0) << "Manipulator::repackPerpandiculars()" << endl;

    const vector<TrackElement*>& perpandiculars = _event->getPerpandiculars();
    for ( size_t iperpand=0 ; iperpand<perpandiculars.size() ; iperpand++ ) {
      TrackElement*  perpandicular = perpandiculars[iperpand];
      DataNegociate* data          = perpandicular->getDataNegociate();

      if (perpandicular->isFixed ()) continue;
      if (perpandicular->isGlobal()) continue;
      if (not data) continue;

      if (RoutingEvent::getStage() == RoutingEvent::Repair) {
        data->setState( DataNegociate::Repair );
        if (data->getStateCount() > 1) data->resetStateCount();
      }
      _fsm.addAction( perpandicular, SegmentAction::SelfRipupPerpand );
    }
    _fsm.addAction( _segment, SegmentAction::SelfRipup|SegmentAction::EventLevel4 );
  }


}  // Kite namespace.
