
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC/LIP6 2008-2009, All Rights Reserved
//
// ===================================================================
//
// $Id$
//
// x-----------------------------------------------------------------x
// |                                                                 |
// |                   C O R I O L I S                               |
// |        K a t a b a t i c  -  Routing Toolbox                    |
// |                                                                 |
// |  Author      :                    Jean-Paul CHAPUT              |
// |  E-mail      :       Jean-Paul.Chaput@asim.lip6.fr              |
// | =============================================================== |
// |  C++ Module  :       "./AutoContact.cpp"                        |
// | *************************************************************** |
// |  U p d a t e s                                                  |
// |                                                                 |
// x-----------------------------------------------------------------x


#include  <cstdlib>
#include  <climits>
#include  <sstream>

#include  "hurricane/Bug.h"
#include  "hurricane/Error.h"
#include  "hurricane/Warning.h"
#include  "hurricane/Layer.h"
#include  "hurricane/ViaLayer.h"
#include  "hurricane/BasicLayer.h"
#include  "hurricane/Technology.h"
#include  "hurricane/Net.h"
#include  "hurricane/Contact.h"
#include  "hurricane/Plug.h"
#include  "hurricane/RoutingPad.h"
#include  "hurricane/Vertical.h"
#include  "hurricane/Horizontal.h"
#include  "hurricane/UpdateSession.h"
#include  "hurricane/DebugSession.h"

#include  "crlcore/RoutingGauge.h"

#include  "katabatic/GCell.h"
#include  "katabatic/AutoContact.h"
#include  "katabatic/AutoSegment.h"
#include  "katabatic/AutoVertical.h"
#include  "katabatic/AutoHorizontal.h"
#include  "katabatic/Session.h"


namespace {

  /*! \class        SegmentEnd
   *  \brief        Segment manipulator (\b internal)
   *
   *                SegmentPosition compute detailed informations about how an
   *                Segment is connected to the current AutoContact. This
   *                object act as a cache, avoiding to recalculate the position
   *                information many times.
   *              
   *                It also provide uniform way of resizing the Segment extention
   *                from the AutoContact.
   */ 
 
  /*! \var          bool  SegmentEnd::_isSourceHook;
   *                set to \b true if the Segment is attached to the AutoContact
   *                through it's source hook (\b false for target \c hook).
   */
 
  /*! \function     SegmentEnd::SegmentEnd ( AutoSegment* segment, bool isSourceHook );
   *  \param        segment      the supporting segment.
   *  \param        isSourceHook initialize _isSourceHook.
   */
 
  /*! \function     static SegmentEnd* SegmentEnd::create ( Hook* hook, bool checking );
   *  \param        contact The AutoContact we are currently processing.
   *  \return       The appropriate SegmentPosition.
   *
   *                This create function allocate the relevant HorizontalPosition or
   *                VerticalPosition derived object, providing an uniform allocator
   *                function.
   */
 
  /*! \function     virtual bool SegmentEnd::isVertical () const;
   *  \return       \b true if the associated Segment is vertical.
   */
 
  /*! \function     virtual bool SegmentEnd::isHorizontal () const;
   *  \return       \b true if the associated Segment is horizontal.
   */
 
  /*! \function     bool SegmentEnd::isSourceHook () const;
   *  \return       The _isSourceHook value (accessor).
   */
 
  /*! \function     bool SegmentEnd::isGlobal () const;
   *  \return       The _isGlobal value (accessor).
   */
 
  /*! \function     virtual DbU::Unit  SegmentEnd::getAxis () const;
   *  \return       For horizontal segment, the Y coordinate and the X coordinate for
   *                vertical ones.
   */
 
  /*! \function     Layer* SegmentEnd::getLayer () const;
   *  \return       The layer of the segment.
   */
 
  /*! \function     Point  SegmentEnd::getEnd () const;
   *  \return       The position of the segment's extremity attached to the AutoContact.
   */
 
 
  /*! \function     void  SegmentEnd::setDelta ( DbU::Unit delta );
   *  \param        delta the new value of the extention.
   *
   *                Adjust the segment's extention. Coordinate must be expressed
   *                as an offset to the absolute coordinate of the relevant hook.
   */
 
  /*! \function     void  SegmentEnd::orient ();
   *                restore correct orientation of the segment (source \e lower than
   *                target), usually needed after a setDelta().
   */
 
 
 
 
  /*! \class        HorizontalEnd
   *  \brief        Horizontal Segment manipulator (\b internal)
   *
   *                This class must only be accessed through it's base class
   *                SegmentPosition, it's constructed through SegmentPosition::create().
   */
 
 
  /*! \class        VerticalEnd
   *  \brief        Vertical Segment manipulator (\b internal)
   *
   *                This class must only be accessed through it's base class
   *                SegmentPosition, it's constructed through SegmentPosition::create().
   */


  using namespace std;
  using namespace Hurricane;
  using namespace Katabatic;


// -------------------------------------------------------------------
// Local Variables.

// const char* badAutoContactAnchor =
//   "AutoContact::AutoContact() :\n\n"
//   "    Only <RoutinPad> are supported to anchor an AutoContact :\n"
//   "    %s\n";

// const char* nonAdjacentLayers =
//   "%s :\n\n"
//   "    %s and %s are not adjacent, cannot build a VIA.\n";

// const char* missingAutoLayer =
//   "AutoContact::create() :\n\n"
//   "    DataBase is lacking \"AutoLayer\" layer, please check technology file.\n";

// const char* emptyJunctionBox =
//   " Empty JunctionBox in %s (internal error).";

  const char* badHookType =
    "Hook of %s is neither a SourceHook nor a TargetHook (internal error).";

  const char* missingAutoSegment =
    "No AutoSegment associated to %s (internal error).";


// Forward Declarations.
  class StackedContact;


// -------------------------------------------------------------------
// Class  :  "::UPoint".


  class UPoint {
    // Constructors.
    public:
      inline            UPoint ( bool isHorizontal, DbU::Unit ux, DbU::Unit uy );
    // Accessors.
      inline DbU::Unit  getUX  () const;
      inline DbU::Unit  getUY  () const;
      inline DbU::Unit  getX   () const;
      inline DbU::Unit  getY   () const;
    // Modifiers.
      inline void       setUX  ( DbU::Unit ux );
      inline void       setUY  ( DbU::Unit uy );
    // Attributes.
    protected:
             bool       _isHorizontal;
             DbU::Unit  _ux;
             DbU::Unit  _uy;
  };


// Inline Functions.
  inline            UPoint::UPoint ( bool isHorizontal, DbU::Unit ux, DbU::Unit uy )
                                   : _isHorizontal(isHorizontal), _ux(ux), _uy(uy) {}
  inline DbU::Unit  UPoint::getUX  () const { return _ux; }
  inline DbU::Unit  UPoint::getUY  () const { return _uy; }
  inline DbU::Unit  UPoint::getX   () const { return (_isHorizontal)?_ux:_uy; }
  inline DbU::Unit  UPoint::getY   () const { return (_isHorizontal)?_uy:_ux; }
  inline void       UPoint::setUX  ( DbU::Unit ux ) { _ux = ux; }
  inline void       UPoint::setUY  ( DbU::Unit uy ) { _uy = uy; }


// -------------------------------------------------------------------
// Class  :  "::SegmentEnd".


  class SegmentEnd {
    public:
      struct Compare : public binary_function<SegmentEnd*,SegmentEnd*,bool> {
          inline bool  operator() ( const SegmentEnd* lhs, const SegmentEnd* rhs ) const;
      };
    public:
    // AutoSegment & Segment wrapped functions.
      inline  bool                 isGlobal       () const;
      inline  bool                 isLocal        () const;
      inline  bool                 isHorizontal   () const;
      inline  bool                 isVertical     () const;
      inline  bool                 isSlackened    () const;
      inline  Net*                 getNet         () const;
      inline  const Layer*         getLayer       () const;
      inline  Hook*                getSourceHook  ();
      inline  Hook*                getTargetHook  ();
      inline  DbU::Unit            getSourceX     () const;
      inline  DbU::Unit            getSourceY     () const;
      inline  DbU::Unit            getTargetX     () const;
      inline  DbU::Unit            getTargetY     () const;
      inline  DbU::Unit            getSourceU     () const;
      inline  DbU::Unit            getTargetU     () const;
      inline  DbU::Unit            getDuSource    () const;
      inline  DbU::Unit            getDuTarget    () const;
      inline  DbU::Unit            getAxis        () const;
      inline  DbU::Unit            getWidth       () const;
      inline  void                 setDuSource    ( DbU::Unit );
      inline  void                 setDuTarget    ( DbU::Unit );
      inline  void                 invert         ();
      inline  void                 invalidate     ();
    // Constructors & Destructors.
      inline                       SegmentEnd     ( AutoSegment* , bool isSourceHook );
      virtual                     ~SegmentEnd     ();
      static  SegmentEnd*          create         ( Hook*, bool checking );
    // Accessors.                                 
      static  size_t               getAllocateds  ();
      inline  bool                 isSourceHook   () const;
      inline  AutoSegment*         getSegment     () const;
      virtual Hook*                getHook        () const;
      inline  Point                getEnd         () const;
      inline  DbU::Unit            getEndX        () const;
      inline  DbU::Unit            getEndY        () const;
      virtual vector<SegmentEnd*>* getForks       ();
      virtual vector<SegmentEnd*>* getAligneds    ();
    // Modifiers.                                 
              void                 setDelta       ( DbU::Unit );
      virtual void                 orient         ();
      virtual void                 addFork        ( SegmentEnd* );
      virtual void                 addAligned     ( SegmentEnd* );
      virtual void                 split          ( vector<StackedContact*>& );
    // Inspector Managment.
      inline  Record*              _getRecord     () const;
      inline  string               _getString     () const;
      inline  string               _getTypeName   () const;
    protected:
    // Attributes.
      static  size_t               _allocateds;
              AutoSegment*         _autoSegment; 
              bool                 _isSourceHook;
  };


}

INSPECTOR_P_SUPPORT(SegmentEnd);

namespace {

         size_t               SegmentEnd::_allocateds    = 0;

