#   This is a component of LinuxCNC
#   Copyright 2013 Chris Morley <chrisinnanaimo@hotmail.com>
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#############################################################################
# This is a gscreen skin customized for a Bridgeport Interact Mill that used a
# Heidenhain TNC 151a controller.
# Chris Brady   Oct 2015
#

import gi
from gi.repository import Gtk as gtk
from gi.repository import Pango as pango

import hal
import gladevcp.makepins # needed for the dialog's calulator widget
import hal_glib

_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
# The only things that really matters is that it's saved as a GTK builder project,
# the toplevel window is caller window1 (The default name) and you connect a destroy
# window signal else you can't close down linuxcnc
class HandlerClass:

    # This will be pretty standard to gain access to everything
    # emc is for control and status of linuxcnc
    # data is important data from gscreen and linuxcnc
    # widgets is all the widgets from the glade files
    # 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

# Hide all menus at the bottom of the default gscreen page
        self.widgets.mode0.hide()
        self.widgets.mode1.hide()
        self.widgets.mode2.hide()
        self.widgets.mode3.hide()
        self.widgets.mode4.hide()
        self.widgets.button_mode.hide()
        self.widgets.diameter_mode.hide()
        self.widgets.aux_coolant_m7.hide()
        self.widgets.aux_coolant_m8.hide()
        self.widgets.show_dtg.hide()
        self.widgets.diameter_mode.hide()
        self.widgets.button_flood.hide()
        self.widgets.button_run.hide()

