import ipkiss3.all as i3


class DCPad(i3.PCell):
    """
    A metal pad that can be interconnected to the metal lines and contacted through a probe or through wire-bonding.
    """

    _name_prefix = "DC_pad"

    class Layout(i3.LayoutView):
        _doc_properties = ["width", "length"]

        width = i3.PositiveNumberProperty(default=300.0, doc="Pad Width [um]")
        length = i3.PositiveNumberProperty(default=400.0, doc="Pad Length [um]")

        def _generate_elements(self, elems):

            width = self.width
            length = self.length

            elems += i3.Rectangle(layer=i3.TECH.PPLAYER.M1, box_size=(length, width), center=(0.0, 0.0))
            return elems

        def _generate_ports(self, ports):
            ports += i3.ElectricalPort(
                name="dc0",
                layer=i3.TECH.PPLAYER.M1,
                position=(0.0, 0.0),
                shape=i3.ShapeRectangle(),
                angle=0.0,
            )
            return ports

    class Netlist(i3.NetlistFromLayout):
        pass


def gen_pad_array(pitch_x=0.6, pitch_y=0.8, npads=(3, 3), pad=DCPad()):
    """Returns an array reference of vias according to the given via width, via spacing an number of vias (x, y)"""
    nx, ny = npads
    origin = (-(nx - 1) / 2.0 * pitch_x, -(ny - 1) / 2.0 * pitch_y)
    return i3.ARef(reference=pad, origin=origin, n_o_periods=(nx, ny), period=(pitch_x, pitch_y))


class DCPadArray(i3.PCell):
    """Array of DCPad."""

    _name_prefix = "DCPadArray"

    class Layout(i3.LayoutView):
        _doc_properties = ["pad_length", "pad_width", "pitch", "n_o_pads"]
        pad_length = i3.PositiveNumberProperty(
            default=400.0,
            doc="Pad Length [um]",
        )
        pad_width = i3.PositiveNumberProperty(
            default=300.0,
            doc="Pad Width [um]",
        )
        pitch = i3.PositiveNumberProperty(default=200.0, doc="Pitch of the DCPads [um]")
        n_o_pads = i3.Tuple2Property(
            default=(1, 3),
            doc="number of DCPads in x and y",
            restriction=i3.RESTRICT_INT_TUPLE2,
        )

        def _generate_instances(self, insts):
            dcpad = DCPad(name=self.name + "_dcpad")
            dcpad.Layout(width=self.pad_width, length=self.pad_length)

            insts += gen_pad_array(
                pitch_x=self.pitch + self.pad_length,
                pitch_y=self.pitch + self.pad_width,
                npads=self.n_o_pads,
                pad=dcpad,
            )
            return insts

        def _generate_ports(self, ports):
            inst = self.instances[0]
            return [
                pt.modified_copy(name=pt.name.rstrip(pt.name[-1]) + "{}".format(int(idx)))
                for idx, pt in enumerate(inst.ports)
            ]

    class Netlist(i3.NetlistView):
        layout_view = i3.ViewInSameCellProperty(i3.LayoutView)

        def _generate_netlist(self, netlist):
            for port in self.layout_view.ports:
                netlist += i3.ElectricalTerm(name=port.name)
            return netlist
