#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California
# All rights reserved.
#

import debug
import geometry
from sram_factory import factory
from bitcell_base_array import bitcell_base_array
from globals import OPTS
from tech import layer


class sky130_bitcell_base_array(bitcell_base_array):
    """
    Abstract base class for bitcell-arrays -- bitcell, dummy, replica
    """
    def __init__(self, name, rows, cols, column_offset):
        super().__init__(name, rows, cols, column_offset)
        debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))

        self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")

    def place_array(self, name_template, row_offset=0, col_offset=0):
        yoffset = 0.0

        for row in range(0, len(self.array_layout)):
            xoffset = 0.0
            for col in range(0, len(self.array_layout[row])):
                self.place_inst = self.insts[(col) + (row) * len(self.array_layout[row])]

                if row % 2 == 0:
                    if col == 0:
                        self.place_inst.place(offset=[xoffset, yoffset + self.cell.height], mirror="MX")
                    elif col % 4 == 0:
                        self.place_inst.place(offset=[xoffset, yoffset + self.cell.height], mirror="MX")
                    elif col % 4 == 3 :
                        self.place_inst.place(offset=[xoffset, yoffset + self.cell.height], mirror="MX")
                    elif col % 4 == 2:
                        self.place_inst.place(offset=[xoffset + self.cell.width, yoffset + self.cell.height], mirror="XY")
                    else:
                        self.place_inst.place(offset=[xoffset, yoffset + self.cell.height], mirror="MX")
                else:
                    if col == 0:
                        self.place_inst.place(offset=[xoffset, yoffset])
                    elif col % 4 == 0:
                        self.place_inst.place(offset=[xoffset, yoffset])
                    elif col % 4 == 3 :
                        self.place_inst.place(offset=[xoffset, yoffset])
                    elif col % 4 == 2:
                        self.place_inst.place(offset=[xoffset + self.cell.width, yoffset], mirror="MY")
                        # self.place_inst.place(offset=[xoffset, yoffset])
                    else:
                        self.place_inst.place(offset=[xoffset, yoffset])

                xoffset += self.place_inst.width
            yoffset += self.place_inst.height

        self.width = max([x.rx() for x in self.insts])
        self.height = max([x.uy() for x in self.insts])

    def get_bitcell_pins(self, row, col):
        """
        Creates a list of connections in the bitcell,
        indexed by column and row, for instance use in bitcell_array
        """
        bitcell_pins = []
        for port in self.all_ports:
            bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))])
        bitcell_pins.append("gnd") # gnd
        bitcell_pins.append("vdd") # vdd
        bitcell_pins.append("vdd") # vpb
        bitcell_pins.append("gnd") # vnb
        bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))])

        return bitcell_pins

    def get_strap_pins(self, row, col, name=""):
        """
        Creates a list of connections in the strap cell,
        indexed by column and row, for instance use in bitcell_array
        """
        if name and "_p" in name:
            strap_pins = ["gnd"]
        else:
            strap_pins = ["vdd"]
        return strap_pins

    def get_col_cap_p_pins(self, row, col):
        """
        """
        strap_pins = ["gnd", "vdd", "gnd"]
        return strap_pins

    def get_col_cap_pins(self, row, col):
        """
        """
        strap_pins = []
        for port in self.all_ports:
            strap_pins.extend([x for x in self.get_bitline_names(port) if "bl" in x and x.endswith("_{0}".format(col))])
        strap_pins.extend(["vdd", "gnd"])
        for port in self.all_ports:
            strap_pins.extend([x for x in self.get_bitline_names(port) if "br" in x and x.endswith("_{0}".format(col))])
        if row == 0:
            strap_pins.extend(["gate_top"])
        else:
            strap_pins.extend(["gate_bottom"])
        return strap_pins

    def get_row_cap_pins(self, row, col):
        """
        """
        strap_pins = ["gnd", "vdd", "gnd"]
        return strap_pins

    def get_corner_pins(self):
        """
        """
        strap_pins = ["vdd", "gnd", "vdd"]
        return strap_pins

    def add_supply_pins(self):
        """ Add the layout pins """
        # Copy a vdd/gnd layout pin from every cell
        for row in range(self.row_size):
            for col in range(self.column_size):
                inst = self.cell_inst[row, col]
                for pin_name in ["vdd", "gnd"]:
                    self.copy_layout_pin(inst, pin_name)
                if row == 2: #add only 1 label per col

                    if 'VPB' in self.cell_inst[row, col].mod.pins:
                        pin = inst.get_pin("vpb")
                        self.objs.append(geometry.rectangle(layer["nwell"],
                                                            pin.ll(),
                                                            pin.width(),
                                                            pin.height()))
                        self.objs.append(geometry.label("vdd", layer["nwell"], pin.center()))

                    if 'VNB' in self.cell_inst[row, col].mod.pins:
                        try:
                            from tech import layer_override
                            if layer_override['VNB']:
                                pin = inst.get_pin("vnb")
                                self.objs.append(geometry.label("gnd", layer["pwellp"], pin.center()))
                                self.objs.append(geometry.rectangle(layer["pwellp"],
                                                                    pin.ll(),
                                                                    pin.width(),
                                                                    pin.height()))
                        except:
                            pin = inst.get_pin("vnb")
                            self.add_label("vdd", pin.layer, pin.center())