# Initialize variables
        self.data.lathe_mode=False
        self.data.graphic_ypos=0
        self.data.graphic_xpos=0
        self.data.view=0
        self.data.homed=0
        self.data.jog_rates=[30,50,80,120]
        self.data.jog_incrs=[0.0002,0.001,0.01,0.1]
        self.data.jog_rate_idx=2
        self.widgets.jog_r1.set_label("%5.4f"% self.data.jog_incrs[0])
        self.widgets.jog_r2.set_label("%4.3f"% self.data.jog_incrs[1])
        self.widgets.jog_r3.set_label("%3.2f"% self.data.jog_incrs[2])
        self.widgets.jog_r4.set_label("%2.1f"% self.data.jog_incrs[3])
        self.widgets.button_mode.hide()
        self.widgets.button_home_all.hide()

    # every 100 milli seconds this gets called
    # we add calls to the regular functions for the widgets we are using.
    # and add any extra calls/code
    def periodic(self):
        self.gscreen.update_dro()
        self.gscreen.update_active_gcodes()
        self.gscreen.update_active_mcodes()
        self.gscreen.update_feed_speed_label()
        self.gscreen.update_tool_label()
        self.update_estop_led()
        self.gscreen.update_machine_on_led()
        self.gscreen.update_jog_rate_label()
        self.gscreen.update_mode_label()
        self.gscreen.update_units_button_label()
        self.update_override_label()
        self.update_spindle()

    def update_spindle(self):
        # Actual speed from hal
        # Limit speed representation to 1 decimal point
        speed = int(self.gscreen.halcomp["spindle-spd-disp"]*10)/10
        self.widgets.meter_spindle_speed.set_property("value", speed)

    # 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()
        self.gscreen.halcomp.newpin("spindle-spd-disp", hal.HAL_FLOAT, hal.HAL_IN)
        self.gscreen.halcomp.newpin("jog-spd-out", hal.HAL_FLOAT, hal.HAL_OUT)
        self.gscreen.halcomp.newpin("jog-inc-out", hal.HAL_FLOAT, hal.HAL_OUT)
        self.data['ext-estop'] = hal_glib.GPin(self.gscreen.halcomp.newpin('ext-estop', hal.HAL_BIT, hal.HAL_IN))
        self.data['ext-estop'].connect('value-changed', self.on_estop_in)
        self.data['enc-fault-x'] = hal_glib.GPin(self.gscreen.halcomp.newpin('enc-fault-x', hal.HAL_BIT, hal.HAL_IN))
        self.data['enc-fault-x'].connect('value-changed', self.on_x_enc_fault)
        self.data['enc-fault-y'] = hal_glib.GPin(self.gscreen.halcomp.newpin('enc-fault-y', hal.HAL_BIT, hal.HAL_IN))
        self.data['enc-fault-y'].connect('value-changed', self.on_y_enc_fault)
        self.data['enc-fault-x'] = hal_glib.GPin(self.gscreen.halcomp.newpin('enc-fault-z', hal.HAL_BIT, hal.HAL_IN))
        self.data['enc-fault-x'].connect('value-changed', self.on_z_enc_fault)

    def on_emc_off(self,*args):
        self.widgets.button_clear.show()
        self.widgets.button_mode.hide()
        self.widgets.button_home_all.hide()
        # Force mode to manual
        self.data.mode_order = (self.data._MAN,self.data._MDI,self.data._AUTO)
        label = self.data.mode_labels
        self.widgets.button_mode.set_label(label[self.data.mode_order[0]])
        self.mode_changed(self.data.mode_order[0])

    def on_btn_clear(self,widget):
        if self.gscreen.halcomp["ext-estop"] == False:
            self.emc.estop_reset(1)
            self.emc.machine_on(1)
            self.widgets.button_clear.hide()
            self.widgets.button_home_all.show()

    def on_estop_in(self,widget):
        self.widgets.mode0.hide()
        if self.gscreen.halcomp["ext-estop"] == True:
            self.emc.estop_reset(1)
            self.emc.machine_on(1)
        else:
            self.emc.machine_off(1)
            self.emc.estop(1)

    def update_estop_led(self):
        if self.data.estopped:
            self.widgets.led_estop.set_active(False)
        else:
            self.widgets.led_estop.set_active(True)

    def on_x_enc_fault(self,hal_object):
        print"X Encoder Fault"
        self.gscreen.add_alarm_entry(_("X Axis Encoder Error"))

    def on_y_enc_fault(self,hal_object):
        print"Y Encoder Fault"
        self.gscreen.add_alarm_entry(_("Y Axis Encoder Error"))

    def on_z_enc_fault(self,hal_object):
        print"Z Encoder Fault"
        self.gscreen.add_alarm_entry(_("Z Axis Encoder Error"))

    def homing(self,*args):
        self.mode_changed(self.data._MAN)
        self.widgets.button_mode.hide()
        self.widgets.button_home_all.show()
        self.widgets.button_move_to.set_sensitive(0)

    def on_hal_status_all_homed(self,widget):
        self.gscreen.on_hal_status_all_homed(1)
        self.data.homed=1
        self.widgets.button_home_all.hide()
        self.widgets.button_mode.show()
        self.widgets.jog_r3.set_active(1)
        self.on_jog_rate(self.widgets.jog_r3)
        self.gscreen.sensitize_widgets(self.data.sensitive_all_homed,1)
        self.widgets.button_move_to.set_sensitive(1)

    def on_interp_run(self,*args):
        self.gscreen.sensitize_widgets(self.data.sensitive_run_idle,False)
        self.widgets.button_reload.set_sensitive(0)

    def on_interp_idle(self,widget):
        self.gscreen.on_hal_status_interp_idle(widget)
        self.widgets.button_reload.set_sensitive(1)

    def on_jog_rate(self,widget):
        if widget == self.widgets.jog_r1:
            self.data.jog_rate_idx=0
            speed = self.data.jog_rates[0]
            self.widgets.jog_r2.set_active(0)
            self.widgets.jog_r3.set_active(0)
            self.widgets.jog_r4.set_active(0)
            self.gscreen.halcomp["jog-spd-out"] = speed
            self.gscreen.halcomp["jog-inc-out"] = self.data.jog_incrs[0]
        elif widget == self.widgets.jog_r2:
            self.data.jog_rate_idx=1
            speed = self.data.jog_rates[1]
            self.widgets.jog_r1.set_active(0)
            self.widgets.jog_r3.set_active(0)
            self.widgets.jog_r4.set_active(0)
            self.gscreen.halcomp["jog-spd-out"] = speed
            self.gscreen.halcomp["jog-inc-out"] = self.data.jog_incrs[1]
        elif widget == self.widgets.jog_r3:
            self.data.jog_rate_idx=2
            speed = self.data.jog_rates[2]
            self.widgets.jog_r1.set_active(0)
            self.widgets.jog_r2.set_active(0)
            self.widgets.jog_r4.set_active(0)
            self.gscreen.halcomp["jog-spd-out"] = speed
            self.gscreen.halcomp["jog-inc-out"] = self.data.jog_incrs[2]
        elif widget == self.widgets.jog_r4:
            self.data.jog_rate_idx=3
            speed = self.data.jog_rates[3]
            self.widgets.jog_r1.set_active(0)
            self.widgets.jog_r2.set_active(0)
            self.widgets.jog_r3.set_active(0)
            self.gscreen.halcomp["jog-spd-out"] = speed
            self.gscreen.halcomp["jog-inc-out"] = self.data.jog_incrs[3]

    def jog_point1(self,widget):
        if self.data.mode_order[0] == self.data._MAN: # if in manual mode
                print("jog point1")
                if widget == self.widgets.jog_plus:
                    self.do_jog(True,True)
                else:
                    self.do_jog(False,True)

    def do_jog(self,direction,action):
        # if manual mode, if jogging
        # if only one axis button pressed
        # jog positive  at selected rate
        if self.data.mode_order[0] == self.data._MAN:
            if len(self.data.active_axis_buttons) > 1:
                print(self.data.active_axis_buttons)
            elif self.data.active_axis_buttons[0][0] == None:
                self.gscreen.homed_status_message = self.widgets.statusbar1.push(1,"No axis selected to jog")
            else:
                if not self.data.active_axis_buttons[0][0] == "s":
                    if not action: cmd = 0
                    elif direction: cmd = 1
                    else: cmd = -1
                    self.emc.jogging(1)
                    jogincr = self.data.jog_incrs[self.data.jog_rate_idx]
                    self.emc.incremental_jog(self.data.active_axis_buttons[0][1],cmd,jogincr)

    def on_mode_clicked(self,widget,event):
        # only change machine modes on click
        if event.type == gdk.BUTTON_PRESS:
            a,b,c = self.data.mode_order
            self.data.mode_order = b,c,a
            label = self.data.mode_labels
            self.widgets.button_mode.set_label(label[self.data.mode_order[0]])
            self.mode_changed(self.data.mode_order[0])

    def mode_changed(self,mode):
        print("Mode Change", mode)
        if mode == self.data._MAN:
            self.widgets.notebook_mode.hide()
            self.widgets.hal_mdihistory.hide()
            self.widgets.dro_frame.show()
            self.widgets.vmode0.show()
            self.widgets.vmode1.hide()
            self.widgets.button_run.set_active(0)
            self.widgets.button_jog_mode.set_active(1)
            self.widgets.button_view.emit("clicked")
        elif mode == self.data._MDI:
            if self.data.plot_hidden:
                self.toggle_offset_view()
            self.emc.set_mdi_mode()
            self.widgets.hal_mdihistory.show()
            self.widgets.vmode0.show()
            self.widgets.vmode1.hide()
            self.widgets.button_run.set_active(0)
            self.widgets.notebook_mode.hide()
            self.widgets.button_jog_mode.set_active(0)
        elif mode == self.data._AUTO:
            self.widgets.vmode0.hide()
            self.widgets.vmode1.show()
            self.widgets.button_run.set_active(0)
            if self.data.full_graphics:
                self.widgets.notebook_mode.hide()
            else:
                self.widgets.notebook_mode.show()
            self.widgets.hal_mdihistory.hide()
            self.widgets.button_jog_mode.set_active(0)

    def on_button_flood(self,widget):
        if self.widgets.button_flood.get_active():
                self.gscreen.halcomp["aux-coolant-m8-out"] = True
        else:
                self.gscreen.halcomp["aux-coolant-m8-out"] = False

    def on_ign_toolc_pressed(self, widget):
        data = widget.get_active()

    def on_tool_change(self,widget):
        if self.widgets.ignore_toolchange.get_active() == True:
            self.gscreen.halcomp["tool-changed"] = True
        else:
            h = self.gscreen.halcomp
            c = h['change-tool']
            n = h['tool-number']
            cd = h['tool-changed']
            print("tool change",c,cd,n)
            if c:
                message =  _("Please change to tool # %s, then click OK."% n)
                self.gscreen.warning_dialog(message, True,pinname="TOOLCHANGE")
            else:
                h['tool-changed'] = False

    def on_button_edit_clicked(self,widget):
        state = widget.get_active()
        if not state:
            self.gscreen.edited_gcode_check()
        self.widgets.notebook_main.set_current_page(0)
        self.widgets.notebook_main.set_show_tabs(not (state))
        self.edit_mode(state)
        if state:
            self.widgets.search_box.show()
        else:
            self.widgets.search_box.hide()

    def edit_mode(self,data):
        print("edit mode pressed",data)
        self.gscreen.sensitize_widgets(self.data.sensitive_edit_mode,not data)
        if data:
            self.widgets.mode6.show()
            self.widgets.dro_frame.hide()
            self.widgets.gcode_view.set_sensitive(1)
            self.data.edit_mode = True
            self.widgets.show_box.hide()
            self.widgets.notebook_mode.show()
            self.widgets.display_btns.hide()
        else:
            self.widgets.mode6.hide()
            self.widgets.dro_frame.show()
            self.widgets.gcode_view.set_sensitive(0)
            self.data.edit_mode = False
            self.widgets.show_box.show()
            self.widgets.display_btns.show()

    def on_button_full_view_clicked(self,widget):
        self.set_full_graphics_view(widget.get_active())

    def on_manual_spindle(self,widget):
        if self.data.mode_order[0] == self.data._AUTO:
            return
        if self.widgets.button_man_spindle.get_active():
            self.widgets.button_man_spindle.set_label("Stop")
            self.emc.spindle_forward(1,self.data.spindle_start_rpm)
        else:
            print("Spindle stop")
            self.widgets.button_man_spindle.set_label("Start")
            self.emc.spindle_off(1)

    def on_spindle_plus(self,widget):
        if self.data.mode_order[0] != self.data._AUTO:
            self.emc.spindle_faster(1)

    def on_spindle_minus(self,widget):
        if self.data.mode_order[0] != self.data._AUTO:
            self.emc.spindle_slower(1)

    def on_view_change(self,widget):
        mode = self.data.mode_order[0]
        if mode == self.data._AUTO:
            self.data.view = self.data.view+1
            if self.data.view > 3:
                self.data.view = 0
            view = self.data.view
        else:
            view = 0
        print("view", view)
        if view == 0:
            # Gremlin + Gcode + DRO
            self.data.full_graphics = False
            self.widgets.show_box.show()
            if mode == self.data._AUTO:
                self.widgets.notebook_mode.show()
            self.widgets.dro_frame.show()
            self.widgets.display_btns.show()
            self.widgets.gremlin.set_property('enable_dro',False)
        elif view == 1:
            # Gremlin style DRO
            self.data.full_graphics = True
            self.widgets.show_box.show()
            self.widgets.notebook_mode.hide()
            self.widgets.dro_frame.hide()
            self.widgets.gremlin.set_property('enable_dro',True)
        elif view == 2:
            # Gremlin + DRO
            self.data.full_graphics = True
            self.widgets.dro_frame.show()
            self.widgets.notebook_mode.hide()
            self.widgets.show_box.show()
            self.widgets.gremlin.set_property('enable_dro',False)
        elif view == 3:
            # DRO + Gcode
            self.data.full_graphics = False
            self.widgets.dro_frame.show()
            if mode == self.data._AUTO:
                self.widgets.notebook_mode.show()
                self.widgets.gcode_view.set_sensitive(0)
            self.widgets.show_box.hide()
            self.widgets.display_btns.hide()
            self.widgets.gremlin.set_property('enable_dro',False)

    def update_override_label(self):
        self.widgets.fo.set_text("FO:  %3d%%"%(round(self.data.feed_override,2)*100))
        self.widgets.mv.set_text("RO:  %3d%%"%(round(self.data.rapid_override,2)*100))
        self.widgets.so.set_text("SO:  %3d%%"%(round(self.data.spindle_override,2)*100))

