// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2008-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// |                   C O R I O L I S                               |
// |         A n a b a t i c  -  Routing Toolbox                     |
// |                                                                 |
// |  Author      :                    Jean-Paul CHAPUT              |
// |  E-mail      :            Jean-Paul.Chaput@lip6.fr              |
// | =============================================================== |
// |  C++ Header  :  "./anabatic/AutoSegment.h"                      |
// +-----------------------------------------------------------------+


#ifndef  ANABATIC_AUTOSEGMENT_H
#define  ANABATIC_AUTOSEGMENT_H

#include <set>
#include <iostream>
#include <functional>
#include "hurricane/Interval.h"
#include "hurricane/Segment.h"
#include "hurricane/Components.h"
#include "hurricane/Contact.h"
namespace Hurricane {
  class Layer;
  class Horizontal;
  class Vertical;
  class Cell;
}
#include "crlcore/RoutingGauge.h"
#include "anabatic/Constants.h"
#include "anabatic/GCell.h"
#include "anabatic/AutoSegments.h"
#include "anabatic/Session.h"


namespace Anabatic {

  using std::array;
  using std::set;
  using std::cerr;
  using std::endl;
  using std::binary_function;
  using Hurricane::StaticObservable;
  using Hurricane::BaseObserver;
  using Hurricane::tab;
  using Hurricane::Interval;
  using Hurricane::Layer;
  using Hurricane::Components;
  using Hurricane::Horizontal;
  using Hurricane::Vertical;
  using Hurricane::Cell;
  using CRL::RoutingGauge;

  class AutoHorizontal;
  class AutoVertical;

// -------------------------------------------------------------------
// Class  :  "AutoSegment".

 

  class AutoSegment {
      friend class AutoHorizontal;
      friend class AutoVertical;

    public:
      static const uint64_t  SegNoFlags           =  0L;
      static const uint64_t  SegHorizontal        = (1L<< 0);
      static const uint64_t  SegFixed             = (1L<< 1);
      static const uint64_t  SegFixedAxis         = (1L<< 2);
      static const uint64_t  SegGlobal            = (1L<< 3);
      static const uint64_t  SegWeakGlobal        = (1L<< 4);
      static const uint64_t  SegLongLocal         = (1L<< 5);
      static const uint64_t  SegCanonical         = (1L<< 6);
      static const uint64_t  SegBipoint           = (1L<< 7);
      static const uint64_t  SegDogleg            = (1L<< 8);
      static const uint64_t  SegStrap             = (1L<< 9);
      static const uint64_t  SegSourceTop         = (1L<<10);
      static const uint64_t  SegSourceBottom      = (1L<<11);
      static const uint64_t  SegTargetTop         = (1L<<12);
      static const uint64_t  SegTargetBottom      = (1L<<13);
      static const uint64_t  SegIsReduced         = (1L<<14);
      static const uint64_t  SegDrag              = (1L<<15);
      static const uint64_t  SegLayerChange       = (1L<<16);
      static const uint64_t  SegSourceTerminal    = (1L<<17);  // Replace Terminal.
      static const uint64_t  SegTargetTerminal    = (1L<<18);  // Replace Terminal.
      static const uint64_t  SegStrongTerminal    = SegSourceTerminal|SegTargetTerminal;
      static const uint64_t  SegWeakTerminal1     = (1L<<19);  // Replace TopologicalEnd.
      static const uint64_t  SegWeakTerminal2     = (1L<<20);  // Replace TopologicalEnd.
      static const uint64_t  SegNotSourceAligned  = (1L<<21);
      static const uint64_t  SegNotTargetAligned  = (1L<<22);
      static const uint64_t  SegUnbound           = (1L<<23);
      static const uint64_t  SegHalfSlackened     = (1L<<24);
      static const uint64_t  SegSlackened         = (1L<<25);
      static const uint64_t  SegAxisSet           = (1L<<26);
      static const uint64_t  SegInvalidated       = (1L<<27);
      static const uint64_t  SegInvalidatedSource = (1L<<28);
      static const uint64_t  SegInvalidatedTarget = (1L<<29);
      static const uint64_t  SegInvalidatedLayer  = (1L<<30);
      static const uint64_t  SegCreated           = (1L<<31);
      static const uint64_t  SegUserDefined       = (1L<<32);
      static const uint64_t  SegAnalog            = (1L<<33);
      static const uint64_t  SegWide              = (1L<<34);
    // Masks.
      static const uint64_t  SegWeakTerminal      = SegStrongTerminal|SegWeakTerminal1|SegWeakTerminal2;
      static const uint64_t  SegNotAligned        = SegNotSourceAligned|SegNotTargetAligned;
      static const uint64_t  SegSpinTop           = SegSourceTop    |SegTargetTop;
      static const uint64_t  SegSpinBottom        = SegSourceBottom |SegTargetBottom;
      static const uint64_t  SegDepthSpin         = SegSpinTop      |SegSpinBottom;