                              SegmentEnd::~SegmentEnd    () { _allocateds--; }
         size_t               SegmentEnd::getAllocateds  () { return _allocateds; }
  inline bool                 SegmentEnd::isGlobal       () const { return _autoSegment->isGlobal(); }
  inline bool                 SegmentEnd::isLocal        () const { return _autoSegment->isLocal(); }
  inline bool                 SegmentEnd::isHorizontal   () const { return _autoSegment->isHorizontal(); }
  inline bool                 SegmentEnd::isVertical     () const { return _autoSegment->isVertical(); }
  inline bool                 SegmentEnd::isSlackened    () const { return _autoSegment->isSlackened(); }
  inline AutoSegment*         SegmentEnd::getSegment     () const { return _autoSegment; }
  inline Net*                 SegmentEnd::getNet         () const { return _autoSegment->getNet(); }
  inline const Layer*         SegmentEnd::getLayer       () const { return _autoSegment->getLayer(); }
  inline Hook*                SegmentEnd::getSourceHook  () { return _autoSegment->getSourceHook(); }
  inline Hook*                SegmentEnd::getTargetHook  () { return _autoSegment->getTargetHook(); }
  inline DbU::Unit            SegmentEnd::getSourceX     () const { return _autoSegment->getSourceX(); }
  inline DbU::Unit            SegmentEnd::getSourceY     () const { return _autoSegment->getSourceY(); }
  inline DbU::Unit            SegmentEnd::getTargetX     () const { return _autoSegment->getTargetX(); }
  inline DbU::Unit            SegmentEnd::getTargetY     () const { return _autoSegment->getTargetY(); }
  inline DbU::Unit            SegmentEnd::getSourceU     () const { return _autoSegment->getSourceU(); }
  inline DbU::Unit            SegmentEnd::getTargetU     () const { return _autoSegment->getTargetU(); }
  inline DbU::Unit            SegmentEnd::getDuSource    () const { return _autoSegment->getDuSource(); }
  inline DbU::Unit            SegmentEnd::getDuTarget    () const { return _autoSegment->getDuTarget(); }
  inline DbU::Unit            SegmentEnd::getAxis        () const { return _autoSegment->getAxis(); }
  inline DbU::Unit            SegmentEnd::getWidth       () const { return _autoSegment->getWidth(); }
  inline void                 SegmentEnd::setDuSource    ( DbU::Unit du ) { _autoSegment->setDuSource(du); }
  inline void                 SegmentEnd::setDuTarget    ( DbU::Unit du ) { _autoSegment->setDuTarget(du); }
  inline void                 SegmentEnd::invert         () { _autoSegment->invert(); }
  inline void                 SegmentEnd::invalidate     () { _autoSegment->invalidate(); }
  inline bool                 SegmentEnd::isSourceHook   () const { return _isSourceHook; }
  inline Point                SegmentEnd::getEnd         () const { return isSourceHook() ? Point(getSourceX(),getSourceY()) : Point(getTargetX(),getTargetY()); }
  inline DbU::Unit            SegmentEnd::getEndX        () const { return isSourceHook() ? getSourceX() : getTargetX(); }
  inline DbU::Unit            SegmentEnd::getEndY        () const { return isSourceHook() ? getSourceY() : getTargetY(); }
         vector<SegmentEnd*>* SegmentEnd::getForks       () { return NULL; }
         vector<SegmentEnd*>* SegmentEnd::getAligneds    () { return NULL; }
         void                 SegmentEnd::addFork        ( SegmentEnd* ) {}
         void                 SegmentEnd::addAligned     ( SegmentEnd* ) {}
         void                 SegmentEnd::split          ( vector<StackedContact*>& ) {}
  inline Record*              SegmentEnd::_getRecord     () const { return _autoSegment->_getRecord(); }
  inline string               SegmentEnd::_getString     () const { return _autoSegment->_getString(); }
  inline string               SegmentEnd::_getTypeName   () const { return "Katabatic::SegmentEnd"; }

  inline bool  SegmentEnd::Compare::operator() ( const SegmentEnd* lhs, const SegmentEnd* rhs ) const
  { return AutoSegment::CompareCanonical() ( lhs->getSegment(), rhs->getSegment() ); }

  inline  SegmentEnd::SegmentEnd ( AutoSegment* segment, bool isSourceHook )
    : _autoSegment(segment)
    , _isSourceHook(isSourceHook)
  {
    _allocateds++;
  }


  Hook* SegmentEnd::getHook () const
  {
    if ( isSourceHook() ) return _autoSegment->getSourceHook();
    return _autoSegment->getTargetHook();
  }


  void  SegmentEnd::orient ()
  {
    if ( ( !isGlobal() ) && ( getSourceU() > getTargetU() ) ) {
      ltrace(99) << "Orient() before - " << this << endl;

      invert ();
      DbU::Unit duSource = getDuSource();
      DbU::Unit duTarget = getDuTarget();
      setDuSource ( duTarget );
      setDuTarget ( duSource );
      _isSourceHook = !_isSourceHook;

      ltrace(99) << "Orient() after  - " << this << endl;
    }
  }


  void  SegmentEnd::setDelta ( DbU::Unit delta )
  {
    ltrace(99) << "setDelta(" << DbU::getLambda(delta) << ") - " << this << endl;

    if ( isSourceHook() ) {
      if ( getDuSource() != delta ) {
        setDuSource ( delta );
        ltrace(99) << "DuSource actualized: " << this << endl;
      }
    } else {
      if ( getDuTarget() != delta ) {
        setDuTarget ( delta );
        ltrace(99) << "DuTarget actualized: " << this << endl;
      }
    }

    orient ();
  }


}


namespace {


// -------------------------------------------------------------------
// Class  :  "::ForkCompare".


  class ForkCompare {
    public:
      inline       ForkCompare ( bool increasing ) : _increasing(increasing) {};
      inline bool  operator()  ( SegmentEnd* lhs, SegmentEnd* rhs ) const;
    protected:
      bool  _increasing;
  };


  bool  ForkCompare::operator() ( SegmentEnd* lhs, SegmentEnd* rhs ) const
  {
    bool superior = rhs->isGlobal();

    if ( lhs->getAxis() == rhs->getAxis() ) {
      if ( lhs->isLocal() && rhs->isLocal() )
        return false;
    } else
      superior = lhs->getAxis() > rhs->getAxis();

    return (_increasing) ? !superior : superior;
  }


// -------------------------------------------------------------------
// Class  :  "::StackedContact".


  class StackedContact : public Contact {

    public:
      static  StackedContact* create         ( Net* , const Layer* , DbU::Unit x, DbU::Unit y );
                              StackedContact ( Net* , const Layer* , DbU::Unit x, DbU::Unit y );
      virtual                ~StackedContact ();
    public:
              void            setAnchor      ( Component* );
              void            addLayer       ( const Layer* );
              void            attachSlave    ( SegmentEnd* );
              void            breakUp        ();

    protected:
              vector<bool>    _useds;
              Component*      _anchor;
    private:
                              StackedContact ( const StackedContact& );
              StackedContact& operator=      ( const StackedContact& );
  };


// -------------------------------------------------------------------
// Class  :  "::GlobalEnd".


  class GlobalEnd : public SegmentEnd {
    public:
                                   GlobalEnd        ( AutoSegment* , bool isSourceHook );
      virtual                     ~GlobalEnd        (); 
      virtual vector<SegmentEnd*>* getForks         ();
      virtual vector<SegmentEnd*>* getAligneds      ();
      virtual void                 split            ( vector<StackedContact*>& );
      virtual void                 addFork          ( SegmentEnd* );
      virtual void                 addAligned       ( SegmentEnd* );
      virtual Segment*             _create          ( Contact* source, Contact* target ) = 0;
    protected:
              vector<SegmentEnd*>  _forks;
              vector<SegmentEnd*>  _aligneds;
  };


  GlobalEnd::GlobalEnd ( AutoSegment* segment, bool isSourceHook )
    : SegmentEnd(segment,isSourceHook)
    , _forks()
    , _aligneds()
  {}


  GlobalEnd::~GlobalEnd ()
  {} 


  vector<SegmentEnd*>* GlobalEnd::getForks ()
  {
    return &_forks;
  }


  vector<SegmentEnd*>* GlobalEnd::getAligneds ()
  {
    return &_aligneds;
  }


  void  GlobalEnd::addFork ( SegmentEnd* segmentEnd )
  {
    for ( size_t i = 0 ; i < _forks.size() ; i++ ) {
      if ( _forks[i] == segmentEnd ) return;
    }
    _forks.push_back ( segmentEnd );
  }


  void  GlobalEnd::addAligned ( SegmentEnd* segmentEnd )
  {
    for ( size_t i = 0 ; i < _aligneds.size() ; i++ ) {
      if ( _aligneds[i] == segmentEnd ) return;
    }
    _aligneds.push_back ( segmentEnd );
  }


  void  GlobalEnd::split ( vector<StackedContact*>& stackedContacts )
  {
    ltrace(99) << "GlobalEnd::split() - " << this << endl;
    ltracein(99);

    sort ( _forks.begin(), _forks.end(), ForkCompare(!isSourceHook()) );

    StackedContact*               contact1        = NULL;
    StackedContact*               contact2        = NULL;
    const Layer*                  contactLayer    = NULL;
    Hook*                         hook            = getHook();
    vector<SegmentEnd*>::iterator it              = _forks.begin();

    if ( it == _forks.end() ) {
      ltrace(99) << "No forks!" << endl;
      stackedContacts.push_back ( StackedContact::create ( getNet()
                                                         , getLayer()
                                                         , getEndX()
                                                         , getEndY()
                                                         ) );
      stackedContacts.back()->attachSlave ( this );

      ltraceout(99);
      return;
    }

    ltrace(99) << "splitted Axis " << DbU::getLambda(getAxis()) << endl;
    ltrace(99) << "iterator Axis " << DbU::getLambda((*it)->getAxis()) << " " << (*it) << endl;

    UPoint center ( isHorizontal(), (*it)->getAxis(), getAxis() );
    contactLayer = Session::getTechnology()->getViaBetween ( getLayer(), (*it)->getLayer() );
    stackedContacts.push_back
      ( StackedContact::create ( getNet(), contactLayer, center.getX(), center.getY() ) );
    contact1 = stackedContacts.back ();
    contact1->attachSlave ( *it );

    hook->detach ();
    hook->attach ( contact1->getBodyHook() );
    setDelta ( 0 );
      
    for ( it++ ; it != _forks.end() ; it++ ) {
      ltrace(99) << "splitted Axis " << DbU::getLambda(getAxis()) << endl;
      ltrace(99) << "iterator Axis " << DbU::getLambda((*it)->getAxis()) << " " << (*it) << endl;

      if ( (*(it-1))->getAxis() != (*it)->getAxis() ) {
        UPoint  center ( isHorizontal(), (*it)->getAxis(), getAxis() );
        contactLayer = Session::getTechnology()->getViaBetween ( getLayer(), (*it)->getLayer() );
        stackedContacts.push_back
          ( StackedContact::create ( getNet(), contactLayer, center.getX(), center.getY() ) );
        contact2 = stackedContacts.back ();
      } else {
        contact2 = contact1;
      }

      if ( contact1 != contact2 ) {
        if ( !isSourceHook() ) _create ( contact1, contact2 );
        else                   _create ( contact2, contact1 );
      }

      contact2->attachSlave ( *it );
      contact1 = contact2;
    }

    for ( it = _aligneds.begin() ; it != _aligneds.end() ; it++ ) {
      if ( isSourceHook() == (*it)->isSourceHook() ) {
        stackedContacts.front()->attachSlave ( *it );
      } else {
        stackedContacts.back()->attachSlave ( *it );
      }
    }

    ltraceout(99);
  }


// -------------------------------------------------------------------
// Class  :  "::HorizontalEnd".


  class HorizontalEnd : public GlobalEnd {
    public:
                        HorizontalEnd ( AutoSegment* , bool isSourceHook );
      virtual          ~HorizontalEnd ();
      virtual Segment*  _create       ( Contact* source , Contact* target );
  };


  HorizontalEnd::HorizontalEnd  ( AutoSegment* horizontal, bool isSourceHook )
    : GlobalEnd(horizontal,isSourceHook)
  { }


  HorizontalEnd::~HorizontalEnd ()
  { }


  Segment* HorizontalEnd::_create ( Contact* source , Contact* target )
  {
    return Horizontal::create ( source, target, getLayer(), getAxis(), getWidth() );
  }


// -------------------------------------------------------------------
// Class  :  "::VerticalEnd".


  class VerticalEnd : public GlobalEnd {
    public:
                        VerticalEnd ( AutoSegment* , bool isSourceHook );
      virtual          ~VerticalEnd (); 
      virtual Segment*  _create     ( Contact* source , Contact* target );
  };


  VerticalEnd::VerticalEnd ( AutoSegment* vertical, bool isSourceHook )
    : GlobalEnd(vertical,isSourceHook)
  { } 


