#!/usr/bin/env python
#-*- coding: UTF-8 -*-

import os
import os.path
import webbrowser
import wx
import re
from time import strftime

from   stomamisc import *


class DirDialog(wx.Dialog):
    
    ID_CB_HIDDEN = wx.NewId()
    ID_TEXTCTRL =  wx.NewId()
    
    def __init__(self, parent, title, path = os.sep, hidden = False, createdir = False):        
        """ Manage (add, remove) scan dirs dialog """
        wx.Dialog.__init__(self, parent, -1, TITLE + ' - Select directory',                           
                           style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.dirctrl = wx.GenericDirCtrl(self,  style = wx.DIRCTRL_DIR_ONLY | wx.SUNKEN_BORDER)
        self.dirctrl.ShowHidden(hidden)
        style = self.dirctrl.GetTreeCtrl().GetWindowStyle() | wx.TR_FULL_ROW_HIGHLIGHT
        self.dirctrl.GetTreeCtrl().SetWindowStyle(style)        
        self.dirctrl.SetPath(path)
        sizer.Add(self.dirctrl, 1, wx.GROW | wx.ALL, BORDER)
        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.onSelChange)
        #self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.onButtonOpen)
        if createdir:
            self.hitreturn = wx.StaticText(self, -1, '')
            font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
            self.hitreturn.SetFont(font)
            sizer.Add(self.hitreturn, 0, wx.GROW | wx.LEFT | wx.RIGHT, BORDER)
        self.st = wx.TextCtrl(self, self.ID_TEXTCTRL, self.dirctrl.GetPath(), style = wx.TE_PROCESS_ENTER | wx.TE_READONLY)
        self.Bind(wx.EVT_TEXT_ENTER, self.onTextEnter, id = self.ID_TEXTCTRL)
        sizer.Add(self.st, 0, wx.GROW | wx.ALL, BORDER)
        self.cbh = wx.CheckBox(self, self.ID_CB_HIDDEN, ' show hidden / dotted dirs') 
        sizer.Add(self.cbh, 0, wx.LEFT | wx.RIGHT, BORDER)
        self.Bind(wx.EVT_CHECKBOX, self.onCheckHidden)
        self.cbh.SetValue(hidden)
        self.hidden = hidden
        
        sl = wx.StaticLine(self, -1)
        sizer.Add(sl, 0, wx.GROW | wx.ALL, BORDER)                

        butopen = wx.Button(self, wx.ID_OPEN)
        butcancel = wx.Button(self, wx.ID_CANCEL)
        self.Bind(wx.EVT_BUTTON, self.onButtonOpen, id = wx.ID_OPEN)
        self.Bind(wx.EVT_BUTTON, self.onButtonNew, id = wx.ID_NEW)
        bs = wx.BoxSizer(wx.HORIZONTAL)
        bs.Add(butopen, 1, wx.GROW | wx.RIGHT, GAP)
        if createdir:
            butnew = wx.Button(self, wx.ID_NEW)
            bs.Add(butnew, 1, wx.GROW | wx.CENTER, GAP)           
        bs.Add(butcancel, 1, wx.GROW | wx.LEFT, GAP)
        sizer.Add(bs, 0,  wx.GROW | wx.CENTER | wx.ALL, BORDER)
        
        self.SetSizerAndFit(sizer)
        self.SetMinSize(wx.Size(350, 400))
        self.Centre()
        self.path = ''
    #-------------------------------------------------------------------------------------------

    def onCheckHidden(self, event):
        self.hidden = not self.hidden
        self.dirctrl.ShowHidden(self.hidden)        
    #-------------------------------------------------------------------------------------------

    def onSelChange(self, event):
        self.st.SetValue(self.dirctrl.GetPath())        
    #-------------------------------------------------------------------------------------------

    def GetPath(self):
        return self.path
    #-------------------------------------------------------------------------------------------

    def onButtonNew(self, event):
        self.hitreturn.SetLabel('enter new folder name and hit return to accept')
        path = self.st.GetValue()
        if not path[-1] == os.sep:
            path += os.sep
        self.st.SetValue(path)
        start = self.st.GetLastPosition()
        path += 'NewFolderName'
        self.st.SetValue(path)
        self.st.SetEditable(True)
        self.st.SetFocus()
        self.st.SetSelection(start, -1)
    #-------------------------------------------------------------------------------------------
        
    def onTextEnter(self, event):
        self.st.SetEditable(False)
        newpath = self.st.GetValue()
        if os.path.exists(newpath):
            dlg = wx.MessageDialog(self, "Directory, '%s'\nalready exists. Choose a different name." % (newpath), TITLE + ' - Create new dir', wx.OK | wx.ICON_WARNING)
            dlg.ShowModal()
            dlg.Destroy()
            return
            
        try:
            os.mkdir(newpath)
            self.dirctrl.ReCreateTree()
            self.dirctrl.ExpandPath(newpath)
            self.path = self.dirctrl.GetPath()
        except:
            dlg = wx.MessageDialog(self, "Sorry, '%s'\ncould not be created. Check your permissions." % (newpath), TITLE + ' - Create new dir', wx.OK | wx.ICON_WARNING)
            dlg.ShowModal()
            dlg.Destroy()
    #-------------------------------------------------------------------------------------------
        
    def onButtonOpen(self, event):
        self.path = self.dirctrl.GetPath()
        self.EndModal(wx.ID_OPEN)
# - class DirDialog(wx.Dialog):---------------------------------------------------------------


