
import sys
import importlib
from qtvcp.core import Path, Qhal, Action, Status
PATH = Path()
QHAL = Qhal()
ACTION = Action()
STATUS = Status()

# get reference to original handler file so we can subclass it
sys.path.insert(0, PATH.SCREENDIR)
module = "{}.{}_handler".format(PATH.BASEPATH,PATH.BASEPATH)
mod = importlib.import_module(module, PATH.SCREENDIR)
sys.path.remove(PATH.SCREENDIR)
HandlerClass = mod.HandlerClass

# return our subclassed handler object
def get_handlers(halcomp, widgets, paths):
    return [UserHandlerClass(halcomp, widgets, paths)]

class UserHandlerClass(HandlerClass):
    def __init__(self, halcomp, widgets, paths):
        super().__init__(halcomp, widgets, paths)
        self._linear_jog_step = 0
        self._linear_jog_last_count = 0
        self._angular_jog_step = 0
        self._angular_jog_last_count = 0
        self._feed_step = 0
        self._feed_last_count = 0        
        self._spindle_step = 0
        self._spindle_last_count = 0
        self._rapid_step = 0
        self._rapid_last_count = 0
        self._max_vel_step = 0
        self._max_vel_last_count = 0
        self._mpg_last_count = 0
    print('Custom subclassed handler loaded\n')

    def init_pins(self):
        super().init_pins()
        self.FEED_RATE_ENABLE = 0
        self.SPINDLE_RATE_ENABLE = 0
        self.ANGULAR_JOG_RATE_ENABLE = 0
        self.JOG_RATE_ENABLE = 0
        self.RAPID_RATE_ENABLE = 0
        self.MAX_VEL_OVERALL_ENABLE = 0
        self.MPG_ENABLE = 0
        # jog pins X axis
        pin = QHAL.newpin("jog.axis.x.plus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 0, 1, fast = False, linear = True))
        pin = QHAL.newpin("jog.axis.x.minus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 0, -1, fast = False, linear = True))

		# jog pins Y axis
        pin = QHAL.newpin("jog.axis.y.plus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 1, 1, fast = False, linear = True))
        pin = QHAL.newpin("jog.axis.y.minus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 1, -1, fast = False, linear = True))

		# jog pins Z axis
        pin = QHAL.newpin("jog.axis.z.plus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 2, 1, fast = False, linear = True))
        pin = QHAL.newpin("jog.axis.z.minus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 2, -1, fast = False, linear = True))

        # jog pins A axis
        pin = QHAL.newpin("jog.axis.a.plus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 3, 1, fast = False, linear = False))
        pin = QHAL.newpin("jog.axis.a.minus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 3, -1, fast = False, linear = False))

        # jog pins B axis
        pin = QHAL.newpin("jog.axis.b.plus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 4, 1, fast = False, linear = False))
        pin = QHAL.newpin("jog.axis.b.minus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 4, -1, fast = False, linear = False))

        # jog pins C axis
        pin = QHAL.newpin("jog.axis.c.plus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 5, 1, fast = False, linear = False))
        pin = QHAL.newpin("jog.axis.c.minus", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.kb_jog(s, 5, -1, fast = False, linear = False))

        # generate the pins to connect counter inputs for slider ANGULAR_JOG 
        pin = QHAL.newpin("jog.override-angular.count-enable", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_count_enable_changed(s,"ANGULAR_JOG_RATE"))
        pin = QHAL.newpin("jog.override-angular.counts", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_counts_value_changed(s,"ANGULAR_JOG_RATE"))
        # make a pin to set turtle jog angular
        pin = QHAL.newpin("jog.override-angular.turtle", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.togle_jog_range_a(s))
        # make a pin to indicated slow/fast button
        pin = QHAL.newpin("jog.override-angular.turtle-led", QHAL.HAL_BIT, QHAL.HAL_OUT)
        # make a pin to step value for ANGULAR_JOG_RATE
        pin = QHAL.newpin("jog.override-angular.step", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._step_value_set(s,"ANGULAR_JOG_RATE"))
        
        # generate the pins to connect counter inputs for slider JOG_RATE  
        pin = QHAL.newpin("jog.override-linear.count-enable", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_count_enable_changed(s,"JOG_RATE"))
        pin = QHAL.newpin("jog.override-linear.counts", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_counts_value_changed(s,"JOG_RATE"))
        # make a pin to set turtle jog vel
        pin = QHAL.newpin("jog.override-linear.turtle", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self.togle_jog_range_l(s))
        # make a pin to indicated slow/fast button
        pin = QHAL.newpin("jog.override-linear.turtle-led", QHAL.HAL_BIT, QHAL.HAL_OUT)
        # make a pin to step value for JOG_RATE 
        pin = QHAL.newpin("jog.override-linear.step", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._step_value_set(s,"JOG_RATE"))

		# generate the pins to connect counter inputs for slider FEED_RATE
        pin = QHAL.newpin("feed.override.count-enable", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_count_enable_changed(s,"FEED_RATE"))
        pin = QHAL.newpin("feed.override.counts", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_counts_value_changed(s,"FEED_RATE"))
        # make a pin to set feed override 100%
        pin = QHAL.newpin("feed.override.btn-100", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda: self.btn_feed_100_clicked())
        # make a pin to step value for FEED_RATE
        pin = QHAL.newpin("feed.override.step", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._step_value_set(s, "FEED_RATE"))
        
        # generate the pins to connect counter inputs for slider SPINDLE_RATE
        pin = QHAL.newpin("spindle.override.count-enable", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_count_enable_changed(s,"SPINDLE_RATE"))
        pin = QHAL.newpin("spindle.override.counts", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_counts_value_changed(s,"SPINDLE_RATE"))
        # make a pin to set spindle 100%
        pin = QHAL.newpin("spindle.override.btn-100", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda: self.btn_spindle_100_clicked())
        # make a pin to step value for SPINDLE_RATE
        pin = QHAL.newpin("spindle.override.step", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._step_value_set(s, "SPINDLE_RATE"))

		# generate the pins to connect counter inputs for slider RAPID_RATE
        pin = QHAL.newpin("rapid.override.count-enable", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_count_enable_changed(s,"RAPID_RATE"))
        pin = QHAL.newpin("rapid.override.counts", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_counts_value_changed(s,"RAPID_RATE"))
        # make a pin to set rapid 100%
        pin = QHAL.newpin("rapid.override.btn-100", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda: self.btn_rapid_100_clicked())
        # make a pin to step value for RAPID_RATE
        pin = QHAL.newpin("rapid.override.step", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._step_value_set(s, "RAPID_RATE"))
        
        # generate the pins to connect counter inputs for slider MAX_VEL_OVERALL
        pin = QHAL.newpin("maxvel.override.count-enable", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_count_enable_changed(s,"MAX_VEL_OVERALL"))
        pin = QHAL.newpin("maxvel.override.counts", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._on_counts_value_changed(s,"MAX_VEL_OVERALL"))
        # make a pin to set max velocity 100%
        pin = QHAL.newpin("maxvel.override.btn-100", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda: self.btn_maxv_100_clicked())
        # make a pin to step value for MAX_VEL_OVERALL
        pin = QHAL.newpin("maxvel.override.step", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._step_value_set(s, "MAX_VEL_OVERALL"))

        #make a pin for enable MPG
        pin = QHAL.newpin("mpg.mpg-enable", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_enable_changed(s))
                
        #make a pins for jog increments
        pin = QHAL.newpin("mpg.mpg-inc.1", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_icr_selected())
        pin = QHAL.newpin("mpg.mpg-inc.2", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_icr_selected())
        pin = QHAL.newpin("mpg.mpg-inc.3", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_icr_selected())
        
        #make a pins for jog angular increments
        pin = QHAL.newpin("mpg.mpg-angular-inc.1", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_icr_selected())
        pin = QHAL.newpin("mpg.mpg-angular-inc.2", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_icr_selected())
        pin = QHAL.newpin("mpg.mpg-angular-inc.3", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_icr_selected())

        #make a pins for axis select
        pin = QHAL.newpin("mpg.axis.x", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin = QHAL.newpin("mpg.axis.y", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin = QHAL.newpin("mpg.axis.z", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin = QHAL.newpin("mpg.axis.a", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin = QHAL.newpin("mpg.axis.b", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin = QHAL.newpin("mpg.axis.c", QHAL.HAL_BIT, QHAL.HAL_IN)

        #make a MPG encoder pin
        pin = QHAL.newpin("mpg.encoder-count", QHAL.HAL_S32, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_on_counts_changed(s))

        #make a pin to cycle change increments
        pin = QHAL.newpin("mpg.mpg-inc.cycle", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_inr_cycle(s))
        pin = QHAL.newpin("mpg.mpg-angular-inc.cycle", QHAL.HAL_BIT, QHAL.HAL_IN)
        pin.value_changed.connect(lambda s: self._mpg_inr_angular_cycle(s))

    def _on_count_enable_changed(self, state, command):
        self['{}_ENABLE'.format(command)] = state

    def _step_value_set(self, step, command):
        if command == "FEED_RATE":
            self._feed_step = step
        elif command == "SPINDLE_RATE":
            self._spindle_step = step
        elif command == "RAPID_RATE":
            self._rapid_step = step
        elif command == "MAX_VEL_OVERALL":
            self._max_vel_step = step
        elif command == "JOG_RATE":
            self._linear_jog_step = step
        elif command == "ANGULAR_JOG_RATE":
            self._angular_jog_step = step
                
    def _on_counts_value_changed(self, counts, command):
        #print(counts,command,self['{}_ENABLE'.format(command)])
        if self['{}_ENABLE'.format(command)]:

            if command == 'JOG_RATE':                
                if counts == self._linear_jog_last_count:
                    self.w.slider_jog_linear.setValue(self.w.slider_jog_linear.value())
                elif counts > self._linear_jog_last_count:
                    self.w.slider_jog_linear.setValue(self.w.slider_jog_linear.value()
                                                  + self.w.slider_jog_linear.maximum() 
                                                  / 100 * self._linear_jog_step)
                else:
                    self.w.slider_jog_linear.setValue(self.w.slider_jog_linear.value()
                                                  - self.w.slider_jog_linear.maximum() 
                                                  / 100 * self._linear_jog_step)
                self._linear_jog_last_count = counts
                                 
            elif command == 'ANGULAR_JOG_RATE':
                if counts == self._angular_jog_last_count:
                    self.w.slider_jog_angular.setValue(self.w.slider_jog_angular.value())
                elif counts > self._angular_jog_last_count:
                    self.w.slider_jog_angular.setValue(self.w.slider_jog_angular.value()
                                                  + self.w.slider_jog_angular.maximum() 
                                                  / 100 * self._angular_jog_step)
                else:
                    self.w.slider_jog_angular.setValue(self.w.slider_jog_angular.value()
                                                  - self.w.slider_jog_angular.maximum() 
                                                  / 100 * self._angular_jog_step)
                self._angular_jog_last_count = counts
                    
            elif command == "FEED_RATE":
                if counts == self._feed_last_count:
                    self.w.slider_feed_ovr.setValue(100)
                elif counts > self._feed_last_count:
                    self.w.slider_feed_ovr.setValue(self.w.slider_feed_ovr.value() + self._feed_step)
                else:
                    self.w.slider_feed_ovr.setValue(self.w.slider_feed_ovr.value() - self._feed_step)
                self._feed_last_count = counts

            elif command == "SPINDLE_RATE":
                if counts == self._spindle_last_count:
                    self.w.slider_spindle_ovr.setValue(100)
                elif counts > self._spindle_last_count:
                    self.w.slider_spindle_ovr.setValue(self.w.slider_spindle_ovr.value() + self._spindle_step)
                else:
                    self.w.slider_spindle_ovr.setValue(self.w.slider_spindle_ovr.value() - self._spindle_step)
                self._spindle_last_count = counts

            elif command == "RAPID_RATE":
                if counts == self._rapid_last_count:
                    self.w.slider_rapid_ovr.setValue(100)
                elif counts > self._rapid_last_count:
                    self.w.slider_rapid_ovr.setValue(self.w.slider_rapid_ovr.value() + self._rapid_step)
                else:
                    self.w.slider_rapid_ovr.setValue(self.w.slider_rapid_ovr.value() - self._rapid_step)
                self._rapid_last_count = counts

            elif command == "MAX_VEL_OVERALL":
                #print("slider max_vel value: ", self.w.slider_maxv_ovr.value())
                if counts == self._max_vel_last_count:
                    self.w.slider_maxv_ovr.setValue(100)
                elif counts > self._max_vel_last_count:
                    self.w.slider_maxv_ovr.setValue(self.w.slider_maxv_ovr.value() 
                                                    + self.w.slider_maxv_ovr.maximum() 
                                                    / 100 * self._max_vel_step)
                else:
                    self.w.slider_maxv_ovr.setValue(self.w.slider_maxv_ovr.value() 
                                                    - self.w.slider_maxv_ovr.maximum() 
                                                    / 100 * self._max_vel_step)
                self._max_vel_last_count = counts                
            else:
                ACTION['SET_{}'.format(command)](counts*100)

    def btn_feed_100_clicked(self):
        self.w.slider_feed_ovr.setValue(100)

    def btn_spindle_100_clicked(self):
        self.w.slider_spindle_ovr.setValue(100)

    def btn_rapid_100_clicked(self):
        self.w.slider_rapid_ovr.setValue(100)

    def togle_jog_range_l(self, state):
        self.w.btn_jog_l_slow.setChecked(state)
        self.w.btn_jog_l_slow.clicked.emit(state)

    def togle_jog_range_a(self, state):
        self.w.btn_jog_a_slow.setChecked(state)
        self.w.btn_jog_a_slow.clicked.emit(state)
    
    def _mpg_enable_changed(self, state):
        self.MPG_ENABLE = state
        if self.MPG_ENABLE:
            self.w.jogincrements_linear.setEnabled(0)
            self.w.jogincrements_angular.setEnabled(0)
            self.h["mpg.mpg-enable"] = 1
        else:
            self.w.jogincrements_linear.setEnabled(1)
            self.w.jogincrements_angular.setEnabled(1)
            self.h["mpg.mpg-enable"] = 0

    def _mpg_icr_selected(self):
        #verification that the hal increments pins match screen increment
        #if no, set it equal screen value to the active hal pin
        for i in range(1, 4):            
            if self.h[f"mpg.mpg-inc.{i}"]:
                if i != self.w.jogincrements_linear.currentIndex():
                    self.w.jogincrements_linear.setCurrentIndex(i)
            if self.h[f"mpg.mpg-angular-inc.{i}"]:
                if i != self.w.jogincrements_angular.currentIndex():
                    self.w.jogincrements_angular.setCurrentIndex(i)

    def _mpg_on_counts_changed(self, counts): 
        linear = True
        if self.MPG_ENABLE and STATUS.is_man_mode() and STATUS.is_all_homed():                            
            if self.h["mpg.axis.x"]:
                joint = 0
            elif self.h["mpg.axis.y"]:
                joint = 1
            elif self.h["mpg.axis.z"]:
                joint = 2
            elif self.h["mpg.axis.a"]:
                joint = 3
                linear = False
            elif self.h["mpg.axis.b"]:
                joint = 4
                linear = False
            elif self.h["mpg.axis.c"]:
                joint = 5
                linear = False  
            else:
                joint = -1      
            if linear:
                distance = STATUS.get_jog_increment()
                rate = STATUS.get_jograte()/60
            else:
                distance = STATUS.get_jog_increment_angular()
                rate = STATUS.get_jograte_angular()/60
            if counts > self._mpg_last_count:
                direction = 1
            else:
                direction = -1
            if joint >= 0 and self.w.jogincrements_linear.currentIndex() != 0:            
                ACTION.JOG(joint, direction, rate, distance)        
        self._mpg_last_count = counts

    def _mpg_inr_cycle(self, state):
        if state:
            i = self.w.jogincrements_linear.currentIndex()
            if i < self.w.jogincrements_linear.count()-1:                 
                self.w.jogincrements_linear.setCurrentIndex(i+1)
            else:
                if i == self.w.jogincrements_linear.count()-1: 
                    self.w.jogincrements_linear.setCurrentIndex(0)
            
    def _mpg_inr_angular_cycle(self, state):
        if state:            
            n = self.w.jogincrements_angular.currentIndex()
            if n < self.w.jogincrements_angular.count()-1:                 
                self.w.jogincrements_angular.setCurrentIndex(n+1)
            else:
                if n == self.w.jogincrements_angular.count()-1: 
                    self.w.jogincrements_angular.setCurrentIndex(0)