    public:
      class Observable : public StaticObservable<1> {
        public:
          enum Indexes { TrackSegment = 0
                       };
        public:
          inline             Observable ();
        private:
                             Observable ( const StaticObservable& );
                 Observable& operator=  ( const StaticObservable& );
      };
    public:
      enum ObserverFlag { Create           = (1 <<  0)
                        , Destroy          = (1 <<  1)
                        , Invalidate       = (1 <<  2)
                        , Revalidate       = (1 <<  3)
                        , RevalidatePPitch = (1 <<  4)
                        };
    public:
      typedef  std::function< void(AutoSegment*) >  RevalidateCb_t;
    public:
             static  void                setAnalogMode              ( bool );
             static  bool                getAnalogMode              ();
      inline static  DbU::Unit           getViaToTopCap             ( size_t depth );
      inline static  DbU::Unit           getViaToBottomCap          ( size_t depth );
      inline static  DbU::Unit           getViaToSameCap            ( size_t depth );
             static  AutoSegment*        create                     ( AutoContact*  source
                                                                    , AutoContact*  target
                                                                    , Segment*      hurricaneSegment
                                                                    );
             static  AutoSegment*        create                     ( AutoContact*  source
                                                                    , AutoContact*  target
                                                                    , Flags         dir
                                                                    , size_t        depth=RoutingGauge::nlayerdepth
                                                                    );
                     void                destroy                    ();
    // Wrapped Segment Functions.                            
             virtual Segment*            base                       () const = 0;
             virtual Segment*            base                       () = 0;
             virtual Horizontal*         getHorizontal              () { return NULL; };
             virtual Vertical*           getVertical                () { return NULL; };
      inline         Cell*               getCell                    () const;
      inline         Net*                getNet                     () const;
      inline         const Layer*        getLayer                   () const;
      inline         Box                 getBoundingBox             () const;
      inline         Hook*               getSourceHook              ();
      inline         Hook*               getTargetHook              ();
      inline         Contact*            getSource                  () const;
      inline         Contact*            getTarget                  () const;
      inline         Component*          getOppositeAnchor          ( Component* ) const;
      inline         Components          getAnchors                 () const;
             virtual DbU::Unit           getX                       () const;
             virtual DbU::Unit           getY                       () const;
      inline         DbU::Unit           getWidth                   () const;
      inline         DbU::Unit           getContactWidth            () const;
      inline         DbU::Unit           getLength                  () const;
      inline         DbU::Unit           getSourcePosition          () const;
      inline         DbU::Unit           getTargetPosition          () const;
      inline         DbU::Unit           getSourceX                 () const;
      inline         DbU::Unit           getSourceY                 () const;
      inline         DbU::Unit           getTargetX                 () const;
      inline         DbU::Unit           getTargetY                 () const;
      inline         void                invert                     ();
      inline         void                setLayer                   ( const Layer* );
    // Predicates.                                           
      inline         bool                isHorizontal               () const;
      inline         bool                isVertical                 () const;
      inline         bool                isGlobal                   () const;
      inline         bool                isWeakGlobal               () const;
      inline         bool                isLongLocal                () const;
      inline         bool                isLocal                    () const;
      inline         bool                isFixed                    () const;
      inline         bool                isFixedAxis                () const;
      inline         bool                isBipoint                  () const;
      inline         bool                isWeakTerminal             () const;
      inline         bool                isWeakTerminal1            () const;
      inline         bool                isWeakTerminal2            () const;
      inline         bool                isTerminal                 () const;
      inline         bool                isDrag                     () const;
      inline         bool                isNotSourceAligned         () const;
      inline         bool                isNotTargetAligned         () const;
      inline         bool                isNotAligned               () const;
                     bool                isStrongTerminal           ( Flags flags=Flags::NoFlags ) const;
      inline         bool                isSourceTerminal           () const;
      inline         bool                isTargetTerminal           () const;
      inline         bool                isLayerChange              () const;
      inline         bool                isSpinTop                  () const;
      inline         bool                isSpinBottom               () const;
      inline         bool                isSpinTopOrBottom          () const;
      inline         bool                isReduced                  () const;
      inline         bool                isStrap                    () const;
      inline         bool                isDogleg                   () const;
      inline         bool                isUnbound                  () const;
      inline         bool                isInvalidated              () const;
      inline         bool                isInvalidatedLayer         () const;
      inline         bool                isCreated                  () const;
      inline         bool                isCanonical                () const;
      inline         bool                isUnsetAxis                () const;
      inline         bool                isSlackened                () const;
      inline         bool                isUserDefined              () const;
                     bool                isReduceCandidate          () const;
                     bool                isUTurn                    () const;
      inline         bool                isAnalog                   () const;
      inline         bool                isWide                     () const;
             virtual bool                _canSlacken                () const = 0;
                     bool                canReduce                  () const;
                     bool                mustRaise                  () const;
                     Flags               canDogleg                  ( Interval );
             virtual bool                canMoveULeft               ( float reserve=0.0 ) const = 0;
             virtual bool                canMoveURight              ( float reserve=0.0 ) const = 0;
                     bool                canMoveUp                  ( float reserve=0.0, Flags flags=Flags::NoFlags ) const;
                     bool                canPivotUp                 ( float reserve=0.0, Flags flags=Flags::NoFlags ) const;
                     bool                canPivotDown               ( float reserve=0.0, Flags flags=Flags::NoFlags ) const;
                     bool                canSlacken                 ( Flags flags=Flags::NoFlags ) const;
             virtual bool                checkPositions             () const = 0;
             virtual bool                checkConstraints           () const = 0;
                     bool                checkDepthSpin             () const;
    // Accessors.                                            
      inline         unsigned long       getId                      () const;
      inline         uint64_t            getFlags                   () const;
             virtual Flags               getDirection               () const = 0;
      inline         GCell*              getGCell                   () const;
             virtual bool                getGCells                  ( vector<GCell*>& ) const = 0;
      inline         AutoContact*        getAutoSource              () const;
      inline         AutoContact*        getAutoTarget              () const;
                     AutoContact*        getOppositeAnchor          ( AutoContact* ) const;
                     size_t              getPerpandicularsBound     ( set<AutoSegment*>& );
      inline         AutoSegment*        getParent                  () const;
      inline         unsigned int        getDepth                   () const;
      inline         DbU::Unit           getPitch                   () const;
                     DbU::Unit           getPPitch                  () const;
#if DISABLED
                     DbU::Unit           getExtensionCap            () const;
#endif
                     DbU::Unit           getExtensionCap            ( Flags ) const;
      inline         DbU::Unit           getAxis                    () const;
                     void                getEndAxes                 ( DbU::Unit& sourceAxis, DbU::Unit& targetAxis ) const;
             virtual DbU::Unit           getSourceU                 () const = 0;
             virtual DbU::Unit           getTargetU                 () const = 0;
             virtual DbU::Unit           getDuSource                () const = 0;
             virtual DbU::Unit           getDuTarget                () const = 0;
      inline         DbU::Unit           getOrigin                  () const;
      inline         DbU::Unit           getExtremity               () const;
             virtual Interval            getSpanU                   () const = 0;
                     Interval            getMinSpanU                () const;
             virtual Interval            getSourceConstraints       ( Flags flags=Flags::NoFlags ) const = 0;
             virtual Interval            getTargetConstraints       ( Flags flags=Flags::NoFlags ) const = 0;
             virtual bool                getConstraints             ( DbU::Unit& min, DbU::Unit& max ) const = 0;
      inline         bool                getConstraints             ( Interval& i ) const;
      inline         const Interval&     getUserConstraints         () const;
      inline         const Interval&     getNativeConstraints       () const;
             virtual DbU::Unit           getSlack                   () const;
      inline         DbU::Unit           getOptimalMin              () const;
      inline         DbU::Unit           getOptimalMax              () const;
      inline         DbU::Unit           getNativeMin               () const;
      inline         DbU::Unit           getNativeMax               () const;
                     Interval&           getOptimal                 ( Interval& i ) const;
             virtual DbU::Unit           getCost                    ( DbU::Unit axis ) const;
             virtual AutoSegment*        getCanonical               ( DbU::Unit& min , DbU::Unit& max );
      inline         AutoSegment*        getCanonical               ( Interval& i );
                     float               getMaxUnderDensity         ( Flags flags );
    // Modifiers.                                            
      inline         void                unsetFlags                 ( uint64_t );
      inline         void                setFlags                   ( uint64_t );
                     void                setFlagsOnAligneds         ( uint64_t );
      inline         void                incReduceds                ();
      inline         void                decReduceds                ();
             virtual void                setDuSource                ( DbU::Unit du ) = 0;
             virtual void                setDuTarget                ( DbU::Unit du ) = 0;
                     void                computeTerminal            ();
             virtual void                updateOrient               () = 0;
             virtual void                updatePositions            () = 0;
             virtual void                updateNativeConstraints    () = 0;
                     void                updateSourceSpin           ();
                     void                updateTargetSpin           ();
                     void                sourceDetach               ();
                     void                targetDetach               ();
                     void                sourceAttach               ( AutoContact* );
                     void                targetAttach               ( AutoContact* );
    //inline         void                mergeUserConstraints       ( const Interval& );
                     void                mergeUserConstraints       ( const Interval& );
      inline         void                resetUserConstraints       ();
      inline         void                setOptimalMin              ( DbU::Unit min );
      inline         void                setOptimalMax              ( DbU::Unit max );
      inline         void                mergeNativeMin             ( DbU::Unit min );
      inline         void                mergeNativeMax             ( DbU::Unit max );
      inline         void                resetNativeConstraints     ( DbU::Unit min, DbU::Unit max );
                     bool                checkNotInvalidated        () const;
      inline         void                setParent                  ( AutoSegment* );
                     void                revalidate                 ();
                     AutoSegment*        makeDogleg                 ( AutoContact* );
                     Flags               makeDogleg                 ( Interval, Flags flags=Flags::NoFlags );
                     Flags               makeDogleg                 ( GCell*  , Flags flags=Flags::NoFlags );
             virtual Flags               _makeDogleg                ( GCell*  , Flags flags ) = 0;
             virtual bool                moveULeft                  () = 0;
             virtual bool                moveURight                 () = 0;
                     bool                slacken                    ( Flags flags );
             virtual bool                _slacken                   ( Flags flags ) = 0;
                     void                _changeDepth               ( unsigned int depth, Flags flags );
                     void                changeDepth                ( unsigned int depth, Flags flags );
                     bool                moveUp                     ( Flags flags=Flags::NoFlags );
                     bool                moveDown                   ( Flags flags=Flags::NoFlags );
                     bool                reduceDoglegLayer          ();
                     bool                reduce                     ();
                     bool                raise                      ();
    // Canonical Modifiers.                                            
                     AutoSegment*        canonize                   ( Flags flags=Flags::NoFlags );
             virtual void                invalidate                 ( Flags flags=Flags::Propagate );
                     void                invalidate                 ( AutoContact* );
                     void                computeOptimal             ( set<AutoSegment*>& processeds );
                     void                setAxis                    ( DbU::Unit, Flags flags=Flags::NoFlags );
                     bool                toConstraintAxis           ( Flags flags=Flags::Realignate );
                     bool                toOptimalAxis              ( Flags flags=Flags::Realignate );
    // Collections & Filters.                                
                     AutoSegments        getOnSourceContact         ( Flags direction );
                     AutoSegments        getOnTargetContact         ( Flags direction );
                     AutoSegments        getCachedOnSourceContact   ( Flags direction );
                     AutoSegments        getCachedOnTargetContact   ( Flags direction );
                     AutoSegments        getAligneds                ( Flags flags=Flags::NoFlags );
                     AutoSegments        getConnecteds              ( Flags flags=Flags::NoFlags );
                     AutoSegments        getPerpandiculars          ( Flags flags=Flags::NoFlags );
                     size_t              getAlignedContacts         ( map<AutoContact*,int>& ) const ;
    // Observers.                         
      template< typename OwnerT >
      inline         OwnerT*             getObserver                ( size_t slot );
      inline         void                setObserver                ( size_t slot, BaseObserver* );
      inline         void                notify                     ( unsigned int flags );
    // Inspector Management.                                 
             virtual Record*             _getRecord                 () const = 0;
             virtual string              _getString                 () const = 0;
             virtual string              _getTypeName               () const = 0;
    // Non-reviewed atomic modifiers.
                     bool                _check                     () const;
#if THIS_IS_DISABLED
             virtual void                desalignate                ( AutoContact* ) = 0;
                     bool                shearUp                    ( GCell*
                                                                    , AutoSegment*& movedUp
                                                                    , float         reserve
                                                                    , Flags         flags );
#endif
                                  
