# -*- coding: iso-8859-1 -*-

import wx
import gettext
from win32com.shell import shell
import win32con
import pywintypes
import os.path
import sys
from ConfigParser import SafeConfigParser, Error
from uninstallcomponents import UninstallKey


_ = wx.GetTranslation

def isWin64():
    return 'PROGRAMFILES(X86)' in os.environ

def split_exe_args(command):
    if command.startswith('"'):
        second = command.find('"',1)
        f = command[1:second]
        args = command[second+1:].strip()
        return f, args
    try:
        index = command.index(" ")
    except ValueError:
        f = command
        args = ""
        return f, args
    while not os.path.isfile(command[:index]):
        try:
            index = command.index(" ", index+1)
        except ValueError:
            return None, ""
    return command[:index], command[index+1:]

class Component(object):
    items = ('label','setup','uninstallpattern','setup64')
    @classmethod
    def fromConfig(cls, cp, component):
        try:
            kwds = dict(cp.items(component))
        except Error:
            kwds = {}
        return cls(**kwds)
    def __init__(self, **kwds):
        for item in self.items: setattr(self, item, kwds.get(item,''))
        if not self.setup64: self.setup64 = self.setup

class Viewer(object):
    items = ('name','exe')
    @classmethod
    def fromConfig(cls, cp, component):
        try:
            kwds = dict(cp.items(component))
        except Error:
            kwds = {}
        return cls(**kwds)
    def __init__(self, **kwds):
        for item in self.items: setattr(self, item, kwds.get(item,''))

class MyFrame(wx.Frame):
    languages = [
        (wx.LANGUAGE_ENGLISH_US,'en','English'),
        (wx.LANGUAGE_GERMAN,'de','Deutsch'),
        (wx.LANGUAGE_FRENCH,'fr','Français')
    ]
    
    def __init__(self, *args, **kwargs):
        for key, default in (
            ('language','en'),
            ('components',[]),
            ('manual',None),
            ('protextdir',os.path.normpath(os.path.join(executable(),'../protext'))),('exedir',os.path.dirname(executable())),
            ('viewer',None)
        ):
            try:
                setattr(self,key,kwargs[key])
                del kwargs[key]
            except KeyError:
                setattr(self,key,default)
            
        kwargs["style"] = wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER
        wx.Frame.__init__(self, *args, **kwargs)
        wx.Locale.AddCatalogLookupPathPrefix(os.path.join(exedir,'locale'))
        self.language = wx.LANGUAGE_DEFAULT
        self.locale = None
        
        self.outer_panel = wx.Panel(self, -1)
        sizer = wx.BoxSizer()
        self.outer_panel.SetSizer(sizer)
        self.main_panel = wx.Panel(self.outer_panel, -1)
        sizer.Add(self.main_panel, 0, wx.ALL, 5)
        self.label_language = wx.StaticText(self.main_panel,-1)
        self.label_doc = wx.StaticText(self.main_panel,-1)
        self.choice_language = wx.Choice(self.main_panel, -1, choices=[label for id,code,label in self.languages])

        self.labels = [wx.StaticText(self.main_panel,-1,c.label) for c in self.components]
        self.install_buttons = [wx.Button(self.main_panel,-1) for c in self.components]
        self.uninstall_buttons = [wx.Button(self.main_panel,-1) for c in self.components]

        self.button_doc = wx.Button(self.main_panel, -1)
        self.Bind(wx.EVT_BUTTON, self.OnOpenManual, self.button_doc)
