# -*- coding: utf-8  -*-
"""
Az életrajzi robot GUI kódja.
"""

import sys, sre, gzip, wx
import  wx.lib.mixins.listctrl as listmix

class SzulHalList(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
    columns = [("", 20), (u"név", 170), (u"* év", 50), (u"* nap", 120),
               (u"† év", 50), (u"† nap", 120), (u"leírás", None)]


    def __init__(self, people, parent=None, ID=-1,
                 pos=wx.DefaultPosition, size=wx.DefaultSize):
        self.people = people
        self.good = [True] * len(people)
        self.parent = parent
        wx.ListCtrl.__init__(self, parent, ID, pos, size,
                             style = wx.LC_REPORT |
                                     wx.LC_VIRTUAL |
                                     wx.BORDER_SIMPLE |
                                     wx.LC_SINGLE_SEL |
                                     wx.LC_HRULES)
        listmix.ListCtrlAutoWidthMixin.__init__(self)
        self.SetItemCount(len(people))

        # Create image list
        imageList = self.imageList = wx.ImageList(16,16)
        tickBmp = wx.ArtProvider_GetBitmap(wx.ART_TICK_MARK, size=(16,16))
        crossBmp = wx.ArtProvider_GetBitmap(wx.ART_CROSS_MARK, size=(16,16))
        self.tick = imageList.Add(tickBmp)
        self.cross = imageList.Add(crossBmp)
        self.SetImageList(imageList, wx.IMAGE_LIST_SMALL)

        # Create columns
        for i, x in enumerate(self.columns):
            self.InsertColumn(i, x[0])
            if x[1]:
                self.SetColumnWidth(i, x[1])

        # Bind events
        self.Bind(wx.EVT_LIST_KEY_DOWN, self.itemKey)


    def OnGetItemText(self, item, col):
        if col == 0:
            return ""
        else:
            return self.people[item][1][col-1] or ""


    def OnGetItemImage(self, item):
        if self.good[item]:
            return self.tick
        else:
            return self.cross


    def itemKey(self, event):
        selected = self.GetNextItem(-1, state=wx.LIST_STATE_SELECTED)
        if selected >= 0 and event.GetKeyCode() in [13,32]:
            self.good[selected] = not self.good[selected]
            self.RefreshItem(selected)


    def loadFrom(self, fileName):
        try:
            f = gzip.open(fileName)
            # [:] to replace list contents, not the list references !!!
            self.people[:], self.good[:] = map(eval, f.readlines())
            f.close()
            self.RefreshAll()
        except IOError, e:
            self.errorMessage('Cannot open file %s for reading:\n%s' % (fileName, str(e)))
        except StandardError, e:
            self.errorMessage('Error wile parsing %s:\n%s' % (fileName, str(e)))
            
    
    def saveTo(self, fileName):
        try:
            f = gzip.open(fileName, "w")
            f.writelines([repr(self.people), '\n', repr(self.good), '\n'])
            f.close()
            self.RefreshAll()
        except IOError, e:
            self.errorMessage('Cannot open file %s for writing:\n%s' % (fileName, str(e)))


    def RefreshAll(self):
        itemCount = len(self.people)
        self.SetItemCount(itemCount)
        self.RefreshItems(0, itemCount-1)


    def errorMessage(self, msg):
            dlg = wx.MessageDialog(self.parent, msg, 'Error', wx.OK|wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()


class SzulHalGUI(wx.App):
    def __init__(self, people=[], savedState=None):
        self.people = people
        self.savedState = savedState
        self.okayed = False
        wx.App.__init__(self)


    def OnInit(self):
        mainFrame = self.mainFrame = \
                    wx.Frame(None,
                             title = u"SzülHalBot",
                             style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)

        mainSizer = wx.BoxSizer(wx.VERTICAL)

        # Create list control
        listCtrl = self.listCtrl = SzulHalList(self.people, mainFrame, size=(1000,400))
        mainSizer.Add(listCtrl, 1, wx.EXPAND | wx.ALL, 5)

        # Create text control
        textCtrl = self.textCtrl = \
                   wx.TextCtrl(mainFrame, size=(-1,54),
                               style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
        mainSizer.Add(textCtrl, 0, wx.EXPAND | wx.ALL, 5)

        # Create selection override buttons
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(wx.StaticText(mainFrame, label="Kiválasztott szövegrész:"),
                  0, wx.CENTER | wx.ALL, 5)
        for i in range(2,len(listCtrl.columns)):
            btn = wx.Button(mainFrame, i-1, listCtrl.columns[i][0])
            sizer.Add(btn, 0, wx.ALL, 5)
        sizer.AddSpacer((40,0))
        sizer.Add(wx.Button(mainFrame, wx.ID_COPY, "* -> †"), 0, wx.ALL, 5)
        mainSizer.Add(sizer, 0, wx.CENTER | wx.ALL, 5)

        # Create stock buttons
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(wx.Button(mainFrame, wx.ID_OPEN), 0, wx.EXPAND | wx.ALL, 5)
        sizer.Add(wx.Button(mainFrame, wx.ID_SAVE), 0, wx.EXPAND | wx.ALL, 5)
        sizer.Add(wx.Button(mainFrame, wx.ID_CANCEL), 0, wx.EXPAND | wx.ALL, 5)
        sizer.Add(wx.Button(mainFrame, wx.ID_OK), 0, wx.EXPAND | wx.ALL, 5)
        mainSizer.Add(sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5)

        # Bind events
        mainFrame.Bind(wx.EVT_LIST_ITEM_SELECTED, self.itemSelect, listCtrl)
        mainFrame.Bind(wx.EVT_BUTTON, self.buttonPress)

        # Set size and display
        mainFrame.SetSizerAndFit(mainSizer)
        mainFrame.Show()

        # Load saved state if requested
        if self.savedState:
            self.listCtrl.loadFrom(self.savedState)
        self.listCtrl.SetFocus()

        # Select first person
        if self.people:
            self.listCtrl.Select(0)

        return True


    def itemSelect(self, event):
        self.detailItem(event.m_itemIndex)
        event.Skip()


    def detailItem(self, item):
        line, (name,by,bd,dy,dd,desc) = self.people[item]

        self.textCtrl.SetValue(line)
        for color, ptrn in \
                { "#ffaaaa": sre.escape(name),
                  "#ffaaff": self.datere(by, bd),
                  "#aaffaa": self.datere(dy, dd),
                  "#aaffff": desc and sre.escape(desc)
                }.items():
            if not ptrn: continue
            match = sre.search(ptrn, line)
            if match:
                self.textCtrl.SetStyle(match.start(), match.end(), wx.TextAttr(colBack=color))


    def datere(self, year, day):
        return (year and "(\[\[)?" + year + "(\]\])?\.?" or "") + \
               (year and day and " *" or "") + \
               (day and "(\[\[)?" + day + "(\]\])?\.?" or "")


    wildcards = "Python data dump (*.pdd)|*.pdd|All files (*)|*"
    def buttonPress(self, event):
        if event.GetId() in [wx.ID_OK, wx.ID_CANCEL]:
            self.okayed = event.GetId() == wx.ID_OK
            if self.okayed:
                self.listCtrl.saveTo('szulhal.pdd')
            self.mainFrame.Hide()
            wx.Exit()

        elif event.GetId() == wx.ID_OPEN:
            dlg = wx.FileDialog(self.mainFrame, "Open saved state",
                                wildcard=self.wildcards, style=wx.OPEN|wx.CHANGE_DIR)
            if dlg.ShowModal() == wx.ID_OK:
                self.listCtrl.loadFrom(dlg.GetPath())
            dlg.Destroy()

        elif event.GetId() == wx.ID_SAVE:
            dlg = wx.FileDialog(self.mainFrame, "Save state as ...",
                                wildcard=self.wildcards, style=wx.SAVE)
            if dlg.ShowModal() == wx.ID_OK:
                self.listCtrl.saveTo(dlg.GetPath())
            dlg.Destroy()

        else:
            selected = self.listCtrl.GetNextItem(-1, state=wx.LIST_STATE_SELECTED)
            if selected >= 0:
                if event.GetId() == wx.ID_COPY:
                    person = self.people[selected][1]
                    person[1:5] = [None,None] + person[1:3]
                else:
                    markedText = self.textCtrl.GetStringSelection()
                    if not markedText: markedText = None
                    self.people[selected][1][event.GetId()] = markedText
                self.listCtrl.RefreshItem(selected)
                self.detailItem(selected)
        self.listCtrl.SetFocus()
        event.Skip()


    def display(self):
        self.MainLoop()
        if not self.okayed:
            return None

        selected = []
        notSelected = []
        for i, x in enumerate(self.people):
            if self.listCtrl.good[i]:
                selected.append(x[1])
            else:
                notSelected.append(x[1])
        return (selected, notSelected)
        
if __name__ == "__main__":
    print SzulHalGUI([(u"Józsi született 1976. augusztus 12-én, egy igazi senkifia.",
                       [u"Józsi", "1976", "augusztus 12", None, None, "senkifia"]),
                      (u"Marcsi világra jött: [[1982]]. [[január 23]]. senki lánya",
                       [u"Marcsi", "1982", u"január 23", None, None, u"senkilánya"])]).display()