#!/usr/bin/python
import linuxcnc
import hal
import gtk
import gtksourceview2 as gtksourceview
import gladevcp.makepins
import pango

_MAN = 0;_MDI = 1;_AUTO = 2;_LOCKTOGGLE = 1

# This is a handler file for using Gscreen's infrastructure
# to load a completely custom glade screen.
# Project - must be saved as a GTK builder project,
#         - the toplevel window is caller window1 (The default name) 
#         - connect an onwindow1_destroy signal else you can't close down linuxcnc 

# standard handler call
def get_handlers(halcomp,builder,useropts,gscreen):
     return [HandlerClass(halcomp,builder,useropts,gscreen)]

class HandlerClass:
    
    # self.emc is for control and status of linuxcnc
    # self.data is important data from gscreen and linuxcnc
    # self.widgets is all the widgets from the glade files
    # self.gscreen is for access to gscreens methods

    def __init__(self, halcomp,builder,useropts,gscreen):
            self.emc = gscreen.emc
            self.data = gscreen.data
            self.widgets = gscreen.widgets
            self.gscreen = gscreen

            # Initialize variables 

            self.data.lathe_mode = True
            self.data.diameter_mode = True
            self.data.homed = 0
            self.data.graphic_ypos = 0
            self.data.graphic_xpos = 0
            self.data.view = 0
            self.data.task_mode = 0
            self.data.estopped = True
            self.data.machine_on = False
            self.data.spindle_request_rpm = 0
            self.data.spindle_dir = 0
            self.data.spindle_speed = 0
            self.data.spindle_start_rpm = 300
            self.spindle_preset = 300
            self.active_spindle_command = "" # spindle command setting
            self.active_feed_command = "" # feed command setting            
            
            #
            self.tooleditor = ""
            self.tooltable = ""
            #variable to hold the active joint, 
            #from the joint dictionary             
            #joint[].home
            #self.data.
            self.active_joint = 0
            #variable to hold the joint flag, might only be needed to jog in joint mode...
            self.jog_flag = False
            #variable to set the jog increment based on the combobox
            # combobox can be read in two ways 
                # 1) as columns 0-x, which you can assign values to or
                # 2) as the actual float values. For continuous jogging set increment = 0
            self.jog_increment = 0.0
            self.joint0_is_homed = False
            self.joint1_is_homed = False
            

    # NOTE: to push a message to the statusbar 
    # self.widgets.statusbar1.push(self.statusbar_id,message)           

    # When the machine starts up we want to 
        # - default into manual mode
        # - hide any buttons/tabs that should not be available until the estop has been cleared 
        #   and the NC has been connected
        # - def mode_changed 

    def init_mode(self):
        # Define the order in which the modes are cycled.       
        self.data.mode_order = _MAN,_MDI,_AUTO
        # Set the mode_button label to reflect the active mode (manual)
        self.data.mode_labels = 0 
        label = self.data.mode_labels
        self.widgets.mode_button.set_label(label[self.data.mode_order[0]])
        # set linuxcnc to manual mode by calling mode_changed 
        self.mode_changed(self.data.mode_order[0])    

    # Function to cycle the mode and keep gscreen's data updated
    #TODO set mode label on start up
    def on_mode_button_button_press_event(self,widget,event):
        if event.type == gtk.gdk.BUTTON_PRESS:
            print "mode button pressed"
            a,b,c = self.data.mode_order
            self.data.mode_order = b,c,a
            label = self.data.mode_labels
            self.widgets.mode_button.set_label(label[self.data.mode_order[0]])
            self.mode_changed(self.data.mode_order[0])

    #TODO show/hide notebook2 tabs based on modes
    def mode_changed(self,mode):
        print "changing mode to"
        if mode == self.data._MAN:
            # set the mode to manual
            self.emc.set_manual_mode()
            # set the manual tab(0) in notebook1 as the current page 
            self.widgets.notebook1.set_current_page(0)
            print "MANUAL"

        elif mode == self.data._MDI:
            # set the mode to MDI
            self.emc.set_mdi_mode()
             # set the MDI tab(1) in notebook1 as the current page 
            self.widgets.notebook1.set_current_page(1)        
            print "MDI"
            
        elif mode == self.data._AUTO:
            # set the mode to AUTO
            self.emc.set_auto_mode()
            # set the Auto tab(2) in notebook1 as the current page 
            self.widgets.notebook1.set_current_page(2)
            print "AUTO"


    # Axis selection radio button
    def on_select_xaxis_button_toggled(self,widget,data=None):
        print "joint 0 selected"
        self.active_joint = 0
        self.widgets.xaxis_selected_led.set_active(True)
        self.widgets.zaxis_selected_led.set_active(False)           

    def on_select_zaxis_button_toggled(self,widget,data=None):
        print "joint 1 selected"
        self.active_joint = 1
        self.widgets.xaxis_selected_led.set_active(False)
        self.widgets.zaxis_selected_led.set_active(True)  

    # Home selected axis
    # check for, manual mode, interp_idle but for now just try to issue  the command
    # TODO conditions for homing
    def on_home_axis_button_clicked(self,widget,data=None):
        if self.data.mode_order[0] == self.data._MAN:
            print "homing joint %s" % self.active_joint
            self.emc.home_selected(self.active_joint)
            # and let gscreen know that the axis has been homed
           
        else:
            #try to send message to statusbar
            self.widgets.statusbar1.push(1, "you fucked up, switch to manual mode for homing")

    #Unhome selected axis
    def on_unhome_axis_button_clicked(self,widget,data=None):
        print "homing joint %s" % self.active_joint
        self.emc.unhome_selected(self.active_joint)



    def on_activate_jog_button_toggled(self,widget,data=None):
        # check the current state of the jog flag, and toggle it TRUE/FALSE
        # this seems like a weird way to do it but it works
        if self.jog_flag == False:        
            self.jog_flag = True
            print "setting jog flag %s" % self.jog_flag
        else:
            self.jog_flag = False
            print "setting jog flag %s" % self.jog_flag            
           
    # Set the float value of the jog increments based on a combobox
    #TODO populte combobox from ini file settings, but for now just set the jog increment
    def on_jog_inc_combobox_changed(self, combobox, data=None):
        print "jog increment float value = %f" % (combobox.hal_pin_f.get())         
        self.jog_increment = combobox.hal_pin_f.get()
        # if the jog increment = 0 use continuous jogging
        if self.jog_increment == 0:
            print "continuous jogging"
        else:
            print "mpg_active increment = %f" % self.jog_increment

    # Manual Spindle
    # check that mode = man, spindle is not already running, interp = idle?
    # potientally could connect these buttons in post-gui.hal to gscreens, default pins that we 
    # have already initialized
    # ...
    # try
    def on_set_spindle_sbutton_value_changed(self,widget,data=None):
        #debug, figure out the value of the halpin
        print "set spindle rpm float value = %f" % (widget.hal_pin_f.get()) 
        # if the spindle is not already running then we can set the sindle speed
        # not sure if I should use spindle_start_rpm or spindle_request_rpm
        # set the spindle        
        self.data.spindle_start_rpm = widget.hal_pin_f.get()  
        print "spindle start rpm = %f" % self.data.spindle_start_rpm

    # spindle fwd/rev/stop
    # need some checks to make sure that
    #   1) sequence is always stop=>fwd=>stop=>rev=>stop=>fwd
    #   2) it okay to do,
    #TODO work out how to remap s code to call gear change based on the spindle_request_rpm
    #     Nuetral gear will be a special case where the user calls a custom M code
    #     and grey out the spinbutton if the spindle is running...if possible
    #     ADD delay between stopping and switching directions. wait for ...
    #OR KISS, handle these through mdi actions? how do you handle checks?

    # assuming self.data.spindle_dir = 0 = stop, 1 = fwd, -1 = rev
    def on_spindle_stop_rbutton_toggled(self,widget,Data=None):
        self.data.spindle_dir = 0
        print "spindle stopped %f" % self.data.spindle_dir
        self.widgets.statusbar1.push(1, "Stopping spindle")
        self.emc.spindle_off(1)

    def on_spindle_fwd_rbutton_toggled(self,widget,Data=None):
        if self.data.spindle_dir == 0:
            self.data.spindle_dir = 1
            print "spindle fwd %f" % self.data.spindle_dir
            self.emc.spindle_forward(1,self.data.spindle_start_rpm)
        else:
            self.widgets.statusbar1.push(1, "Stop spindle before changing directions")     
       
    def on_spindle_rev_rbutton_toggled(self,widget,Data=None):
        if self.data.spindle_dir == 0:
            self.data.spindle_dir = -1    
            print "spindle reverse %f" % self.data.spindle_dir
            self.emc.spindle_reverse(1,self.data.spindle_start_rpm)
        else:
            self.widgets.statusbar1.push(1, "Stop spindle before changing directions") 

    # OVERRIDES  ---------------------------------------------------------
    # Note: ini file settings are in units/sec vs gscreen units/min, 
    # therefore we want to use the scaled-value
    # No idea how/why these work(  ?,      ?,         ?)
    def on_feed_override_value_changed (self, widget, data=None):
        # Read the speedcontrol pins to determine values. 
        # At this point there are no conditions to make sure values are within min/max etc
        print "feed override value = %f" % self.gscreen.halcomp["feed_override.value"]
        print "feed override scaled-value = %f" % self.gscreen.halcomp["feed_override.scaled-value"]
        rate = self.gscreen.halcomp["feed_override.scaled-value"]
        self.emc.feed_override(rate)
        
    def on_spindle_override_value_changed (self, widget, data=None):
        # Read the speedcontrol pins to determine values. 
        # At this point there are no conditions to make sure values are within min/max etc
        print "spindle override value = %f" % self.gscreen.halcomp["spindle_override.value"]
        print "spindle override scaled-value = %f" % self.gscreen.halcomp["spindle_override.scaled-value"]
        spindle_rate = self.gscreen.halcomp["spindle_override.scaled-value"]
        self.emc.spindle_override(spindle_rate)       

    def on_rapid_override_value_changed (self, widget, data=None):
        # Read the speedcontrol pins to determine values. 
        # At this point there are no conditions to make sure values are within min/max etc
        print "rapid override value = %f" % self.gscreen.halcomp["rapid_override.value"]
        print "rapid override scaled-value = %f" % self.gscreen.halcomp["rapid_override.scaled-value"]
        rapid_rate = self.gscreen.halcomp["rapid_override.scaled-value"]
        self.emc.rapid_override(rapid_rate)

    def on_jog_override_value_changed (self, widget, data=None):
        # Read the speedcontrol pins to determine values. 
        # At this point there are no conditions to make sure values are within min/max etc
        print "jog override value = %f" % self.gscreen.halcomp["jog_override.value"]
        print "jog override scaled-value = %f" % self.gscreen.halcomp["jog_override.scaled-value"]
        jog_rate = self.gscreen.halcomp["jog_override.scaled-value"]
        self.emc.max_velocity(jog_rate)             


    # Gremlin Widget Buttons -----------------------------------------------------------------
    def on_zoom_plus_button_clicked(self,widget):
        self.widgets.gremlin.zoom_in()

    def on_zoom_minus_button_clicked(self,widget):
        self.widgets.gremlin.zoom_out()

    def on_pan_up_button_clicked(self,widget):
        self.data.graphic_ypos = self.data.graphic_ypos-8
        self.widgets.gremlin.pan(self.data.graphic_xpos,self.data.graphic_ypos)

    def on_pan_down_button_clicked(self,widget):
        self.data.graphic_ypos = self.data.graphic_ypos+8
        self.widgets.gremlin.pan(self.data.graphic_xpos,self.data.graphic_ypos) 

    def on_pan_right_button_clicked(self,widget):
        self.data.graphic_xpos = self.data.graphic_xpos+8
        self.widgets.gremlin.pan(self.data.graphic_xpos,self.data.graphic_ypos)

    def on_pan_left_button_clicked(self,widget):
        self.data.graphic_xpos = self.data.graphic_xpos-8
        self.widgets.gremlin.pan(self.data.graphic_xpos,self.data.graphic_ypos)

    def on_change_view_button_clicked(self,widget):
        # Since this control is for a CNC lathe we only want to use
        # views P,Y,Y2, (0,2,3?) 
        self.data.view = self.data.view+1
        if self.data.view > 2:
            self.data.view =0
        else:
            view = 0
        
        view = self.data.view
        
        if view == 0:
            self.widgets.gremlin.set_property('view','P')
            print "gremlin view P"

        elif view == 1:
            print"gremlin view y"
            self.widgets.gremlin.set_property('view','Y')

        elif view == 2:
            print"gremlin view y2"
            self.widgets.gremlin.set_property('view','Y2')

    def on_clear_view_button_clicked(self,widget):
        print "clear plot"
        self.widgets.gremlin.clear_live_plotter()
        
    # leds and labels
    # HAL-leds  - if no HAL-Pin is created, then the led can be controlled by a python function. To know when the led has been
    #             turned on in your code, you can create a function that does something when the code changes the led 
    #             example def on_hal_led_pin_changed(self,hal_led,data=None):
    #                           you do you here
    #           - if a HAL-Pin is created for the led than it is connected in the custom post-gui.hal file 
    #               

    

    
    # call this funtion every 100ms to update the screens leds
    #def update_leds(self,*args):
    #    update_axis_homed_leds()
    #def update_axis_homed_leds(self):
    #    if self.data.estopped:
    #        self.widgets.xaxis_homed_led.set_active(False)
    #    else:
    #        self.widgets.xaxis_homed.set_active(True)    





    # This connects siganals without using glade's autoconnect method
    # Widgets that are the same as the default gscreen use this method
    # Widgets that are user created are connected using glades auto-connect method
    def connect_signals(self,handlers):
        signal_list = [ ["window1","destroy", "on_window1_destroy"],
                        ["run_halshow","clicked", "on_halshow"],
                        ["run_status","clicked", "on_status"],
                        ["run_halmeter","clicked", "on_halmeter"],
                        ["run_halscope","clicked", "on_halscope"],
                        ["run_ladder","clicked", "on_ladder"],
                        ["metric_select", "clicked","on_metric_select_clicked"],
                        ["pop_statusbar", "clicked", "on_pop_statusbar_clicked"],
                        ["button_option_stop", "clicked", "on_button_option_stop_clicked"],
                        #["button_index_tool", "clicked", "on_index_tool"],
                        ["theme_choice", "changed", "on_theme_choice_changed"]
                        # add other signals here
                      ]
        for i in signal_list:
            if len(i) == 3:
                self.gscreen.widgets[i[0]].connect(i[1], self.gscreen[i[2]])
            elif len(i) == 4:
                self.gscreen.widgets[i[0]].connect(i[1], self.gscreen[i[2]],i[3])

        # for custom signals we can connect them here
        #self.widgets.mode_button.connect("button_press_event", "self.on_mode_button_clicked")

    # We don't want Gscreen to initialize it's regular widgets because this custom
    # screen doesn't have most of them. However, we do want to use some of the simpler 
    # ones 
    # 
    def initialize_widgets(self):
        self.gscreen.init_show_windows()
        self.gscreen.init_embeded_terminal()
        self.gscreen.init_dynamic_tabs()
        self.gscreen.init_statusbar()
        self.gscreen.init_tooleditor()
        self.gscreen.init_themes()        
        self.gscreen.change_theme(self.data.theme_name)
        self.gscreen.set_dro_units(self.data.dro_units)
        # FIXME
        # self.init_mode()


    # Initialize hal-pins that we need access to  
    def initialize_pins(self):
        self.gscreen.init_spindle_pins()
        self.gscreen.init_coolant_pins()
        self.gscreen.init_jog_pins()
        self.gscreen.init_override_pins()
        self.gscreen.init_control_pins()   

    # every 100 milli seconds these functions get called
    def periodic(self):    
        self.gscreen.update_active_gcodes()
        self.gscreen.update_active_mcodes() 
        self.gscreen.update_units_button_label()
        self.gscreen.update_tool_label()
        self.gscreen.update_feed_speed_label()   
        
        #self.update_leds()   



    def __getitem__(self, item):
        return getattr(self, item)
    def __setitem__(self, item, value):
        return setattr(self, item, value)


# standard handler call
def get_handlers(halcomp,builder,useropts,gscreen):
     return [HandlerClass(halcomp,builder,useropts,gscreen)]