    protected:                    
    // Internal: Static Attributes.
      static size_t                        _allocateds;
      static size_t                        _globalsCount;
      static bool                          _analogMode;
      static bool                          _initialized;
      static vector< array<DbU::Unit*,3> > _extensionCaps;
    // Internal: Attributes.      
      const  unsigned long                 _id;
             GCell*                        _gcell;
             uint64_t                      _flags;
             unsigned int                  _depth      : 8;
             unsigned int                  _optimalMin :16;
             unsigned int                  _optimalMax :16;
             unsigned int                  _reduceds   : 2;
             DbU::Unit                     _sourcePosition;
             DbU::Unit                     _targetPosition;
             Interval                      _userConstraints;
             Interval                      _nativeConstraints;
             AutoSegment*                  _parent;
             Observable                    _observers;
                                  
    // Internal: Constructors & Destructors.
    protected:                    
                                         AutoSegment     ( Segment* segment );
             virtual                    ~AutoSegment     ();
             static  void                _preCreate      ( AutoContact* source, AutoContact* target );
             virtual void                _postCreate     ();
             virtual void                _preDestroy     ();
             static  void                _initialize     ();
    private:                                      
                                         AutoSegment     ( const AutoSegment& );
                     AutoSegment&        operator=       ( const AutoSegment& );
    protected:                                    
                     void                _invalidate     ();
      inline         uint64_t            _getFlags       () const;
                     std::string         _getStringFlags () const;
             virtual void                _setAxis        ( DbU::Unit ) = 0;