##        if self.viewer:
##            self.button_doc_alternative = wx.Button(self.main_panel, -1)
##            self.Bind(wx.EVT_BUTTON, self.OnOpenManual, self.button_doc_alternative)
        self.button_exit = wx.Button(self.main_panel, -1)
        self.Bind(wx.EVT_CHOICE, self.OnLanguageSelect, self.choice_language)
        for button in self.install_buttons:
            self.Bind(wx.EVT_BUTTON, self.OnInstallButton, button)
        for button in self.uninstall_buttons:
            self.Bind(wx.EVT_BUTTON, self.OnUninstallButton, button)
        self.Bind(wx.EVT_BUTTON, self.OnExit, self.button_exit)

        self.UpdateLanguage(False)
        self.__set_properties()
        self.__do_layout()
    def __set_properties(self):
        icon_file = os.path.join("icons","tex.ico")
        if os.path.exists(icon_file):
            self.SetIcon(wx.IconFromLocation(wx.IconLocation(icon_file,0)))
        if self.locale:
            language = self.locale.GetName().split("_")[0]
            try:
                index = [code for id,code,label in self.languages].index(language)
                self.choice_language.SetSelection(index)
            except ValueError:
                self.choice_language.SetSelection(wx.NOT_FOUND)
    def __do_layout(self):
        gb_sizer = wx.GridBagSizer(5,5)
        self.main_panel.SetSizer(gb_sizer)
        row = 0
        gb_sizer.Add(self.label_language, wx.GBPosition(row, 0))
        gb_sizer.Add(self.choice_language, wx.GBPosition(row, 1), wx.GBSpan(colspan=2))
        
        row += 1
        gb_sizer.Add((1,1), wx.GBPosition(row,0))

        row += 1
        gb_sizer.Add(self.label_doc, wx.GBPosition(row, 0))
        gb_sizer.Add(self.button_doc, wx.GBPosition(row, 1), wx.GBSpan(colspan=2))
##        if not self.viewer:
##            gb_sizer.Add(self.button_doc, wx.GBPosition(row, 1), wx.GBSpan(colspan=2))
##        else:
##            gb_sizer.Add(self.button_doc, wx.GBPosition(row, 1))
##            gb_sizer.Add(self.button_doc_alternative, wx.GBPosition(row, 2))

        row += 1
        gb_sizer.Add((1,1), wx.GBPosition(row,0))
        
        for label, install_button, uninstall_button in zip(self.labels, self.install_buttons, self.uninstall_buttons):
            row += 1
            gb_sizer.Add(label, wx.GBPosition(row, 0))
            gb_sizer.Add(install_button, wx.GBPosition(row, 1))
            gb_sizer.Add(uninstall_button, wx.GBPosition(row, 2))
        
        row += 1
        gb_sizer.Add((1,1), wx.GBPosition(row,0))
        
        row += 1
        gb_sizer.Add(self.button_exit, wx.GBPosition(row, 0), wx.GBSpan(colspan=3), wx.ALIGN_RIGHT)

        #gb_sizer.Fit(self)
        self.outer_panel.GetSizer().Fit(self)
        self.Layout()
    def OnOpenManual(self, event):
        source = event.GetEventObject()
        code = self.languages[self.choice_language.GetSelection()][1]
        if self.manual:
            manual = os.path.join(self.protextdir,self.manual%code)
            #wx.MessageBox(u"Öffne %s"%manual, "Debug")
            if self.viewer: # and source is self.button_doc_alternative:
                viewer = os.path.normpath(os.path.join(self.protextdir,self.viewer.exe))
                self.Execute(viewer,args='"%s"'%manual,elevate='never')
            else:
                self.Execute(manual,elevate='never')
        event.Skip()
    def OnInstallButton(self, event):
        source = event.GetEventObject()
        index = self.install_buttons.index(source)
        setup = self.components[index].setup64 if isWin64() else self.components[index].setup
        #wx.MessageBox("Starte %s"%setup,"Debug")
        cmd, args = split_exe_args(setup)
        cmd = os.path.normpath(os.path.join(self.protextdir, cmd))
        #print cmd # Debug
        if cmd and os.path.exists(cmd):
            self.Execute(cmd, args)
        elif cmd:
            msgbox = wx.MessageDialog(self,_('Cannot execute: ')+cmd, _('Error'), style=wx.OK|wx.CENTER|wx.ICON_ERROR)
            msgbox.ShowModal()
        else:
            msgbox = wx.MessageDialog(self,_('Cannot execute: ')+setup, _('Error'), style=wx.OK|wx.CENTER|wx.ICON_ERROR)
            msgbox.ShowModal()
        event.Skip()
    def OnUninstallButton(self, event):
        source = event.GetEventObject()
        index = self.uninstall_buttons.index(source)
        keys = UninstallKey.fetchUninstallablePrograms(self.components[index].uninstallpattern)
        if keys:
            dlg = wx.SingleChoiceDialog(self, _('Select component for uninstallation and click OK'), _('Uninstall component'), [key.name for key in keys])
            dlg.SetSelection(0)
            result = dlg.ShowModal()
            if result == wx.ID_OK:
                index = dlg.GetSelection()
                cmd = keys[index].command
                cmd, args = split_exe_args(cmd)
                if cmd: self.Execute(cmd, args)
        else:
            msgbox = wx.MessageDialog(self,_('No installed version found'), _('Info'), style=wx.OK|wx.CENTER)
            msgbox.ShowModal()
        event.Skip()
    def OnLanguageSelect(self, event=None):
        index = self.choice_language.GetSelection()
        try:
            self.language = [id for id, code, lan in self.languages][index]
        except IndexError:
            self.language = self.languages[0][0]
        wx.CallAfter(self.UpdateLanguage)
        if event: event.Skip()
    def OnExit(self, event):
        event.Skip()
        wx.CallAfter(self.Close)
    def UpdateLanguage(self, redraw=True):
        if self.locale: del self.locale
        self.locale = wx.Locale(self.language)
        if not self.locale.IsOk():
            del self.locale
            self.locale = wx.Locale(self.languages[0][0])
        self.locale.AddCatalog('protext')
        if not self.locale.IsLoaded('protext'):
            del self.locale
            self.locale = wx.Locale(self.languages[0][0])
            self.locale.AddCatalog('protext')
        
        self.label_language.SetLabel(_("Language:"))
        self.label_doc.SetLabel(_("Manual:"))
        
        for button in self.install_buttons:
            button.SetLabel(_("Install"))
        for button in self.uninstall_buttons:
            button.SetLabel(_("Uninstall"))
        self.button_doc.SetLabel(_("Open"))