  VerticalEnd::~VerticalEnd ()
  { }


  Segment* VerticalEnd::_create ( Contact* source , Contact* target )
  {
    return Vertical::create ( source, target, getLayer(), getAxis(), getWidth() );
  }


// -------------------------------------------------------------------
// Static Generic Constructor for all SegmentEnd.


  SegmentEnd* SegmentEnd::create ( Hook* hook, bool checking )
  {
    bool isSourceHook = (dynamic_cast<Segment::SourceHook*>(hook));
    if ( !isSourceHook && ( dynamic_cast<Segment::TargetHook*>(hook) == NULL ) ) {
      cerr << Error ( badHookType, getString(hook->getComponent()).c_str() ) << endl;
      return NULL;
    }

    AutoSegment* autoSegment = Session::lookup ( dynamic_cast<Segment*>(hook->getComponent()) );

    if ( !autoSegment )
      throw Error ( missingAutoSegment, getString(hook->getComponent()).c_str() );

    if ( !checking )
      autoSegment->invalidate ();

    if ( autoSegment->isGlobal() ) {
      if ( autoSegment->isHorizontal() )
        return new HorizontalEnd ( autoSegment, isSourceHook );
      else
        return new VerticalEnd ( autoSegment, isSourceHook );
    } else {
      if ( autoSegment->isHorizontal() )
        return new SegmentEnd ( autoSegment, isSourceHook );
    }
    return new SegmentEnd ( autoSegment, isSourceHook );
  }


// -------------------------------------------------------------------
// Class  :  "::JunctionBox".


  class JunctionBox {

    public:
    // Constructor & Destructor.
                    JunctionBox        ( AutoContact*, bool checking );
                   ~JunctionBox        ();
    // Predicates.                     
      inline bool   isVFlat            ();
      inline bool   isHFlat            ();
      inline bool   isFlat             ();
      inline bool   isPunctual         ();
      inline bool   isVEmpty           ();
      inline bool   isHEmpty           ();
      inline bool   isEmpty            ();
             bool   isHExtended        ();
             bool   isVExtended        ();
             bool   canGoOutside       ( const AutoSegment* ) const;
             bool   canHDesalignate    () const;
             bool   canVDesalignate    () const;
             void   getZSpan           ( size_t& zMin, size_t& zMax ) const;
    // Modifiers.                    
             void   checkTopology      ();
             void   revalidateTopology ();
             void   computeGlobalStem  ();
             void   computeAlignate    ();
             void   mergeX             ( DbU::Unit );
             void   mergeY             ( DbU::Unit );
             void   mergeAnchor        ();
             void   merge              ( Hook* );
             void   postMerge          ( SegmentEnd* );
             void   resizePunctual     ();
             void   resize             ();
             void   breakUpPunctual    ();
             void   breakUp            ();
             void   split              ();
             void   splitTerminal      ();
             void   updateContacts     ( VirtualContacts& );
             void   restoreHConnexity  ( DbU::Unit x, bool split );
             void   restoreVConnexity  ( DbU::Unit y, bool split );

    protected:
    // Attributes.
      RoutingGauge*        _routingGauge;
      AutoContact*         _contact;
      Component*           _anchor;
      DbU::Unit            _xMin;
      DbU::Unit            _yMin;
      DbU::Unit            _xMax;
      DbU::Unit            _yMax;
      SegmentEnd*          _globalStem;
      vector<SegmentEnd*>  _globalEnds;
      vector<SegmentEnd*>  _localEnds;
      vector<size_t>       _layerStack;
      size_t               _wireCount;
      bool                 _failsafe;
      bool                 _checking;
  };


  inline bool  JunctionBox::isVFlat     () { return _yMin == _yMax; }
  inline bool  JunctionBox::isHFlat     () { return _xMin == _xMax; }
  inline bool  JunctionBox::isFlat      () { return isHFlat() || isVFlat(); }
  inline bool  JunctionBox::isPunctual  () { return isHFlat() && isVFlat(); }
  inline bool  JunctionBox::isVEmpty    () { return _yMin > _yMax; }
  inline bool  JunctionBox::isHEmpty    () { return _xMin > _xMax; }
  inline bool  JunctionBox::isEmpty     () { return isHEmpty() || isVEmpty(); }


  JunctionBox::JunctionBox ( AutoContact* contact, bool checking )
    : _routingGauge(Session::getRoutingGauge())
    , _contact     (contact)
    , _anchor      (NULL)
    , _xMin        (+1)
    , _yMin        (+1)
    , _xMax        (-1)
    , _yMax        (-1)
    , _globalStem  (NULL)
    , _globalEnds  ()
    , _localEnds   ()
    , _layerStack  (Session::getRoutingGauge()->getDepth())
    , _wireCount   (0)
    , _failsafe    (false)
    , _checking    (checking)
  {
    ltrace(110) << "JunctionBox() " << contact << endl;
    ltracein(109);

    forEach ( Hook*, hook, _contact->getBodyHook()->getSlaveHooks() ) merge ( *hook );
    mergeAnchor ();

    sort ( _globalEnds.begin(), _globalEnds.end(), SegmentEnd::Compare() );
    sort ( _localEnds.begin() , _localEnds.end() , SegmentEnd::Compare() );

    if ( ( _wireCount < 1 ) && !_contact->getAnchor() )
      cerr << Warning("%s has less than 2 wires (%d)"
                     ,getString(_contact).c_str(),_wireCount) << endl;

    computeGlobalStem ();
    if ( _globalStem ) {
      ltrace(109) << "_globalStem: " << _globalStem << endl;
      for ( size_t i=0 ; i < _localEnds.size() ; i++ )
        postMerge ( _localEnds[i] );
      for ( size_t i=0 ; i < _globalEnds.size() ; i++ )
        postMerge ( _globalEnds[i] );
      
      ltraceout(109);
      return;
    }

    if ( isPunctual() || (isFlat() && !_contact->getAnchor()) ) {
      ltraceout(109);
      return;
    }

    // JunctionBox is empty, non-flat or flat with anchor.
    _failsafe = true;
    ltraceout(109);
  }
  

  JunctionBox::~JunctionBox ()
  {
    for ( size_t i = 0 ; i < _globalEnds.size() ; i++ ) delete _globalEnds[i];
    for ( size_t i = 0 ; i < _localEnds.size()  ; i++ ) delete _localEnds[i];
  }


  bool  JunctionBox::isHExtended ()
  {
    if ( _globalStem ) {
      ltrace(109) << "JunctionBox::isHExtended(): " << _globalStem->isHorizontal() << endl;
      return _globalStem->isHorizontal();
    }
    return _contact->isHAlignate();
  }


  bool  JunctionBox::isVExtended ()
  {
    if ( _globalStem ) {
      ltrace(109) << "JunctionBox::isVExtended(): " << _globalStem->isVertical() << endl;
      return _globalStem->isVertical();
    }
    return _contact->isVAlignate();
  }


  void  JunctionBox::getZSpan ( size_t& zMin, size_t& zMax ) const
  {
    bool minFound = false;

    zMin = 0;
    zMax = 0;
    for ( size_t i=0 ; i<_layerStack.size() ; i++ ) {
      if ( !minFound ) {
        if ( _layerStack[i] > 0 ) {
          zMin = zMax = i;
          minFound = true;
        }
      } else {
        if ( _layerStack[i] > 0 ) {
          zMax = i;
        }
      }
    }
  }