    public:
      struct CompareId : public binary_function<AutoSegment*,AutoSegment*,bool> {
          inline bool  operator() ( const AutoSegment* lhs, const AutoSegment* rhs ) const;
      };
    public:
      struct CompareByDepthLength : public binary_function<AutoSegment*,AutoSegment*,bool> {
          bool operator() ( AutoSegment* lhs, AutoSegment* rhs ) const;
      };
    public:
      struct CompareByDepthAxis : public binary_function<AutoSegment*,AutoSegment*,bool> {
          bool operator() ( AutoSegment* lhs, AutoSegment* rhs ) const;
      };
    public:
      typedef std::set<AutoSegment*,CompareByDepthLength>  DepthLengthSet;
      typedef std::set<AutoSegment*,CompareId>             IdSet;

    // Static Utilities.
    public:
      static inline uint64_t      swapSourceTargetFlags      ( AutoSegment* );
      static inline bool          areAlignedsAndDiffLayer    ( AutoSegment*, AutoSegment* );
      static        AutoSegment*  getGlobalThroughDogleg     ( AutoSegment* dogleg, AutoContact* from );
      static        bool          isTopologicalBound         ( AutoSegment*  seed, Flags flags );
      static inline bool          arePerpandiculars          ( AutoSegment* a, AutoSegment* b );
      static inline bool          arePerpandiculars          ( bool isHorizontalA, AutoSegment* b );
      static inline bool          areAligneds                ( AutoSegment* a, AutoSegment* b );
      static        Flags         getPerpandicularState      ( AutoContact* contact
                                                             , AutoSegment* source
                                                             , AutoSegment* current
                                                             , bool         isHorizontalMaster
                                                             , const Layer* masterLayer=NULL
                                                             );
      static inline Flags         getPerpandicularState      ( AutoContact* contact
                                                             , AutoSegment* source
                                                             , AutoSegment* current
                                                             , AutoSegment* master
                                                             );
      static void                 getTopologicalInfos        ( AutoSegment*          seed
                                                             , vector<AutoSegment*>& collapseds
                                                             , vector<AutoSegment*>& perpandiculars
                                                             , DbU::Unit&            leftBound
                                                             , DbU::Unit&            rightBound
                                                             );
      static int                  getTerminalCount           ( AutoSegment* seed
                                                             , vector<AutoSegment*>& collapseds
                                                             );
      static inline int           getTerminalCount           ( AutoSegment* seed );
      static inline size_t        getGlobalsCount            ();
      static inline size_t        getAllocateds              ();
      static inline unsigned long getMaxId                   ();
  };


// Inline Functions.
  inline  DbU::Unit       AutoSegment::getViaToTopCap         ( size_t depth ) { return (depth < _extensionCaps.size()) ? *(_extensionCaps[depth][0]) : 0; }
  inline  DbU::Unit       AutoSegment::getViaToBottomCap      ( size_t depth ) { return (depth < _extensionCaps.size()) ? *(_extensionCaps[depth][1]) : 0; }
  inline  DbU::Unit       AutoSegment::getViaToSameCap        ( size_t depth ) { return (depth < _extensionCaps.size()) ? *(_extensionCaps[depth][2]) : 0; }
  inline  unsigned long   AutoSegment::getId                  () const { return _id; }
  inline  Cell*           AutoSegment::getCell                () const { return base()->getCell(); }
  inline  Net*            AutoSegment::getNet                 () const { return base()->getNet(); }
  inline  const Layer*    AutoSegment::getLayer               () const { return base()->getLayer(); }
  inline  Box             AutoSegment::getBoundingBox         () const { return base()->getBoundingBox(); }
  inline  Hook*           AutoSegment::getSourceHook          () { return base()->getSourceHook(); }
  inline  Hook*           AutoSegment::getTargetHook          () { return base()->getTargetHook(); }
  inline  Contact*        AutoSegment::getSource              () const { return static_cast<Contact*>(base()->getSource()); }
  inline  Contact*        AutoSegment::getTarget              () const { return static_cast<Contact*>(base()->getTarget()); }
  inline  Component*      AutoSegment::getOppositeAnchor      ( Component* anchor ) const { return base()->getOppositeAnchor(anchor); };
  inline  AutoSegment*    AutoSegment::getParent              () const { return _parent; }
  inline  DbU::Unit       AutoSegment::getSourcePosition      () const { return _sourcePosition; }
  inline  DbU::Unit       AutoSegment::getTargetPosition      () const { return _targetPosition; }
  inline  DbU::Unit       AutoSegment::getSourceX             () const { return base()->getSourceX(); }
  inline  DbU::Unit       AutoSegment::getSourceY             () const { return base()->getSourceY(); }
  inline  DbU::Unit       AutoSegment::getTargetX             () const { return base()->getTargetX(); }
  inline  DbU::Unit       AutoSegment::getTargetY             () const { return base()->getTargetY(); }
  inline  DbU::Unit       AutoSegment::getWidth               () const { return base()->getWidth(); }
  inline  DbU::Unit       AutoSegment::getLength              () const { return base()->getLength(); }
  inline  void            AutoSegment::invert                 () { base()->invert(); }
  inline  GCell*          AutoSegment::getGCell               () const { return _gcell; }
  inline  AutoContact*    AutoSegment::getAutoSource          () const { return Session::lookup(getSource()); }
  inline  AutoContact*    AutoSegment::getAutoTarget          () const { return Session::lookup(getTarget()); }
  inline  bool            AutoSegment::getConstraints         ( Interval& i ) const { return getConstraints(i.getVMin(),i.getVMax()); }
  inline  AutoSegment*    AutoSegment::getCanonical           ( Interval& i ) { return getCanonical(i.getVMin(),i.getVMax()); }
  inline  unsigned int    AutoSegment::getDepth               () const { return _depth; }
  inline  DbU::Unit       AutoSegment::getPitch               () const { return Session::getPitch(getDepth(),Flags::NoFlags); }
  inline  DbU::Unit       AutoSegment::getAxis                () const { return isHorizontal()?base()->getY():base()->getX(); }
  inline  DbU::Unit       AutoSegment::getOrigin              () const { return isHorizontal()?_gcell->getYMin():_gcell->getXMin(); }
  inline  DbU::Unit       AutoSegment::getExtremity           () const { return isHorizontal()?_gcell->getYMax():_gcell->getXMax(); }
  inline  DbU::Unit       AutoSegment::getOptimalMin          () const { return DbU::lambda(_optimalMin) + getOrigin(); }
  inline  DbU::Unit       AutoSegment::getOptimalMax          () const { return DbU::lambda(_optimalMax) + getOrigin(); }
  inline  DbU::Unit       AutoSegment::getNativeMin           () const { return _nativeConstraints.getVMin(); }
  inline  DbU::Unit       AutoSegment::getNativeMax           () const { return _nativeConstraints.getVMax(); }
  inline  const Interval& AutoSegment::getUserConstraints     () const { return _userConstraints; }
  inline  const Interval& AutoSegment::getNativeConstraints   () const { return _nativeConstraints; }
                                                              
