#!/usr/bin/env python
"""
JX Session Manager:

jxsessionmgr.py

GUI interface to add and remove JX icons on the desktop.  You can add icons for
JX Catalog or for JX Administration.  If you create more than one JX catalog
icon you can run multiple JX Catalog sessions at the same time.
"""

import os
import sys
try:
    import gtk
except RuntimeError:
    raise SystemExit("Runtime Error: Unable to initialize graphical environment.")
from glob import glob
from gobject import GError
from gladelib import SigController, GUI
from jxicon import icon_factory, add_option_handling, JXIconError, DEFAULT_POSREQUESTPORT



# some constants
if sys.platform == "win32":
    import winlib
    # Turn on button icons!
    gtk.settings_get_default().set_long_property("gtk-button-images", True, "main")
    AMADOR_PATH = os.path.join(os.environ['PROGRAMFILES'], "Amador")
    BIN_PATH = os.path.join(AMADOR_PATH, "bin")
    PYTHON_PATH = winlib.get_pythonpath() + "pythonw.exe"
else:
    AMADOR_PATH = "/usr/share/amador"
    BIN_PATH = "/usr/local/bin"
    PYTHON_PATH = "/usr/bin/python"
GLADE_FILE = os.path.join(AMADOR_PATH, "glade", "jxsessionmgr.glade")
FRONTENDSTARTER = "FrontEndStarter"
BACKENDSTARTER = "BackEndStarter"
JXSESSION_MGR = "jxsessionmgr.py"
JXCONFIG = "jxconfig.py"
JXSESSION_MGR_CMD = os.path.join(BIN_PATH, JXSESSION_MGR)
JXCONFIG_CMD = os.path.join(BIN_PATH, JXCONFIG)
TYPE_CATALOG = "Catalog"
TYPE_ADMIN = "Admin"
TYPE_MGR = "Manager"
TYPE_CFG = "Config"
NOT_APP = "N/A"
HELP_MSG = """Use 'JX Session Manager' to create icons on your desktop
to access different features of the JX Catalog.  There are 4
types of icons that can be added to your desktop:

    1) JX Catalog
    2) JX Administration
    3) JX Configuration
    4) JX Session Management

The first type, "JX Catalog", creates an icon that allows you to
start the JX catalog running in the background.  You can create
more that one "JX Catalog" icon which allows you to run multiple
JX catalog sessions at the same time.  This means you can enter
the catalog from one Point of Sale (POS) screen and then switch
to another POS screen and enter the JX Catalog again.  Since you
can jump back and forth between different JX Catalog screens, when
you eventually exit to POS from JX, Windows (or Linux) may not
always display the AutoPoint POS screen you expect.  In this case
you can find the correct POS screen in the task bar or use ALT-TAB
to switch between the different windows.

The second type, "JX Administration", creates an icon that allows
access to do JX administration tasks such as which line codes to
show and their priorities, etc.

The third type, "JX Configuration", creates an icon to display or
change the JX configuration.  NOTE: this is rarely needed by the
end-user since this information is entered when the catalog is
installed and rarely ever changes.

The fourth type, "JX Session Mgmnt", refers to this program.  If
you delete this icon, you can manually restart this program and
recreate the icon for the JX Session Manager.

Click on the 'Add' button to add a new icon or 'Remove' button to
remove an icon from the desktop.
"""



def run_dialog(msg, label, dialog, markup=False):
    if markup:
        label.set_label(str(msg))
    else:
        label.set_text(str(msg))
    resp = dialog.run()
    dialog.hide()
    return resp





