#   Programmer: Daniel Pozmanter
#   E-mail:     drpython@bluebottle.com
#   Note:       You must reply to the verification e-mail to get through.
#
#   Copyright 2003-2007 Daniel Pozmanter
#
#   Distributed under the terms of the GPL (GNU Public License)
#
#    DrPython is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program 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, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#drScript Menu

import os.path
import wx
import drFileDialog
import drScrolledMessageDialog
from drPrefsFile import ExtractPreferenceFromText
import drShortcutsFile
import drShortcuts
from drMenu import drMenu

def updatescripts(scriptfile, paths, titles):
    l = len(paths)
    x = 0
    f = open(scriptfile, 'w')
    while x < l:
        f.write("<path>" + paths[x] + "</path><title>" + titles[x] + "</title>\n")
        x = x + 1
    f.close()

class drNewShellDialog(wx.Dialog):

    def __init__(self, parent, title):
        wx.Dialog.__init__(self, parent, -1, title, wx.Point(50, 50), wx.Size(375, 250), wx.DEFAULT_DIALOG_STYLE | wx.MAXIMIZE_BOX | wx.THICK_FRAME | wx.RESIZE_BORDER)

        self.ID_SAVE = 1005

        self.theSizer = wx.FlexGridSizer(6, 3, 5, 10)

        self.btnSave = wx.Button(self, self.ID_SAVE, "&Save")

        self.parent = parent

        self.txtTitle = wx.TextCtrl(self, -1, "",  wx.Point(15, 325), wx.Size(250, -1))
        self.txtCommand = wx.TextCtrl(self, -1, "",  wx.Point(15, 325), wx.Size(250, -1))
        self.txtArguments = wx.TextCtrl(self, -1, "",  wx.Point(15, 325), wx.Size(250, -1))
        self.txtDirectory = wx.TextCtrl(self, -1, "",  wx.Point(15, 325), wx.Size(250, -1))
        self.chkRunInPrompt = wx.CheckBox(self, -1, "")
        self.chkRunInPrompt.SetValue(True)

        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)

        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, "Title:"), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(self.txtTitle, 0, wx.SHAPED)

        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, "Command:"), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(self.txtCommand, 0, wx.SHAPED)

        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, "Arguments:"), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(self.txtArguments, 0, wx.SHAPED)

        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, "Directory:"), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(self.txtDirectory, 0, wx.SHAPED)

        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, "Run In Prompt:"), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(self.chkRunInPrompt, 0, wx.SHAPED)

        self.btnClose = wx.Button(self, 101, "&Close")
        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(wx.StaticText(self, -1, " "), 0, wx.ALIGN_CENTER | wx.SHAPED)
        self.theSizer.Add(self.btnClose, 0, wx.SHAPED | wx.ALIGN_CENTER)
        self.theSizer.Add(self.btnSave, 0, wx.SHAPED | wx.ALIGN_RIGHT)
        self.txtTitle.SetFocus()
        self.btnSave.SetDefault()

        self.SetAutoLayout(True)
        self.SetSizer(self.theSizer)

        self.exitstatus = 0

        self.Bind(wx.EVT_BUTTON,  self.OnbtnSave, id=self.ID_SAVE)
        self.Bind(wx.EVT_BUTTON,  self.OnbtnClose, id=101)

    def GetExitStatus(self):
        return self.exitstatus

    def GetShellTuple(self):
        return self.txtTitle.GetValue(), self.txtCommand.GetValue(), self.txtArguments.GetValue(), self.txtDirectory.GetValue(), int(self.chkRunInPrompt.GetValue())

    def OnbtnClose(self, event):
        self.exitstatus = 0
        self.Close(1)

    def OnbtnSave(self, event):
        self.exitstatus = 1
        self.Close(1)

    def SetShellTuple(self, title, command, args, dir, inprompt):
        self.txtTitle.SetValue(title)
        self.txtCommand.SetValue(command)
        self.txtArguments.SetValue(args)
        self.txtDirectory.SetValue(dir)
        self.chkRunInPrompt.SetValue(inprompt)

