#!/usr/bin/python

import sys		
from   Hurricane        import *
from   CRL              import *
from   math             import sqrt, ceil
import helpers
from   helpers.io       import ErrorMessage as Error
from   helpers          import trace
import oroshi

from capacitorunit import CapacitorUnit

def toDbU    ( l ): return DbU.fromPhysical( l, DbU.UnitPowerMicro )
def toPhy    ( l ): return DbU.toPhysical  ( l, DbU.UnitPowerMicro )

def doBreak( level, message ):
    UpdateSession.close()
    Breakpoint.stop( level, message )
    UpdateSession.open()

helpers.staticInitialization( True )




class NonUnitCapacitor(CapacitorUnit):


    rules = oroshi.getRules()



    def __init__( self, device, capacitorType, direction, capacitance, capacitorUnit, abutmentBoxPosition, capUnitTopPlates_spacing = -1 ):

        self.device                = device
        self.capacitorType         = capacitorType
        self.direction             = direction
	self.capacitance           = capacitance
	self.capacitorUnit         = capacitorUnit 	
	self.abutmentBoxPosition   = abutmentBoxPosition 
	self.capUnitTopPlates_spacing = capUnitTopPlates_spacing

	self.unitCapDim = CapacitorUnit.__computeCapDim__( self, capacitorUnit, capacitorType  ) 

        if self.__isDirectionOk__(direction):
	    self.nonUnitCapDim = {"width" : self.unitCapDim["width"] , "height" : 0 } if direction == "vertical" else {"width" : 0 , "height" : self.unitCapDim["width"] }

	self.nonUnitCapDim_sideLimit = 0  
        self.dummyCapDim             = {}

        return



    def __isDirectionOk__( self, direction ):

         state = True if direction in ["horizontal","vertical"] else False
         if state == False : raise Error(1,'__isDirectionOk__() : The direction must be either "vertical" or "horizontal" : %s.' % direction)

         return state



    def setRules( self ):

	CapacitorUnit.setRules(self)

        if self.capacitorType == 'MIMCap':
            self.__setattr__( "minWidth_dummyTopPlate" , CapacitorUnit.rules.minWidth_metcapdum )

        elif self.capacitorType == 'PIPCap':
            self.__setattr__( "minWidth_dummyTopPlate" , CapacitorUnit.rules.minWidth_cpoly     )

	return



    def create( self, b, t ) :

        UpdateSession.open()           

	self.setRules()
	self.computeDimensions()

	if self.__isCapacitorOk__() :

	    print('drawing capacitor')
	    activeCapacitor = CapacitorUnit   ( self.device, self.capacitorType, self.abutmentBoxPosition, capDim = self.nonUnitCapDim ) 
    	    activeCapacitor.create( b, t )      

            side = "height" if self.direction == "vertical" else "width"
	    if self.__isNonUnitCapSideOk__( side )  :

    	        print("drawing dummy too")
#	        activeCapacitor = CapacitorUnit  ( self.device, activeCapacitance, self.capacitorType, self.abutmentBoxPosition ) 

		dummyAbutmentBoxPosition = [ self.abutmentBoxPosition[0], self.abutmentBoxPosition[1] - CapacitorUnit.computeAbutmentBoxDimensions( self, self.dummyCapDim )["height"] ] if self.direction == "vertical" else [ self.abutmentBoxPosition[0] + CapacitorUnit.computeAbutmentBoxDimensions( self, self.nonUnitCapDim )["width"] , self.abutmentBoxPosition[1] ]

                dummyCapacitor = CapacitorUnit( self.device, self.capacitorType, dummyAbutmentBoxPosition, capDim = self.dummyCapDim ) 
#    	        activeCapacitor.create( b, t )   
    	        dummyCapacitor.create ( b, t )   

            else : print("not drawing dummy")
            