class TreeViews:
    """
    Object for creating and manipulating treeviews for JX Session Manager
    """
    def __init__(self, gui):
        self.gui = gui
        self.session_list = self.create_session_view()

    def create_session_view(self):
        session_list = gtk.ListStore(gtk.gdk.Pixbuf, str, str, str)
        treeview = self.gui.session_treeview
        treeview.set_model(session_list)
        column = gtk.TreeViewColumn("Icon", gtk.CellRendererPixbuf(), pixbuf=0 )
        treeview.append_column(column)
        column = gtk.TreeViewColumn("Name", gtk.CellRendererText(), text=1)
        treeview.append_column(column)
        column = gtk.TreeViewColumn("type", gtk.CellRendererText(), text=2)
        treeview.append_column(column)
        column = gtk.TreeViewColumn("port", gtk.CellRendererText(), text=3)
        treeview.append_column(column)
        treeview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
        return session_list

    def poplulate_sessions(self, jxicon):
        try:
            model = self.session_list
            image = jxicon.fe_icon_image
            cat_pixbuf = gtk.gdk.pixbuf_new_from_file(image)
            image = jxicon.be_icon_image
            admin_pixbuf = gtk.gdk.pixbuf_new_from_file(image)
        except GError, err:
            run_dialog(str(err), self.gui.error_msg, self.gui.error_dialog)
            return

        for icon in jxicon.JXicons():
            target = jxicon.get_target(icon)
            #print "icon target is", target
            # defualt to admin icon
            image = admin_pixbuf
            if target.find(FRONTENDSTARTER) >= 0:
                icon_type = TYPE_CATALOG
                image = cat_pixbuf
            elif target.find(BACKENDSTARTER) >= 0:
                icon_type = TYPE_ADMIN
                # don't allow adding another admin icon!
                self.gui.jxadmin_radiobutton.set_sensitive(False)
            elif target.find(JXCONFIG) >= 0:
                icon_type = TYPE_CFG
                # don't allow adding another config icon!
                self.gui.jxcfg_radiobutton.set_sensitive(False)
            elif target.find(JXSESSION_MGR) >= 0:
                icon_type = TYPE_MGR
                # don't allow adding another mgr icon!
                self.gui.jxmgr_radiobutton.set_sensitive(False)
            else:
                # have to use something!
                icon_type = TYPE_ADMIN

            # just want the base JX icon name without PATH or extension
            short_name = os.path.splitext( os.path.split(icon)[-1] )[0]  
            if icon_type == TYPE_CATALOG:          
                fields = target.split()
                try:
                    i = fields.index("-R")
                    port = int(fields[i+1])
                except ValueError:
                    port = jxicon.base_port
            else:
                port = NOT_APP
            model.append([image, short_name, icon_type, port])

    def add_session(self, icon, name, name_type, port=None):
        model = self.session_list
        icon = gtk.gdk.pixbuf_new_from_file(icon)
        if port is None:
            port = NOT_APP
        #print "add_session() and args are:", icon, name, name_type, port
        model.append([icon, name, name_type, port])





class Main_Callbacks( SigController ):
    """
    Call backs for the main window
    """

    def __init__(self, gui, jxicon):
        # attach glade callback signals
        SigController.__init__(self, gui)
        self.gui = gui
        self.jxicon = jxicon
        self.gui.remove_button.set_sensitive(False)
        main = self.gui.main
        self.gui.confirm_dialog.set_transient_for(main)
        self.gui.help_window.set_transient_for(main)
        self.gui.addwindow.set_transient_for(main)
        self.gui.error_dialog.set_transient_for(main)
        self.gui.help_label.set_text(HELP_MSG)

    ########### actual callbacks beyond this point #######
    def on_quit_button_clicked(self, widget):
        gtk.main_quit()

    def on_main_delete_event(self, widget, event):
        gtk.main_quit()

    def on_help_button_clicked(self, widget):
        self.gui.help_window.show_all()

    def on_add_button_clicked(self, widget):
        self.gui.addwindow.show_all()

    def on_remove_button_clicked(self, widget):
        store, iter = self.gui.session_treeview.get_selection().get_selected()
        if not iter:
            return
        name, icon_type = store.get(iter, 1, 2)
        resp = run_dialog("<big>Remove '%s' JX Icon: '%s'?</big>" % (icon_type, name),
                          self.gui.remove_label, self.gui.confirm_dialog, True)
        if resp == gtk.RESPONSE_OK:
            try:
                self.jxicon.delete(name)
                store.remove(iter)
                if icon_type == TYPE_CFG:
                    self.gui.jxcfg_radiobutton.set_sensitive(True)
                elif icon_type == TYPE_ADMIN:
                    self.gui.jxadmin_radiobutton.set_sensitive(True)
                elif icon_type == TYPE_MGR:
                    self.gui.jxmgr_radiobutton.set_sensitive(True)
            except JXIconError, err:
                run_dialog(err, self.gui.error_msg, self.gui.error_dialog)

    def on_close_button_clicked(self, widget):
        # this is for the close button in the help window
        self.gui.help_window.hide()
        return True

    def on_help_window_delete_event(self, widget, event):
        widget.hide()
        return True

    def on_session_treeview_cursor_changed(self, widget):
        self.gui.remove_button.set_sensitive(True)