  inline  bool            AutoSegment::isHorizontal           () const { return _flags & SegHorizontal; }
  inline  bool            AutoSegment::isVertical             () const { return not (_flags & SegHorizontal); }
  inline  bool            AutoSegment::isFixed                () const { return _flags & SegFixed; }
  inline  bool            AutoSegment::isFixedAxis            () const { return _flags & SegFixedAxis; }
  inline  bool            AutoSegment::isGlobal               () const { return _flags & SegGlobal; }
  inline  bool            AutoSegment::isWeakGlobal           () const { return _flags & SegWeakGlobal; }
  inline  bool            AutoSegment::isLongLocal            () const { return _flags & SegLongLocal; }
  inline  bool            AutoSegment::isLocal                () const { return not (_flags & SegGlobal); }
  inline  bool            AutoSegment::isBipoint              () const { return _flags & SegBipoint; }
  inline  bool            AutoSegment::isWeakTerminal         () const { return _flags & SegWeakTerminal; }
  inline  bool            AutoSegment::isWeakTerminal1        () const { return _flags & SegWeakTerminal1; }
  inline  bool            AutoSegment::isWeakTerminal2        () const { return _flags & SegWeakTerminal2; }
  inline  bool            AutoSegment::isSourceTerminal       () const { return _flags & SegSourceTerminal; }
  inline  bool            AutoSegment::isTargetTerminal       () const { return _flags & SegTargetTerminal; }
  inline  bool            AutoSegment::isTerminal             () const { return _flags & SegStrongTerminal; }
  inline  bool            AutoSegment::isDrag                 () const { return _flags & SegDrag; }
  inline  bool            AutoSegment::isNotSourceAligned     () const { return _flags & SegNotSourceAligned; }
  inline  bool            AutoSegment::isNotTargetAligned     () const { return _flags & SegNotTargetAligned; }
  inline  bool            AutoSegment::isNotAligned           () const { return (_flags & SegNotAligned) == SegNotAligned; }
  inline  bool            AutoSegment::isDogleg               () const { return _flags & SegDogleg  ; }
  inline  bool            AutoSegment::isUnbound              () const { return _flags & SegUnbound  ; }
  inline  bool            AutoSegment::isStrap                () const { return _flags & SegStrap; }
  inline  bool            AutoSegment::isLayerChange          () const { return _flags & SegLayerChange; }
  inline  bool            AutoSegment::isSpinTop              () const { return ((_flags & SegSpinTop   ) == SegSpinTop); }
  inline  bool            AutoSegment::isSpinBottom           () const { return ((_flags & SegSpinBottom) == SegSpinBottom); }
  inline  bool            AutoSegment::isSpinTopOrBottom      () const { return isSpinTop() or isSpinBottom(); }
  inline  bool            AutoSegment::isReduced              () const { return _flags & SegIsReduced; }
  inline  bool            AutoSegment::isSlackened            () const { return _flags & SegSlackened; }
  inline  bool            AutoSegment::isCanonical            () const { return _flags & SegCanonical; }
  inline  bool            AutoSegment::isUnsetAxis            () const { return not (_flags & SegAxisSet); }
  inline  bool            AutoSegment::isInvalidated          () const { return _flags & SegInvalidated; }
  inline  bool            AutoSegment::isInvalidatedLayer     () const { return _flags & SegInvalidatedLayer; }
  inline  bool            AutoSegment::isCreated              () const { return _flags & SegCreated; }
  inline  bool            AutoSegment::isUserDefined          () const { return _flags & SegUserDefined; }
  inline  bool            AutoSegment::isAnalog               () const { return _flags & SegAnalog; }
  inline  bool            AutoSegment::isWide                 () const { return _flags & SegWide; }
  inline  void            AutoSegment::setFlags               ( uint64_t flags ) { _flags |=  flags; }
  inline  void            AutoSegment::unsetFlags             ( uint64_t flags ) { _flags &= ~flags; }
                                                              