  void  JunctionBox::revalidateTopology ()
  {
    _contact->setInvalidatedTopology ( false );
    _contact->setCorner ( false );
    if ( !_contact->getAnchor() ) {
      size_t  horizontals = 0;
      size_t  verticals   = 0;

      for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
        if ( _globalEnds[i]->isHorizontal() ) horizontals++;
        else                                  verticals++;
      }
      for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
        if ( _localEnds[i]->isHorizontal() ) horizontals++;
        else                                 verticals++;
      }
      _contact->setCorner (   (horizontals == 1)
                          and (verticals   == 1)
                          and (not _contact->isHAlignate())
                          and (not _contact->isVAlignate()) );
    }
   
    checkTopology ();
  }


  void  JunctionBox::checkTopology ()
  {
    vector<string> errors;

    bool    anchored           = (_contact->getAnchor());
    bool    alignateHorizontal = _contact->isHAlignate() || anchored;
    bool    alignateVertical   = _contact->isVAlignate() || anchored;
    bool    globalHorizontal   = false;
    bool    globalVertical     = false;
    size_t  localHorizontals   = 0;
    size_t  localVerticals     = 0;

    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      if ( _globalEnds[i]->isHorizontal() ) {
        globalHorizontal = true;
        localHorizontals++;
      } else {
        globalVertical = true;
        localVerticals++;
      }
    }

    for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
      if ( _localEnds[i]->isHorizontal() ) localHorizontals++;
      else                                 localVerticals++;
    }

    if ( !(localHorizontals || globalHorizontal || anchored) )
      errors.push_back ( "No horizontal components" );

    if ( !(localVerticals || globalVertical || anchored) )
      errors.push_back ( "No vertical components" );

    if ( !alignateHorizontal && !globalVertical && (localHorizontals > 1) )
      errors.push_back ( "Disconnecteds horizontals components" );

    if ( !alignateVertical && !globalHorizontal && (localVerticals > 1) )
      errors.push_back ( "Disconnecteds verticals components" );

    if ( _globalEnds.size() > 3 )
      errors.push_back ( "More than three globals" );

    if ( ( _globalEnds.size() == 3 ) && ( _localEnds.size() ) )
      errors.push_back ( "Three globals AND locals" );

    if ( _globalEnds.size() + _localEnds.size() + ((anchored)?1:0) < 2 )
      errors.push_back ( "Less than two connections" );

    if ( errors.size() ) {
      cerr << Error("AutoContact topology of %s",getString(_contact).c_str()) << endl;
      if ( anchored )
        cerr << "        A: " << _contact->getAnchor() << endl;

      for ( size_t i=0 ; i < _globalEnds.size() ; i++ )
        cerr << "        G: " << _globalEnds[i] << endl;

      for ( size_t i=0 ; i < _localEnds.size() ; i++ )
        cerr << "        L: " << _localEnds[i] << endl;

      for ( size_t i=0 ; i < errors.size() ; i++ )
        cerr << "        " << errors[i] << endl;
    }
  }


  bool  JunctionBox::canGoOutside ( const AutoSegment* segment ) const
  {
    if ( _contact->isCorner () ) return true;
    if ( _contact->getAnchor() ) return false;

    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      if ( _globalEnds[i]->isHorizontal() xor segment->isHorizontal() ) {
        ltrace(200) << "canGoOutside(): true (has global) " << _contact << endl;
        return true;
      }
    }

    return false;
  }


  bool  JunctionBox::canHDesalignate () const
  {
    if (  _contact->getAnchor  () ) return false;
    if ( !_contact->isHAlignate() ) return false;

    SegmentEnd* globalHorizontal = NULL;
    SegmentEnd* globalVertical   = NULL;

    size_t verticals = 0;
    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      ltrace(109) << _globalEnds[i]->getSegment() << endl;
      if ( _globalEnds[i]->isHorizontal() ) {
        globalHorizontal = _globalEnds[i];
      } else {
        globalVertical = _globalEnds[i];
        verticals++;
      }
    }

    for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
      ltrace(109) << _localEnds[i]->getSegment() << endl;
      if ( _localEnds[i]->isVertical() ) verticals++;
    }

    ltrace(200) << "canHDesalignate(Contact*) - " << _contact << endl;
    ltrace(200) << "  Vertical stem: " << globalVertical
                << " isVAlignate():"   << _contact->isVAlignate()
                << " verticals:"       << verticals
                << endl;
    return (globalVertical != NULL) && (_contact->isVAlignate() || (verticals == 1));
  }


  bool  JunctionBox::canVDesalignate () const
  {
    if (  _contact->getAnchor  () ) return false;
    if ( !_contact->isVAlignate() ) return false;

    SegmentEnd* globalHorizontal = NULL;
    SegmentEnd* globalVertical   = NULL;

    size_t horizontals = 0;
    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      if ( _globalEnds[i]->isHorizontal() ) {
        globalHorizontal = _globalEnds[i];
        horizontals++;
      } else {
        globalVertical = _globalEnds[i];
      }
    }

    for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
      ltrace(109) << _localEnds[i]->getSegment() << endl;
      if ( _localEnds[i]->isHorizontal() ) horizontals++;
    }

    ltrace(200) << "canVDesalignate(Contact*) - " << _contact << endl;
    ltrace(200) << "  Vertical stem: " << globalHorizontal
                << " isHAlignate():"   << _contact->isHAlignate()
                << " horizontals:"     << horizontals
                << endl;
    return (globalHorizontal != NULL) && (_contact->isHAlignate() || (horizontals == 1));
  }


  void  JunctionBox::restoreHConnexity ( DbU::Unit x, bool split )
  {
    ltrace(200) << "restoreHConnexity() - @" << DbU::getValueString(x) << " " << _contact << endl;

    _contact->invalidate ();

    if ( _contact->isHAlignate() ) return;
    if ( _contact->getAnchor  () ) {
      _contact->setHAlignate ( true );
      return;
    }

    bool                slackened    = false;
    SegmentEnd*         verticalStem = NULL;
    vector<SegmentEnd*> horizontals;
    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      if ( _globalEnds[i]->isHorizontal() ) {
        horizontals.push_back ( _globalEnds[i] ) ;
      } else {
        verticalStem = _globalEnds[i];
      }
    }

    if ( verticalStem ) {
      ltrace(200) << "Done nothing has vertical stem: " << verticalStem << endl;
      return;
    }

    for ( size_t i=0 ; i<_localEnds.size() ; i++ ) {
      if ( _localEnds[i]->isHorizontal() )
        horizontals.push_back ( _localEnds[i] ) ;
      else
        slackened = slackened or _localEnds[i]->isSlackened();
    }

    if ( (horizontals.size() == 1) and (horizontals[0]->isGlobal()) ) {
      ltrace(200) << "Done nothing, has only a horizontal stem: " << horizontals[0] << endl;
      return;
    }

    if ( !split ) {
      _contact->setHAlignate ( true );
      return;
    }

    GCell*       gcell = _contact->getGCell ();
    Net*         net   = _contact->getNet   ();
    const Layer* layer = dynamic_cast<const ViaLayer*>(_contact->getLayer())->getTop();
    if ( _routingGauge->getLayerDirection(layer) != Constant::Vertical )
      layer = dynamic_cast<const ViaLayer*>(_contact->getLayer())->getBottom();
    
    _contact->setVAlignate ( true );
    AutoContact* splitContact = NULL;
    for ( size_t i=1 ; i<horizontals.size() ; i++ ) {
      if ( splitContact ) splitContact->setVAlignate ( true );

      ltrace(200) << "| Separate " << horizontals[i]->getSegment()->base()
                  << ":" << horizontals[i]->getSegment() << endl;

      horizontals[i]->getHook()->detach();

      splitContact = AutoContact::create ( gcell, net, _contact->getLayer() );
      AutoSegment* segment = AutoVertical::create ( _contact 
                                                  , splitContact
                                                  , layer
                                                  , x //globalHorizontals[i]->getAxis()
                                                  , DbU::lambda(2.0)
                                                  , AutoSegment::Local
                                                  , false
                                                  , false
                                                  );
      horizontals[i]->getHook()->attach ( splitContact->getContact()->getBodyHook() );
      segment->setSlackened ( slackened );
      ltrace(200) << "restoreHConnexity() strap:  " << segment << endl;
    }
  }


  void  JunctionBox::restoreVConnexity ( DbU::Unit y, bool split )
  {
    ltrace(200) << "restoreVConnexity() - @" << DbU::getValueString(y) << " " << _contact << endl;

    _contact->invalidate ();

    if ( _contact->isVAlignate() ) return;
    if ( _contact->getAnchor  () ) {
      _contact->setVAlignate ( true );
      return;
    }

    bool                slackened      = false;
    SegmentEnd*         horizontalStem = NULL;
    vector<SegmentEnd*> verticals;
    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      if ( _globalEnds[i]->isVertical() ) {
        verticals.push_back ( _globalEnds[i] ) ;
      } else {
        horizontalStem = _globalEnds[i];
      }
    }

    if ( horizontalStem ) {
      ltrace(200) << "Done nothing, has horizontal stem: " << horizontalStem << endl;
      return;
    }

    for ( size_t i=0 ; i<_localEnds.size() ; i++ ) {
      if ( _localEnds[i]->isVertical() )
        verticals.push_back ( _localEnds[i] ) ;
      else
        slackened = slackened or _localEnds[i]->isSlackened();
    }

    if ( (verticals.size() == 1) and (verticals[0]->isGlobal()) ) {
      ltrace(200) << "Done nothing, has only a vertical stem: " << verticals[0] << endl;
      return;
    }

    if ( !split ) {
      _contact->setVAlignate ( true );
      return;
    }

    GCell*       gcell = _contact->getGCell ();
    Net*         net   = _contact->getNet   ();
    const Layer* layer = dynamic_cast<const ViaLayer*>(_contact->getLayer())->getBottom();
    if ( _routingGauge->getLayerDirection(layer) != Constant::Horizontal )
      layer = dynamic_cast<const ViaLayer*>(_contact->getLayer())->getTop();
    
    _contact->setHAlignate ( true );
    AutoContact* splitContact = NULL;
    for ( size_t i=1 ; i<verticals.size() ; i++ ) {
      if ( splitContact ) splitContact->setHAlignate ( true );

      ltrace(200) << "| Separate " << verticals[i]->getSegment()->base()
                  << ":" << verticals[i]->getSegment() << endl;

      verticals[i]->getHook()->detach();

      splitContact = AutoContact::create ( gcell, net, _contact->getLayer() );
      AutoSegment* segment = AutoHorizontal::create ( _contact 
                                                    , splitContact
                                                    , layer
                                                    , y //globalVerticals[i]->getAxis()
                                                    , DbU::lambda(2.0)
                                                    , AutoSegment::Local
                                                    , false
                                                    , false
                                                    );
      verticals[i]->getHook()->attach ( splitContact->getContact()->getBodyHook() );
      segment->setSlackened ( slackened );
      ltrace(200) << "restoreVConnexity() strap:  " << segment << endl;
    }
  }


  void  JunctionBox::computeAlignate ()
  {

    bool    globalHorizontal   = false;
    bool    globalVertical     = false;
    size_t  horizontals        = 0;
    size_t  verticals          = 0;

    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      if ( _globalEnds[i]->isHorizontal() ) {
        globalHorizontal = true;
        horizontals++;
      } else {
        globalVertical = true;
        verticals++;
      }
    }

    for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
      if ( _localEnds[i]->isHorizontal() ) horizontals++;
      else                                 verticals++;
    }

    if ( !globalVertical && (horizontals > 1) )
      _contact->setHAlignate ( true );

    if ( !globalHorizontal && (verticals > 1) )
      _contact->setVAlignate ( true );

    ltrace(109) << "computeAlignate(): [AFTER] " << _contact << endl;
  }


  void  JunctionBox::computeGlobalStem ()
  {
    SegmentEnd* globalHorizontal = NULL;
    SegmentEnd* globalVertical   = NULL;
    size_t      horizontals      = 0;
    size_t      verticals        = 0;

    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      if ( _globalEnds[i]->isHorizontal() ) {
        globalHorizontal = _globalEnds[i];
        horizontals++;
      } else {
        globalVertical = _globalEnds[i];
        verticals++;
      }
    }

    for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
      if ( _localEnds[i]->isHorizontal() ) horizontals++;
      else                                 verticals++;
    }

    ltrace(109) << "computeGlobalStem(): " << _contact << endl;
    ltrace(109) << "| h:" << horizontals << " v:" << verticals << endl;

    if ( globalVertical && (horizontals > 1) && !_contact->isHAlignate() ) {
      ltrace(109) << "| Vertical GlobalStem h:" << horizontals << " v:" << verticals << endl;
      _globalStem = globalVertical;
    }

    if ( globalHorizontal && (verticals > 1) && !_contact->isVAlignate() ) {
      ltrace(109) << "| Horizontal GlobalStem h:" << horizontals << " v:" << verticals << endl;
      _globalStem = globalHorizontal;
    }


    if ( (horizontals > 1) && (verticals > 1) && !_contact->isVAlignate() && !_contact->isHAlignate() ) {
      ltrace(109) << "* Bad AutoContact: " << _contact << endl;

      for ( size_t i=0 ; i < _globalEnds.size() ; i++ )
        ltrace(109) << "| G: " << _globalEnds[i] << endl;

      for ( size_t i=0 ; i < _localEnds.size() ; i++ )
        ltrace(109) << "| L: " << _localEnds[i] << endl;
    }
  }


  void  JunctionBox::mergeX ( DbU::Unit x )
  {
    if ( _xMin > _xMax ) { _xMin = _xMax = x; return; }
    if ( x < _xMin     ) { _xMin = x; return; }
    if ( x > _xMax     ) { _xMax = x; return; }
  }


  void  JunctionBox::mergeY ( DbU::Unit y )
  {
    if ( _yMin > _yMax ) { _yMin = _yMax = y; return; }
    if ( y < _yMin     ) { _yMin = y; return; }
    if ( y > _yMax     ) { _yMax = y; return; }
  }


  void  JunctionBox::mergeAnchor ()
  {
    _anchor = _contact->getAnchor ();
    if ( !_anchor ) return;

    RoutingPad* rp = dynamic_cast<RoutingPad*>(_anchor);
    if ( !rp ) {
      _failsafe = true;
      return;
    }

    _layerStack [ _routingGauge->getLayerDepth(_anchor->getLayer()) ] ++;
    _wireCount++;

    Point source = rp->getSourcePosition ();
    Point target = rp->getTargetPosition ();
    if ( ( source.getX() == target.getX() ) || isHEmpty() ) {
      ltrace(109) << "merge() Axis "
                  << DbU::getLambda(source.getX()) << " [RoutingPad] "
                  << rp->getLayer() << endl;
      mergeX ( source.getX() );
    }
    if ( ( source.getY() == target.getY() ) || isVEmpty() ) {
      ltrace(109) << "merge() Axis "
                  << DbU::getLambda(source.getY()) << " [RoutingPad] "
                  << rp->getLayer() << endl;
      mergeY ( source.getY() ); 
    }
  }


  void  JunctionBox::merge ( Hook* hook )
  {
    SegmentEnd* segmentEnd = SegmentEnd::create ( hook, _checking );
    if ( !segmentEnd ) return;

    _layerStack [ _routingGauge->getLayerDepth(segmentEnd->getLayer()) ] ++;
    _wireCount++;

    if ( segmentEnd->isGlobal() ) {
      ltrace(109) << "merge() Axis "
                  << DbU::getLambda(segmentEnd->getAxis())
                  << " [global] " << segmentEnd << endl;
      _globalEnds.push_back ( segmentEnd );
    } else {
      ltrace(109) << "merge() Axis " << DbU::getLambda(segmentEnd->getAxis())
                  << " [local] " << segmentEnd << endl;
      _localEnds.push_back ( segmentEnd );
    }

    if ( segmentEnd->isHorizontal() ) mergeY ( segmentEnd->getAxis() );
    else                              mergeX ( segmentEnd->getAxis() );
  }


  void  JunctionBox::postMerge ( SegmentEnd* segmentEnd )
  {
    if ( segmentEnd == _globalStem ) return;

    if ( _globalStem->isHorizontal() xor segmentEnd->isHorizontal() )
      _globalStem->addFork ( segmentEnd );
    else
      _globalStem->addAligned ( segmentEnd );
  }


  void  JunctionBox::resizePunctual ()
  {
    Point     center;
    DbU::Unit delta;

    if ( isEmpty() ) center = _contact->getCenter();
    else if ( isPunctual() ) {
      center.setX ( _xMin );
      center.setY ( _yMin );
    } else {
      center.setX ( (_xMin+_xMax)/2 );
      center.setY ( (_yMin+_yMax)/2 );
    }

    for ( size_t i=0 ; i < _globalEnds.size() ; i++ ) {
      if ( _globalEnds[i]->isHorizontal() )
        delta = center.getX() - _contact->getX();
      else
        delta = center.getY() - _contact->getY();
      _globalEnds[i]->setDelta ( delta );
    }

    for ( size_t i=0 ; i < _localEnds.size() ; i++ ) {
      if ( _localEnds[i]->isHorizontal() )
        delta = center.getX() - _contact->getX();
      else
        delta = center.getY() - _contact->getY();

      _localEnds[i]->setDelta ( delta );
    }

    Box constraint = _contact->getConstraintBox()/*.inflate(DbU::lambda(0.5))*/;
    if ( !constraint.contains(center) )
      cerr << Bug("%s [%s %s] outside constraint %s."
                 ,getString(_contact).c_str()
                 ,DbU::getValueString(center.getX()).c_str()
                 ,DbU::getValueString(center.getY()).c_str()
                 ,getString(constraint).c_str()) << endl;
  }


  void  JunctionBox::resize ()
  {
    ltrace(99) << "JunctionBox::resize() - <Box "
               << DbU::getLambda(_xMin) << " " << DbU::getLambda(_yMin) << " "
               << DbU::getLambda(_xMax) << " " << DbU::getLambda(_yMax)
               << ">" << endl;

    if ( !_wireCount ) {
      cerr << Warning("Standalone %s skipped.",getString(_contact).c_str()) << endl;
      return;
    }

    if ( _failsafe || isPunctual() || !_globalStem )
      resizePunctual ();
    else {
      // Flat geometry.
      DbU::Unit deltaMin;
      DbU::Unit deltaMax;
      DbU::Unit deltaFork;

      if ( _globalStem->isHorizontal() ) {
        deltaMin  = _xMin - _contact->getX();
        deltaMax  = _xMax - _contact->getX();
        deltaFork = _yMin - _contact->getY();
      } else {
        deltaMin  = _yMin - _contact->getY();
        deltaMax  = _yMax - _contact->getY();
        deltaFork = _xMin - _contact->getX();
      }

      _globalStem->setDelta ( _globalStem->isSourceHook() ? deltaMin : deltaMax );

      vector<SegmentEnd*>* forks    = _globalStem->getForks();
      vector<SegmentEnd*>* aligneds = _globalStem->getAligneds();

      for ( size_t i=0 ; i < aligneds->size() ; i++ )
        (*aligneds)[i]->setDelta ( (*aligneds)[i]->isSourceHook() ? deltaMax : deltaMin );

      for ( size_t i=0 ; i < forks->size() ; i++ )
        (*forks)[i]->setDelta ( deltaFork );
    }
  }


  void  JunctionBox::split ()
  {
    ltrace(200) << "JunctionBox::split() - " << _contact << endl;

    size_t zMin, zMax;
    size_t anchorDepth = 0;
    getZSpan ( zMin, zMax );

    if ( _anchor ) {
      ltrace(200) << "Anchor: " << _anchor << endl;

      anchorDepth = _routingGauge->getLayerDepth(_anchor->getLayer());
      if ( anchorDepth == 0 ) {
        if ( zMax-zMin < 2 ) return;
        splitTerminal ();
        _contact->split ();
        return;
      }
    }

    ltracein(200);
    ltrace(200) << "Z span: [" << zMin << ":" << zMax << "]" << endl;
    ltrace(200) << "Global Stem: " << _globalStem << endl;

    if ( zMax-zMin > 3 ) {
      cerr << Error("AutoContact::split(): Spans on more than 4 layers, ignoring."
                    "\n                     %s",getString(_contact).c_str()) << endl;
      ltraceout(200);
      return;
    }

    _contact->invalidate ();

    if ( zMax-zMin < 2 ) {
      const Layer* contactLayer = _routingGauge->getContactLayer(zMin);
      _contact->setLayer ( contactLayer );
      ltrace(200) << "Needs only to change Layer." << endl;
      ltraceout(200);
      return;
    }

  // The complete case.
    bool                hExtended = isHExtended();
    bool                vExtended = isVExtended();
    bool                xFound    = false;
    bool                yFound    = false;
    vector<SegmentEnd*> hBottom;
    vector<SegmentEnd*> vBottom;
    vector<SegmentEnd*> hTop;
    vector<SegmentEnd*> vTop;
    Point               position;

    for ( size_t i=0; i < _globalEnds.size() ; i++ ) {
      ltrace(200) << "| G: " << _globalEnds[i] << endl;
      if ( _globalEnds[i]->isHorizontal() ) {
        if ( not yFound ) {
          yFound = true;
          position.setY ( _globalEnds[i]->getAxis() );
        }
        if ( _routingGauge->getLayerDepth(_globalEnds[i]->getLayer()) < zMin+2 )
          hBottom.push_back ( _globalEnds[i] );
        else
          hTop.push_back ( _globalEnds[i] );
      } else {
        if ( not xFound ) {
          xFound = true;
          position.setX ( _globalEnds[i]->getAxis() );
        }
        if ( _routingGauge->getLayerDepth(_globalEnds[i]->getLayer()) < zMin+2 )
          vBottom.push_back ( _globalEnds[i] );
        else
          vTop.push_back ( _globalEnds[i] );
      }
    }

    for ( size_t i=0; i < _localEnds.size() ; i++ ) {
      ltrace(200) << "| L: " << _localEnds[i] << endl;
      if ( _localEnds[i]->isHorizontal() ) {
        if ( not yFound ) {
          yFound = true;
          position.setY ( _localEnds[i]->getAxis() );
        }
        if ( _routingGauge->getLayerDepth(_localEnds[i]->getLayer()) < zMin+2 )
          hBottom.push_back ( _localEnds[i] );
        else
          hTop.push_back ( _localEnds[i] );
      } else {
        if ( not xFound ) {
          xFound = true;
          position.setX ( _localEnds[i]->getAxis() );
        }
        if ( _routingGauge->getLayerDepth(_localEnds[i]->getLayer()) < zMin+2 )
          vBottom.push_back ( _localEnds[i] );
        else
          vTop.push_back ( _localEnds[i] );
      }
    }

    if ( not xFound ) position.setX ( _xMin );
    if ( not yFound ) position.setY ( _yMin );

    for ( size_t i=0 ; i<hTop.size() ; i++ ) hTop[i]->getHook()->detach ();
    for ( size_t i=0 ; i<vTop.size() ; i++ ) vTop[i]->getHook()->detach ();

    AutoContact* corner = AutoContact::create ( _contact->getGCell()
                                              , _contact->getNet()
                                              , _routingGauge->getContactLayer(zMin+1)
                                              );
    ltrace(200) << "Corner " << corner << endl;

    AutoSegment* segment = AutoSegment::create ( _contact
                                               , corner
                                               , _routingGauge->getLayerDirection(zMin+1)
                                               , AutoSegment::Local
                                               );
    DbU::Unit axis = (segment->isHorizontal()) ? position.getY() : position.getX();
    segment->setLayer       ( _routingGauge->getRoutingLayer(zMin+1) );
    segment->setAxis        ( axis );
    segment->setSlackened   ( true );
    segment->setLayerChange ( true );
    ltrace(200) << "Corner @" << DbU::getValueString(axis) << " " << segment << endl;

    if ( vExtended ) _contact->setVAlignate ( true );
    if ( hExtended ) _contact->setHAlignate ( true );

    AutoContact* secondary = NULL;
    if ( zMax-zMin == 3 ) {
      secondary = AutoContact::create ( _contact->getGCell()
                                      , _contact->getNet()
                                      , _routingGauge->getContactLayer(zMin+2)
                                      );
      ltrace(200) << "Secondary " << secondary << endl;

      segment = AutoSegment::create ( corner
                                    , secondary
                                    , _routingGauge->getLayerDirection(zMin+2)
                                    , AutoSegment::Local
                                    );
      axis = (segment->isHorizontal()) ? position.getY() : position.getX();
      segment->setLayer       ( _routingGauge->getRoutingLayer(zMin+2) );
      segment->setAxis        ( axis );
      segment->setCanonical   ( true );
      segment->setSlackened   ( true );
      segment->setLayerChange ( true );
      ltrace(200) << "Secondary @" << DbU::getValueString(axis) << " " << segment << endl;
    } else
      secondary = corner;

    for ( size_t i=0 ; i<hTop.size() ; i++ ) hTop[i]->getHook()->attach ( secondary->getBodyHook() );
    for ( size_t i=0 ; i<vTop.size() ; i++ ) vTop[i]->getHook()->attach ( secondary->getBodyHook() );

    if ( _contact->isVAlignate() ) secondary->setVAlignate(true);
    if ( _contact->isHAlignate() ) secondary->setHAlignate(true);

    if ( hExtended ) {
      ltrace(200) << "Original was H extended: restore V connexity." << endl;
      _contact ->restoreVConnexity ( position.getY(), true );
      secondary->restoreVConnexity ( position.getY(), true );
    }

    if ( vExtended ) {
      ltrace(200) << "Original was V extended: restore H connexity." << endl;
      _contact ->restoreHConnexity ( position.getX(), true );
      secondary->restoreHConnexity ( position.getX(), true );
    }

    ltraceout(200);
  }


  void  JunctionBox::splitTerminal ()
  {
    ltrace(200) << "JunctionBox::splitTerminal(): AutoSegment connected to RoutingPad." << endl;
    ltracein(200);
    Point position = _contact->getPosition ();

    _contact->getAnchorHook()->detach ();

    RoutingPad* routingPad = dynamic_cast<RoutingPad*> ( _anchor );
    if ( !routingPad ) {
      cerr << Bug("JunctionBox::splitTerminal(): %s is not anchored on a <RoutingPad>."
                 ,getString(_contact).c_str()) << endl;
      ltraceout(200);
      return;
    }

    AutoContact* rpContact = AutoContact::fromRp ( _contact->getGCell()
                                                 , routingPad
                                                 , _routingGauge->getContactLayer(0)
                                                 , position
                                                 , DbU::lambda(1.0), DbU::lambda(1.0)
                                                 );
    AutoContact* via23 = AutoContact::create ( _contact->getGCell()
                                             , _contact->getNet()
                                             , _routingGauge->getContactLayer(1)
                                             );

    AutoSegment* segment = AutoSegment::create ( rpContact
                                               , via23
                                               , Constant::Horizontal
                                               , AutoSegment::Local
                                               , true  // terminal.
                                               , false // Temporary: *not* collapsed.
                                               );
    segment->setLayer ( _routingGauge->getRoutingLayer(1) );
    segment->setAxis  ( position.getY() );
    ltrace(200) << "@" << DbU::getValueString(position.getY()) << segment << endl;

    segment = AutoSegment::create ( via23
                                  , _contact
                                  , Constant::Vertical
                                  , AutoSegment::Local
                                  , false // terminal.
                                  , false //true  // collapsed.
                                  );
    segment->setAxis   ( position.getX() );
    segment->setLayer  ( _routingGauge->getRoutingLayer(2) );
    _contact->setLayer ( _routingGauge->getContactLayer(1) );
    ltrace(200) << "@" << DbU::getValueString(position.getX()) << segment << endl;

    ltraceout(200);
  }


  void  JunctionBox::breakUpPunctual ()
  {
    Component*      anchor = _contact->getAnchor();
    Point           center;
    StackedContact* stackedContact;

    if ( isEmpty() ) center = _contact->getCenter();
    else if ( isPunctual() ) {
      center.setX ( _xMin );
      center.setY ( _yMin );
    } else {
      center.setX ( (_xMin+_xMax)/2 );
      center.setY ( (_yMin+_yMax)/2 );
    }

    const Layer* layer = NULL;
    if      ( !_localEnds.empty () ) layer = _localEnds [0]->getLayer();
    else if ( !_globalEnds.empty() ) layer = _globalEnds[0]->getLayer();
    else if ( anchor )               layer = anchor->getLayer ();

    stackedContact = StackedContact::create ( _contact->getNet()
                                            , layer
                                            , center.getX()
                                            , center.getY()
                                            );

    if ( anchor ) stackedContact->setAnchor ( anchor );

    for ( size_t i=0 ; i < _globalEnds.size() ; i++ )
      stackedContact->attachSlave ( _globalEnds[i] );

    for ( size_t i=0 ; i < _localEnds.size() ; i++ )
      stackedContact->attachSlave ( _localEnds[i] );

    stackedContact->breakUp ();
    stackedContact->destroy ();
    ltrace(99) << "JunctionBox::breakUpPunctual() succeded" << endl;
  }


  void  JunctionBox::breakUp ()
  {
    ltrace(99) << "JunctionBox::breakUp() - <Box "
               << DbU::getLambda(_xMin) << " " << DbU::getLambda(_yMin) << " "
               << DbU::getLambda(_xMax) << " " << DbU::getLambda(_yMax)
               << ">" << endl;

    if ( !_wireCount ) {
      cerr << Warning("Standalone %s skipped.",getString(_contact).c_str()) << endl;
      return;
    }

    if ( _failsafe or isPunctual() )
      breakUpPunctual ();
    else {
      if ( not _globalStem ) {
        cerr << Bug ( "JunctionBox::breakUp(): Flatten geometry whitout global stem,\n"
                      "      on %p:%s."
                    , _contact->base()
                    , getString(_contact).c_str()
                    ) << endl;
        breakUpPunctual ();
      } else {
      // Flat geometry.
        vector<StackedContact*>  stackedContacts;

        _globalStem->split ( stackedContacts );
        for ( size_t i=0 ; i < stackedContacts.size() ; i++ ) {
          stackedContacts[i]->breakUp ();
          stackedContacts[i]->destroy ();
        }
      }
    }
    ltrace(99) << "JunctionBox::breakUp() succeded" << endl;
  }


  void  JunctionBox::updateContacts ( VirtualContacts& vcs )
  {
    ltrace(109) << "JunctionBox::updateContacts()" << endl;
    ltracein(109);

    vcs.clear ();

    Component*  anchor = _contact->getAnchor ();
    RoutingPad* rp     = dynamic_cast<RoutingPad*>(anchor);
    if ( rp )
      vcs.merge ( Point(_xMin,_yMin), rp->getLayer() );

    vector<SegmentEnd*>::iterator it  = _localEnds.begin();
    for ( ; it != _localEnds.end() ; it++ )
      vcs.merge ( (*it)->getEnd(), (*it)->getLayer() ); 
     
    for ( it = _globalEnds.begin() ; it != _globalEnds.end() ; it++ )
      vcs.merge ( (*it)->getEnd(), (*it)->getLayer() );

    ltraceout(109);
  }


  StackedContact::~StackedContact ()
  {
    ltrace(99) << "StackedContact::~StackedContact() - " << (void*)this << endl;
  }


  StackedContact::StackedContact ( Net* net, const Layer* layer, DbU::Unit x, DbU::Unit y )
    : Contact(net,layer,x,y)
    , _useds(Session::getRoutingGauge()->getDepth())
    , _anchor(NULL)
  {
    for ( unsigned index = 0 ; index < Session::getRoutingGauge()->getDepth() ; index++ )
      _useds [ index ] = false;

    forEach ( BasicLayer*, basicLayer, getLayer()->getBasicLayers() )
      addLayer ( *basicLayer );
  }


  StackedContact* StackedContact::create ( Net* net, const Layer* layer, DbU::Unit x, DbU::Unit y )
  {
    StackedContact* contact = new StackedContact ( net, layer, x, y );
    contact->_postCreate ();

    ltrace(99) << "create: " << contact << endl;

    return contact;
  }


  void  StackedContact::addLayer ( const Layer* layer )
  {
    if ( !Session::getTechnology()->isMetal(layer) ) return;

    unsigned int index = Session::getRoutingGauge()->getLayerDepth ( layer );
    if ( index == UINT_MAX ) return;

    ltrace(99) << "StackedContact::addLayer() - " << layer << " [" << index << "]" << endl;

    _useds [ index ]  = true;
  }


  void  StackedContact::setAnchor ( Component* anchor )
  {
    if ( (_anchor=anchor) ) {
      forEach ( BasicLayer*, layer, _anchor->getLayer()->getBasicLayers() )
        addLayer ( *layer );
    }
  }


  void  StackedContact::attachSlave ( SegmentEnd* segmentEnd )
  {
    ltrace(88) << "add at " << getCenter() << " " << segmentEnd->getLayer() << endl;

    addLayer ( segmentEnd->getLayer() );

    segmentEnd->setDelta ( 0 );

    Hook* hook = segmentEnd->getHook();
    hook->detach ();
    hook->attach ( getBodyHook() );
  }


  void  StackedContact::breakUp ()
  {
    ltrace(99) << "StakedContact::breakUp() - " << this << endl;

    unsigned int  zMin     = 0;
    unsigned int  zMax     = Session::getRoutingGauge()->getDepth() - 1;
    Contact*      contacts [ zMax+1 ];

    for ( unsigned int i=0 ; i <= zMax ; i++ ) contacts[i] = NULL;

    for ( ; (zMin <= zMax) && !_useds[zMin] ; zMin++ );
    for ( ; (zMax > 0    ) && !_useds[zMax] ; zMax-- );

    ltrace(99) << "Contact depth span [" << zMin << ":" << zMax << "]" << endl;

    if ( zMin >  zMax ) return;
    if ( zMin == zMax ) {
      if ( _anchor )
        contacts[zMin] = Contact::create ( _anchor
                                         , Session::getRoutingGauge()->getRoutingLayer(zMin)
                                         , getX() - _anchor->getX()
                                         , getY() - _anchor->getY()
                                         , DbU::lambda(1.0), DbU::lambda(1.0)
                                         );
      else
        contacts[zMin] = Contact::create ( getNet() 
                                         , Session::getRoutingGauge()->getRoutingLayer(zMin)
                                         , getX()
                                         , getY()
                                         , DbU::lambda(1.0), DbU::lambda(1.0)
                                         );
      ltrace(88) << "Creating [" << zMin << "] " << contacts[zMin] << endl;
    } else {
      if ( _anchor )
        contacts[zMin] = contacts[zMin+1]
                       = Contact::create ( _anchor
                                         , Session::getRoutingGauge()->getContactLayer(zMin)
                                         , getX() - _anchor->getX()
                                         , getY() - _anchor->getY()
                                         , DbU::lambda(1.0), DbU::lambda(1.0)
                                         );
      else
        contacts[zMin] = contacts[zMin+1]
                       = Contact::create ( getNet() 
                                         , Session::getRoutingGauge()->getContactLayer(zMin)
                                         , getX()
                                         , getY()
                                         , DbU::lambda(1.0), DbU::lambda(1.0)
                                         );
      ltrace(88) << "Creating [" << zMin << "] " << contacts[zMin] << endl;

      for ( unsigned int j = zMin+1 ; j < zMax ; j++ ) {
        contacts[j] = contacts[j+1]
                    = Contact::create ( contacts[j-1]
                                      , Session::getRoutingGauge()->getContactLayer(j)
                                      , 0
                                      , 0
                                      , DbU::lambda(1.0), DbU::lambda(1.0)
                                      );
        ltrace(88) << "Creating [" << j << "] " << contacts[j] << endl;
      }
    }

    Hook* bodyHook = getBodyHook ();
    Hook* currHook = bodyHook->getNextHook ();

    while ( currHook != bodyHook ) {
      Hook* nextHook = currHook->getNextHook ();

      currHook->_setNextHook ( currHook );
      Segment* segment = dynamic_cast<Segment*>(currHook->getComponent());
      ltrace(88) << "Reattach [" << Session::getRoutingGauge()->getLayerDepth(segment->getLayer())
                 << "] " << segment << endl;
      currHook->attach ( contacts[Session::getRoutingGauge()->getLayerDepth(segment->getLayer())]->getBodyHook() );

      currHook = nextHook;
    }

    bodyHook->_setNextHook ( bodyHook );
    ltrace(99) << "StakedContact::breakUp() succeeded" << endl;
  }


