#!/usr/bin/env python
"""
fedecatUI.py

This provides the Graphical User Interface (GUI) for the Federated catalog.  It runs in
the System tray (Notification Area) and includes an XMLRPC Server that listens for
commands to popup on the screen.  This software runs on both Windows and Linux systems.

Normally it takes NO arguments.  You can run it directly (in debug mode) with the command:

fedecatUI -d

"""

try:
    import gtk
except RuntimeError:
    print "Runtime Error: Unable to initialize graphical environment."
    raise SystemExit
import sys
import os
from socket import error
from SimpleXMLRPCServer import SimpleXMLRPCServer
import gobject
from gladelib import GUI
from fxlib import WINDOWS, FED_LOGO, GLADE_FILE, TITLE_BAR, REVISION, CLIENT_PORT, \
                     GROUPS_SUBGROUPS_CACHE, AMADOR_PATH, ICONS, FEDECAT_PATH
from fxlib.callbacks import Main_Callbacks, Selected_Callbacks
from fxlib.catalog import FXCatalog, FXCatalogError, ProgressWindow
from fxlib.status import run_dialog
from fxlib.ipaddress import my_ipaddress, serverbyclientip
if WINDOWS:
    import wmi



# some constants
BG_COLOR = "#CCCCBB"
SELECTED_BG_COLOR = "#EEEEEE"
FRAME_BG_COLOR = "#999999"
FEDECAT_ICON = os.path.join(AMADOR_PATH, ICONS, "fedicon.png")





class RPCFunctions:

    def __init__(self, gui, fxcat):
        self.gui = gui
        self.fxcat = fxcat

    def _listMethods(self):
        return ['show_window']

    def show_window(self, termno, custno, session_id, custname):
        # set terminal number needed for any orders
        self.fxcat.termno = termno
        self.fxcat.custno = custno
        self.fxcat.session_id = session_id
        self.gui.mainwindow.show_all()
        # this doesn't work right!
        ##self.gui.mainwindow.present()
        # this forces window to the TOP
        self.gui.mainwindow.set_keep_above(True)
        self.gui.mainwindow.maximize()
        self.gui.select_entry.grab_focus()
        self.gui.customer_label.set_text("Customer: %d %s" % (custno, custname))
        # once the window pops up on TOP, turn off always on top feature
        gobject.timeout_add(250, lambda: gui.mainwindow.set_keep_above(False))
        # enter another gtk.main() level here.
        # Have to do this so that the Autopoint caller will hang until the user returns
        # from the catalog and then will process any selected sell line items passed back.
        # Without this the AutoPoint caller never sees any sell line parts!
        gtk.main()



class TrayIcon:

    def __init__(self):
        self.staticon = gtk.StatusIcon()
        self.staticon.set_from_file(FEDECAT_ICON)
        #gtk.status_icon_new_from_file(TRAY_ICON)
        #self.staticon.set_from_stock(gtk.STOCK_YES)
        self.staticon.set_visible(True)
        # self.staticon.connect("popup_menu", self.popup)
        self.popup_menu = gtk.Menu()
        #menu_item = gtk.ImageMenuItem(gtk.STOCK_ABOUT)
        menu_item = gtk.ImageMenuItem("About Federated Catalog")
        menu_item.set_image(gtk.image_new_from_stock(gtk.STOCK_ABOUT, gtk.ICON_SIZE_MENU))
        menu_item.connect("activate", self.on_about)
        self.popup_menu.append(menu_item)
        #menu_item = gtk.ImageMenuItem(gtk.STOCK_QUIT)
        menu_item = gtk.ImageMenuItem("Halt Federated Catalog")
        menu_item.set_image(gtk.image_new_from_stock(gtk.STOCK_QUIT, gtk.ICON_SIZE_MENU))
        menu_item.connect("activate", self.on_quit)
        self.popup_menu.append(menu_item)
        self.staticon.connect("popup-menu", self.on_popup, self.popup_menu)
        self.staticon.set_tooltip("AutoPoint's Federated Catalog Interface")

    def on_popup(self, widget, button, time, menu):
        menu.show_all()
        menu.popup(None, None, None, 3, time)

    def on_about(self, widget):
        dialog = gtk.AboutDialog()
        dialog.set_name("Federated Catalog - rev: ")
        dialog.set_version(REVISION)
        dialog.set_comments("AutoPoint's Federated Catalog Interface for part lookup.")
        dialog.run()
        dialog.destroy()

    def on_quit(self, widget):
        dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, 
                    gtk.BUTTONS_YES_NO,
                    "Are you sure you want to halt the Fedrated catalog Interface?")
        if WINDOWS:
            # for some reason windows defaults to yes...i want NO
            dialog.set_default_response(gtk.RESPONSE_NO)
        resp = dialog.run()
        dialog.destroy()
        if resp == gtk.RESPONSE_YES:
            for i in range(gtk.main_level()):
                gtk.main_quit()