  inline  uint64_t        AutoSegment::getFlags               () const { return _flags; }
  inline  uint64_t        AutoSegment::_getFlags              () const { return _flags; }
  inline  void            AutoSegment::incReduceds            () { if (_reduceds<3) ++_reduceds; }
  inline  void            AutoSegment::decReduceds            () { if (_reduceds>0) --_reduceds; }
  inline  void            AutoSegment::setLayer               ( const Layer* layer ) { base()->setLayer(layer); _depth=Session::getLayerDepth(layer); _flags|=SegInvalidatedLayer; }
  inline  void            AutoSegment::setOptimalMin          ( DbU::Unit min ) { _optimalMin = (unsigned int)DbU::getLambda(min-getOrigin()); }
  inline  void            AutoSegment::setOptimalMax          ( DbU::Unit max ) { _optimalMax = (unsigned int)DbU::getLambda(max-getOrigin()); }
  inline  void            AutoSegment::mergeNativeMin         ( DbU::Unit min ) { _nativeConstraints.getVMin() = std::max( min, _nativeConstraints.getVMin() ); }
  inline  void            AutoSegment::mergeNativeMax         ( DbU::Unit max ) { _nativeConstraints.getVMax() = std::min( max, _nativeConstraints.getVMax() ); }
  inline  void            AutoSegment::resetNativeConstraints ( DbU::Unit min, DbU::Unit max ) { _nativeConstraints = Interval( min, max ); }
//inline  void            AutoSegment::mergeUserConstraints   ( const Interval& constraints ) { _userConstraints.intersection(constraints); }
  inline  void            AutoSegment::resetUserConstraints   () { _userConstraints = Interval(false); }