// -------------------------------------------------------------------
// Class  :  "::FixedJunctionBox".


  class FixedJunctionBox {

    public:
    // Constructor & Destructor.
                    FixedJunctionBox     ( AutoContact*, bool checking );
                   ~FixedJunctionBox     ();
    // Modifiers.
             void   checkTopology   ();
             void   merge           ( Hook* );
             void   resize          ();
             void   breakUp         ();

    protected:
    // Attributes.
      AutoContact*         _contact;
      vector<SegmentEnd*>  _segmentEnds;
      bool                 _checking;
  };


  FixedJunctionBox::FixedJunctionBox ( AutoContact* contact, bool checking )
    : _contact(contact)
    , _segmentEnds()
    , _checking(checking)
  {
    ltrace(110) << "FixedJunctionBox() " << contact << endl;
    ltracein(109);

    forEach ( Hook*, hook, _contact->getBodyHook()->getSlaveHooks() ) merge ( *hook );

    ltraceout(109);
  }
  

  FixedJunctionBox::~FixedJunctionBox ()
  {
    for ( size_t i=0 ; i<_segmentEnds.size() ; i++ ) delete _segmentEnds[i];
  }


  void  FixedJunctionBox::checkTopology ()
  { }


  void  FixedJunctionBox::merge ( Hook* hook )
  {
    SegmentEnd* segmentEnd = SegmentEnd::create ( hook, _checking );
    if ( !segmentEnd ) return;

    ltrace(109) << "merge() Axis "
                << DbU::getLambda(segmentEnd->getAxis())
                << " [global] " << segmentEnd << endl;
    _segmentEnds.push_back ( segmentEnd );
  }


  void  FixedJunctionBox::resize ()
  {
    for ( size_t i=0 ; i<_segmentEnds.size() ; i++ ) _segmentEnds[i]->setDelta(0);
  }


  void  FixedJunctionBox::breakUp ()
  {
    Component*      anchor = _contact->getAnchor();
    StackedContact* stackedContact;

    const Layer* layer = NULL;
    if      ( !_segmentEnds.empty () ) layer = _segmentEnds[0]->getLayer();
    else if ( anchor )                 layer = anchor->getLayer ();

    stackedContact = StackedContact::create ( _contact->getNet()
                                            , layer
                                            , _contact->getX()
                                            , _contact->getY()
                                            );

    if ( anchor ) stackedContact->setAnchor ( anchor );

    for ( size_t i=0 ; i < _segmentEnds.size() ; i++ )
      stackedContact->attachSlave ( _segmentEnds[i] );

    stackedContact->breakUp ();
    stackedContact->destroy ();
    ltrace(99) << "FixedJunctionBox::breakUp() succeded" << endl;
  }


} // End of local namespace.




