// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2018-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++ Module  :       "./NetBuilderVH.cpp"                       |
// +-----------------------------------------------------------------+


#include <cstdlib>
#include <sstream>
#include "hurricane/Bug.h"
#include "hurricane/Breakpoint.h"
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/DebugSession.h"
#include "hurricane/Layer.h"
#include "hurricane/BasicLayer.h"
#include "hurricane/RegularLayer.h"
#include "hurricane/Technology.h"
#include "hurricane/DataBase.h"
#include "hurricane/Net.h"
#include "hurricane/NetExternalComponents.h"
#include "hurricane/NetRoutingProperty.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/RoutingPads.h"
#include "hurricane/Pad.h"
#include "hurricane/Pin.h"
#include "hurricane/Plug.h"
#include "hurricane/Cell.h"
#include "hurricane/Instance.h"
#include "hurricane/Vertical.h"
#include "hurricane/Horizontal.h"
#include "crlcore/AllianceFramework.h"
#include "crlcore/RoutingGauge.h"
#include "crlcore/Measures.h"
#include "anabatic/AutoContactTerminal.h"
#include "anabatic/AutoContactTurn.h"
#include "anabatic/AutoContactHTee.h"
#include "anabatic/AutoContactVTee.h"
#include "anabatic/AutoSegment.h"
#include "anabatic/NetBuilderVH.h"
#include "anabatic/AnabaticEngine.h"


namespace Anabatic {

  using std::swap;
  using Hurricane::Transformation;
  using Hurricane::Warning;
  using Hurricane::Error;
  using Hurricane::Pin;

  
  NetBuilderVH::NetBuilderVH ()
    : NetBuilder()
  { }


