import wx, wx.html, sys
from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
from etmHTML import ETMhtml
from etmCAL import ETM12cal
from etmParsers import *

item_hash = {
    'action'   : action_html,
    'event'    : event_html,
    'note'     : note_html,
    'reminder' : reminder_html,
    'task'     : task_html,
}

view_hash = {
    'busy view'   : busyview_html,
    'data view'   : dataview_html,
    'item view'   : itemview_html,
    'ledger view' : ledgerview_html,
    'main view'   : mainview_html
}


class MyHtmlWindow(wx.html.HtmlWindow):
    def __init__(self, parent, id, pos = wx.DefaultPosition, size=wx.DefaultSize, style=0):
        wx.html.HtmlWindow.__init__(self, parent, id, pos, size,
            style=wx.BORDER_SUNKEN)
        if "gtk2" in wx.PlatformInfo:
            self.SetStandardFonts(htmlfont+4, '', '')
        else:
            self.SetFonts('', '', [i for i in range(htmlfont,
                htmlfont+13, 2)])

    # Keep it from taking the focus
    def AcceptsFocus(self, *args, **kwargs):
        return False

class ETMdialog(wx.Dialog):
    def __init__(self, parent = None, size=wx.DefaultSize, value = '', mode = 'item', check = False, id = ''):
        wx.Dialog.__init__(
            self, parent, -1, 'etm', size=wx.DefaultSize, pos=wx.DefaultPosition, 
            style=wx.DEFAULT_DIALOG_STYLE)
        self.parent = parent
        self.mode = mode
        self.check = check
        self.id = id
        if value == '':
            mode = 'project'
            self.value = ''
        else:
            # value = 'view', i, l, b, d
            self.value = value.upper()
        if self.mode == 'item':
            self.help_hash = item_hash
        else:
            self.help_hash = view_hash

        self.help_list = self.help_hash.keys()
        self.help_list.sort()

        sizer = wx.BoxSizer(wx.VERTICAL)

        vbox = wx.BoxSizer(wx.VERTICAL)

        self.html = MyHtmlWindow(self, -1, size=(640,340))
        self.html.Bind(wx.EVT_CHAR, self.OnChar)
        self.html.SetBorders(5)
        if mode == 'project':
            html = project_html
        else:
            html = self.line2html(value)
        self.start_page = html
        self.page = html
        self.html.SetPage(self.page)
        self.printer = wx.html.HtmlEasyPrinting()
        self.printer.SetFonts('', '', [i for i in range(htmlprintfont,
            htmlprintfont+13, 2)])
        self.printdata = self.printer.GetPrintData()
        self.printdata.SetColour(False)
        self.Bind(wx.EVT_CHAR, self.OnChar)

        vbox.Add(self.html, 1, wx.EXPAND | wx.ALL, 5)
        if value in ['m', 'b', 'i', 'l', 'd']:
            txt = ''
        else:
            txt = value

        self.text = ExpandoTextCtrl(self, size=(560,-1), value=txt,
            style = wx.BORDER_SIMPLE | wx.TE_PROCESS_ENTER )
        self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.text)
        self.text.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.text.Bind(wx.EVT_TEXT_ENTER, self.OnEnter, self.text)
        self.text.SetInsertionPoint(len(value))
        self.text.Bind(wx.EVT_CHAR, self.OnChar)
        vbox.Add(self.text, 0, wx.ALL | wx.EXPAND, 4)

        sizer.Add(vbox, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 1)

        btnsizer = wx.StdDialogButtonSizer()

        self.btn1 = wx.Button(self, wx.ID_OK)
        self.btn1.SetDefault()
        self.btn1.Bind(wx.EVT_BUTTON, self.OnOk)
        btnsizer.AddButton(self.btn1)

        self.btn2 = wx.Button(self, wx.ID_CANCEL)
        self.btn2.Bind(wx.EVT_BUTTON, self.OnCancel)
        btnsizer.AddButton(self.btn2)
        self.btn3 = wx.Button(self, wx.ID_HELP)
        self.btn3.Bind(wx.EVT_BUTTON, self.getHelp)
        btnsizer.AddButton(self.btn3)
        btnsizer.Realize()

        sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.BOTTOM, 2)

        self.SetSizer(sizer)
        sizer.Fit(self)

    def OnEnter(self, event):
        event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED,
            self.btn1.GetId()) 
        self.btn1.Command(event)
        event.Skip()

    def OnRefit(self, evt):
        # For the Expando control
        self.Fit()

    def getSelection(self, prompt, choices, dflt=None):
        dlg = wx.SingleChoiceDialog(self, prompt, 'etm',
                choices, wx.CHOICEDLG_STYLE)
        if dflt:
            dlg.SetSelection(dflt)
        res = (dlg.ShowModal() == wx.ID_OK)
        if res:
            retval = dlg.GetStringSelection()
        else:
            retval = ""
        dlg.Destroy()
        return(retval)

    def OnKeyDown(self, event):
        keycode = event.GetKeyCode()
        # print "OnKeyDown", keycode, self.mode
        if keycode == wx.WXK_RETURN and self.mode == 'view':
            event.Skip(False)
            self.OnEnter(event)
        else:
            event.Skip()

    def line2type(self, line):
        if self.mode == 'item':
            m = type_regex.match(line)
            dflt = 0
            if m:
                t = m.group(1) 
                if t == '~':
                    dflt = self.help_list.index('action')
                elif t == '*':
                    dflt = self.help_list.index('event')
                elif t == '!':
                    dflt = self.help_list.index('note')
                elif t == '&':
                    dflt = self.help_list.index('reminder')
                elif t[0] in ['.', '_', '+', '-']:
                    dflt = self.help_list.index('task')
                elif t == '':
                    dflt = self.help_list.index('project')
        else: # view
            m = view_regex.match(line)
            dflt = 3
            if m:
                t = m.group(1) 
                if t == 'b':
                    dflt = self.help_list.index('busy view')
                elif t == 'd':
                    dflt = self.help_list.index('data view')
                elif t == 'i':
                    dflt = self.help_list.index('item view')
                elif t == 'l':
                    dflt = self.help_list.index('ledger view')
                else: # t = 'm'
                    dflt = self.help_list.index('main view')

        return(dflt)

    def line2html(self, line):
        dflt = self.line2type(line)
        return(self.help_hash[self.help_list[dflt]])

    def getHelp(self, event=None):
        if self.mode == 'item':
            line = self.text.GetValue()
            dflt = self.line2type(line)
            choice = self.getSelection('help topics', self.help_list, dflt)
            if choice:
                html = self.help_hash[choice] 
                self.page = html
        else: # mode = 'view'
            self.page = self.start_page
        self.html.SetPage(self.page)

    def OnCancel(self, event):
        if self.mode == 'view' or not self.text.IsModified() or self.parent.cancel():
            event.Skip()

    def OnOk(self, event):
        if self.check:
            t = None
            msg = []
            entry = self.text.GetValue()
            entry = newline_regex.sub('', entry)
            orig_options = deepcopy(self.parent.etmData.options)
            self.parent.etmData.options.clear()
            if self.mode == 'item':
                hash, t = self.parent.etmData.line2hash(entry)
                if (auto_set_timezone and 'z' not in hash and 
                        ('d' in hash or hash['type'] != task)): 
                    hash['z'] = self.parent.ltz
                if etmUser and 'U' not in hash:
                    hash['U'] = etmUser
                if self.id:
                    hash['id'] = self.id
                msg, hash = self.parent.etmData.check_hash(hash, t = t )
            elif self.mode == 'project':
                hash, t = self.parent.etmData.line2hash(entry, item = False)
                msg, hash = self.parent.etmData.check_hash(hash, item = False)
                hash['details'] = entry
            else: # view
                # parse options here
                hash = {}
                res = historyleader.sub('', entry)
                hash, msg, s = parse_opts("%s %s" % (self.value.lower(), res))
                if not msg:
                    self.parent.etmData.options = hash
                    if s and s not in self.parent.cur_lst and s not in \
                        self.parent.cur_hist:
                        self.parent.cur_lst.append(s)
                    if self.value == 'M':
                        # main view
                        s = get_mainopts(self.parent.etmData.options)
                        self.parent.statusbar.SetStatusText(s, 2)
                        self.parent.showDay(force = True)
                        event.Skip()
                    elif self.value == 'I':
                        h, lst = self.parent.etmData.show(view = 'h')
                        outlst = ['<title>%s</title><table width="100%%" padding = "0" cellspacing = "0" border = "0">' % h]
                        for item in lst:
                            try:
                                outlst.append(item)
                            except:
                                print 'exception', item
                        outlst.append('</table>')
                        html = "\n".join(outlst)
                        self.SetTitle(h)
                        self.page = html
                        self.html.SetPage(self.page)
                        self.html.Refresh()
                    elif self.value == 'D':
                        h, lst = self.parent.etmData.prepare_data()
                        outlst = ['<title>%s</title><pre>' % h]
                        for item in lst:
                            outlst.append(item.pre())
                        outlst.append('</pre>')
                        html = "\n".join(outlst)
                        self.SetTitle(h)
                        self.page = html
                        self.html.SetPage(self.page)
                        self.html.Refresh()
                    elif self.value == 'L':
                        self.parent.etmData.show(view = 'h')
                        h, lst = self.parent.etmData.prepare_ledger()
                        outlst = ['<title>%s</title><font color="blue"><pre>' % h]
                        for x in lst:
                            outlst.append(x.pre())
                        outlst.append('</pre>')
                        html = "\n".join(outlst)
                        self.SetTitle(h)
                        self.page = html
                        self.html.SetPage(self.page)
                        self.html.Refresh()
                    elif self.value == 'B':
                        self.parent.etmData.show(view = 'h')
                        hdr, lst, cols = self.parent.etmData.prepare_busy()
                        if hdr:
                            outlst = ['<title>%s</title><pre>' % hdr]
                        else:
                            outlst = ['<title>busy view</title><pre>']
                        for x in lst:
                            outlst.append(x.pre())
                        outlst.append('</pre>')
                        html = "\n".join(outlst)
                        self.SetTitle(hdr)
                        self.page = html
                        self.html.SetPage(self.page)
                        self.html.Refresh()
            if self.id:
                hash['id'] = self.id
            if msg:
                try:
                    page = "\n".join(msg)
                    dlg = wx.MessageDialog(None, page, 'etm',
                            wx.OK)
                    return(dlg.ShowModal())
                except:
                    print 'except', msg
            else:
                if self.mode == 'item' and t:
                    prefix = '@'
                    sl = [t, hash['description']]
                    if  t == '*':
                        keys = event_keys
                    elif t == '~':
                        keys = action_keys
                    elif t == '!':
                        keys = note_keys
                    elif t == '&':
                        keys = reminder_keys
                    else:
                        keys = task_keys
                elif self.mode == 'project':
                    prefix = ''
                    keys = project_keys
                    sl = []
                else: # mode = view
                    prefix = '-'
                    keys = [y for y in opt_keys[self.value.lower()]]
                    sl = []
                for key in sort_keys:
                    if key in keys:
                        if has(hash, key) and hash[key]:
                            value = hash[key]
                            sl.append("%s%s %s" % (prefix, key, value))
                line = " ".join(sl)
                if self.mode == 'item':
                    self.text.ChangeValue(hash['details'])
                    self.parent.etmData.options = orig_options
                    if self.parent.confirm(hash):
                        event.Skip()
                elif self.mode == 'project':
                    self.parent.etmData.options = orig_options
                    if self.parent.confirm(hash):
                        event.Skip()
                elif self.mode == 'view' and self.value != 'M':
                    self.parent.etmData.options = orig_options

        else:
            event.Skip()

    def OnPrint(self, event):
        self.printer.SetHeader(
          '<center><font size="+1">%s</font></center>' %
          self.html.GetOpenedPageTitle())
        self.printer.SetFooter(
                '<center>Page @PAGENUM@ of @PAGESCNT@</center>')
        self.printer.PrintText(self.page)


    def insert_text(self, text):
        if self.mode == 'item':
            self.text.WriteText(text)
        else:
            pt = self.text.GetInsertionPoint()
            self.text.Replace(pt, pt, text)
            self.text.Refresh()

    def OnChar(self, event):
        keycode = event.GetKeyCode()
        # print "OnChar", keycode
        shift = event.ShiftDown()
        # if self.mode == 'item' and keycode == wx.WXK_F1:  # F1 Show Help
        if keycode == wx.WXK_F1:  # F1 Show Help
            self.getHelp()
        elif keycode == wx.WXK_F2:  # F2 get date
            self.dlg = ETM12cal()
            self.dlg.Show()
        elif keycode in [wx.WXK_UP]:
            try:
                self.dlg.cal_advance -= 1
                self.dlg.show_cal()
            except:
                event.Skip()
        elif keycode in [wx.WXK_DOWN]:
            try:
                self.dlg.cal_advance += 1
                self.dlg.show_cal()
            except:
                event.Skip()
        elif keycode in [wx.WXK_HOME]:
            try:
                self.dlg.cal_advance = 0
                self.dlg.show_cal()
            except:
                event.Skip()
        elif keycode in [17]:    # Ctrl-Q quit
            try:
                self.dlg.OnQuit(event)
            except:
                event.Skip()
        elif keycode in [16]:    # Ctrl-P print
            self.OnPrint(event)
        elif keycode == 27: # Esc cancel
                self.OnCancel(event)
        elif keycode == wx.WXK_TAB:
            p = self.text.GetInsertionPoint()
            if self.mode == 'view':
                entry = self.text.GetString(0,p)
                if entry:
                    regex = re.compile(r'^%s' % entry)
                    length = len(entry)
                else:
                    regex = re.compile(r'^.*')
                    length = 0
                templates = [x for x in list(self.parent.cur_hist +
                    self.parent.cur_lst) if regex.match(x)]
                self.insert_text(self.getSelection('history items',
                    templates)[length:])
            else:
                templates = list(self.parent.cur_tmpl)
                abbrv = self.parent.cur_abbrv
                entry = self.text.GetString(0,p)
                m = abbrv_entry.match(entry)
                if m and m.group(1) in abbrv:
                    start = p - len(m.group(1)) - len(m.group(2))
                    key = m.group(1)
                    value = abbrv[key]
                    rplc = abbrv[m.group(1)]
                    self.text.Replace(start, p, value)
                    self.text.Refresh()
                else:
                    txt = self.getSelection('template items', templates)
                    m = abbrv_regex.match(txt)
                    if m:
                        txt = m.group(2) 
                    self.insert_text(txt)

        elif shift and keycode == 32:
            # shift + space completion
            try:
                p = self.text.GetInsertionPoint()
                if self.mode == 'item':
                    s = self.text.GetString(0,p)
                else:
                    s = self.text.GetValue()[0:p]
                m = lastfield_regex.match(s)
            except:
                m = None
            if m:
                field = m.group(1)
                entry = m.group(2).strip()
                if entry:
                    regex = re.compile(r'^%s' % entry)
                    length = len(entry)
                else:
                    regex = re.compile(r'^.*')
                    length = 0
                if field == 'c':
                    contexts = [x for x in list(self.parent.etmData.contexts.keys()) if regex.match(x)]
                    contexts.sort()
                    self.insert_text(self.getSelection('contexts',
                        contexts)[length:])
                elif field == 'k': # keyword
                    keywords = [x for x in list(self.parent.etmData.keywords.keys()) if regex.match(x)]
                    keywords.sort()
                    self.insert_text(self.getSelection('keywords',
                        keywords)[length:])
                elif field == 'r': # repeats
                    repeats = [x for x in list(self.parent.etmData.repeats) if regex.match(x)]
                    repeats.sort()
                    self.insert_text(self.getSelection('repeats',
                        repeats)[length:])
                elif field == 'p': # projects
                    projects = [x for x in list(self.parent.etmData.projects) if regex.match(x)]
                    repeats.sort()
                    self.insert_text(self.getSelection('projects',
                        projects)[length:])
                elif field == 'z': # zones
                    zones = [x for x in list(self.parent.etmData.zones) if regex.match(x)]
                    zones.sort()
                    self.insert_text(self.getSelection('zones',
                        zones)[length:])
        else:
            event.Skip()


class App(wx.App):
    def OnInit(self):
        dlg = ETMdialog(size=(300, -1), value="b",  mode = 'view')
        response = dlg.ShowModal() 
        if response == wx.ID_OK:
            print "ok", dlg.text.GetValue()
        else:
            print "cancel"
        dlg.Destroy()
        return True

def main():
    app = App(redirect=False)
    app.MainLoop()

if __name__ == '__main__':
    main()