#	    abutmentBoxDimensions = self.computeAbutmentBoxDimensions(capDim)
 #           CapacitorUnit.drawAbutmentBox( self )

	else : raise Error(1,'create() : Impossible to draw capacitor in the defined geometric limits.')

        UpdateSession.close()

	return










    def __isCapacitorOk__( self ):

	capacitorMax = self.computeCapacitorMax()

	print("CMax",capacitorMax) 
	print("self.capacitance",self.capacitance)
	print("self.capUnitTopPlates_spacing",toPhy(self.capUnitTopPlates_spacing))

	return True if self.capacitance < capacitorMax else False




    def computeDimensions( self ):

	if self.capUnitTopPlates_spacing == -1 :
	    CapacitorUnit.computeAbutmentBoxDimensions(self, self.unitCapDim )
	    self.capUnitTopPlates_spacing = 2*(self.minSpacing_botPlate + self.enclosure_botPlate_topPlate)

	self.nonUnitCapDim_sideLimit = 2*self.unitCapDim["width"] - self.minWidth_dummyTopPlate

        if self.direction == "vertical":
 	    self.nonUnitCapDim["height"] = self.computeNonUnitCapheight()
        else :  self.nonUnitCapDim["width"] = self.computeNonUnitCapheight()

	print("sideLimit",toPhy(self.nonUnitCapDim_sideLimit))
        print("self.capUnitTopPlates_spacing",toPhy(self.capUnitTopPlates_spacing))
        print('self.nonUnitCapDim["width"]',toPhy(self.nonUnitCapDim["width"]))
        print('self.nonUnitCapDim["height"]',toPhy(self.nonUnitCapDim["height"]))


        nonUnitCapDim_sideMax      = 2*self.unitCapDim["width"] + self.capUnitTopPlates_spacing
        self.dummyCapDim["width" ] =   self.unitCapDim["width" ]  if self.direction == "vertical" else nonUnitCapDim_sideMax - self.capUnitTopPlates_spacing - self.nonUnitCapDim["width"]
        self.dummyCapDim["height"] =   nonUnitCapDim_sideMax - self.capUnitTopPlates_spacing - self.nonUnitCapDim["height"] if self.direction == "vertical" else self.unitCapDim["width" ]

        print("self.dummyCapDim",toPhy(self.dummyCapDim["width" ]))
        print("self.dummyCapDim",toPhy(self.dummyCapDim["height" ]))
	return



    def computeCapacitorMax( self ):

	[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = CapacitorUnit.__setCapacitorPerUnit__(self, self.capacitorType)
	capUnit_width                                       = toPhy( self.unitCapDim["width"]            )
	topPlates_spacing                                   = toPhy( self.capUnitTopPlates_spacing )
	print("[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ]",[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ])
	print("width",capUnit_width)
	CMax = ( 2*capUnit_width + topPlates_spacing )*capUnit_width*areaCapacitorPerUnit + ( 3*capUnit_width + topPlates_spacing )*perimeterCapacitorPerUnit

	return CMax



    def computeNonUnitCapheight( self ):


	[ areaCapacitorPerUnit, perimeterCapacitorPerUnit ] = CapacitorUnit.__setCapacitorPerUnit__(self, self.capacitorType)
	width                                               = toPhy( self.unitCapDim["width"]            )
	height                                              = self.capacitance/( (width*areaCapacitorPerUnit + perimeterCapacitorPerUnit) + width*perimeterCapacitorPerUnit )

	print("height",height)
	return toDbU(height)



    def __isNonUnitCapSideOk__( self, side ): 

        if side in ["width","height"]:
            state = True if self.nonUnitCapDim[side] < self.nonUnitCapDim_sideLimit else False

        else : raise Error(1,'__isNonUnitCapSideOk__() : The side must be either "width" or "height" : %s.' % side)

        return state


























def scriptMain( **kw ):

    editor = None
    if kw.has_key('editor') and kw['editor']:
        editor = kw['editor']

    UpdateSession.open()
    device = AllianceFramework.get().createCell( 'nonUnitCapacitor' )
    device.setTerminal( True )

    bottomPlate_net = Net.create( device, 'b' )
    bottomPlate_net.setExternal( True )  
    b = device.getNet("b")
    doBreak( 1, 'Done building bottomPlate')

    topPlate_net    = Net.create( device, 't' )
    topPlate_net.setExternal( True )  
    t = device.getNet("t")
    doBreak( 1, 'Done building tNet')

    if editor:
        UpdateSession.close(        )
        editor.setCell     ( device ) 
        editor.fit         (        )            
        UpdateSession.open (        )     

    nonUnitCapacitor = NonUnitCapacitor ( device, 'PIPCap', 'horizontal', 65, 50, [0,0] )
    nonUnitCapacitor.create(b,t)          
                      
    AllianceFramework.get().saveCell( device, Catalog.State.Views )

    return True