  NetBuilderVH::~NetBuilderVH () { }

  
  void  NetBuilderVH::doRp_AutoContacts ( GCell*        gcell
                                        , Component*    rp
                                        , AutoContact*& source
                                        , AutoContact*& target
                                        , uint64_t      flags
                                        )
  {
    cdebug_log(145,1) << getTypeName() << "::doRp_AutoContacts()" << endl;
    cdebug_log(145,0)   << rp << endl;

    source = target = NULL;

    Point        sourcePosition;
    Point        targetPosition;
    const Layer* rpLayer        = rp->getLayer();
    size_t       rpDepth        = Session::getLayerDepth( rp->getLayer() );
    Flags        direction      = Session::getDirection ( rpDepth );
    DbU::Unit    viaSide        = Session::getViaWidth  ( rpDepth );
    DbU::Unit    gridPosition   = 0;

    getPositions( rp, sourcePosition, targetPosition );

    if (sourcePosition.getX() > targetPosition.getX()) swap( sourcePosition, targetPosition );
    if (sourcePosition.getY() > targetPosition.getY()) swap( sourcePosition, targetPosition );

    GCell* sourceGCell = Session::getAnabatic()->getGCellUnder( sourcePosition );
    GCell* targetGCell = Session::getAnabatic()->getGCellUnder( targetPosition );

    if (rpDepth == 0) {
      rpLayer   = Session::getContactLayer(0);
      direction = Flags::Vertical;
      viaSide   = Session::getViaWidth( rpDepth );

      RoutingPad* rrp = dynamic_cast<RoutingPad*>( rp );
      if (rrp) {
        // if (not getAnabatic()->getConfiguration()->selectRpComponent(rrp)) {
        //   cerr << Warning( "%s::doRp_AutoContacts(): %s has no components on grid."
        //                  , getTypeName().c_str()
        //                  , getString(rp).c_str() ) << endl;
        // }
      } else {
        cerr << Warning( "%s::doRp_AutoContacts(): %s is *not* a RoutingPad."
                       , getTypeName().c_str()
                       , getString(rp).c_str() ) << endl;
      }
    }

#if 0
  // Quasi-punctual M1 terminal.
    if (flags & VSmall) {
      Box                ab             = rp->getCell()->getBoundingBox();
      RoutingLayerGauge* gaugeMetal3    = Session::getLayerGauge( 2 );
      DbU::Unit          metal3axis     = gaugeMetal3->getTrackPosition( ab.getYMin()
                                                                       , ab.getYMax()
                                                                       , sourcePosition.getY()
                                                                       , Constant::Nearest );
      DbU::Unit          viaSideProtect = Session::getViaWidth((size_t)0);

      AutoContact* sourceVia12 = AutoContactTerminal::create( sourceGCell
                                                            , rp
                                                            , Session::getContactLayer(0)
                                                            , sourcePosition
                                                            , viaSideProtect, viaSideProtect
                                                            );
      AutoContact* targetVia12 = AutoContactTerminal::create( targetGCell
                                                            , rp
                                                            , Session::getContactLayer(0)
                                                            , targetPosition
                                                            , viaSideProtect, viaSideProtect
                                                            );
      AutoContact* sourceVia23 = AutoContactTurn::create( sourceGCell, net, Session::getContactLayer(1) );
      AutoContact* targetVia23 = AutoContactTurn::create( targetGCell, net, Session::getContactLayer(1) );
      sourceVia23->setY( metal3axis );
      targetVia23->setY( metal3axis );
      sourceVia23->setX( sourcePosition.getX() );
      targetVia23->setX( targetPosition.getX() );

      AutoSegment* segmentS = AutoSegment::create( sourceVia12, sourceVia23, Flags::Vertical );
      AutoSegment* segmentT = AutoSegment::create( targetVia12, targetVia23, Flags::Vertical );
      AutoSegment* segmentM = AutoSegment::create( sourceVia23, targetVia23, Flags::Horizontal );

      sourceVia12->setFlags( CntFixed );
      sourceVia23->setFlags( CntFixed );
      targetVia12->setFlags( CntFixed );
      targetVia23->setFlags( CntFixed );
      segmentS->setFlags( AutoSegment::SegFixed );
      segmentT->setFlags( AutoSegment::SegFixed );
      segmentM->setFlags( AutoSegment::SegFixed );

      cdebug_log(145,0) << "Hard protect: " << rp << endl;
      cdebug_log(145,0) << "X:" << DbU::getValueString(sourcePosition.getX())
                        << " Metal3 Track Y:" << DbU::getValueString(metal3axis) << endl;
    }
#endif

  // Non-M1 terminal or punctual M1 protections.
    if ( (rpDepth != 0) or ((sourcePosition == targetPosition) and (gridPosition == 0)) ) {
      map<Component*,AutoSegment*>::iterator irp = getRpLookup().find( rp );
      if (irp == getRpLookup().end()) {
        AutoContact* sourceProtect = AutoContactTerminal::create( sourceGCell
                                                                , rp
                                                                , rpLayer
                                                                , sourcePosition
                                                                , viaSide, viaSide
                                                                );
        AutoContact* targetProtect = AutoContactTerminal::create( targetGCell
                                                                , rp
                                                                , rpLayer
                                                                , targetPosition
                                                                , viaSide, viaSide
                                                                );
        sourceProtect->setFlags( CntFixed );
        targetProtect->setFlags( CntFixed );

        AutoSegment* segment = AutoSegment::create( sourceProtect, targetProtect, direction );
        segment->setFlags( AutoSegment::SegFixed );

        getRpLookup().insert( make_pair(rp,segment) );
      }
    }

    if (sourcePosition != targetPosition) {
      if (flags & DoSourceContact)
        source = AutoContactTerminal::create( sourceGCell
                                            , rp
                                            , rpLayer
                                            , sourcePosition
                                            , viaSide, viaSide
                                            );
      if (flags & DoTargetContact)
        target = AutoContactTerminal::create( targetGCell
                                            , rp
                                            , rpLayer
                                            , targetPosition
                                            , viaSide, viaSide
                                            );
    }

    if (not source and not target) {
      source = target = AutoContactTerminal::create( gcell
                                                   , rp
                                                   , rpLayer
                                                   , rp->getCenter()
                                                   , viaSide, viaSide
                                                   );
    }

    cdebug_tabw(145,-1);
    return;
  }


