import pya
from pya import *
from SiEPIC.utils import get_technology, get_technology_by_name
from SiEPIC.utils import arc, arc_wg, arc_to_waveguide, points_per_circle#,layout
import math

class phc_H0c_oxide(pya.PCellDeclarationHelper):
  """
  Input: length, width
  """
  import numpy
  
  def __init__(self):

    # Important: initialize the super class
    super(phc_H0c_oxide, self).__init__()

    self.param("a", self.TypeDouble, "lattice constant (microns)", default = 0.690)     
    self.param("n", self.TypeInt, "Number of holes in x and y direction", default = 30)     
    self.param("r", self.TypeDouble, "hole radius (microns)", default = 0.125)
    self.param("wg_dis", self.TypeInt, "Waveguide distance (number of holes)", default = 3)
    self.param("n_bus", self.TypeInt, "Bus number, 1 or 2 ", default = 2)
    self.param("n_vertices", self.TypeInt, "Vertices of a hole", default = 20)                                
    self.param("S1x", self.TypeDouble, "S1x shift", default = 0.28)     
    self.param("S2x", self.TypeDouble, "S2x shift", default = 0.193)     
    self.param("S3x", self.TypeDouble, "S3x shift", default = 0.194)     
    self.param("S4x", self.TypeDouble, "S4x shift", default = 0.162)
    self.param("S5x", self.TypeDouble, "S5x shift", default = 0.113)
    self.param("S1y", self.TypeDouble, "S1y shift", default = -0.016)
    self.param("S2y", self.TypeDouble, "S2y shift", default = 0.134)
    TECHNOLOGY = get_technology_by_name('EBeam')
    self.param("layer", self.TypeLayer, "Layer", default = TECHNOLOGY['Si'])
    self.param("pinrec", self.TypeLayer, "PinRec Layer", default = TECHNOLOGY['PinRec'])
    self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec'])
    self.param("textl", self.TypeLayer, "Text Layer", default = TECHNOLOGY['Text'])

  def display_text_impl(self):
    # Provide a descriptive text for the cell
    return "phc_H0c_oxide_a%s-r%.3f-wg_dis%.3f-n%.3f" % \
    (self.a, self.r, self.wg_dis, self.n)
  
  def coerce_parameters_impl(self):
    pass

  def can_create_from_shape(self, layout, shape, layer):
    return False
    
  def produce_impl(self):
  
    # fetch the parameters
    dbu = self.layout.dbu
    ly = self.layout

    LayerSi = self.layer
    LayerSiN = ly.layer(self.layer)
    LayerPinRecN = ly.layer(self.pinrec)
    LayerDevRecN = ly.layer(self.devrec)
    LayerTextN = ly.layer(self.textl)

    # Fetch all the parameters:
    a = self.a/dbu
    r = self.r/dbu
    wg_dis = self.wg_dis+1
    n_vertices = self.n_vertices
    n_bus = self.n_bus
    n = int(math.ceil(self.n/2))
    Sx = [self.S1x,self.S2x,self.S3x,self.S4x,self.S5x]
    Sy = [self.S1y,0,self.S2y]
    if n_bus == 1:
      Sx = [0,0,0,0,0]
      Sy = [0,0,0]
          
    if wg_dis%2 == 0:
      length_slab_x = (2*n-1)*a
    else:
      length_slab_x = 2*n*a
    
    length_slab_y = 2*(wg_dis+15)*a*math.sqrt(3)/2
    
    n_x = n
    n_y = wg_dis+10

    # Define Si slab and hole region for future subtraction
    Si_slab = pya.Region()
    Si_slab.insert(pya.Box(-length_slab_x/2, -length_slab_y/2, length_slab_x/2, length_slab_y/2))
    hole = pya.Region()
    hole_r = r

    # function to generate points to create a circle
    def circle(x,y,r):
      npts = n_vertices
      theta = 2 * math.pi / npts # increment, in radians
      pts = []
      for i in range(0, npts):
        pts.append(Point.from_dpoint(pya.DPoint((x+r*math.cos(i*theta))/1, (y+r*math.sin(i*theta))/1)))
      return pts
     
    # raster through all holes with shifts and waveguide 
    
    hole_cell = circle(0,0,hole_r)
    hole_poly = pya.Polygon(hole_cell)  

    for j in range(-n_y,n_y+1):
      if j%2 == 0 and j != wg_dis:
        for i in range(-n_x,n_x+1):
          if j == -wg_dis and i > 3 and n_bus == 2:
            None 
          elif j == 0 and i in (1,-1,2,-2,3,-3,4,-4,5,-5):
            hole_x = abs(i)/i*(abs(i)-0.5+Sx[abs(i)-1])*a
            hole_y = 0 
            hole_trans = pya.Trans(Trans.R0, hole_x,hole_y)
            hole_t = hole_poly.transformed(hole_trans)
            hole.insert(hole_t)           
          elif i!=0:
            hole_x = abs(i)/i*(abs(i)-0.5)*a
            hole_y = j*a*math.sqrt(3)/2
            hole_trans = pya.Trans(Trans.R0, hole_x,hole_y)
            hole_t = hole_poly.transformed(hole_trans)
            hole.insert(hole_t) 
      elif j%2 == 1 and j != wg_dis:
        for i in range(-n_x,n_x+1):
          if j == -wg_dis and i > 3 and n_bus == 2:
            None
          elif i == 0 and j in (1,-1,3,-3):
            hole_x = 0
            hole_y = j*a*(math.sqrt(3)/2)+abs(j)/j*a*Sy[abs(j)-1]
            hole_trans = pya.Trans(Trans.R0, hole_x,hole_y)
            hole_t = hole_poly.transformed(hole_trans)
            hole.insert(hole_t) 
          else:  
            hole_x = i*a
            hole_y = j*a*math.sqrt(3)/2
            hole_trans = pya.Trans(Trans.R0, hole_x,hole_y)
            hole_t = hole_poly.transformed(hole_trans)
            hole.insert(hole_t) 
            
    phc = Si_slab - hole
    self.cell.shapes(LayerSiN).insert(phc)
    
    # Pins on the waveguide:    
    pin_length = 200
    pin_w = a
    wg_pos = a*math.sqrt(3)/2*wg_dis
    
    t = pya.Trans(Trans.R0, -length_slab_x/2,wg_pos)
    pin = pya.Path([pya.Point(pin_length/2, 0), pya.Point(-pin_length/2, 0)], pin_w)
    pin_t = pin.transformed(t)
    self.cell.shapes(LayerPinRecN).insert(pin_t)
    text = pya.Text ("pin1", t)
    shape = self.cell.shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu

    t = pya.Trans(Trans.R0, length_slab_x/2,wg_pos)
    pin = pya.Path([pya.Point(-pin_length/2, 0), pya.Point(pin_length/2, 0)], pin_w)
    pin_t = pin.transformed(t)
    self.cell.shapes(LayerPinRecN).insert(pin_t)
    text = pya.Text ("pin2", t)
    shape = self.cell.shapes(LayerPinRecN).insert(text)
    shape.text_size = 0.4/dbu
    
    #pin for drop waveguide
    if n_bus == 2:
      t = pya.Trans(Trans.R0, length_slab_x/2,-wg_pos)
      pin_t = pin.transformed(t)
      self.cell.shapes(LayerPinRecN).insert(pin_t)
      text = pya.Text ("pin3", t)
      shape = self.cell.shapes(LayerPinRecN).insert(text)
      shape.text_size = 0.4/dbu

    # Create the device recognition layer -- make it 1 * wg_width away from the waveguides.
    points = [[-length_slab_x/2,0], [length_slab_x/2, 0]]
    points = [Point(each[0], each[1]) for each in points]
    path = Path(points, length_slab_y)   
    self.cell.shapes(LayerDevRecN).insert(path.simple_polygon())
   