########################################################################################################################
## Mabrains Company LLC
##
## Mabrains Via Generator for Skywaters 130nm
########################################################################################################################
from .layers_definiations import *
import pya
import math
import pandas as pd


"""
Mabrains Via Generator for Skywaters 130nm
"""



class ViaGenerator(pya.PCellDeclarationHelper):
    """
    Mabrains Via Generator for Skywaters 130nm
    """
    layers = ["metal1","metal2","metal3","metal4","metal5"]


    def __init__(self):

        ## Initialize super class.
        super(ViaGenerator, self).__init__()
        # declare the parameters
        #self.param("ls", self.TypeLayer, "Starting Layer", default=pya.LayerInfo(1, 0))
        #self.param("le", self.TypeLayer, "Ending Layer", default=pya.LayerInfo(1, 0))

        self.param("metal", self.TypeString, "Choose metal type AL or CU", default="AL")
        ending_layer = self.param("ending_metal",self.TypeString,"choose the ending material",default = "metal1")
        ending_layer.add_choice("metal1", "l_met1")
        ending_layer.add_choice("metal2", "l_met2")
        ending_layer.add_choice("metal3", "l_met3")
        ending_layer.add_choice("metal4", "l_met4")
        ending_layer.add_choice("metal5", "l_met5")
        self.param("width", self.TypeDouble, "width", hidden = True)
        self.param("height", self.TypeDouble, "height", hidden = True)

        self.param("metal", self.TypeString, "Choose metal type AL or CU", default="AL")
        self.param("via_type", self.TypeString, "Choose via type", default="via")

        #self.param("via", self.TypeLayer, "via_layer", default = pya.LayerInfo(via_lay_num,via_lay_dt), hidden = True)

        # Below shows how to create hidden parameter is used to determine whether the radius has changed
        # or the "s" handle has been moved
        ## self.param("ru", self.TypeDouble, "Radius", default = 0.0, hidden = True)
        ## self.param("rd", self.TypeDouble, "Double radius", readonly = True)

        def number_spc_contacts(self, box_width, min_enc, cont_spc, cont_width):
            """ Calculate number of cantacts in a given dimensions and the free space for symmetry.
                By getting the min enclosure,the width of the box,the width of the cont. or via
                and the spacing between cont. or via
                Parameters
                ----------
                box_width : double
                    The length you place the via or cont. in
                min_enc : double
                    the spacing between the edge of the box and the first via or cont.
                cont_spc : double
                    the spacing between different via's or cont
                cont_width: double
                    the cont. or via width in the same direction
            """

            spc_cont = box_width - 2 * min_enc
            num_cont = int((spc_cont + cont_spc) / (cont_width + cont_spc))
            free_spc = box_width - (num_cont * cont_width + (num_cont - 1) * cont_spc)
            return num_cont, free_spc
    def display_text_impl(self):
        # Provide a descriptive text for the cell
        return "(" + self.via_type + " metal = "+self.metal +")"

    def coerce_parameters_impl(self):

        # We employ coerce_parameters_impl to decide whether the handle or the
        # numeric parameter has changed (by comparing against the effective
        # radius ru) and set ru to the effective radius. We also update the
        # numerical value or the shape, depending on which on has not changed.
        pass

    def can_create_from_shape_impl(self):
        # Implement the "Create PCell from shape" protocol: we can use any shape which
        # has a finite bounding box
        return self.shape.is_box() or self.shape.is_polygon() or self.shape.is_path()

    def parameters_from_shape_impl(self):
        # Implement the "Create PCell from shape" protocol: we set r and l from the shape's
        # bounding box width and layer
        self.width =  self.shape.bbox().width()
        self.height = self.shape.bbox().height()
        #global layer_number = self.layout.get_info(self.layer).layer

    def transformation_from_shape_impl(self):
        # Implement the "Create PCell from shape" protocol: we use the center of the shape's
        # bounding box to determine the transformation
        return pya.Trans(self.shape.bbox().p1)

    def produce_impl(self):
        ru_dbu = 1000

        # compute the circle
        #pts = []
        #da = math.pi * 2 / 4
        #for i in range(0, 4):
        #pts.append(pya.Point.from_dpoint(pya.DPoint(ru_dbu * math.cos(i * da), ru_dbu * math.sin(i * da))))
        l_met1 = self.layout.layer(met1_lay_num, met1_lay_dt)
        l_met2 = self.layout.layer(met2_lay_num, met2_lay_dt)
        l_met3 = self.layout.layer(met3_lay_num, met3_lay_dt)
        l_met4 = self.layout.layer(met4_lay_num, met4_lay_dt)
        l_met5 = self.layout.layer(met5_lay_num, met5_lay_dt)
        self.cell.shapes(l_met1).insert(pya.Box(0,0,self.width,self.height))
        # create the shape
        l_via = self.layout.layer(via_lay_num, via_lay_dt)
        l_via2 = self.layout.layer(via2_lay_num, via2_lay_dt)
        l_via3 = self.layout.layer(via3_lay_num, via3_lay_dt)
        l_via4 = self.layout.layer(via4_lay_num, via4_lay_dt)


        AL_via = pya.Box(0,0,0.15*ru_dbu,0.15*ru_dbu)
        AL_via2 = pya.Box(0,0,0.2*ru_dbu,0.2*ru_dbu)
        AL_via3 = pya.Box(0,0,0.2*ru_dbu,0.2*ru_dbu)
        AL_via4 = pya.Box(0,0,0.8*ru_dbu,0.8*ru_dbu)

        print(self.ending_metal)
        CU_via = pya.Box(0,0,0.18*ru_dbu,0.18*ru_dbu)
        if self.metal == "CU":
            self.cell.shapes(l_via).insert(CU_via)
        else:
            if self.via_type == "via":
                self.cell.shapes(l_via).insert(AL_via)
            elif self.via_type == "via2":
                self.cell.shapes(l_via2).insert(AL_via2)
            elif self.via_type == "via3":
                self.cell.shapes(l_via3).insert(AL_via3)
            else :
                self.cell.shapes(l_via4).insert(AL_via4)