namespace Katabatic {


// -------------------------------------------------------------------
// Class  :  "Katabatic::VirtualContacts::VC".


  bool operator== ( const VirtualContacts::VC& lhs
                  , const VirtualContacts::VC& rhs )
  {
    return lhs._point == rhs._point;
  }


  void  VirtualContacts::VC::merge ( const Layer* layer )
  {
    if ( _layer->contains(layer) ) return;
    Layer *newLayer = Session::getTechnology()->getLayer ( _layer->getMask() & layer->getMask() );

    if ( !newLayer ) return;
    _layer = newLayer;
  }


  void  VirtualContacts::merge ( const Point& point, const Layer* layer )
  {
    VC  vc ( point, layer );

    ltrace(109) << "VirtualContacts::merge() " << point << " " << layer << endl;

    vector<VC>::iterator  it  = _vcs.begin();
    vector<VC>::iterator  end = _vcs.end();

    for ( ; it != end ; it++ ) {
      if ( *it == vc ) { (*it).merge ( layer ); return; }
    }

    _vcs.push_back ( vc );
    _boundingBox.merge ( Box(point).inflate(DbU::lambda(1.0)) );
  }


// -------------------------------------------------------------------
// Class  :  "Katabatic::AutoContact".


  size_t      AutoContact::_maxId       = 0;
  size_t      AutoContact::_allocateds  = 0;
  const Name  AutoContact::_goName      = "Katabatic::AutoContact";