# Gremlin display buttons
    def on_d_zoomp_pressed(self,widget):
        self.widgets.gremlin.zoom_in()
    def on_d_zoomm_pressed(self,widget):
        self.widgets.gremlin.zoom_out()
    def on_d_up_pressed(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_d_down_pressed(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_d_right_pressed(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_d_left_pressed(self,widget):
        self.data.graphic_xpos = self.data.graphic_xpos-8
        self.widgets.gremlin.pan(self.data.graphic_xpos,self.data.graphic_ypos)

# Connect to gscreens regular signals and add a couple more
    def connect_signals(self,handlers):
        self.gscreen.connect_signals(handlers)
        # connect to handler file callbacks:
        self.gscreen.widgets.d_zoomp.connect("clicked", self.on_d_zoomp_pressed)
        self.gscreen.widgets.d_zoomm.connect("clicked", self.on_d_zoomm_pressed)
        self.gscreen.widgets.d_up.connect("clicked", self.on_d_up_pressed)
        self.gscreen.widgets.d_down.connect("clicked", self.on_d_down_pressed)
        self.gscreen.widgets.d_left.connect("clicked", self.on_d_left_pressed)
        self.gscreen.widgets.d_right.connect("clicked", self.on_d_right_pressed)
        self.gscreen.widgets.button_man_spindle.connect("clicked", self.on_manual_spindle)
        self.gscreen.widgets.button_spindle_plus.connect("clicked", self.on_spindle_plus)
        self.gscreen.widgets.button_spindle_minus.connect("clicked", self.on_spindle_minus)
        self.gscreen.widgets.button_view.connect("clicked", self.on_view_change)
        self.gscreen.widgets.button_mode.connect("button_press_event", self.on_mode_clicked)
        self.gscreen.widgets.button_edit.connect("clicked", self.on_button_edit_clicked)
        self.gscreen.widgets.button_flood.connect("clicked", self.on_button_flood)
        self.gscreen.widgets.ignore_toolchange.connect("clicked", self.on_ign_toolc_pressed)
        self.gscreen.widgets.jog_r1.connect("pressed", self.on_jog_rate)
        self.gscreen.widgets.jog_r2.connect("pressed", self.on_jog_rate)
        self.gscreen.widgets.jog_r3.connect("pressed", self.on_jog_rate)
        self.gscreen.widgets.jog_r4.connect("pressed", self.on_jog_rate)
        self.gscreen.widgets.jog_plus.connect("clicked", self.jog_point1)
        self.gscreen.widgets.jog_minus.connect("clicked", self.jog_point1)
        self.gscreen.widgets.button_homing.connect("clicked", self.homing)
        self.widgets.hal_status.connect("all-homed",self.on_hal_status_all_homed)
        self.widgets.hal_status.connect("state-off",self.on_emc_off)
        self.gscreen.widgets.button_clear.connect("clicked", self.on_btn_clear)
        self.widgets.hal_status.connect("interp-idle",self.on_interp_idle)
        self.widgets.hal_status.connect("interp-run",self.on_interp_run)

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