class AddWindow_Callbacks( SigController ):
    """
    Call backs for the window to add a new icon to the desktop
    """
    def __init__(self, gui, jxicon):
        # attach glade callback signals
        SigController.__init__(self, gui)
        self.gui = gui
        self.jxicon = jxicon
        # do this here instead of in Main Callbacks because this object needs it below
        self.treeview = TreeViews(gui)
        self.treeview.poplulate_sessions(jxicon)

    def create_jxcat_icon(self):
        name = self.jxicon.next_icon_name()
        if name.startswith("JX."):
            args = None
            port = DEFAULT_POSREQUESTPORT
        else:
            port = self.jxicon.get_port()
            args = "-R %d" % port
        self.jxicon.create(name, self.jxicon.fecmd, args)
        image = self.jxicon.fe_icon_image
        self.treeview.add_session(image, os.path.splitext(name)[0], TYPE_CATALOG, port)

    def create_jxadmin_icon(self):
        name = "JX Admin"
        self.jxicon.create(name, self.jxicon.becmd)
        image = self.jxicon.be_icon_image
        self.treeview.add_session(image, name, TYPE_ADMIN)
        self.gui.jxadmin_radiobutton.set_sensitive(False)
        self.gui.jxadmin_radiobutton.set_active(False)

    def create_jxmgr_icon(self):
        name = "JX Session Mgr"
        self.jxicon.create(name, PYTHON_PATH, JXSESSION_MGR_CMD)
        image = self.jxicon.be_icon_image
        self.treeview.add_session(image, name, TYPE_MGR)
        self.gui.jxmgr_radiobutton.set_sensitive(False)
        self.gui.jxmgr_radiobutton.set_active(False)

    def create_jxcfg_icon(self):
        name = "JXconfig"
        self.jxicon.create(name, PYTHON_PATH, JXCONFIG_CMD)
        image = self.jxicon.be_icon_image
        self.treeview.add_session(image, name, TYPE_CFG)
        self.gui.jxcfg_radiobutton.set_sensitive(False)
        self.gui.jxcfg_radiobutton.set_active(False)

    ##### actual callback beyound this point ############

    def on_addwindow_delete_event(self, widget, event):
        widget.hide()
        return True

    def on_cancel_button_clicked(self, widget):
        self.gui.addwindow.hide()

    def on_ok_button_clicked(self, widget):
        try:
            sess_type = self.get_radiobutton_setting()
            if sess_type == TYPE_CATALOG:
                self.create_jxcat_icon()
            elif sess_type == TYPE_ADMIN:
                self.create_jxadmin_icon()
            elif sess_type == TYPE_MGR:
                self.create_jxmgr_icon()
            elif sess_type == TYPE_CFG:
                self.create_jxcfg_icon()
            else:
                raise JXIconError("Unknown icon type")
        except JXIconError, err:
            run_dialog(err, self.gui.error_msg, self.gui.error_dialog)
        else:
            self.gui.addwindow.hide()

    def get_radiobutton_setting(self):
        if self.gui.jxcat_radiobutton.get_active():
            return TYPE_CATALOG
        elif self.gui.jxadmin_radiobutton.get_active():
            return TYPE_ADMIN
        elif self.gui.jxmgr_radiobutton.get_active():
            return TYPE_MGR
        elif self.gui.jxcfg_radiobutton.get_active():
            return TYPE_CFG
        else:
            # This shouldn't happen
            return None

    def on_addwindow_show(self, widget):
        # always show default radio button as 'JX Catalog Session'
        self.gui.jxcat_radiobutton.set_active(True)






if __name__ == "__main__":
    jxicon = icon_factory()
    # initialize GUI side and handle call backs
    gui = GUI(GLADE_FILE, "main")
    Main_Callbacks(gui, jxicon)
    try:
        add_option_handling(jxicon)
    except (OSError, IOError):
        run_dialog("JX does not appear to be installed on this system.",
                   gui.error_msg, gui.error_dialog)
        raise SystemExit
    AddWindow_Callbacks(gui, jxicon)
    gtk.main()
