#!/usr/bin/env python

import sys, os
BASE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
libdir = os.path.join(BASE, "lib", "python")
datadir = os.path.join(BASE, "share", "linuxcnc")
sys.path.insert(0, libdir)
xmlname = os.path.join(datadir,"grotius.glade")

# import libraries
import pygtk
pygtk.require("2.0")
import gtk
import linuxcnc, hal
import gremlin
import gladevcp.makepins
import gobject
##
#rt hal THC
import hal, time

# path to TCL for external programs only needed for halshow button
TCLPATH = os.environ['LINUXCNC_TCL_DIR']

# main class
class grotius_gui(object):

  def __init__(self, inifile):


    self.builder = gtk.Builder()
    self.builder.add_from_file(xmlname)
    self.builder.connect_signals(self)
    self.version = os.environ['LINUXCNCVERSION']
    self.ini_file_path = os.environ['INI_FILE_NAME']
    self.ini_file_object = linuxcnc.ini(self.ini_file_path)
    self.machine_name = self.ini_file_object.find('EMC', 'MACHINE')
    self.cnc = linuxcnc
    self.command = linuxcnc.command()
    self.status = linuxcnc.stat()
    self.error = linuxcnc.error_channel()
    self.halcomp = hal.component("grotius_gui")
    self.panel = gladevcp.makepins.GladePanel(self.halcomp, xmlname, self.builder, None)
    self.halcomp.ready()
    global statusbar
    statusbar = self.builder.get_object('statusbar')
    global context_id
    context_id = statusbar.get_context_id("status")
    self.filechooser = self.builder.get_object('filechooser')
    self.filefilter = gtk.FileFilter()
    self.filefilter.set_name('Machinable Files')
    self.filefilter.add_pattern('*.ngc')
    self.filefilter.add_pattern('*.NGC')
    self.filechooser.add_filter(self.filefilter)
    self.filefilter = gtk.FileFilter()
    self.filefilter.set_name("All files")
    self.filefilter.add_pattern("*")
    self.filechooser.add_filter(self.filefilter)
    self.filechooser.set_current_folder('/home/grotius/linuxcnc/nc_files')

    self.gremlin = grotius_gremlin(self.ini_file_object)

    self.use_commanded = self.builder.get_object('cb_use_commanded')
    if self.gremlin.use_commanded: self.use_commanded.set_active(True)
    self.show_limits = self.builder.get_object('cb_show_limits')
    if self.gremlin.show_limits: self.show_limits.set_active(True)
    self.show_extents = self.builder.get_object('cb_show_extents')
    if self.gremlin.show_extents: self.show_extents.set_active(True)
    self.show_live_plot = self.builder.get_object('cb_show_live_plot')
    if self.gremlin.show_live_plot: self.show_live_plot.set_active(True)
    self.metric_units = self.builder.get_object('cb_metric_units')
    if self.gremlin.metric_units: self.metric_units.set_active(True)
    self.show_program = self.builder.get_object('cb_show_program')
    if self.gremlin.show_program: self.show_program.set_active(True)
    self.show_rapids = self.builder.get_object('cb_show_rapids')
    if self.gremlin.show_rapids: self.show_rapids.set_active(True)
    self.use_relative = self.builder.get_object('cb_use_relative')
    if self.gremlin.use_relative: self.use_relative.set_active(True)
    self.show_tool = self.builder.get_object('cb_show_tool')
    if self.gremlin.show_tool: self.show_tool.set_active(True)
    self.show_dtg = self.builder.get_object('cb_show_dtg')
    if self.gremlin.show_dtg: self.show_dtg.set_active(True)

    self.gremlin.current_view = 'p'
    self.plot = self.builder.get_object('vbox10')
    self.plot.pack_start(self.gremlin)
    self.plot.reorder_child(self.gremlin, 1)

    self.task_mode = {
      0 : 'Unknown Mode',
      1 : 'Manual Mode',
      2 : 'Auto Mode',
      3 : 'MDI Mode',
      }

    self.mode_label = self.builder.get_object('mode_label')
    gobject.timeout_add(100, self.periodic)
    self.window = self.builder.get_object('main_window')
    self.window.set_title(self.machine_name + ' Version ' + self.version)
    self.window.show_all()


#THC active/deactive
    self.h = hal.component("thc")
    self.h.newpin("enable", hal.HAL_BIT, hal.HAL_IN) 
    self.h.newparam("velocity", hal.HAL_FLOAT, hal.HAL_RO) 

  def on_thc_on_pressed(self, widget, data=None):
    self.h['enable'] = 1  #led in linux halmeter on
  def on_thc_off_pressed(self, widget, data=None):
    self.h['enable'] = 0  #led in linux halmeter off