  AutoContact* AutoContact::fromRp ( GCell*       gcell
                                   , RoutingPad*  routingPad
                                   , const Layer* layer
                                   , Point        point
                                   , DbU::Unit    width
                                   , DbU::Unit    height
                                   , bool         fixed
                                   )
  {
    routingPad->getBodyHook()->detach ();

    DbU::Unit  x      = 0;
    DbU::Unit  y      = 0;
    Entity*    entity = routingPad->getOccurrence().getEntity();

    // Assumes there is no rotation in the Transformation.
    if      ( dynamic_cast<Horizontal*>(entity) ) { x = point.getX(); }
    else if ( dynamic_cast<Vertical*  >(entity) ) { y = point.getY(); }

    return AutoContact::create ( gcell
                               , routingPad
                               , layer
                               , x, y
                               , width, height
                               , false, false
                               , fixed
                               );
  }


  AutoContact::AutoContact ( GCell*   gcell
                           , Contact* contact
                           , bool     hAlignate
                           , bool     vAlignate
                           )
    : ExtensionGo     (contact->getCell())
    , _id             (_maxId++)
    , _contact        (contact)
    , _gcell          (gcell)
    , _invalid        (false)
    , _invalidTopology(true)
    , _isTerminal     (false)
    , _fixed          (false)
    , _hAlignate      (hAlignate)
    , _vAlignate      (vAlignate)
    , _isCorner       (false)
    , _dxMin          (0)
    , _dxMax          (_gcell->getXMax()-_gcell->getX())
    , _dyMin          (0)
    , _dyMax          (_gcell->getYMax()-_gcell->getY())
    , _subContacts    ()
  {
    _allocateds++;
    _gcell->addContact ( this );
  }


  void  AutoContact::_postCreate ()
  {
    ExtensionGo::_postCreate ();

    restoreNativeConstraintBox ();

    ltrace(90) << "Native CBox: " << this
               << " <" << DbU::getLambda(getCBXMin())
               << " "  << DbU::getLambda(getCBYMin())
               << " "  << DbU::getLambda(getCBXMax())
               << " "  << DbU::getLambda(getCBYMax()) << ">" << endl;
    
    Session::link ( this );
    invalidate ();

    ltrace(90) << "AutoContact::_postCreate() - " << this << " in " << _gcell << endl;
  }


  void  AutoContact::_preDestroy ()
  {
    DebugSession::open ( _contact->getNet() );

    ltrace(90) << "AutoContact::_preDestroy() - <AutoContact id:" << _id << ">" << endl;

    if ( not _contact->getSlaveComponents().isEmpty() ) {
      cerr << Error("Base contact still have slaves components, cancelled.\n"
                   "        (%s)"
                   ,_getString().c_str()) << endl;
      DebugSession::close ();
      return;
    }

    if ( not Session::doDestroyTool() ) {
      _gcell->removeContact ( this );
      Session::unlink ( this );
    }
        
    ExtensionGo::_preDestroy ();
    if ( Session::doDestroyBaseContact() )
      _contact->destroy ();

    DebugSession::close ();
  }


  AutoContact::~AutoContact ()
  {
    _allocateds--;
  }


  AutoContact* AutoContact::create (       GCell* gcell
                                   ,       Net*   net
                                   , const Layer* layer
                                   ,       bool   hAlignate
                                   ,       bool   vAlignate
                                   )
  {
    Contact* contact = Contact::create ( net
                                       , layer
                                       , gcell->getCenter().getX()
                                       , gcell->getCenter().getY()
                                       , DbU::lambda(2.0)
                                       , DbU::lambda(2.0)
                                       );
    AutoContact* autoContact = new AutoContact ( gcell, contact, hAlignate, vAlignate );

    autoContact->_postCreate ();

    ltrace(90) << "create(net*) " << autoContact << endl;
    return autoContact;
  }


  AutoContact* AutoContact::create (       GCell*      gcell
                                   ,       RoutingPad* rp
                                   , const Layer*      layer
                                   , const DbU::Unit   dx
                                   , const DbU::Unit   dy
                                   , const DbU::Unit   width
                                   , const DbU::Unit   height
                                   ,       bool        hAlignate
                                   ,       bool        vAlignate
                                   ,       bool        fixed
                                   )
  {
    Contact* contact = Contact::create ( rp
                                       , layer
                                       , dx /*- rp->getX()*/
                                       , dy /*- rp->getY()*/
                                       , width
                                       , height
                                       );
    AutoContact* autoContact = new AutoContact ( gcell, contact, hAlignate, vAlignate );
    
    autoContact->setFixed    ( fixed );
    autoContact->setTerminal ( true );
    autoContact->_postCreate ();

    ltrace(90) << "create(RoutingPad*) " << autoContact << endl;
    return autoContact;
  }


  bool  AutoContact::canDestroy ( bool error ) const
  {
    if ( not _contact->getSlaveComponents().isEmpty() ) {
      if ( error ) {
        cerr << Error("Base contact still have slaves components, cancelled.\n"
                     "        (%s)"
                     ,_getString().c_str()) << endl;
      }
      return false;
    }
    return true;
  }


  size_t  AutoContact::getSegmentEndAllocateds ()
  {
    return SegmentEnd::getAllocateds();
  }


  size_t  AutoContact::getAllocateds ()
  {
    return _allocateds;
  }


  const Name& AutoContact::getStaticName ()
  {
    return _goName;
  }


  const Name& AutoContact::getName () const
  {
    return _goName;
  }


  unsigned int  AutoContact::getMinDepth () const
  {
    size_t minDepth = (size_t)-1;
    Component* anchor = getAnchor ();
    if ( anchor ) {
      minDepth = min ( minDepth, Session::getRoutingGauge()->getLayerDepth(anchor->getLayer()) );
    //ltrace(200) << "Anchor:" << anchor << endl;
    }

    forEach ( Component*, icomponent, getSlaveComponents() ) {
      minDepth = min ( minDepth, Session::getRoutingGauge()->getLayerDepth(icomponent->getLayer()) );
    //ltrace(200) << "Slave:" << *icomponent << endl;
    }

    return (unsigned int)minDepth;
  }


  void  AutoContact::getLengths ( DbU::Unit* lengths, set<AutoSegment*>& processeds )
  {
    forEach ( Hook*, ihook, getBodyHook()->getSlaveHooks() ) {
      bool isSourceHook = (dynamic_cast<Segment::SourceHook*>(*ihook));
      if ( !isSourceHook && ( dynamic_cast<Segment::TargetHook*>(*ihook) == NULL ) ) {
        cerr << Error ( badHookType, getString(ihook->getComponent()).c_str() ) << endl;
        return;
      }

      bool     isHorizontal = true;
      Segment* segment      = dynamic_cast<Horizontal*>((*ihook)->getComponent());
      if ( !segment ) {
        isHorizontal = false;
        segment      = dynamic_cast<Vertical*>((*ihook)->getComponent());
        if ( !segment )
          continue;
      }

      AutoSegment* autoSegment = Session::lookup ( segment );
      if ( not autoSegment or processeds.find(autoSegment) != processeds.end() )
        continue;
      processeds.insert ( autoSegment );

      size_t     depth  = Session::getRoutingGauge()->getLayerDepth(segment->getLayer());
      DbU::Unit  length;
      if ( autoSegment->isLocal() ) {
        length = segment->getLength();
        lengths[depth] += length;
        if ( abs(length) >= DbU::lambda(50.0) )
          cerr << Error("Supicious length:%.2f of %s."
                       ,DbU::getLambda(length),getString(autoSegment).c_str()) << endl;
      } else {
        if ( isHorizontal ) {
          if ( isSourceHook )
            lengths[depth] += _gcell->getBoundingBox().getXMax() - segment->getSourceX();
          else
            lengths[depth] += segment->getTargetX() - _gcell->getBoundingBox().getXMin();
        } else {
          if ( isSourceHook )
            lengths[depth] += _gcell->getBoundingBox().getYMax() - segment->getSourceY();
          else
            lengths[depth] += segment->getTargetY() - _gcell->getBoundingBox().getYMin();
        }
      }
    }
  }


  Box  AutoContact::getNativeConstraintBox () const
  {
  //if ( _fixed ) return Box(getCenter());

    Component* component = getAnchor();
    if ( component == NULL ) return _gcell->getBoundingBox ();
    
    DbU::Unit   xMin;
    DbU::Unit   xMax;
    DbU::Unit   yMin;
    DbU::Unit   yMax;
    Vertical*   vertical;
    Horizontal* horizontal;
    RoutingPad* routingPad;

    if ( (horizontal = dynamic_cast<Horizontal*>(component))) {
      xMin = horizontal->getSourcePosition().getX();
      xMax = horizontal->getTargetPosition().getX();
      yMin = yMax
           = horizontal->getTargetPosition().getY();
    } else if ( (vertical = dynamic_cast<Vertical*>(component)) ) {
      yMin = vertical->getSourcePosition().getY();
      yMax = vertical->getTargetPosition().getY();
      xMin = xMax
           = vertical->getTargetPosition().getX();
    } else if ( (routingPad = dynamic_cast<RoutingPad*>(component)) ) {
      Entity* entity = routingPad->getOccurrence().getEntity();

    // Assumes there is no rotation in the Transformation.
      if ( dynamic_cast<Horizontal*>(entity) ) {
        xMin = routingPad->getSourcePosition().getX();
        xMax = routingPad->getTargetPosition().getX();
        yMin = yMax
             = routingPad->getTargetPosition().getY();
      } else if ( dynamic_cast<Vertical*>(entity) ) {
        yMin = routingPad->getSourcePosition().getY();
        yMax = routingPad->getTargetPosition().getY();
        xMin = xMax
             = routingPad->getTargetPosition().getX();
      } else {
        xMin = xMax = routingPad->getPosition().getX();
        yMin = yMax = routingPad->getPosition().getY();
      }
    } else {
      xMin = xMax = component->getPosition().getX();
      yMin = yMax = component->getPosition().getY();
    }

    order ( xMin, xMax );
    order ( yMin, yMax );

    return Box ( xMin, yMin, xMax, yMax );
  }