class EditTaskDialog(wx.Dialog):

    ID_TC_NAME = wx.NewId()
    ID_TC_SOURCE = wx.NewId()
    ID_BTN_SOURCE = wx.NewId()
    ID_TC_TARGET = wx.NewId()
    ID_BTN_TARGET = wx.NewId()
    ID_CB_INCLUDE = wx.NewId()
    ID_CB_OVERRIDE = wx.NewId()
    ID_LC_REGEXP = wx.NewId()
    ID_BTN_ADDDIR = wx.NewId()
    ID_RB_NONE = wx.NewId()
    ID_RB_TAR = wx.NewId()
    ID_RB_TARGZ = wx.NewId()
    ID_RB_TARBZ2 = wx.NewId()
    ID_RB_ZIP = wx.NewId()
    ID_CB_TS = wx.NewId()
    ID_RB_TS1 = wx.NewId()
    ID_RB_TS2 = wx.NewId()
    ID_TC_EXMASK = wx.NewId()
    ID_BTN_EXLIST = wx.NewId()
    EDITMSG = 'You can edit the regular expression. To accept, press RETURN'
    NOEDITMSG = 'You are currently not in edit mode'
    
    def __init__(self, parent, config, jobtimer, taskname = '', clone = False):
        """ place TaskDialog items on a dialog with 4 tabs """
        
        wx.Dialog.__init__(self, parent, -1, TITLE + ' - New / Edit backup task')                           
        self.parent = parent
        self.config = config
        self.config.write()
        self.jobtimer = jobtimer
        self.timerstate = jobtimer.IsRunning()
        jobtimer.Stop()
        background_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND)
        collist = config['Misc']['hlcolor']
        self.hlcolor = (int(collist[0]), int(collist[1]), int(collist[2]))
        try:   
            self.icon = wx.Icon(ICONPATH + os.sep + APPICON, wx.BITMAP_TYPE_ICO)
        except:
            self.icon = None

        self.taskname = taskname
        self.datetime = strftime('%Y%m%d%H%M')
        self.edit = len(taskname)
        # new   ::= edit == 0, clone == False
        # clone ::= edit != 0, clone == True
        # edit  ::= edit != 0, clone == False
        if self.edit:
            if clone:
                self.task = self.config['Tasks'][taskname].dict()
                self.taskname = 'clone_of_task-' + taskname
            else:    
                self.task = self.config['Tasks'][taskname]
        else:            
            self.taskname = 'task-' + self.datetime
            self.task = initTaskExample()['Example']
            self.task['targetpath'] = config['Scan']['lasttarget']
        self.selectindex = len(self.task['exclude']) - 1
        sizer = wx.BoxSizer(wx.VERTICAL)
        row1 = wx.BoxSizer(wx.HORIZONTAL)
        self.nb = wx.Notebook(self, -1)
        row1.Add(self.nb) #, 1, wx.GROW | wx.ALL, GAP)        

        self.initTab1(background_color, clone)
        self.initTab2(background_color)
        self.initTab3(background_color)
        self.initTab4()
        self.initTab5()
        
        butok = wx.Button(self, wx.ID_OK, '&OK')
        self.Bind(wx.EVT_BUTTON, self.onOk, id = wx.ID_OK)
        butcancel = wx.Button(self, wx.ID_CANCEL, '&Cancel')
        self.Bind(wx.EVT_BUTTON, self.onCancel, id = wx.ID_CANCEL)
        
        row2 = wx.BoxSizer(wx.HORIZONTAL)
        row2.AddStretchSpacer()
        row2.Add(butok, 0, wx.GROW | wx.ALL, BORDER)
        row2.Add(butcancel, 0, wx.GROW | wx.ALL, BORDER)
        row2.AddStretchSpacer()

        sizer.Add(row1, 0, wx.GROW | LRT, BORDER)
        sizer.Add(row2, 0, wx.GROW | wx.LEFT | wx.RIGHT, BORDER)
        self.SetSizer(sizer)
        self.Fit()
        self.Center()
    #-------------------------------------------------------------------------------------------

    def initTab1(self, background_color, clone):
        page1 = wx.Panel(self.nb, -1)
        p1sizer = wx.BoxSizer(wx.VERTICAL)
        p1sz = wx.FlexGridSizer(1, 2, 0, 0)
        p1sz.AddGrowableCol(1)
        st = wx.StaticText(page1, -1, 'Task name: ')
        p1sz.Add(st, 0, wx.ALL, GAP)
        if self.edit and not clone:
            self.tcname = wx.TextCtrl(page1, self.ID_TC_NAME, self.taskname,
                                      style = wx.TE_READONLY)
            self.tcname.SetBackgroundColour(background_color)            
        else:
            self.tcname = wx.TextCtrl(page1, self.ID_TC_NAME, self.taskname)
        p1sz.Add(self.tcname, 0, wx.GROW | wx.ALL, GAP)                                                  
        p1sizer.Add(p1sz, 0, wx.GROW | LRT, BORDER)
        page1.SetSizer(p1sizer)
        self.nb.AddPage(page1, ' Task Id ')       
    #-------------------------------------------------------------------------------------------

    def initTab2(self, background_color):
        page2 = wx.Panel(self.nb, -1)
        p2sizer = wx.BoxSizer(wx.VERTICAL)  
        p2sz = wx.FlexGridSizer(4, 3, 0, 0)
        p2sz.AddGrowableCol(1)
        st = wx.StaticText(page2, -1, 'Source path: ')
        p2sz.Add(st, 0, wx.ALL, GAP)
        self.tcsource = wx.TextCtrl(page2, self.ID_TC_SOURCE, self.task['sourcepath'], style = wx.TE_READONLY)
        self.tcsource.SetBackgroundColour(background_color)
        p2sz.Add(self.tcsource, 1, wx.GROW | wx.ALL, GAP)
        self.btnsource = wx.Button(page2, self.ID_BTN_SOURCE, 'Browse') #, size = wx.Size(60,  -1))
        self.Bind(wx.EVT_BUTTON, self.onSource, id = self.ID_BTN_SOURCE)
        p2sz.Add(self.btnsource, 0, wx.ALL, GAP)
        st = wx.StaticText(page2, -1, 'Subdirs: ')
        p2sz.Add(st, 0, wx.ALL, GAP)
        self.cbi = wx.CheckBox(page2, self.ID_CB_INCLUDE, ' (if checked - include subdirs)') 
        p2sz.Add(self.cbi, 0, wx.ALL, GAP)
        self.Bind(wx.EVT_CHECKBOX, self.onCheckInclude, id = self.ID_CB_INCLUDE)
        self.cbi.SetValue(self.task['subinclude'] == 'True')
        p2sz.AddStretchSpacer()
        st = wx.StaticText(page2, -1, 'Target path: ')
        p2sz.Add(st, 0, wx.ALL, GAP)
        self.tctarget = wx.TextCtrl(page2, self.ID_TC_TARGET, self.task['targetpath'], style = wx.TE_READONLY)
        self.tctarget.SetBackgroundColour(background_color)
        p2sz.Add(self.tctarget, 1, wx.GROW | wx.ALL, GAP)
        self.btntarget = wx.Button(page2, self.ID_BTN_TARGET, 'Browse') # , size = wx.Size(60,  -1))
        self.Bind(wx.EVT_BUTTON, self.onTarget, id = self.ID_BTN_TARGET)
        p2sz.Add(self.btntarget, 0, wx.ALL, GAP)
        st = wx.StaticText(page2, -1, 'Override: ')
        p2sz.Add(st, 0, wx.ALL, GAP)       
        self.cbo = wx.CheckBox(page2, self.ID_CB_OVERRIDE, ' (if checked - no override target warning)') 
        p2sz.Add(self.cbo, 0, wx.ALL, GAP)
        self.Bind(wx.EVT_CHECKBOX, self.onCheckOverride, id = self.ID_CB_OVERRIDE)
        self.cbo.SetValue(self.task['override'] == 'True')
        p2sizer.Add(p2sz, 0, wx.GROW | LRT, BORDER)        
        page2.SetSizer(p2sizer)
        self.nb.AddPage(page2, ' Paths ')
    #-------------------------------------------------------------------------------------------

    def initTab3(self, background_color):
        page3 = wx.Panel(self.nb, -1)
        p3sizer = wx.BoxSizer(wx.VERTICAL)  
        p3sz = wx.FlexGridSizer(3, 1, 0, 0)
        p3sz.AddGrowableCol(0)
        self.msgtext = wx.StaticText(page3, -1, "Example: the coloured dirs / files are matched by one or more valid exclude re's")
        font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
        self.msgtext.SetFont(font)
        p3sz.Add(self.msgtext, 0, wx.GROW | wx.ALL, GAP)
        self.tlb = wx.TextCtrl(page3, -1, size = wx.Size(-1, 170),
                               style = wx.TE_RICH | wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP)
        p3sz.Add(self.tlb, 0, wx.EXPAND | wx.ALL, GAP)
        self.updateExamples()
        self.colourizeList()        
        self.lc = wx.ListCtrl(page3, self.ID_LC_REGEXP, size = wx.Size(-1, 100),
                              style = wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_SINGLE_SEL)
        p3sz.Add(self.lc, 0, wx.EXPAND | wx.ALL, GAP)
        self.lc.InsertColumn(0, 'Exclude regular expression', width = 380)
        self.lc.InsertColumn(1, 'Status', width = 60)
        self.updateListCtrl()
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onSelected)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.onEdit)        
        self.msgtext = wx.StaticText(page3, -1, self.NOEDITMSG)
        font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
        self.msgtext.SetFont(font)
        p3sz.Add(self.msgtext, 0, wx.GROW | wx.ALL, GAP)
        self.tcexmask = wx.TextCtrl(page3, self.ID_TC_EXMASK, style = wx.TE_PROCESS_ENTER | wx.TE_READONLY)
        self.tcexmask.SetBackgroundColour(background_color)
        p3sz.Add(self.tcexmask, 0, wx.GROW | wx.ALL, GAP)
        self.Bind(wx.EVT_TEXT_ENTER, self.onTextEnter, id = self.ID_TC_EXMASK)
        p3sizer.Add(p3sz, 0, wx.GROW | LRT, BORDER)

        butadd = wx.Button(page3, wx.ID_ADD)
        butadddir = wx.Button(page3, self.ID_BTN_ADDDIR, 'Add &dir')
        butedit = wx.Button(page3, wx.ID_EDIT)
        butrem = wx.Button(page3, wx.ID_REMOVE)
        buthelp = wx.Button(page3, wx.ID_HELP)
        self.Bind(wx.EVT_BUTTON, self.onButtonAdd, id = wx.ID_ADD)
        self.Bind(wx.EVT_BUTTON, self.onButtonAddDir, id = self.ID_BTN_ADDDIR)
        self.Bind(wx.EVT_BUTTON, self.onEdit, id = wx.ID_EDIT)
        self.Bind(wx.EVT_BUTTON, self.onButtonRem, id = wx.ID_REMOVE)
        self.Bind(wx.EVT_BUTTON, self.onButtonHelp, id = wx.ID_HELP)

        butsz = wx.BoxSizer(wx.HORIZONTAL)
        butsz.Add(butadd, 1, wx.GROW | wx.ALL, GAP)
        butsz.Add(butadddir, 1, wx.GROW | wx.ALL, GAP)
        butsz.Add(butedit, 1, wx.GROW | wx.ALL, GAP)
        butsz.Add(butrem, 1, wx.GROW | wx.ALL, GAP)
        butsz.Add(buthelp, 1, wx.GROW | wx.ALL, GAP)

        p3sizer.Add(butsz, 0, wx.GROW | wx.LEFT | wx.RIGHT, BORDER)
        page3.SetSizer(p3sizer)
        self.nb.AddPage(page3, " Exclude re's")
    #-------------------------------------------------------------------------------------------

    def initTab4(self):
        page4 = wx.Panel(self.nb, -1)
        p4sizer = wx.BoxSizer(wx.VERTICAL)         
        p4sz = wx.FlexGridSizer(5, 1, 0, 0)
        self.rbm1 = wx.RadioButton(page4, self.ID_RB_NONE, 'no compression, just copy files', style = wx.RB_GROUP)
        p4sz.Add(self.rbm1, 0, 0, 0)
        self.Bind(wx.EVT_RADIOBUTTON, self.onRadioCompr, id = self.ID_RB_NONE)
        self.compr = self.task['comprmeth'] in ['tar', 'tar.gz', 'tar.bz2', 'zip']
        self.rbm1.SetValue(not self.compr)
        self.rbm2 = wx.RadioButton(page4, self.ID_RB_TAR, 'tape archive (tar)')
        p4sz.Add(self.rbm2, 0, 0, 0)
        self.Bind(wx.EVT_RADIOBUTTON, self.onRadioCompr, id = self.ID_RB_TAR)
        self.rbm2.SetValue(self.task['comprmeth'] == 'tar')
        self.rbm3 = wx.RadioButton(page4, self.ID_RB_TARGZ, 'zipped tape archive (tar.gz)')
        p4sz.Add(self.rbm3, 0, 0, 0)
        self.Bind(wx.EVT_RADIOBUTTON, self.onRadioCompr, id = self.ID_RB_TARGZ)
        self.rbm3.SetValue(self.task['comprmeth'] == 'tar.gz')
        self.rbm4 = wx.RadioButton(page4, self.ID_RB_TARBZ2, 'zipped tape archive (tar.bz2)')
        p4sz.Add(self.rbm4, 0, 0, 0)
        self.Bind(wx.EVT_RADIOBUTTON, self.onRadioCompr, id = self.ID_RB_TARBZ2)
        self.rbm4.SetValue(self.task['comprmeth'] == 'tar.bz2')
        self.rbm5 = wx.RadioButton(page4, self.ID_RB_ZIP, 'zip archive (zip)')
        p4sz.Add(self.rbm5, 0, 0, 0)
        self.Bind(wx.EVT_RADIOBUTTON, self.onRadioCompr, id = self.ID_RB_ZIP)
        self.rbm5.SetValue(self.task['comprmeth'] == 'zip')

        p4sizer.Add(p4sz, 0, wx.GROW | LRT, BORDER)
        page4.SetSizer(p4sizer)
        self.nb.AddPage(page4, ' Compression ')
    #-------------------------------------------------------------------------------------------

    def initTab5(self):
        page5 = wx.Panel(self.nb, -1)
        p5sizer = wx.BoxSizer(wx.VERTICAL)  
        p5sz = wx.FlexGridSizer(3, 2, 0, 0)
        p5sz.AddGrowableCol(1)
        st = wx.StaticText(page5, -1, 'Time stamp:')
        p5sz.Add(st, 0, wx.ALL, GAP)
        self.cbts = wx.CheckBox(page5, self.ID_CB_TS, ' (i.e.: %s)' % (self.datetime)) 
        p5sz.Add(self.cbts, 0, wx.ALL, GAP)
        self.Bind(wx.EVT_CHECKBOX, self.onCheckTimeSt, id = self.ID_CB_TS)
        self.cbts.SetValue(self.task['timestamp'] == 'True')
        st = wx.StaticText(page5, -1, 'Append: ')
        p5sz.Add(st, 0, wx.ALL, GAP)
        self.rbts1 = wx.RadioButton(page5, self.ID_RB_TS1, ' (format: archivename-yyyymmddhhmm)     ', style = wx.RB_GROUP)
        p5sz.Add(self.rbts1, 0, 0, 0)
        self.Bind(wx.EVT_RADIOBUTTON, self.onRadioTs, id = self.ID_RB_TS1)
        self.rbts1.SetValue(self.task['tsappend'] == 'True')
        st = wx.StaticText(page5, -1, 'Prepend: ')
        p5sz.Add(st, 0, wx.ALL, GAP)
        self.rbts2 = wx.RadioButton(page5, self.ID_RB_TS2, ' (format: yyyymmddhhmm-archivename)')
        p5sz.Add(self.rbts2, 0, 0, 0)
        self.Bind(wx.EVT_RADIOBUTTON, self.onRadioTs, id = self.ID_RB_TS2)
        self.rbts2.SetValue(self.task['tsappend'] == 'False')
        p5sz.AddStretchSpacer()        
        if not self.compr: self.cbts.Enable(False)
        if not self.compr or self.task['timestamp'] == 'False':
            self.rbts1.Enable(False)
            self.rbts2.Enable(False)
        p5sizer.Add(p5sz, 0, wx.GROW | LRT, BORDER)
        page5.SetSizer(p5sizer)
        self.nb.AddPage(page5, ' Misc ')       
    #-------------------------------------------------------------------------------------------

    def onButtonAdd(self, event):
        self.tcexmask.SetEditable(False)
        self.msgtext.SetLabel(self.NOEDITMSG)
        font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
        self.msgtext.SetFont(font)
        self.tcexmask.Clear()
        self.tcexmask.WriteText('(.*)~')
        self.task['exclude'].append('(.*)~')
        self.selectindex = len(self.task['exclude']) - 1
        self.updateListCtrl()
        self.onEdit()
    #-------------------------------------------------------------------------------------------

    def onButtonAddDir(self, event):
        self.tcexmask.SetEditable(False)
        self.msgtext.SetLabel(self.NOEDITMSG)
        font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
        self.msgtext.SetFont(font)        
        dlg = DirDialog(self, TITLE + ' - select exclude dir', self.task['sourcepath'],
                        self.parent.config['Misc']['hiddendirs'] == 'True', False)
        if dlg.ShowModal() == wx.ID_OPEN:
            path = dlg.GetPath().replace('\\', '/')
            mask = path + '/(.*)'
        else:
            return
        dlg.Destroy()

        self.task['exclude'].append(mask)
        self.selectindex = len(self.task['exclude']) - 1
        self.updateListCtrl()
        self.onEdit()
    #-------------------------------------------------------------------------------------------

    def onButtonHelp(self, event):
        #try:
        #    self.rehelpwindow.Show()
        #    self.rehelpwindow.Iconize(False)
        #except:
        #    self.rehelpwindow = stomahelp.HelpFrame(self, self.icon, APPPATH, 're-syntax.html')
        #    self.rehelpwindow.Show()        
        webbrowser.open(os.path.join(APPPATH, 're-syntax.html'))  
    #-------------------------------------------------------------------------------------------

    def updateExamples(self):    
        sourcepath = self.tcsource.GetValue()
        self.expdirlist = []
        try:
            dirlist = os.listdir(sourcepath)
            dirlist.sort()
            for item in dirlist:
                self.expdirlist.append(os.path.join(sourcepath, item))
        except:
            pass
    #-------------------------------------------------------------------------------------------

    def colourizeList(self):
        self.tlb.Clear()
        parsers = []
        for mask in self.task['exclude']:
            if len(mask):
                if mask.endswith('/(.*)'):
                    mask = mask.replace('/(.*)', '')
                mask = mask.replace('+', '\\+')
                try:
                    p = re.compile(mask)
                    parsers.append(p)
                except:
                    pass

        for pathname in self.expdirlist:
            if not LINUX:
                pathname = pathname.replace('\\', '/')
            match = False
            for parser in parsers:
                if parser.search(pathname): 
                    match = True
                    break
            start = self.tlb.GetInsertionPoint()
            self.tlb.WriteText('%s\n' % (pathname))
            stop = self.tlb.GetLastPosition()   # GetInsertionPoint() - 1
            if match:
                self.tlb.SetStyle(start, stop, wx.TextAttr(BLACK, self.hlcolor))
    #-------------------------------------------------------------------------------------------

    def updateListCtrl(self):
        self.lc.DeleteAllItems()
        for i, item in enumerate(self.task['exclude']):
            self.lc.InsertStringItem(i, item)
            try:
                re.compile(item)
                self.lc.SetStringItem(i, 1, 'valid')
            except:
                self.lc.SetItemTextColour(i, wx.RED)
                self.lc.SetStringItem(i, 1, 'error')