#Text entry test glade
  def on_button_pressed(self, button, data=None):
    self.entry1 = self.builder.get_object("entry1")
    self.entry2 = self.builder.get_object("entry2")
    self.result1 = self.builder.get_object("result1")
    self.x = float(self.entry1.get_text())
    self.y = float(self.entry2.get_text())
    self.z = str(int(self.x + self.y))
    print "optelsom"
    self.result1.set_text(self.z)

    self.h['velocity'] = float(int(self.x + self.y))


#Toorts on/off
  def on_torch_on_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MDI)
    self.command.mdi("M3 S1")
    
  def on_torch_off_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MDI)
    self.command.mdi("M5 S1") 

#sample
  #def on_hal_button1_pressed(self, widget, data=None): 
    #self.update_statusbar("oke dit werkt, trigger nu een input pin")
    #print("Hi")

    #self.floatvalue = self.builder.get_object("floatvalue")
    #self.sfm = float(self.floatvalue.get_text()) 
    #self.rpm = str(int(self.sfm + 10)) 
    #self.floatvalue.set_text(self.rpm)


#display view 
  def on_view_3d_pressed(self, widget, data=None):
    self.gremlin.current_view = 'p'
    self.gremlin.set_current_view()

  def on_view_top_pressed(self, widget, data=None):
    self.gremlin.current_view = 'z'
    self.gremlin.set_current_view()

  def on_view_side_pressed(self, widget, data=None):
    self.gremlin.current_view = 'x'
    self.gremlin.set_current_view()

  def on_clear_live_plot_clicked(self, widget, data=None):
    self.gremlin.clear_live_plotter()
  def on_clear_status_bar_clicked(self, widget, data=None):
    statusbar.pop(context_id)

  def on_zoom_in_clicked(self, widget, data=None):
    self.gremlin.zoomin()
  def on_zoom_out_clicked(self, widget, data=None):
    self.gremlin.zoomout()

#programma start - stop - pauze - resume
  def on_btn_program_clicked(self, widget, data=None):
    self.name = gtk.Buildable.get_name(widget)
    if self.name == 'btn_start':
      self.command.mode(self.cnc.MODE_AUTO)
      self.command.wait_complete()
      self.command.auto(self.cnc.AUTO_RUN,1)
      self.update_mode_status()
    elif self.name == 'btn_stop':self.command.abort()
    elif self.name == 'btn_pause': self.command.auto(self.cnc.AUTO_PAUSE)
    elif self.name == 'btn_resume': self.command.auto(self.cnc.AUTO_RESUME)

#emergency stop and machine on
  def on_emergency_stop_pressed(self, widget, data=None):  
    self.command.state(self.cnc.STATE_ESTOP) 
    
  def on_machine_on_pressed(self, widget, data=None):  
    self.command.state(self.cnc.STATE_ESTOP_RESET) 
    self.command.state(self.cnc.STATE_ON) 

#halmeter
  def on_halmeter_pressed(self, widget, data=None):
    p = os.popen( "halmeter &" )

#classicladder
  def on_classicladder_pressed(self, widget, data=None):
    p = os.popen( "classicladder  &", "w" )

#halshow
  def on_halshow_pressed(self, widget, data=None):
    p = os.popen( "tclsh %s/bin/halshow.tcl &" % TCLPATH )

#program speed
  def on_change_program_speed_pressed(self, widget, data=None):
    self.command.maxvel(self.builder.get_object("program_speed").get_value()/60)

#x-axis buttons
  def on_program_x_zero_pressed(self, widget, data=None):
     self.command.mode(self.cnc.MODE_MDI)
     self.command.mdi("G10 L20 P1 X0")

  def on_jog_x_plus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 0, self.builder.get_object("jog_speed").get_value()/60)

  def on_jog_x_plus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 0)

  def on_jog_x_minus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 0, self.builder.get_object("jog_speed").get_value()/-60)

  def on_jog_x_minus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 0)

#y-axis buttons
  def on_program_y_zero_pressed(self, widget, data=None):
     self.command.mode(self.cnc.MODE_MDI)
     self.command.mdi("G10 L20 P1 Y0")

  def on_jog_y_plus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 1, self.builder.get_object("jog_speed").get_value()/60)

  def on_jog_y_plus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 1)

  def on_jog_y_minus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 1, self.builder.get_object("jog_speed").get_value()/-60)

  def on_jog_y_minus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 1)