class FedecatXMLRPCServer( SimpleXMLRPCServer ):

    def __init__(self, addr):
        SimpleXMLRPCServer.__init__(self, addr, allow_none=True)
        gobject.io_add_watch(self.socket, gobject.IO_IN, self.do_request)

    def do_request(self, source, condition):
        if WINDOWS:
            from time import sleep
            # had to add this stupid kludge because of issue in windows sockets
            # see: http://bugs.python.org/issue9090
            # This prevents error in SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_post()
            # at the call to 'self.rfile.read(chunk_size)':
            #    "A non-blocking socket operation could not be completed immediately"
            sleep(0.5)
        self.handle_request()
        return True



def set_misc_screen_settings(gui):
    gui.mainwindow.set_title(TITLE_BAR)
    gui.mainwindow.modify_bg( gtk.STATE_NORMAL, gtk.gdk.color_parse(BG_COLOR))
    gui.selected_frame.modify_bg( gtk.STATE_NORMAL, gtk.gdk.color_parse(FRAME_BG_COLOR))
    gui.selected_eventbox.modify_bg( gtk.STATE_NORMAL, gtk.gdk.color_parse(SELECTED_BG_COLOR))
    # set federated logo image from file
    gui.fedlogo.set_from_file(FED_LOGO)



def splash_screen():
    splash_screen = ProgressWindow(" Federated Catalog Startup ",
                             "\n  Bringing up Federated Catalog in the backgroud...  \n")
    splash_screen.pbar.set_text("Revision %s" % REVISION)
    splash_screen.splash(2000)



class ProcessFinder:

    def __init__(self):
        pass

    def running(self, program, firstarg):
        copies = 0
        if WINDOWS:
            for process in wmi.WMI().Win32_Process(name=program):
                arg = process.CommandLine.split()[-1]
                if arg[-1] == '"':
                    arg = arg[:-1]
                if arg.endswith(firstarg):
                    copies += 1
        else:
            print "Write the Linux version!"
        return (copies > 1)




if __name__ == "__main__":
    # initialize GUI side and its callbacks
    gui = GUI(GLADE_FILE, "mainwindow")
    try:
        if ProcessFinder().running("pythonw.exe", "fedecatUI.py"):
            raise FXCatalogError("Federated Catalog is already running.")
        # some versions return '127.0.0.1' which won't work!
        #client_ip = socket.gethostbyname( socket.gethostname() )
        client_ip = my_ipaddress()
        server_ip = serverbyclientip(client_ip)
        fxcat = FXCatalog(server_ip)
        set_misc_screen_settings(gui)
        Main_Callbacks(gui, fxcat)
        Selected_Callbacks(gui, fxcat)
        # download groups and subgroups off the internet
        fxcat.cache_groups_subgroups(GROUPS_SUBGROUPS_CACHE)
        splash_screen()
    except (FXCatalogError, error), err:
        run_dialog( str(err), gui.errlabel, gui.errdialog)
        raise SystemExit

    if len(sys.argv) > 1 and sys.argv[1] == '-d':
        # for debugging only
        gui.mainwindow.show_all()
        # default focus to "Select:" entry
        gui.select_entry.grab_focus()
    else:
        try:
            server = FedecatXMLRPCServer((client_ip, CLIENT_PORT))
            server.register_introspection_functions()
            server.register_instance(RPCFunctions(gui, fxcat))
        except error, err:
            run_dialog(str(err), gui.errlabel, gui.errdialog)
            raise SystemExit
        # create tray icon for this program
        TrayIcon()
    gtk.main()