  AutoContact* NetBuilderVH::doRp_Access ( GCell* gcell, Component* rp, uint64_t flags )
  {
    cdebug_log(145,1) << getTypeName() << "::doRp_Access() - flags:" << flags << endl;

    AutoContact* rpContactSource;
    AutoContact* rpContactTarget;

    flags |= checkRoutingPadSize( rp );

    doRp_AutoContacts( gcell, rp, rpContactSource, rpContactTarget, flags );

    if (not (flags & (HAccess|HAccessEW))) {
      AutoContact* subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
      AutoContact* subContact2 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );
      AutoSegment::create( rpContactSource, subContact1, Flags::Vertical  );
      AutoSegment::create( subContact1,     subContact2, Flags::Horizontal );
      rpContactSource = subContact2;
    } else {
      if (flags & VSmall) {
        AutoContact* subContact1 = NULL;
        if (flags & HAccessEW)
          subContact1 = AutoContactHTee::create( gcell, rp->getNet(), Session::getContactLayer(1) );
        else
          subContact1 = AutoContactTurn::create( gcell, rp->getNet(), Session::getContactLayer(1) );

        AutoSegment::create( rpContactSource, subContact1, Flags::Vertical );
        rpContactSource = subContact1;
      }
    }

    cdebug_tabw(145,-1);