#z-axis buttons
  def on_program_z_zero_pressed(self, widget, data=None):
     self.command.mode(self.cnc.MODE_MDI)
     self.command.mdi("G10 L20 P1 Z0")

  def on_jog_z_plus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 2, self.builder.get_object("jog_speed").get_value()/60)

  def on_jog_z_plus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 2)

  def on_jog_z_minus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 2, self.builder.get_object("jog_speed").get_value()/-60)

  def on_jog_z_minus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 2)

#a-axis buttons
  def on_program_a_zero_pressed(self, widget, data=None):
     self.command.mode(self.cnc.MODE_MDI)
     self.command.mdi("G10 L20 P1 A0")

  def on_jog_a_plus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 3, self.builder.get_object("jog_speed").get_value()/60)

  def on_jog_a_plus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 3)

  def on_jog_a_minus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 3, self.builder.get_object("jog_speed").get_value()/-60)

  def on_jog_a_minus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 3)

#b-axis buttons
  def on_program_b_zero_pressed(self, widget, data=None):
     self.command.mode(self.cnc.MODE_MDI)
     self.command.mdi("G10 L20 P1 B0")

  def on_jog_b_plus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 4, self.builder.get_object("jog_speed").get_value()/60)

  def on_jog_b_plus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 4)

  def on_jog_b_minus_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.jog(self.cnc.JOG_CONTINUOUS, 4, self.builder.get_object("jog_speed").get_value()/-60)

  def on_jog_b_minus_released(self, widget, data=None):
    self.command.jog(self.cnc.JOG_STOP, 4)

#machine home all
  def on_machine_zero_all_pressed(self, widget, data=None): 
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.home(0)
    self.command.home(1)
    self.command.home(2)
    self.command.home(3)
    self.command.home(4)

#program offset
  def on_program_zero_all_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MDI)
    self.command.mdi("G10 L20 P1 X0")
    self.command.mdi("G10 L20 P1 Y0")
    self.command.mdi("G10 L20 P1 Z0")
    self.command.mdi("G10 L20 P1 A0")
    self.command.mdi("G10 L20 P1 B0")

#machine home XYZAB axis
  def on_machine_x_zero_pressed(self, widget, data=None): 
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.home(0)
  def on_machine_y_zero_pressed(self, widget, data=None): 
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.home(1)
  def on_machine_z_zero_pressed(self, widget, data=None): 
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.home(2)
  def on_machine_a_zero_pressed(self, widget, data=None): 
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.home(3)
  def on_machine_b_zero_pressed(self, widget, data=None): 
    self.command.mode(self.cnc.MODE_MANUAL)
    self.command.home(4)

#machine move to home position
  def on_goto_zero_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_MDI)
    self.command.mdi("G1 X0 Y0 Z0 A0 B0 F2000")

#file load
  def on_load_gcode_pressed(self, widget, data=None):
    self.command.mode(self.cnc.MODE_AUTO)
    response = self.filechooser.run()
    if response == gtk.RESPONSE_OK:
      self.file = self.filechooser.get_filename()
      self.command.reset_interpreter()
      self.command.program_open(self.file)
      self.command.wait_complete()
      self.gremlin.load(self.file)
    elif response == gtk.RESPONSE_CANCEL:
      print 'Closed, no files selected'
    self.filechooser.hide()

#menu functions
  def on_menu_file_open_activate(self, widget, data=None):
    self.command.mode(self.cnc.MODE_AUTO)
    response = self.filechooser.run()
    if response == gtk.RESPONSE_OK:
      self.file = self.filechooser.get_filename()
      self.command.reset_interpreter()
      self.command.program_open(self.file)
      self.command.wait_complete()
      self.gremlin.load(self.file)
    elif response == gtk.RESPONSE_CANCEL:
      print 'Closed, no files selected'
    self.filechooser.hide()

  def on_menu_view_activate(self, widget, data=None):
    self.name = gtk.Buildable.get_name(widget)
    if self.name == 'menu_view_p': self.gremlin.current_view = 'p'
    elif self.name == 'menu_view_x': self.gremlin.current_view = 'x'
    elif self.name == 'menu_view_y': self.gremlin.current_view = 'y'
    elif self.name == 'menu_view_z': self.gremlin.current_view = 'z'
    self.gremlin.set_current_view()

  def on_menu_file_quit_activate(self, widget, data=None):
    print 'file quit'
    gtk.main_quit()