class drScriptMenu(drMenu):
    def __init__(self, parent):
        drMenu.__init__(self, parent)

        self.dynamicscriptext = ""

        self.ID_ADD_SCRIPT = 3100
        self.ID_NEW_SCRIPT = 3101
        self.ID_EXISTING_SCRIPT = 3102
        self.ID_SHELL_COMMAND = 3103

        self.ID_EDIT_SCRIPT = 3003
        self.ID_REMOVE_SCRIPT = 3005
        self.ID_DYNAMIC_SCRIPT = 3006

        self.ID_EXAMPLE_SCRIPTS = 3010

        self.ID_SCRIPT_BASE = parent.ID_SCRIPT_BASE

        self.ID_SCRIPT_MENU = 3500

        self.parent = parent
        self.preferencesdirectory = parent.preferencesdirectory
        self.programdirectory = parent.programdirectory
        self.shortcutsdirectory = parent.shortcutsdirectory

        self.scriptcount = 0
        self.scripts = []
        self.titles = []

        self.setupMenu()

        self.ExampleScriptCount = 0

        self.loadscripts()

    def getdrscriptmenulabel(self, label):
        shortcuttext = ''

        if not self.parent.DrScriptShortcuts:
            return label

        if label in self.titles:
            i = self.titles.index(label)
            self.parent.DrScriptShortcuts[i]
            shortcuttext = drShortcuts.GetShortcutLabel(self.parent.DrScriptShortcuts[i])

        if len(shortcuttext) > 1:
            if shortcuttext == "Tab":
                shortcuttext += " "
            return label + '\t' + shortcuttext

        return label

    def reloadscripts(self, oldlength = -1, SyncShortcuts = 1):
        if oldlength < 0:
            oldlength = len(self.scripts)
        mnuitems = self.GetMenuItems()
        num = len(mnuitems)
        x = 0
        while x < num:
            self.Remove(mnuitems[x].GetId())
            #mnuitems[x].Destroy()
            x = x + 1
        self.scripts = []
        self.titles = []
        self.setupMenu()
        self.loadscripts(SyncShortcuts)
        self.parent.DrScriptShortcutNames = []
        if self.titles:
            for l in self.titles:
                self.parent.DrScriptShortcutNames.append(l)

    def loadscripts(self, SyncShortcuts = 1):
        self.scriptcount = 0
        if self.parent.prefs.drscriptloadexamples:
            self.examplemenu = wx.Menu()
            self.loadscriptsfromfile(self.programdirectory + "/examples/DrScript/drscript.dat", self.examplemenu, 1)
            self.AppendMenu(self.ID_EXAMPLE_SCRIPTS, "Examples", self.examplemenu)
            self.AppendSeparator()

        self.ExampleScriptCount = self.scriptcount

        self.loadscriptsfromfile(self.preferencesdirectory + "/drscript.dat", self)

        #Either there is no shortcuts file, or it is out of sync.
        if SyncShortcuts:
            l = len(self.titles)
            if l != len(self.parent.DrScriptShortcuts):
                self.parent.DrScriptShortcuts = []
                self.parent.DrScriptShortcutNames = []

                x = 0
                while x < l:
                    self.parent.DrScriptShortcuts.append(' #')
                    self.parent.DrScriptShortcutNames.append(self.titles[x])
                    x = x + 1

    def loadscriptsfromfile(self, scriptfile, target, appendprogpath = 0):
        if os.path.exists(scriptfile):
            folders = [target]
            folderindex = 0
            menuTitles = []
            menuTitleindex = -1
            lastCount = 0
            try:
                #Read from the file
                f = open(scriptfile, 'rb')
                #Initialize
                line = f.readline()
                while len(line) > 0:
                    c = line.count('\t')
                    line = line[c:].rstrip()

                    while lastCount > c:
                        folders[(folderindex - 1)].AppendMenu(self.ID_SCRIPT_MENU, menuTitles.pop(), folders.pop())
                        folderindex = folderindex - 1
                        menuTitleindex = menuTitleindex - 1
                        lastCount = lastCount - 1

                    if line[0] == '>':
                        folders.append(wx.Menu())
                        menuTitles.append(line[1:])
                        folderindex = folderindex + 1
                        menuTitleindex = menuTitleindex + 1
                        c = c + 1
                    else:
                        line_path = ExtractPreferenceFromText(line, "path")
                        if appendprogpath:
                            line_path = self.programdirectory + "/" + line_path.replace('\\', '/')
                        else:
                            if not os.path.isabs(line_path):
                                line_path = os.path.join(self.parent.drscriptsdirectory, line_path)
                        line_title = ExtractPreferenceFromText(line, "title")
                        if os.path.exists(line_path):
                            self.titles.append(line_title)
                            folders[folderindex].Append((self.ID_SCRIPT_BASE + self.scriptcount), self.getdrscriptmenulabel(line_title))
                            self.parent.Bind(wx.EVT_MENU, self.OnScript, id=(self.ID_SCRIPT_BASE + self.scriptcount))
                            self.scripts.append(line_path)
                            self.scriptcount = self.scriptcount + 1
                    lastCount = c
                    line = f.readline()
                f.close()
                #Add any menus not yet added:
                c = 0
                while lastCount > c:
                    folders[(folderindex - 1)].AppendMenu(self.ID_SCRIPT_MENU, menuTitles.pop(), folders.pop())
                    folderindex = folderindex - 1
                    menuTitleindex = menuTitleindex - 1
                    lastCount = lastCount - 1
            except:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Your drscript file is a tad messed up.\n"), "Error")

    def OnAddExistingScript(self, event):
        scriptfile = self.preferencesdirectory + "/drscript.dat"
        dlg = drFileDialog.FileDialog(self.parent, "Select Script File", self.parent.prefs.wildcard)
        if self.parent.drscriptsdirectory:
            try:
                dlg.SetDirectory(self.parent.drscriptsdirectory)
            except:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Error Setting Default Directory To: " +
                    self.parent.drscriptsdirectory), "DrPython Error")
        if dlg.ShowModal() == wx.ID_OK:
            filen = dlg.GetPath().replace("\\", "/")
            p = os.path.basename(filen) #patch by AB (suggests filename as title), 06.03.2007, thanks
            s = os.path.splitext(p)
            d = wx.TextEntryDialog(self.parent, 'Enter Script Title:', 'Add DrScript: Title', s[0]) #end patch by AB
            title = ""
            if d.ShowModal() == wx.ID_OK:
                title = d.GetValue()
            d.Destroy()
            if not title:
                drScrolledMessageDialog.ShowMessage(self.parent,
                    ("Bad script title.\nDrPython will politely ignore your request to add this script."), "Error")
                return
            self.Append((self.ID_SCRIPT_BASE + self.scriptcount), title, title)
            self.parent.Bind(wx.EVT_MENU, self.OnScript, id=(self.ID_SCRIPT_BASE + self.scriptcount))

            #if directory is relativ, store only filename without path
            pth = self.parent.drscriptsdirectory.lower()
            if filen.lower().startswith (pth):
                filen = filen[len(pth):]
                if filen[0] == '/':
                    filen = filen[1:]

            self.scripts.append(filen)
            self.titles.append(title)

            self.parent.DrScriptShortcuts.append('')
            self.parent.DrScriptShortcutNames.append(title)

            self.scriptcount += 1
            try:
                f = open(scriptfile, 'a')
                f.write("<path>" + filen + "</path><title>" + title + "</title>\n")
                f.close()

                #Update the shortcuts Too.
                shortcutsfile = self.shortcutsdirectory + "/drscript.shortcuts.dat"
                drShortcutsFile.WriteShortcuts(shortcutsfile, self.parent.DrScriptShortcuts,
                    self.parent.DrScriptShortcutNames, "", False)
            except:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Problem saving script.\n"), "Error")
        dlg.Destroy()

    def OnAddNewScript(self, event):
        scriptfile = self.preferencesdirectory + "/drscript.dat"
        dlg = drFileDialog.FileDialog(self.parent, "Save New Script File As", self.parent.prefs.wildcard, IsASaveDialog=True)
        if self.parent.drscriptsdirectory:
            try:
                dlg.SetDirectory(self.parent.drscriptsdirectory)
            except:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Error Setting Default Directory To: " + self.parent.drscriptsdirectory), "DrPython Error")
        if dlg.ShowModal() == wx.ID_OK:
            filename = dlg.GetPath().replace("\\", "/")
            if not filename.endswith('.py'):
                filename += '.py'
            s = os.path.splitext(filename)[0]
            s = os.path.basename(s)
            d = wx.TextEntryDialog(self.parent, "Enter Script Title:", "Add DrScript: Title", s)
            title = ""
            if d.ShowModal() == wx.ID_OK:
                title = d.GetValue()
            d.Destroy()
            if not title:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Bad script title.\nDrPython will politely ignore your request to add this script."), "Error")
                return

            cfile = file(filename, 'wb')
            cfile.write("#drscript\n\n")
            cfile.close()

            self.Append((self.ID_SCRIPT_BASE + self.scriptcount), title, title)
            self.parent.Bind(wx.EVT_MENU, self.OnScript, id=(self.ID_SCRIPT_BASE + self.scriptcount))

            #if directory is relativ, store only filename without path
            pth = self.parent.drscriptsdirectory.lower()
            fname = filename
            if filename.lower().startswith (pth):
                fname = filename[len(pth):]
                if fname[0] == '/':
                    fname = fname[1:]
            
            self.scripts.append(fname)
            self.titles.append(fname)

            self.parent.DrScriptShortcuts.append('')
            self.parent.DrScriptShortcutNames.append(title)

            self.scriptcount += 1
            try:
                f = open(scriptfile, 'a')
                f.write("<path>" + fname + "</path><title>" + title + "</title>\n")
                f.close()

                shortcutsfile = self.shortcutsdirectory + "/drscript.shortcuts.dat"
                drShortcutsFile.WriteShortcuts(shortcutsfile, self.parent.DrScriptShortcuts, self.parent.DrScriptShortcutNames, "", False)
            except:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Problem saving script.\n"), "Error")

            old = self.parent.txtDocument.filename
            if (len(old) > 0) or (self.parent.txtDocument.GetModify()):
                self.parent.OpenFile(filename, True)
            else:
                self.parent.OpenFile(filename, False)
        dlg.Destroy()

    def OnAddShellCommand(self, event):
        scriptfile = self.preferencesdirectory + "/drscript.dat"
        dlg = drFileDialog.FileDialog(self.parent, "Save New Shell Command As", self.parent.prefs.wildcard, IsASaveDialog=True)
        if self.parent.drscriptsdirectory:
            try:
                dlg.SetDirectory(self.parent.drscriptsdirectory)
            except:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Error Setting Default Directory To: " +
                    self.parent.drscriptsdirectory), "DrPython Error")
        if dlg.ShowModal() == wx.ID_OK:
            filen = dlg.GetPath().replace("\\", "/")
            d = drNewShellDialog(self.parent, "New Shell Command")
            if self.parent.PLATFORM_IS_WIN:
                d.SetSize(wx.Size(425, 350))
            d.ShowModal()
            if d.GetExitStatus():
                title, cmd, args, dir, inprompt = d.GetShellTuple()
                d.Destroy()
            else:
                d.Destroy()
                return
            if not title:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Bad shell title.\nDrPython will politely ignore your request to add this shell command."), "Error")
                return

            if args.find("<Current File>") > -1:
                args = args.replace("<Current File>", self.parent.txtDocument.filename)
            if args.find("<Current Directory>") > -1:
                args = args.replace("<Current Directory>", os.path.split(self.parent.txtDocument.filename)[0])
            if dir.find("<Current Directory>") > -1:
                dir = dir.replace("<Current Directory>", os.path.split(self.parent.txtDocument.filename)[0])

            cfile = file(filen, 'wb')
            scripttext = "#drscript shell command\n\n"
            if dir:
                scripttext = scripttext + 'import os\n\nos.chdir("' + dir + '")\n\n'

            if inprompt:
                scripttext = scripttext + 'DrFrame.Execute("' + cmd + ' ' + args + '", "Running Shell Command")\n\n'
            else:
                scripttext = scripttext + 'wx.Shell("' + cmd + ' ' + args + '")\n\n'
            cfile.write(scripttext)
            cfile.close()

            self.Append((self.ID_SCRIPT_BASE + self.scriptcount), title, title)
            self.parent.Bind(wx.EVT_MENU, self.OnScript, id=(self.ID_SCRIPT_BASE + self.scriptcount))
            self.scripts.append(filen)
            self.titles.append(title)

            self.parent.DrScriptShortcuts.append('')
            self.parent.DrScriptShortcutNames.append(title)

            self.scriptcount = self.scriptcount + 1
            try:
                f = open(scriptfile, 'a')
                f.write("<path>" + filen + "</path><title>" + title + "</title>\n")
                f.close()

                shortcutsfile = self.shortcutsdirectory + "/drscript.shortcuts.dat"
                drShortcutsFile.WriteShortcuts(shortcutsfile, self.parent.DrScriptShortcuts, self.parent.DrScriptShortcutNames, "", False)
            except:
                drScrolledMessageDialog.ShowMessage(self.parent, ("Problem saving script.\n"), "Error")
        dlg.Destroy()

    def OnDynamicScript(self, event):
        from drDynamicDrScriptDialog import drDynamicDrScriptDialog
        d = drDynamicDrScriptDialog(self.parent, self.dynamicscriptext)
        d.ShowModal()
        self.dynamicscriptext = d.GetText()
        d.Destroy()

    def OnEditScript(self, event):
        if self.scripts:
            def tuplify(x, y):
                return (x, y)

            def detuplify(x):
                return x[0]

            array = map(tuplify, self.titles, self.scripts)
            array.sort()

            titles = map(detuplify, array)
            d = wx.SingleChoiceDialog(self.parent, "Select the Script to Edit:", "Edit Script", titles, wx.CHOICEDLG_STYLE)
            #d.SetSize(wx.Size(250, 250))
            answer = d.ShowModal()
            d.Destroy()
            if answer == wx.ID_OK:
                i = d.GetSelection()
                filename = array[i][1].replace("\\", "/")
                self.parent.OpenOrSwitchToFile(filename, editRecentFiles=False)
        else:
            drScrolledMessageDialog.ShowMessage(self.parent, ("There aren't any scripts to edit.\nTry \"New Script\" or \"Add Script\" Instead."), "Error")

    def OnScript(self, event):
        scriptindex = event.GetId() - self.ID_SCRIPT_BASE

        scriptfname = self.scripts[scriptindex]
        #relativ path? => complete script filename
        if not os.path.isabs(scriptfname):
            scriptfname = os.path.join(self.parent.drscriptsdirectory, scriptfname)

        f = open(scriptfname, 'r')
        scripttext = f.read()
        f.close()

        if scripttext.find("DrFilename") > -1:
            scripttext = scripttext.replace("DrFilename", "self.parent.txtDocument.filename")
        if scripttext.find("DrScript") > -1:
            scripttext = scripttext.replace("DrScript", "self.parent.DrScript")
        if scripttext.find("DrDocument") > -1:
            scripttext = scripttext.replace("DrDocument", "self.parent.txtDocument")
        if scripttext.find("DrPrompt") > -1:
            scripttext = scripttext.replace("DrPrompt", "self.parent.txtPrompt")
        if scripttext.find("DrFrame") > -1:
            scripttext = scripttext.replace("DrFrame", "self.parent")

        try:
            code = compile((scripttext + '\n'), scriptfname, 'exec')
        except:
            drScrolledMessageDialog.ShowMessage(self.parent, ("Error compiling script."),
                "Error", wx.DefaultPosition, wx.Size(550,300))
            return

        try:
            exec(code)
        except:
            drScrolledMessageDialog.ShowMessage(self.parent, ("Error running script."),
                "Error", wx.DefaultPosition, wx.Size(550,300))
            return

    def setupMenu(self):
        addscriptmenu = wx.Menu()
        addscriptmenu.Append(self.ID_NEW_SCRIPT, "&New Script...")
        addscriptmenu.Append(self.ID_EXISTING_SCRIPT, "&Existing Script...")
        addscriptmenu.Append(self.ID_SHELL_COMMAND, "&Shell Command...")

        self.AppendMenu(self.ID_ADD_SCRIPT, "&Add Script", addscriptmenu)
        self.Append(self.ID_EDIT_SCRIPT, "&Edit Script...")
        self.Append(self.ID_DYNAMIC_SCRIPT, "&Dynamic DrScript...")
        self.AppendSeparator()

        self.parent.Bind(wx.EVT_MENU, self.OnAddExistingScript, id=self.ID_EXISTING_SCRIPT)
        self.parent.Bind(wx.EVT_MENU, self.OnAddNewScript, id=self.ID_NEW_SCRIPT)
        self.parent.Bind(wx.EVT_MENU, self.OnAddShellCommand, id=self.ID_SHELL_COMMAND)
        self.parent.Bind(wx.EVT_MENU, self.OnEditScript, id=self.ID_EDIT_SCRIPT)
        self.parent.Bind(wx.EVT_MENU, self.OnDynamicScript, id=self.ID_DYNAMIC_SCRIPT)