  inline  DbU::Unit  AutoSegment::getContactWidth () const
  { return getWidth() + Session::getViaWidth(getLayer()) - Session::getWireWidth(getLayer()); }


  inline  void  AutoSegment::setParent ( AutoSegment* parent )
  {
    if ( parent == this ) {
      cerr << "Parentage Looping: " << parent->_getString() << endl;
    }
    _parent = parent;
  }

  inline bool  AutoSegment::CompareId::operator() ( const AutoSegment* lhs, const AutoSegment* rhs ) const
  { return lhs->getId() < rhs->getId(); }
 
  inline uint64_t  AutoSegment::swapSourceTargetFlags ( AutoSegment* segment )
  {
    uint64_t segFlags  = segment->getFlags();
    uint64_t swapFlags = segment->getFlags() & ~(SegSourceTop        |SegTargetTop
                                                |SegSourceBottom     |SegTargetBottom
                                                |SegSourceTerminal   |SegTargetTerminal
                                                |SegNotSourceAligned |SegNotTargetAligned
                                                |SegInvalidatedSource|SegInvalidatedTarget
                                                );

    swapFlags |= (segFlags & SegSourceTop        ) ? SegTargetTop         : SegNoFlags;
    swapFlags |= (segFlags & SegSourceBottom     ) ? SegTargetBottom      : SegNoFlags;
    swapFlags |= (segFlags & SegSourceTerminal   ) ? SegTargetTerminal    : SegNoFlags;
    swapFlags |= (segFlags & SegNotSourceAligned ) ? SegNotTargetAligned  : SegNoFlags;
    swapFlags |= (segFlags & SegInvalidatedSource) ? SegInvalidatedTarget : SegNoFlags;

    swapFlags |= (segFlags & SegTargetTop        ) ? SegSourceTop         : SegNoFlags;
    swapFlags |= (segFlags & SegTargetBottom     ) ? SegSourceBottom      : SegNoFlags;
    swapFlags |= (segFlags & SegTargetTerminal   ) ? SegSourceTerminal    : SegNoFlags;
    swapFlags |= (segFlags & SegNotTargetAligned ) ? SegNotSourceAligned  : SegNoFlags;
    swapFlags |= (segFlags & SegInvalidatedTarget) ? SegInvalidatedSource : SegNoFlags;
    return swapFlags;
  }