#checkboxes
  def on_cb_toggled(self, widget, data=None):
    self.name = gtk.Buildable.get_name(widget)
    if self.name == 'cb_program_alpha': pass
    elif self.name == 'cb_use_commanded':
      if widget.get_active():self.gremlin.use_commanded = True
      else:self.gremlin.use_commanded = False
    elif self.name == 'cb_show_limits':
      if widget.get_active():self.gremlin.show_limits = True
      else:self.gremlin.show_limits = False
    elif self.name == 'cb_show_extents':
      if widget.get_active():self.gremlin.show_extents_option = True
      else:self.gremlin.show_extents_option = False
    elif self.name == 'cb_show_live_plot':
      if widget.get_active():self.gremlin.show_live_plot = True
      else:self.gremlin.show_live_plot = False
    elif self.name == 'cb_metric_units':
      if widget.get_active():self.gremlin.metric_units = True
      else:self.gremlin.metric_units = False
    elif self.name == 'cb_show_program':
      if widget.get_active():self.gremlin.show_program = True
      else:self.gremlin.show_program = False
    elif self.name == 'cb_show_rapids':
      if widget.get_active():self.gremlin.show_rapids = True
      else:self.gremlin.show_rapids = False
    elif self.name == 'cb_use_relative':
      if widget.get_active():self.gremlin.use_relative = True
      else:self.gremlin.use_relative = False
    elif self.name == 'cb_show_tool':
      if widget.get_active():self.gremlin.show_tool = True
      else:self.gremlin.show_tool = False
    elif self.name == 'cb_show_dtg':
      if widget.get_active():self.gremlin.show_dtg = True
      else:self.gremlin.show_dtg = False
    self.gremlin._redraw()

#statusbar
  @staticmethod
  def update_statusbar(message):
      statusbar.push(context_id, message)

  def update_mode_status(self):
    self.status.poll()
    self.mode_label.set_text(str(self.task_mode[self.status.task_mode]))

  def periodic(self): # fetch status items and update screen
    # poll the error channel
    self.error_status = self.error.poll()
    if self.error_status:
      self.error_kind, self.error_text = self.error_status
      if self.error_kind in (linuxcnc.NML_ERROR, linuxcnc.OPERATOR_ERROR):
        self.error_type = "Error: "
      else:
        self.error_type = "Info: "
      self.message_id = self.update_statusbar(self.error_type + self.error_text)

    # poll the status channel
    self.status.poll()
    dict = {0:'None', 1:'MDI',2:'Auto', 3:'Manual'}
    data = self.status.task_mode
    text = dict[data]
    self.builder.get_object("mode_label").set_text(text)

    #update machine dro's
    data = self.status.actual_position[0]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_x").set_text(text)

    data = self.status.actual_position[1]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_y").set_text(text)

    data = self.status.actual_position[2]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_z").set_text(text)

    data = self.status.actual_position[3]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_a").set_text(text)

    data = self.status.actual_position[4]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_b").set_text(text)
    return True

##test met led input en z toets drukken -- hal_led2 = down -- hal_led4 = up --

  #def on_hal_led2_hal_pin_changed(self,hal_led,data=None):
    #self.command.mode(linuxcnc.MODE_MANUAL)
    #self.command.jog(linuxcnc.JOG_CONTINUOUS, 2, self.builder.get_object("jog_speed").get_value()/-60)
  #def hal_led2_hal_pin_changed_cb(self,hal_led,data=None):
    #self.command.jog(linuxcnc.JOG_STOP, 2)

  def on_main_window_destroy(self, widget, data=None):
    print 'quit with cancel'
    gtk.main_quit()

  def postgui(self):
    inifile = linuxcnc.ini(self.ini_file_path)
    postgui_halfile = inifile.find("HAL", "POSTGUI_HALFILE")
    return postgui_halfile,sys.argv[2]

class grotius_gremlin(gremlin.Gremlin):
  def __init__(self, inifile):
    gremlin.Gremlin.__init__(self, inifile)

  def report_gcode_error(self, result, seq, filename):
    import gcode
    error_str = gcode.strerror(result)
    error = 'G-Code error in ' + os.path.basename(filename) + ' Near line ' + str(seq) + ' of ' + filename + ' ' + error_str
    grotius_gui.update_statusbar(error)

# run the program
if __name__ == "__main__":
  if len(sys.argv) > 2 and sys.argv[1] == '-ini':
    hwg = grotius_gui(sys.argv[2])
  else:
    hwg = grotius_gui()

  # load a postgui file if one is present in the INI file
  postgui_halfile,inifile = grotius_gui.postgui(hwg)

  if postgui_halfile:
    res = os.spawnvp(os.P_WAIT, "halcmd", ["halcmd", "-i",inifile,"-f", postgui_halfile])
    if res: raise SystemExit, res

  gtk.main()
