class Switch:
    """ Ideal switch class. Contains functions to initiliaze
    the switch according to name tag, unique cell position,
    update system matrix on each iteration. """
    def __init__(self, switch_index, switch_pos, switch_tag):
        """ Constructor to initialize value.
        Also, takes in the identifiers -
        index (serial number), cell position and tag. """
        self.type="Switch"
        self.number=switch_index
        self.pos=switch_pos
        self.tag=switch_tag
        self.has_voltage="yes"
        self.switch_level=120.0
        self.current=0.0
        self.voltage=0.0
        self.polrty=[-1, -1]
        self.resistor_on=0.01
        self.status="off"
        self.control_tag=["Control"]
        self.control_values=[0.0]

    def display(self):
        print "Switch is ",
        print self.tag,
        print " located at ",
        print self.pos,
        print " with negative polarity towards %s" %(csv_element(self.polrty))

        return

    def ask_values(self, x_list, ckt_mat, sys_branch):
        """ Writes the values needed to the spreadsheet."""
        switch_params=["Switch"]
        switch_params.append(self.tag)
        switch_params.append(self.pos)
        switch_params.append("Voltage level (V) = %f" %self.switch_level)        

        if self.polrty==[-1, -1]:
            # Looking for a default value of polarity
            # in the neighbouring cells
            self.switch_elem=csv_tuple(self.pos)
            if self.switch_elem[0]>0:
                if ckt_mat[self.switch_elem[0]-1][self.switch_elem[1]]:
                    self.polrty=[self.switch_elem[0]-1, self.switch_elem[1]]
            if self.switch_elem[1]>0:
                if ckt_mat[self.switch_elem[0]][self.switch_elem[1]-1]:
                    self.polrty=[self.switch_elem[0], self.switch_elem[1]-1]

            if self.switch_elem[0]<len(ckt_mat)-1:
                if ckt_mat[self.switch_elem[0]+1][self.switch_elem[1]]:
                    self.polrty=[self.switch_elem[0]+1, self.switch_elem[1]]
            if self.switch_elem[1]<len(ckt_mat)-1:
                if ckt_mat[self.switch_elem[0]][self.switch_elem[1]+1]:
                    self.polrty=[self.switch_elem[0], self.switch_elem[1]+1]
        else:
            for c1 in range(len(sys_branch)):
                if csv_tuple(self.pos) in sys_branch[c1]:
                    if not self.polrty in sys_branch[c1]:
                        print
                        print "!"*50
                        print "ERROR!!! Switch polarity should be in the same branch as the switch. Check switch at %s" %self.pos
                        print "!"*50
                        print

        switch_params.append("Negative polarity towards (cell) = %s" %csv_element(self.polrty))
        switch_params.append("Name of control signal = %s" %self.control_tag[0])
        print switch_params
        x_list.append(switch_params)

        return


    def get_values(self, x_list, ckt_mat):
        """ Takes the parameter from the spreadsheet."""
        self.switch_level=float(x_list[0].split("=")[1])
        # Choosing 1 micro Amp as the leakage current that
        # is drawn by the switch in off state.
        self.resistor_off=self.switch_level/1.0e-6
        self.resistor=self.resistor_off


        switch_polrty=x_list[1].split("=")[1]

        # Convert the human readable form of cell
        # to [row, column] form
        while switch_polrty[0]==" ":
            switch_polrty=switch_polrty[1:]

        self.polrty=csv_tuple(switch_polrty)
        
        if not ckt_mat[self.polrty[0]][self.polrty[1]]:
            print "Polarity incorrect. Branch does not exist at %s" %csv_element(self.polrty)

        self.control_tag[0]=x_list[2].split("=")[1]
        while self.control_tag[0][0]==" ":
            self.control_tag[0]=self.control_tag[0][1:]

        return



    def transfer_to_sys(self, sys_loops, mat_e, mat_a, mat_b, mat_u, source_list):
        """ The matrix A in E.dx/dt=Ax+Bu will be updated by the
        resistor value of the switch."""


        for c1 in range(len(sys_loops)):
            for c2 in range(c1, len(sys_loops)):
                # Updating the elements depending
                # on the sense of the loops (aiding or opposing)
                for c3 in range(len(sys_loops[c1][c2])):
                    # Check if current source position is there in the loop.
                    if csv_tuple(self.pos) in sys_loops[c1][c2][c3]:
                        # Add current source series resistor
                        # if branch is in forward direction
                        if sys_loops[c1][c2][c3][-1]=="forward":
                            mat_a.data[c1][c2]+=self.resistor
                        else:
                            # Else subtract if branch is in reverse direction
                            mat_a.data[c1][c2]-=self.resistor
                        # Because the matrices are symmetric
                        mat_a.data[c2][c1]=mat_a.data[c1][c2]

                        # If the positive polarity appears before the voltage position
                        # it means as per KVL, we are moving from +ve to -ve
                        # and so the voltage will be taken negative
                        if sys_loops[c1][c1][c2].index(self.polrty)>sys_loops[c1][c1][c2].index(csv_tuple(self.pos)):
                            if sys_loops[c1][c1][c2][-1]=="forward":
                                mat_b.data[c1][source_list.index(self.pos)]=-1.0
                            else:
                                mat_b.data[c1][source_list.index(self.pos)]=1.0
                        else:
                            if sys_loops[c1][c1][c2][-1]=="forward":
                                mat_b.data[c1][source_list.index(self.pos)]=1.0
                            else:
                                mat_b.data[c1][source_list.index(self.pos)]=-1.0

        return


    def transfer_to_branch(self, sys_branch, source_list):
        """ Update the resistor info of the switch
        to the branch list """

        if csv_tuple(self.pos) in sys_branch:
            sys_branch[-1][0][0]+=self.resistor

        # For the switch forward voltage drop.
        if csv_tuple(self.pos) in sys_branch:
            if sys_branch.index(self.polrty)>sys_branch.index(csv_tuple(self.pos)):
                sys_branch[-1][1][source_list.index(self.pos)]=-1.0
            else:
                sys_branch[-1][1][source_list.index(self.pos)]=1.0

        return


    def generate_val(self, source_lst, sys_loops, mat_e, mat_a, mat_b, mat_u, t, dt):
        """ The switch forward drop voltage is updated
        in the matrix u in E.dx/dt=Ax+Bu ."""

        if self.status=="on":
            mat_u.data[source_lst.index(self.pos)][0]=0.7
        else:
            mat_u.data[source_lst.index(self.pos)][0]=0.0

        return

            
    def update_val(self, sys_loops, lbyr_ratio, mat_e, mat_a, mat_b, state_vec, mat_u, sys_branches, sys_events):
        """ This function calculates the actual current in the 
        switch branch. With this, the branch voltage is found 
        with respect to the existing switch resistance. The switch
        voltage is then used to decide the turn on condition. """

        # Local variable to calculate the branch
        # current from all loops that contain
        # the current source branch.
        act_current=0.0

        for c1 in range(len(sys_loops)):
            for c2 in range(len(sys_loops[c1][c1])):
                if csv_tuple(self.pos) in sys_loops[c1][c1][c2]:
                    # If switch negative polarity is after the switch
                    # position, the current is positive.
                    if sys_loops[c1][c1][c2].index(self.polrty)>sys_loops[c1][c1][c2].index(csv_tuple(self.pos)):
                        # Then check is the loop is aiding or opposing
                        # the main loop.
                        if sys_loops[c1][c1][c2][-1]=="forward":

                            act_current+=state_vec.data[c1][0]
                        else:
                            act_current-=state_vec.data[c1][0]
                    else:
                        if sys_loops[c1][c1][c2][-1]=="forward":
                            act_current-=state_vec.data[c1][0]
                        else:
                            act_current+=state_vec.data[c1][0]

        self.current=act_current
        self.voltage=self.current*self.resistor

        # Identifying the position of the switch branch
        # to generate events.
        for c1 in range(len(sys_branches)):
            if csv_tuple(self.pos) in sys_branches[c1]:
                branch_pos=c1


        # Switch will turn on when it is forward biased
        # and it is gated on.
		if self.control_values[0]>=1.0 and self.voltage>1.0:
			if self.status=="off":
				sys_events[branch_pos]="yes"
				self.status="on"

        # Switch will turn off when gated off or
		# when current becomes negative.
		if self.control_values[0]==0.0 or self.current<0.0:
			if self.status=="on":
				sys_events[branch_pos]="yes"
				self.status="off"


        if self.status=="off":
            self.resistor=self.resistor_off
        else:
            self.resistor=self.resistor_on


        return