# -*- coding: utf-8 -*-
#
# This file is part of EventGhost.
# Copyright (C) 2005-2009 Lars-Peter Voss <bitmonster@eventghost.org>
#
# EventGhost is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 2 as published by the
# Free Software Foundation;
#
# EventGhost is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import eg
import wx
import string
from types import StringTypes


class Text(eg.TranslatableStrings):
    title = "Find"
    searchLabel = "Fi&nd what:"
    wholeWordsOnly = "Match &whole word only"
    caseSensitive = "&Match case"
    searchParameters = "Search action parameters also"
    direction = "Direction"
    findButton = "&Find Next"
    up = "&Up"
    down = "&Down"
    notFoundMesg = '"%s" couldn\'t be found.'



class FindDialog(wx.Dialog):

    def __init__(self, parent, document):
        wx.Dialog.__init__(
            self,
            parent,
            -1,
            title = Text.title,
            style = wx.DEFAULT_DIALOG_STYLE
        )
        self.parent = parent
        self.choices = [""]
        textCtrl = wx.TextCtrl(self)
        wholeWordsOnlyCb = wx.CheckBox(self, -1, Text.wholeWordsOnly)
        caseSensitiveCb = wx.CheckBox(self, -1, Text.caseSensitive)
        searchParametersCb = wx.CheckBox(self, -1, Text.searchParameters)
        searchParametersCb.SetValue(1)
        directionRb = wx.RadioBox(
            self,
            label = Text.direction,
            choices = [Text.up, Text.down],
            style = wx.RA_SPECIFY_ROWS
        )
        directionRb.SetSelection(1)
        searchButton = wx.Button(self, -1, Text.findButton)
        searchButton.SetDefault()
        searchButton.Enable(False)
        cancelButton = wx.Button(self, wx.ID_CANCEL, eg.text.General.cancel)

        acv = wx.ALIGN_CENTER_VERTICAL
        upperLeftSizer = eg.HBoxSizer(
            (wx.StaticText(self, -1, Text.searchLabel), 0, acv|wx.RIGHT, 5),
            (textCtrl, 1, wx.EXPAND),
        )
        cbSizer = eg.VBoxSizer(
            (wholeWordsOnlyCb),
            (caseSensitiveCb, 0, wx.TOP, 5),
            (searchParametersCb, 0, wx.TOP, 5),
        )
        lowerLeftSizer = eg.HBoxSizer(
            (cbSizer, 0, acv|wx.RIGHT, 10),
            (directionRb),
        )
        leftSizer = eg.VBoxSizer(
            (upperLeftSizer, 0, wx.EXPAND|wx.ALL, 5),
            (lowerLeftSizer, 0, wx.EXPAND|wx.ALL, 5),
        )
        btnSizer = eg.VBoxSizer(
            (searchButton, 0, wx.EXPAND),
            (cancelButton, 0, wx.EXPAND|wx.TOP, 5),
        )
        sizer = eg.HBoxSizer(
            (leftSizer, 1, wx.EXPAND),
            (btnSizer, 0, wx.EXPAND|wx.ALL, 5),
        )
        self.SetSizerAndFit(sizer)
        self.SetMinSize(self.GetSize())

        searchButton.Bind(wx.EVT_BUTTON, self.OnFindButton)
        def EnableSearchButton(event):
            enable = textCtrl.GetValue() != ""
            searchButton.Enable(enable)
        textCtrl.Bind(wx.EVT_TEXT, EnableSearchButton)

        self.textCtrl = textCtrl
        self.wholeWordsOnlyCb = wholeWordsOnlyCb
        self.caseSensitiveCb = caseSensitiveCb
        self.searchParametersCb = searchParametersCb
        self.directionRb = directionRb
        self.searchButton = searchButton
        #self.Bind(wx.EVT_CLOSE, self.OnCancel)
        #cancelButton.Bind(wx.EVT_BUTTON, self.OnCancel)


    def Show(self):
        self.CenterOnParent()
        eg.Utils.EnsureVisible(self)
        wx.Dialog.Show(self)
        self.Raise()
        self.textCtrl.SetSelection(-1, -1)
        self.textCtrl.SetFocus()


    @eg.LogIt
    def OnCancel(self, event):
        self.Destroy()


    def OnFindButton(self, event=None):
        item = self.parent.treeCtrl.GetSelectedNode()
        startItem = item
        originalSearchValue = self.textCtrl.GetValue()
        if self.caseSensitiveCb.GetValue():
            convertFunc = lambda s: s
            key = originalSearchValue
        else:
            convertFunc = string.lower
            key = originalSearchValue.lower()

        if self.directionRb.GetSelection():
            iterFunc = eg.TreeItem.GetNextItem
        else:
            iterFunc = eg.TreeItem.GetPreviousItem
        ActionItem = eg.ActionItem
        keyLen = len(key)
        if self.wholeWordsOnlyCb.GetValue():
            matchFunc = lambda text, pos: (
                (
                    pos == 0
                    or not text[pos - 1].isalnum()
                )
                and (
                    keyLen + pos == len(text)
                    or not text[pos + keyLen].isalnum()
                )
            )
        else:
            matchFunc = lambda text, res: True
        searchParameters = self.searchParametersCb.GetValue()
        while True:
            item = iterFunc(item)
            if startItem is item:
                dlg = wx.MessageDialog(
                    None,
                    Text.notFoundMesg % originalSearchValue,
                    eg.APP_NAME,
                    wx.OK | wx.ICON_INFORMATION
                )
                dlg.ShowModal()
                dlg.Destroy()
                if self.IsShown():
                    self.Show()
                return
            text = convertFunc(item.GetLabel())
            pos = text.find(key)
            if pos != -1 and matchFunc(text, pos):
                item.Select()
                return
            if searchParameters and isinstance(item, ActionItem):
                for arg in item.GetArguments():
                    if type(arg) in StringTypes:
                        text = convertFunc(arg)
                        try:
                            pos = text.find(key)
                        except UnicodeDecodeError:
                            # silently ignore unicode errors for byte strings
                            pos = -1
                        if pos != -1 and matchFunc(text, pos):
                            item.Select()
                            return