  Interval  AutoContact::getUConstraints ( unsigned int direction ) const
  {
    if ( direction == Constant::Horizontal ) {
      return Interval ( getCBYMin(), getCBYMax() );
    }
    return Interval ( getCBXMin(), getCBXMax() );
  }


  AutoContacts  AutoContact::getCollapseds ( unsigned int direction )
  {
    return AutoContacts_Collapsed ( this, direction );
  }


  void  AutoContact::invalidate ()
  {
    if ( !isInvalidated() ) {
      ltrace(110) << "AutoContact::invalidate() - " << this << endl;
      setInvalidated ( true );
      Session::invalidate ( this );
      getGCell()->invalidate ();
    }
  }


  void  AutoContact::revalidate ()
  {
    updateGeometry ();
    if ( _invalidTopology )
      revalidateTopology ();
  }


  void  AutoContact::updateGeometry ()
  {
    DebugSession::open ( getNet(), 80 );

    ltrace(110) << "AutoContact::updateGeometry() " << this << endl;
    ltracein(110);

    _contact->invalidate ( false );
    setInvalidated ( false );

    if ( isFixed() ) {
      FixedJunctionBox junctionBox ( this, false );
      junctionBox.resize ();
    } else {
      JunctionBox junctionBox ( this, false );
      junctionBox.resize ();
      junctionBox.updateContacts ( _subContacts );
    }
#if defined(CHECK_DATABASE)
    checkTopology();
#endif

    ltraceout(110);

    DebugSession::close ();
  }


  void  AutoContact::setGCell ( GCell* gcell )
  {
    invalidate ();
    if ( _gcell ) _gcell->removeContact ( this );

    _gcell = gcell;
    if ( _gcell ) {
      _gcell->addContact ( this );
      _contact->setPosition ( _gcell->getCenter() );
      _dxMin = 0;
      _dyMin = 0;
      _dxMax = _gcell->getXMax()-_gcell->getX();
      _dyMax = _gcell->getYMax()-_gcell->getY();
    } else {
      cerr << Bug("NULL GCell for %p:%s.",_contact,_getString().c_str()) << endl;
    }
  }


  void  AutoContact::breakUp ()
  {
    if ( isFixed() ) {
      FixedJunctionBox(this,false).breakUp();
    } else {
      JunctionBox(this,false).breakUp();
    }
    ltrace(110) << "AutoContact::breakUp() succeded" << endl;
  }


  void  AutoContact::split ()
  {
    DebugSession::open ( getNet() );
    JunctionBox(this,false).split();
    DebugSession::close ();
  }


  void  AutoContact::checkTopology ()
  {
    ltrace(110) << "checkTopology() " << this << endl;

    if ( isFixed() ) {
      FixedJunctionBox(this,true).checkTopology();
    } else {
      JunctionBox(this,true).checkTopology();
    }
  }


  void  AutoContact::revalidateTopology ()
  {
    ltrace(110) << "revalidateTopology() " << this << endl;

    JunctionBox(this,true).revalidateTopology();
  }


  bool  AutoContact::isAlignate ( unsigned int direction ) const
  {
    return (_hAlignate && (direction == Constant::Horizontal))
        || (_vAlignate && (direction == Constant::Vertical  ));
  }


  bool  AutoContact::isHExtended ()
  { return JunctionBox(this,true).isHExtended(); }


  bool  AutoContact::isVExtended ()
  { return JunctionBox(this,true).isVExtended(); }


  void  AutoContact::computeAlignate ()
  {
    if ( !isFixed() )
      JunctionBox(this,true).computeAlignate();
  }


  bool  AutoContact::canGoOutsideGCell ( const AutoSegment* segment )
  { return JunctionBox(this,true).canGoOutside(segment); }


  bool  AutoContact::canHDesalignate ()
  { return JunctionBox(this,true).canHDesalignate(); }


  bool  AutoContact::canVDesalignate ()
  { return JunctionBox(this,true).canVDesalignate(); }


  bool  AutoContact::hDesalignate ()
  {
    bool desalignate = JunctionBox(this,true).canHDesalignate();

    if ( desalignate ) setHAlignate ( false );
    return desalignate;
  }


  bool  AutoContact::vDesalignate ()
  {
    bool desalignate = JunctionBox(this,true).canVDesalignate();

    if ( desalignate ) setVAlignate ( false );
    return desalignate;
  }


  void  AutoContact::restoreHConnexity ( DbU::Unit x, bool split )
  { JunctionBox(this,true).restoreHConnexity ( x, split ); }


  void  AutoContact::restoreVConnexity ( DbU::Unit y, bool split )
  { JunctionBox(this,true).restoreVConnexity ( y, split ); }


  bool  AutoContact::canMoveUp ( AutoSegment* moved ) const
  {
    ltrace(200) << "AutoContact::canMoveUp() " << this << endl;
    size_t viaDepth = 100;

    RoutingGauge* rg         = Session::getRoutingGauge();
    size_t        movedDepth = rg->getLayerDepth(moved->getLayer());

    Component* anchor = getAnchor ();
    if ( anchor ) {
      viaDepth = rg->getLayerDepth(anchor->getLayer());
      ltrace(200) << "| Anchor depth: " << viaDepth << endl;
    }

    forEach ( Segment*, isegment, _contact->getSlaveComponents().getSubSet<Segment*>() ) {
      if ( *isegment == moved->base() ) continue;

      size_t depth = rg->getLayerDepth(isegment->getLayer());
      if ( viaDepth == 100 ) viaDepth = depth;
      else
        if ( viaDepth != depth ) return false;

      ltrace(200) << "| Segment depth: " << depth << endl;
    }

    return ( movedDepth+1 == viaDepth );
  }


  void  AutoContact::setConstraintBox ( const Box& box )
  {
    setCBXMin ( box.getXMin() );
    setCBXMax ( box.getXMax() );
    setCBYMin ( box.getYMin() );
    setCBYMax ( box.getYMax() );
    ltrace(110) << "setConstraintBox() - " << this << " " << getConstraintBox() << endl;
    ltrace(110) << "* " << _gcell << endl;
  }


  bool  AutoContact::restrictConstraintBox ( DbU::Unit    constraintMin
                                           , DbU::Unit    constraintMax
                                           , unsigned int direction
                                           , bool         warnOnError )
  {
    if ( direction & Constant::Horizontal ) {
      if ( (constraintMin > getCBYMax()) or (constraintMax < getCBYMin()) ) {
        if ( Session::getDemoMode() or not warnOnError ) return false;

        cerr << Error ( "Incompatible DY restriction on %s", _getString().c_str() ) << endl;
        if ( constraintMin > getCBYMax() )
          cerr << Error ( "(constraintMin > CBYMax : %.2lf > %.2lf)"
                        , DbU::getLambda(constraintMin)
                        , DbU::getLambda(getCBYMax()) )
               << endl;
        if ( constraintMax < getCBYMin() )
          cerr << Error ( "(constraintMax < CBYMin : %.2lf < %.2lf)"
                        , DbU::getLambda(constraintMax)
                        , DbU::getLambda(getCBYMin()) )
               << endl;
        return false;
      }
      setCBYMin ( max(getCBYMin(),constraintMin) );
      setCBYMax ( min(getCBYMax(),constraintMax) );
    } else if ( direction & Constant::Vertical ) {
      if ( (constraintMin > getCBXMax()) || (constraintMax < getCBXMin()) ) {
        if ( Session::getDemoMode() or not warnOnError ) return false;

        cerr << Error ( "Incompatible DX restriction on %s", _getString().c_str() ) << endl;
        if ( constraintMin > getCBXMax() )
          cerr << Error ( "(constraintMin > CBXMax : %.2lf > %.2lf)"
                        , DbU::getLambda(constraintMin)
                        , DbU::getLambda(getCBXMax()) )
               << endl;
        if ( constraintMax < getCBXMin() )
          cerr << Error ( "(constraintMax < CBXMin : %.2lf < %.2lf)"
                        , DbU::getLambda(constraintMax)
                        , DbU::getLambda(getCBXMin()) )
               << endl;
        return false;
      }
      setCBXMin ( max(getCBXMin(),constraintMin) );
      setCBXMax ( min(getCBXMax(),constraintMax) );
    }
    ltrace(110) << "restrictConstraintBox() - " << this << " " << getConstraintBox() << endl;
    return true;
  }


  void  AutoContact::restoreNativeConstraintBox ()
  {
    setConstraintBox ( getNativeConstraintBox() );
  }

                 
  Box& AutoContact::intersectConstraintBox ( Box& box ) const
  {
    return box = box.getIntersection ( getConstraintBox() );
  }


  Box  AutoContact::getBoundingBox () const
  {
    return _gcell->getBoundingBox ();
  }


  void  AutoContact::translate ( const DbU::Unit& tx, const DbU::Unit& ty )
  {
    cerr << Warning("Calling AutoContact::translate() is likely a bug.") << endl;
    _contact->translate ( tx, ty );
  }


  string  AutoContact::_getString () const
  {
    string  s = _contact->_getString();
    s.insert ( 1, "id: " );
    s.insert ( 4, getString(_id) );
    s.insert ( s.size()-1, (_fixed     )?" F":" -" );
    s.insert ( s.size()-1, (_isTerminal)? "t": "-" );
    s.insert ( s.size()-1, (_hAlignate) ? "h": "-" );
    s.insert ( s.size()-1, (_vAlignate) ? "v": "-" );
    s.insert ( s.size()-1, (_invalid)   ? "i": "-" );

    // Point p = _contact->getCenter();
    // s.insert ( s.size()-1, " [" );
    // s.insert ( s.size()-1, DbU::getValueString(p.getX()) );
    // s.insert ( s.size()-1, ":" );
    // s.insert ( s.size()-1, DbU::getValueString(p.getY()) );
    // s.insert ( s.size()-1, "]" );
    return s;
  }


  Record* AutoContact::_getRecord () const
  {
    Record* record = _contact->_getRecord ();
    record->add ( getSlot ( "_gcell"        , _gcell             ) );
    record->add ( getSlot ( "_constraintBox", getConstraintBox() ) );
    record->add ( getSlot ( "_fixed"        , _fixed             ) );
    record->add ( getSlot ( "_isTerminal"   , _isTerminal        ) );
    record->add ( getSlot ( "_hAlignate"    , _hAlignate         ) );
    record->add ( getSlot ( "_vAlignate"    , _vAlignate         ) );
    record->add ( getSlot ( "_invalid"      , _invalid           ) );
    return record;
  }


} // End of Katabatic namespace.