#        x, y = self.lc.GetSizeTuple()                # fix for win32
#        self.lc.SetColumnWidth(0, x + 10)            # fix for win32
#        self.lc.SetColumnWidth(0, wx.LIST_AUTOSIZE)  # does not work
        listitem = self.lc.GetItem(self.selectindex)
        listitem.SetState(wx.LIST_STATE_SELECTED)
        self.lc.SetItem(listitem)
    #-------------------------------------------------------------------------------------------

    def onSelected(self, event):
        selectindex = event.GetIndex()
        if selectindex >= 0:
            self.selectindex = selectindex
            self.tcexmask.Clear()
            self.tcexmask.SetEditable(False)
            self.msgtext.SetLabel(self.NOEDITMSG)
            font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
            self.msgtext.SetFont(font)
    #-------------------------------------------------------------------------------------------

    def onEdit(self, event = None):
        self.tcexmask.Clear()
        self.tcexmask.WriteText(self.task['exclude'][self.selectindex])
        self.tcexmask.SetEditable(True)
        self.tcexmask.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
        self.msgtext.SetLabel(self.EDITMSG)
        font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
        self.msgtext.SetFont(font)        
        self.tcexmask.SetFocusFromKbd()
        self.tcexmask.SetInsertionPointEnd()
    #-------------------------------------------------------------------------------------------

    def onTextEnter(self, event):
        self.task['exclude'][self.selectindex] = self.tcexmask.GetValue().strip()
        self.updateListCtrl()
        self.tcexmask.SetEditable(False)
        self.tcexmask.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
        self.tcexmask.Clear()
        self.msgtext.SetLabel(self.NOEDITMSG)
        font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
        self.msgtext.SetFont(font)        
        self.lc.SetFocus()
        self.colourizeList()
    #-------------------------------------------------------------------------------------------

    def onButtonRem(self, event):
        self.tcexmask.SetEditable(False)
        self.msgtext.SetLabel(self.NOEDITMSG)
        font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
        self.msgtext.SetFont(font)        
        if self.selectindex != - 1:
            del self.task['exclude'][self.selectindex]
            self.tcexmask.Clear()            
            self.selectindex = len(self.task['exclude']) - 1
            self.updateListCtrl()
        self.colourizeList()    
    #-------------------------------------------------------------------------------------------

    def onSource(self, event):
        dlg = DirDialog(self, TITLE + ' - select sourcepath', self.task['sourcepath'],
                        self.parent.config['Misc']['hiddendirs'] == 'True', False)
        if dlg.ShowModal() == wx.ID_OPEN:
            path = os.path.normpath(dlg.GetPath())
            self.task['sourcepath'] = path
            self.tcsource.SetValue(path)
            if path == '/':
                if '/proc/(.*)' not in self.task['exclude']:
                    self.task['exclude'].append('/proc/(.*)')
                    self.updateListCtrl()
                    dlg = wx.MessageDialog(self, "You have choosen '/' as source path! For security reasons\n'/proc/(.*)' has been added to the Exclude re's list.",
                                   TITLE + ' - New / Edit backup task', wx.OK | wx.ICON_INFORMATION)
                    dlg.ShowModal()
                    dlg.Destroy()
        dlg.Destroy()
        self.updateExamples()
        self.colourizeList()
    #-------------------------------------------------------------------------------------------

    def onTarget(self, event):
        dlg = DirDialog(self, TITLE + ' - select targetpath', self.task['targetpath'],
                        self.parent.config['Misc']['hiddendirs'] == 'True', True)
        if dlg.ShowModal() == wx.ID_OPEN:
            path = os.path.normpath(dlg.GetPath())
            self.task['targetpath'] = path
            self.tctarget.SetValue(path)
        dlg.Destroy()
    #-------------------------------------------------------------------------------------------

    def onCheckInclude(self, event):
        self.task['subinclude'] = str(self.cbi.GetValue())
    #-------------------------------------------------------------------------------------------

    def onCheckOverride(self, event):
        self.task['override'] = str(self.cbo.GetValue())
    #-------------------------------------------------------------------------------------------

    def onRadioCompr(self, event):
        if self.rbm2.GetValue():
            self.task['comprmeth'] = 'tar'
        elif self.rbm3.GetValue():
            self.task['comprmeth'] = 'tar.gz'
        elif self.rbm4.GetValue():
            self.task['comprmeth'] = 'tar.bz2'
        elif self.rbm5.GetValue():
            self.task['comprmeth'] = 'zip'
        else:
            self.task['comprmeth'] = 'no compression'
        self.compr = self.task['comprmeth'] != 'no compression'
        if self.compr:
            self.cbts.Enable(True)
            self.rbts1.Enable(True)
            self.rbts2.Enable(True)
        else:
            self.cbts.Enable(False)
            self.rbts1.Enable(False)
            self.rbts2.Enable(False)            
    #-------------------------------------------------------------------------------------------

    def onCheckTimeSt(self, event):
        timestamp = self.cbts.GetValue()
        self.task['timestamp'] = str(timestamp)
        self.rbts1.Enable(timestamp)
        self.rbts2.Enable(timestamp)
    #-------------------------------------------------------------------------------------------

    def onRadioTs(self, event):
        self.task['tsappend'] = str(self.rbts1.GetValue())
    #-------------------------------------------------------------------------------------------

    def restoreTimer(self):
        if self.timerstate:
            self.jobtimer.Start(JOB_TIME_SLICE)
    #-------------------------------------------------------------------------------------------
            
    def onCancel(self, event):
        self.config.reload()      # read old values
        self.restoreTimer()   
        event.Skip()
    #-------------------------------------------------------------------------------------------

    def onOk(self, event):     
        if self.parent.config['Tasks'].has_key(self.tcname.GetValue()) and not self.edit:
            dlg = wx.MessageDialog(self, "The choosen taskname already exists!\nPlease use a different taskname.",
                                   TITLE + ' - New / Edit backup task', wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            self.restoreTimer() 
            return
        else:
            self.restoreTimer() 
            event.Skip()
    #-------------------------------------------------------------------------------------------

    def getValues(self):
        return self.task, self.tcname.GetValue()
# - class EditTaskDialog(wx.Dialog):---------------------------------------------------------------

  
class TasksManDialog(wx.Dialog):
    
    ID_CLONE = wx.NewId()
    
    def __init__(self, parent, updateJobwin, writeToLogwin, config, jobtimer, index = 0):        
        """  add, edit or remove backup tasks """
        wx.Dialog.__init__(self, parent, -1, TITLE + ' - Manage backup tasks',                           
                           style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
        self.Bind(wx.EVT_CLOSE, self.onButtonClose)
        self.Bind(wx.EVT_RIGHT_DOWN, self.onContext)
        self.config = config
        self.jobtimer = jobtimer
        self.parent = parent
        self.updateJobwin = updateJobwin
        self.writeToLogwin = writeToLogwin
        sizer = wx.BoxSizer(wx.VERTICAL)
        gbsz = wx.GridBagSizer(BORDER, BORDER)      
        
        sb = wx.StaticBox(self, -1, ' Existing backup tasks ')
        col1 = wx.StaticBoxSizer(sb, wx.HORIZONTAL)
        self.tasklist = wx.ListBox(self, -1, size = wx.Size(155, -1),
                                   style = wx.LB_SINGLE | wx.LB_HSCROLL)
        col1.Add(self.tasklist, 1, wx.GROW | wx.ALL, GAP)
        self.Bind(wx.EVT_LISTBOX, self.onClickTask)
        self.Bind(wx.EVT_LISTBOX_DCLICK, self.onButtonEdit)
        self.tasklist.Bind(wx.EVT_RIGHT_DOWN, self.onContext)
        gbsz.Add(col1, wx.GBPosition(0, 0), wx.GBSpan(1, 1), wx.GROW)

        sb = wx.StaticBox(self, -1, ' Task info ')
        col2 = wx.StaticBoxSizer(sb, wx.HORIZONTAL)
        self.ti = wx.ListCtrl(self, -1, style = wx.LC_REPORT | wx.LC_NO_HEADER | \
                              wx.LC_SINGLE_SEL | wx.LC_HRULES | wx.BORDER_SUNKEN)
        self.ti.Bind(wx.EVT_RIGHT_DOWN, self.onContext)
        self.ti.InsertColumn(0, '')
        self.ti.InsertColumn(1, '')
        if len(self.config['Tasks']):
            tasknames = self.config['Tasks'].keys()
            self.onClickTask(None, tasknames[0])                
        col2.Add(self.ti, 2, wx.GROW | wx.ALL, GAP)
        gbsz.Add(col2, wx.GBPosition(0, 1), wx.GBSpan(1, 2), wx.GROW)
                
        butnew = wx.Button(self, wx.ID_NEW)
        butedit = wx.Button(self, wx.ID_EDIT)
        butclone = wx.Button(self, self.ID_CLONE, 'C&lone')
        butrem = wx.Button(self, wx.ID_REMOVE)
        butclear = wx.Button(self, wx.ID_CLEAR)
        butclose = wx.Button(self, wx.ID_CLOSE)
        self.Bind(wx.EVT_BUTTON, self.onButtonClose, id = wx.ID_CLOSE)
        self.Bind(wx.EVT_BUTTON, self.onButtonNew, id = wx.ID_NEW)
        self.Bind(wx.EVT_BUTTON, self.onButtonClone, id = self.ID_CLONE)
        self.Bind(wx.EVT_BUTTON, self.onButtonRem, id = wx.ID_REMOVE)
        self.Bind(wx.EVT_BUTTON, self.onButtonEdit, id = wx.ID_EDIT)
        self.Bind(wx.EVT_BUTTON, self.onButtonClear, id = wx.ID_CLEAR)
        row2 = wx.BoxSizer(wx.HORIZONTAL)
        row2.Add(butnew, 1, wx.GROW | wx.RIGHT, GAP)
        row2.Add(butedit, 1, wx.GROW | wx.LEFT | wx.RIGHT, GAP)
        row2.Add(butclone, 1, wx.GROW | wx.LEFT | wx.RIGHT, GAP)
        row2.Add(butrem, 1, wx.GROW | wx.LEFT | wx.RIGHT, GAP)
        row2.Add(butclear, 1, wx.GROW | wx.LEFT | wx.RIGHT, GAP)
        row2.Add(butclose, 1, wx.GROW | wx.LEFT, GAP)
        gbsz.Add(row2, wx.GBPosition(1, 0), wx.GBSpan(1, 3), wx.GROW)
       
        gbsz.AddGrowableCol(0)
        gbsz.AddGrowableCol(1)
        gbsz.AddGrowableRow(0)

        sizer.Add(gbsz, 1, wx.GROW | wx.ALL, BORDER)
        self.SetMinSize(wx.Size(640, 480))
        self.SetSizer(sizer)
        self.Fit()
        self.Centre()

        self.initContextMenu()
        self.updateKeys()
        try:
            self.tasklist.Select(index)
            self.onClickTask(None, self.tasknames[index])  
        except:
            pass
    #-------------------------------------------------------------------------------------------

    def initContextMenu(self):
        self.popupID0 = wx.NewId()  
        self.popupID1 = wx.NewId()          
        self.popupID2 = wx.NewId()
        self.popupID3 = wx.NewId()
        self.popupID4 = wx.NewId()
        self.popupID5 = wx.NewId()
        
        self.Bind(wx.EVT_MENU, self.onButtonNew, id = self.popupID0)
        self.Bind(wx.EVT_MENU, self.onButtonEdit, id = self.popupID1)
        self.Bind(wx.EVT_MENU, self.onButtonClone, id = self.popupID2)
        self.Bind(wx.EVT_MENU, self.onButtonRem, id = self.popupID3)
        self.Bind(wx.EVT_MENU, self.onButtonClear, id = self.popupID4)
        self.Bind(wx.EVT_MENU, self.onButtonClose, id = self.popupID5)
    #-------------------------------------------------------------------------------------------

    def onContext(self, event):
        """ context menu handler """
        menu = wx.Menu()
        menu.Append(self.popupID0, 'New task')
        menu.Append(self.popupID1, 'Edit task')
        menu.Append(self.popupID2, 'Clone task')
        menu.Append(self.popupID3, 'Remove task')
        menu.Append(self.popupID4, 'Clear tasks')
        menu.AppendSeparator()   
        menu.Append(self.popupID5, 'Close dialog')
        self.PopupMenu(menu)
        menu.Destroy()
    #-------------------------------------------------------------------------------------------      

    def onClickTask(self, event = None, taskname = ''):
        self.ti.DeleteAllItems()
        if len(self.config['Tasks']) == 0: return
        if event != None:
            taskname = event.GetString()
        if (len(taskname) == 0):
            taskname = self.tasknames[0]

        taskdata = self.config['Tasks'][taskname]
          
        self.ti.InsertStringItem(0, 'Task name:')
        self.ti.InsertStringItem(1, '')
        self.ti.InsertStringItem(2, 'Source path:')
        self.ti.InsertStringItem(3, 'Include subdirs:')
        self.ti.InsertStringItem(4, 'Target path:')
        self.ti.InsertStringItem(5, 'Override target content:')
        self.ti.InsertStringItem(6, '')
        self.ti.InsertStringItem(7, 'Compression methode:')
        self.ti.InsertStringItem(8, '')
        self.ti.InsertStringItem(9, 'Time stamp:')
        self.ti.InsertStringItem(10, 'Append Ts:')
        self.ti.InsertStringItem(11, 'Exclude reg exp list:')
        i = 12
        while i < 11 + len(taskdata['exclude']):
            self.ti.InsertStringItem(i, '')
            i += 1
        self.ti.InsertStringItem(i, '')
        i += 1
        self.ti.InsertStringItem(i, 'Last time executed at:')
        self.ti.SetColumnWidth(0, wx.LIST_AUTOSIZE)
       
        self.ti.SetStringItem(0, 1, taskname)
        self.ti.SetStringItem(2, 1, taskdata['sourcepath'])
        self.ti.SetStringItem(3, 1, taskdata['subinclude'])
        self.ti.SetStringItem(4, 1, taskdata['targetpath'])
        self.ti.SetStringItem(5, 1, taskdata['override'])
        self.ti.SetStringItem(7, 1, taskdata['comprmeth'])
        self.ti.SetStringItem(9, 1, taskdata['timestamp'])        
        self.ti.SetStringItem(10, 1, taskdata['tsappend'])
        index = 11
        if len(taskdata['exclude']):
            for item in taskdata['exclude']:
                self.ti.SetStringItem(index, 1, item)
                index += 1
        else:
            self.ti.SetStringItem(index, 1, '---')
            index += 1
        index += 1
        if taskdata['lastrun'].startswith('2000'):
            self.ti.SetStringItem(index, 1, 'never')
        else:
            self.ti.SetStringItem(index, 1, taskdata['lastrun'])
        self.ti.SetColumnWidth(1, wx.LIST_AUTOSIZE)
    #-------------------------------------------------------------------------------------------

    def removeTaskFromJob(self, taskname, doit):
        affected = []
        for jobname in self.config['Jobs'].keys():
            jobdata = self.config['Jobs'][jobname]
            if taskname in jobdata['tasklist']:
                affected.append(jobname)
                if doit:
                    jobdata['tasklist'].remove(taskname)
                    jobdata['taskcount'] = str(len(jobdata['tasklist']))
        return affected
    #-------------------------------------------------------------------------------------------
        
    def onButtonClone(self, event):
        taskids = self.tasklist.GetSelections()       
        if len(taskids):
            taskname = self.tasklist.GetString(taskids[0])                       
            dlg = EditTaskDialog(self, self.config, self.jobtimer, taskname, True)        
            if dlg.ShowModal() == wx.ID_OK:
                task, taskname = dlg.getValues()
                self.config['Tasks'][taskname] = task
                self.writeToLogwin('Backup tasks - 1 task (%s) added to list' % (taskname))
                self.updateKeys()
                self.onClickTask(taskname = taskname)            
            dlg.Destroy()
            self.tasklist.Select(self.tasknames.index(taskname))
        else:
            try:
                self.tasklist.Select(0)
            except:
                pass            
        self.Layout()
    #-------------------------------------------------------------------------------------------

    def onButtonClear(self, event):
        tasknames = self.tasklist.GetStrings()
        notwarned = True
        if len(tasknames):
            for taskname in tasknames:
                affected = self.removeTaskFromJob(taskname, False)
                if len(affected):
                    if notwarned:
                        notwarned = False
                        msg = 'This task is assigned to the following jobs:\n\n'
                        for item in affected:
                            msg = msg + item + '\n'
                        dlg = wx.MessageDialog(self, msg + '\nDelete task and remove from jobs anyway?',
                                               TITLE + ' - selected task deletion',
                                               wx.YES | wx.NO | wx.ICON_QUESTION)
                        if dlg.ShowModal() != wx.ID_YES:
                            return
                        else:
                            dummy = self.removeTaskFromJob(taskname, True)
                    else:
                        dummy = self.removeTaskFromJob(taskname, True)
                del self.config['Tasks'][taskname]
            self.updateKeys()
            self.ti.DeleteAllItems()
        self.updateKeys()
        self.onClickTask()   
        self.writeToLogwin('Backup tasks - all tasks removed from list', RED)
        self.Layout()
    #-------------------------------------------------------------------------------------------

    def onButtonClose(self, event):
        self.Destroy()
    #-------------------------------------------------------------------------------------------
        
    def onButtonNew(self, event):
        dlg = EditTaskDialog(self, self.config, self.jobtimer)
        taskname = ''
        if dlg.ShowModal() == wx.ID_OK:
            task, taskname = dlg.getValues()
            self.config['Tasks'][taskname] = task
            self.writeToLogwin('Backup tasks - 1 task (%s) added to list' % (taskname))
            self.updateKeys()
            self.onClickTask(taskname = taskname)            
        dlg.Destroy()
        if taskname:
            self.tasklist.Select(self.tasknames.index(taskname))
        else:
            try:
                self.tasklist.Select(0)
            except:
                pass            
        self.Layout()
    #-------------------------------------------------------------------------------------------

    def onButtonRem(self, event = None):
        taskids = self.tasklist.GetSelections()
        if len(taskids):
            taskname = self.tasklist.GetString(taskids[0])
            affected = self.removeTaskFromJob(taskname, False)
            doit = True
            if len(affected):
                msg = 'This task is assigned to the following job(s):\n\n'
                for item in affected: msg = msg + "'" + item + "'\n"
                dlg = wx.MessageDialog(self, msg + '\nDelete task and remove from job(s) anyway?',
                                       TITLE + ' - selected task deletion',
                                       wx.YES | wx.NO | wx.ICON_QUESTION)
                if dlg.ShowModal() != wx.ID_YES:
                    doit = False
            if doit:
                self.removeTaskFromJob(taskname, True)                  
                del self.config['Tasks'][taskname]
                self.writeToLogwin("Backup tasks - task '%s' removed from list" % (taskname))
                self.updateKeys()
                self.ti.DeleteAllItems()
                self.onClickTask()
        else:
            self.writeToLogwin("Backup tasks - there is no task to remove")
        try:
            self.tasklist.Select(0)
        except:
            pass            
        self.Layout()        
    #-------------------------------------------------------------------------------------------
            
    def onButtonEdit(self, event):
        taskids = self.tasklist.GetSelections()
        if len(taskids):
            taskname = self.tasklist.GetString(taskids[0])
            dlg = EditTaskDialog(self, self.config, self.jobtimer, taskname)
            if dlg.ShowModal() == wx.ID_OK:
                task, taskname = dlg.getValues()
                self.config['Tasks'][taskname] = task
            dlg.Destroy()
            self.updateKeys()
            self.onClickTask(taskname = taskname)
            self.tasklist.Select(self.tasknames.index(taskname))
            self.Layout()
    #-------------------------------------------------------------------------------------------

    def updateKeys(self):
        self.tasknames = self.config['Tasks'].keys()
        self.tasknames.sort()
        self.tasklist.Set(self.tasknames)
        self.updateJobwin() 
# - class BackupTasksDialog(wx.Dialog):---------------------------------------------------------------


if __name__ == '__main__':
    app = wx.PySimpleApp()
    dlg = DirDialog(None, TITLE + ' - select sourcepath', os.sep, createdir = True)
    if dlg.ShowModal() == wx.ID_OK: 
        #dlg = DirDialog(self, TITLE + ' - select sourcepath', self.task['sourcepath'], self.parent.config['Misc']['hiddendirs'] == 'True')
        #if dlg.ShowModal() == wx.ID_OPEN:
            path = os.path.normpath(dlg.GetPath())
            print path
            
    dlg.Destroy()
    app.MainLoop()