##        if self.viewer:
##            self.button_doc_alternative.SetLabel("%s (%s %s)"%(_("Open"),_("with"),viewer.name))
        self.button_exit.SetLabel(_("Exit"))
        
        if redraw:
            self.outer_panel.GetSizer().Fit(self)
            self.Layout()
            self.Update()
    def Execute(self, path, args="", **kwargs):
        elevate = kwargs.get('elevate','ifneeded')
        action = "runas" if elevate=='always' else "open"
        try:
            shell.ShellExecuteEx(
                fMask = 0,
                nShow = win32con.SW_NORMAL,
                lpVerb = action,
                lpFile = path,
                lpDirectory = os.path.dirname(path),
                lpParameters = args
            )
        except pywintypes.error, error:
            if elevate=='ifneeded' and error.winerror==5:
                self.Execute(path, *args, elevate='always')
            else:
                msgbox = wx.MessageDialog(self,_("Running %s failed with the following error:")%" ".join([path,args])+"\n\n%s"%error.strerror,_("Error"), style=wx.OK|wx.CENTER|wx.ICON_ERROR)
                msgbox.ShowModal()
                msgbox.Destroy()
        

def executable():
    if hasattr(sys,'frozen'):
        path = sys.executable
    else:
        path = sys.argv[0]
    path = os.path.abspath(path)
    return path


if __name__ == "__main__":
    #gettext.install('protext','./locale', unicode=False)
    cp = SafeConfigParser()
    exedir = os.path.dirname(executable())
    cp.read([os.path.join(exedir,'protext.ini')])
    protextdir = os.path.normpath(os.path.join(exedir,cp.get('General','protextdir')))
    #print protextdir
    components = cp.get('General', 'components').split()
    components = [Component.fromConfig(cp, component) for component in components]
    manual = cp.get('General','manual',raw=True)
    viewer = Viewer.fromConfig(cp, 'PdfViewer')
    if not viewer.exe or not os.path.exists(os.path.join(protextdir,viewer.exe)):
        viewer = None
    
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    frame_main = MyFrame(None, -1, "proTeXt", protextdir=protextdir, exedir=exedir, manual=manual, components=components, language='de', viewer=viewer)
    app.SetTopWindow(frame_main)
    frame_main.Show()
    app.MainLoop()