  inline bool  AutoSegment::areAlignedsAndDiffLayer ( AutoSegment* s1, AutoSegment* s2 )
  { return s1 and s2
      and  (s1->isHorizontal() == s2->isHorizontal())
      and  (s1->getLayer() != s2->getLayer()); }

  inline bool  AutoSegment::arePerpandiculars ( AutoSegment* a, AutoSegment* b )
  { return a and b and (a->isHorizontal() != b->isHorizontal()); }

  inline bool  AutoSegment::arePerpandiculars ( bool isHorizontalA, AutoSegment* b )
  { return b and (isHorizontalA != b->isHorizontal()); }

  inline bool  AutoSegment::areAligneds ( AutoSegment* a, AutoSegment* b )
  { return a and b and (a->isHorizontal() == b->isHorizontal()); }

  inline Flags  AutoSegment::getPerpandicularState ( AutoContact* contact
                                                   , AutoSegment* source
                                                   , AutoSegment* current
                                                   , AutoSegment* master  )
  {
    return getPerpandicularState ( contact, source, current, master->isHorizontal(), master->getLayer() );
  }


  inline int  AutoSegment::getTerminalCount ( AutoSegment* seed )
  {
    cdebug_log(145,0) << "getTerminalCount() - " << seed << endl;

    vector<AutoSegment*>  collapseds;
    vector<AutoSegment*>  perpandiculars;
    DbU::Unit             leftBound;
    DbU::Unit             rightBound;

    getTopologicalInfos ( seed
                        , collapseds
                        , perpandiculars
                        , leftBound
                        , rightBound
                        );

    return getTerminalCount ( seed, collapseds );
  }


  inline size_t  AutoSegment::getGlobalsCount () { return _globalsCount; }
  inline size_t  AutoSegment::getAllocateds   () { return _allocateds; }


  inline void  AutoSegment::setObserver ( size_t slot, BaseObserver* observer )
  { _observers.setObserver( slot, observer ); }

  template<typename OwnerT>
  inline OwnerT* AutoSegment::getObserver ( size_t slot )
  { return _observers.getObserver<OwnerT>(slot); }

  inline void  AutoSegment::notify ( unsigned int flags )
  { _observers.notify( flags ); }

  inline AutoSegment::Observable::Observable () : StaticObservable<1>() { }


} // End of Anabatic namespace.


INSPECTOR_P_SUPPORT(Anabatic::AutoSegment);


# endif  // ANABATIC_AUTOSEGMENT_H