    return rpContactSource;
  }


  bool  NetBuilderVH::_do_1G_1PinM2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1PinM2() [Managed Configuration - Optimized] " << getTopology() << endl;

    Pin* pin = dynamic_cast<Pin*>( getRoutingPads()[0]->getOccurrence().getEntity() );
    if (   (pin->getAccessDirection() != Pin::AccessDirection::SOUTH)
       and (pin->getAccessDirection() != Pin::AccessDirection::NORTH) ) {
      cerr << Error( "%s::do_1G_1PinM2(): %s *must* be north or south."
                   , getTypeName().c_str()
                   , getString(pin).c_str() ) << endl;
    }

    uint64_t  flags = NoFlags;
    if      (east()) { flags |= HAccess|VSmall; }
    else if (west()) { flags |= HAccess|VSmall; }
    
    setBothCornerContacts( doRp_Access(getGCell(),getRoutingPads()[0],flags) );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_xG_1PinM2 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_xG_1PinM2() [Managed Configuration] " << getTopology() << endl;

    Pin* pin = dynamic_cast<Pin*>( getRoutingPads()[0]->getOccurrence().getEntity() );
    if (   (pin->getAccessDirection() != Pin::AccessDirection::SOUTH)
       and (pin->getAccessDirection() != Pin::AccessDirection::NORTH) ) {
      cerr << Error( "%s::do_xG_1PinM2(): %s *must* be north or south."
                   , getTypeName().c_str()
                   , getString(pin).c_str() ) << endl;
    }

    RoutingPad*  rp         = getRoutingPads()[0];
    AutoContact* pinContact = NULL;
    doRp_AutoContacts( getGCell(), rp, pinContact, pinContact, HSmall|VSmall );

    if (not north() and not south()) {
      AutoContact* subContact1 = AutoContactHTee::create( getGCell(), rp->getNet(), Session::getContactLayer(1) );
      AutoSegment::create( pinContact, subContact1, Flags::Vertical );
      setBothCornerContacts( subContact1 );
    } else {
      AutoContact* subContact1 = AutoContactVTee::create( getGCell(), rp->getNet(), Session::getContactLayer(1) );
      AutoSegment::create( pinContact, subContact1, Flags::Vertical );
      
      if (east() and west()) {
        AutoContact* subContact2 = AutoContactVTee::create( getGCell(), rp->getNet(), Session::getContactLayer(1) );
        AutoSegment::create( subContact1, subContact2, Flags::Vertical );
      
        setSouthWestContact( (south()) ? subContact1 : subContact2 );
        setNorthEastContact( (south()) ? subContact2 : subContact1 );
      } else
        setBothCornerContacts( subContact1 );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_1G_1PinM3 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1PinM3() [Managed Configuration - Optimized] " << getTopology() << endl;

    Pin* pin = dynamic_cast<Pin*>( getRoutingPads()[0]->getOccurrence().getEntity() );
    if (   (pin->getAccessDirection() != Pin::AccessDirection::EAST)
       and (pin->getAccessDirection() != Pin::AccessDirection::WEST) ) {
      cerr << Error( "%s::do_1G_1PinM2(): %s *must* be east or west."
                   , getTypeName().c_str()
                   , getString(pin).c_str() ) << endl;
    }

    AutoContact* pinContact = NULL;
    doRp_AutoContacts( getGCell(), getRoutingPads()[0], pinContact, pinContact, HSmall|VSmall );

    if (east() or west()) {
      AutoContact* subContact1 = AutoContactTurn::create( getGCell(), getRoutingPads()[0]->getNet(), Session::getContactLayer(1) );
      AutoContact* subContact2 = AutoContactTurn::create( getGCell(), getRoutingPads()[0]->getNet(), Session::getContactLayer(1) );

      AutoSegment::create( pinContact , subContact1, Flags::Horizontal  );
      AutoSegment::create( subContact1, subContact2, Flags::Vertical );
      pinContact = subContact2;
    } else {
      AutoContact* subContact1 = NULL;
      subContact1 = AutoContactTurn::create( getGCell(), getRoutingPads()[0]->getNet(), Session::getContactLayer(1) );

      AutoSegment::create( pinContact, subContact1, Flags::Horizontal );
      pinContact = subContact1;
    }

    setBothCornerContacts( pinContact );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_xG_1PinM3 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_xG_1PinM3() [Managed Configuration] " << getTopology() << endl;

    RoutingPad* rp  = getRoutingPads()[0];
    Pin*        pin = dynamic_cast<Pin*>( rp->getOccurrence().getEntity() );
    if (   (pin->getAccessDirection() != Pin::AccessDirection::EAST)
       and (pin->getAccessDirection() != Pin::AccessDirection::WEST) ) {
      cerr << Error( "%s::do_xG_1PinM3(): %s *must* be east or west."
                   , getTypeName().c_str()
                   , getString(pin).c_str() ) << endl;
    }

    AutoContact* pinContact = NULL;
    doRp_AutoContacts( getGCell(), rp, pinContact, pinContact, HSmall|VSmall );

    if (not east() and not west()) {
      AutoContact* subContact1 = AutoContactVTee::create( getGCell(), rp->getNet(), Session::getContactLayer(1) );
      AutoSegment::create( pinContact, subContact1, Flags::Horizontal );
      setBothCornerContacts( subContact1 );
    } else {
      AutoContact* subContact1 = AutoContactHTee::create( getGCell(), rp->getNet(), Session::getContactLayer(1) );
      AutoSegment::create( pinContact, subContact1, Flags::Horizontal );
      
      if (north() and south()) {
        AutoContact* subContact2 = AutoContactHTee::create( getGCell(), rp->getNet(), Session::getContactLayer(1) );
        AutoSegment::create( subContact1, subContact2, Flags::Horizontal );
      
        setSouthWestContact( (west()) ? subContact1 : subContact2 );
        setNorthEastContact( (west()) ? subContact2 : subContact1 );
      } else
        setBothCornerContacts( subContact1 );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_1G_1M1 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_1M1() [Managed Configuration - Optimized] " << getTopology() << endl;

    uint64_t  flags = NoFlags;
    if      (east()) { flags |= HAccess|VSmall; }
    else if (west()) { flags |= HAccess|VSmall; }

    setBothCornerContacts( doRp_Access(getGCell(),getRoutingPads()[0],flags) );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_1G_xM1 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_1G_" << (int)getConnexity().fields.M1 << "M1() [Defered Configuration]" << endl;

    _do_xG_xM1_xM3();

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_2G_1M1 ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_2G_1M1 [Managed Configuration]" << endl;
    cdebug_log(145,0) << "north:     " << north() << endl;
    cdebug_log(145,0) << "south:     " << south() << endl;
    cdebug_log(145,0) << "east:      " << east() << endl;
    cdebug_log(145,0) << "west:      " << west() << endl;

    AutoContact* tee  = NULL;

    if (east() and west()) {
      tee = doRp_Access( getGCell(), getRoutingPads()[0], HAccessEW|VSmall );
    } else {
      AutoContact* turn = doRp_Access( getGCell(), getRoutingPads()[0], HAccess|VSmall );

      if (east() or west())
        tee = AutoContactHTee::create( getGCell(), getNet(), Session::getDContactLayer() );
      else
        tee = AutoContactVTee::create( getGCell(), getNet(), Session::getDContactLayer() );

      AutoSegment::create( turn, tee, Flags::Horizontal );
    }
    setBothCornerContacts( tee );

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_xG_xM1_xM3 ()
  {
  // Implicit hypothesis : we have at least two globals and at least one terminal.
    
    cdebug_log(145,1) << getTypeName()
                      << "::_do_xG_"  << (int)getConnexity().fields.M1
                      << "M1_"        << (int)getConnexity().fields.M3
                      << "M3() [G:"   << (int)getConnexity().fields.globals << " Managed Configuration]" << endl;
    cdebug_log(145,0) << "getConnexity(): " << getConnexity().connexity << endl;
    cdebug_log(145,0) << "north:     " << north() << endl;
    cdebug_log(145,0) << "south:     " << south() << endl;
    cdebug_log(145,0) << "east:      " << east() << endl;
    cdebug_log(145,0) << "west:      " << west() << endl;

    sortRpByX( getRoutingPads(), NoFlags ); // increasing X.

    size_t       iLast        = getRoutingPads().size()-1;
    AutoContact* leftContact  = NULL;
    AutoContact* rightContact = NULL;

    if (south() or west()) {
      leftContact = doRp_Access( getGCell(), getRoutingPads()[0], HAccessEW|VSmall );
      if (south() and west()) {
        setSouthWestContact( AutoContactHTee::create( getGCell(), getNet(), Session::getDContactLayer() ) );
        AutoSegment::create( getSouthWestContact(), leftContact, Flags::Horizontal );
      } else {
        if (west())
          setSouthWestContact( leftContact );
        else {
          setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), Session::getDContactLayer() ) );
          AutoSegment::create( leftContact, getSouthWestContact(), Flags::Horizontal );
        }
      }
    } else {
      leftContact = doRp_Access( getGCell(), getRoutingPads()[0], HAccess|VSmall );
    }
    
    for ( size_t i=1 ; i<getRoutingPads().size()-1 ; ++i ) {
      rightContact = doRp_Access( getGCell(), getRoutingPads()[i], HAccessEW|VSmall );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );

      leftContact = rightContact;
    }

    if (north() or east()) {
      if (getRoutingPads().size() > 1) {
        rightContact = doRp_Access( getGCell(), getRoutingPads()[iLast], HAccessEW|VSmall );
        AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
      } else {
        rightContact = leftContact;
      }

      if (north() and east()) {
        setNorthEastContact( AutoContactHTee::create( getGCell(), getNet(), Session::getDContactLayer() ) );
        AutoSegment::create( rightContact, getNorthEastContact(), Flags::Horizontal );
      } else {
        if (east())
          setNorthEastContact( rightContact );
        else {
          setNorthEastContact( AutoContactTurn::create( getGCell(), getNet(), Session::getDContactLayer() ) );
          AutoSegment::create( rightContact, getNorthEastContact(), Flags::Horizontal );
        }
      }
    } else {
      rightContact = doRp_Access( getGCell(), getRoutingPads()[iLast], HAccess|VSmall );
      AutoSegment::create( leftContact, rightContact, Flags::Horizontal );
    }

    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_2G ()
  {
    cdebug_log(145,0) << getTypeName() << "::_do_2G()" << endl;
    return _do_xG();
  }

  bool  NetBuilderVH::_do_xG ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_xG()" << endl;

    const Layer* viaLayer = Session::getDContactLayer();

    if (getConnexity().fields.globals == 2) {
      setBothCornerContacts( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
    } else if (getConnexity().fields.globals == 3) {
      if (east() and west()) {
        setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
        setNorthEastContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer ) );
        if (south()) swapCornerContacts();

        AutoSegment::create( getSouthWestContact(), getNorthEastContact(), Flags::Vertical );
      } else {
        setSouthWestContact( AutoContactTurn::create( getGCell(), getNet(), viaLayer ) );
        setNorthEastContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer ) );
        if (west()) swapCornerContacts();

        AutoSegment::create( getSouthWestContact(), getNorthEastContact(), Flags::Horizontal );
      }
    } else { // fields.globals == 4.
      AutoContact* turn = AutoContactTurn::create( getGCell(), getNet(), viaLayer );
      setSouthWestContact( AutoContactHTee::create( getGCell(), getNet(), viaLayer ) );
      setNorthEastContact( AutoContactVTee::create( getGCell(), getNet(), viaLayer ) );
      AutoSegment::create( getSouthWestContact(), turn, Flags::Horizontal );
      AutoSegment::create( turn, getNorthEastContact(), Flags::Vertical   );
    } 
    cdebug_tabw(145,-1);
    return true;
  }


  bool  NetBuilderVH::_do_globalSegment ()
  {
    cdebug_log(145,1) << getTypeName() << "::_do_globalSegment()" << endl;

    if (getSourceContact()) {
      AutoContact* targetContact
        = ( getSegmentHookType(getFromHook()) & (NorthBound|EastBound) )
        ? getNorthEastContact() : getSouthWestContact() ;
      AutoSegment* globalSegment = AutoSegment::create( getSourceContact()
                                                      , targetContact
                                                      , static_cast<Segment*>( getFromHook()->getComponent() )
                                                      );
      globalSegment->setFlags( (getDegree() == 2) ? AutoSegment::SegBipoint : 0 );
      cdebug_log(145,0) << "Create global segment: " << globalSegment << endl;
  
    // HARDCODED VALUE.
      if ( (getTopology() & Global_Fixed) and (globalSegment->getAnchoredLength() < 2*Session::getSliceHeight()) )
        addToFixSegments( globalSegment );
        
      if (getConnexity().fields.globals < 2) {
        cdebug_tabw(145,-1);
        return false;
      }
    } else
      setFromHook( NULL );
    
    push( east (), getNorthEastContact() );
    push( west (), getSouthWestContact() );
    push( north(), getNorthEastContact() );
    push( south(), getSouthWestContact() );

    cdebug_tabw(145,-1);
    return true;
  }


  void  NetBuilderVH::singleGCell ( AnabaticEngine* anbt, Net* net )
  {
    cdebug_log(145,1) << getTypeName() << "::singleGCell() " << net << endl;

    vector<RoutingPad*>  rps;

    for ( RoutingPad* rp : net->getRoutingPads() ) {
      if (Session::getRoutingGauge()->getLayerDepth(rp->getLayer()) == 0) {
        rps.push_back( rp );
        continue;
      }
      cerr << Error( "%s::singleGCell(): Non metal1 terminals are not managed yet.\n"
                     "        (%s)"
                   , getTypeName().c_str()
                   , getString(rp).c_str()
                   ) << endl;
      cdebug_tabw(145,-1);
      return;
    }

    if (rps.size() < 2) {
      cerr << Error( "%s::singleGCell(): For %s, less than two Plugs/Pins (%d)."
                   , getTypeName().c_str()
                   , getString(net).c_str()
                   , rps.size() ) << endl;
      cdebug_tabw(145,-1);
      return;
    }

    if (rps.empty()) {
      cerr << Error( "%s::singleGCell(): No terminals for Net \"%s\"."
                   , getTypeName().c_str()
                   , getString(net->getName()).c_str() ) << endl;
      cdebug_tabw(145,-1);
      return;
    }

    sortRpByX( rps, NetBuilder::NoFlags ); // increasing X.

    GCell* gcell1 = anbt->getGCellUnder( (*rps.begin ())->getCenter() );
    GCell* gcell2 = anbt->getGCellUnder( (*rps.rbegin())->getCenter() );

    if (not gcell1) {
      cerr << Error( "%s::singleGCell(): No GCell under %s."
                   , getTypeName().c_str()
                   , getString(*(rps.begin())).c_str() ) << endl;
      cdebug_tabw(145,-1);
      return;
    }
    if (gcell1 != gcell2) {
      cerr << Error( "%s::singleGCell(): Not under a single GCell %s."
                   , getTypeName().c_str()
                   , getString(*(rps.rbegin())).c_str() ) << endl;
      cdebug_tabw(145,-1);
      return;
    }

    cdebug_log(145,0) << "singleGCell " << gcell1 << endl;

    AutoContact* source = NULL;
    AutoContact* target = NULL;

    for ( size_t irp=1 ; irp<rps.size() ; ++irp ) {
      source = doRp_Access( gcell1, rps[irp-1], HAccess|VSmall );
      target = doRp_Access( gcell1, rps[irp  ], HAccess|VSmall );
      AutoSegment::create( source, target, Flags::Horizontal );
    }

    cdebug_tabw(145,-1);
  }


  string  NetBuilderVH::getTypeName () const
  { return "NetBuilderVH"; }


}  // Anabatic namespace.
