# -*- coding: utf-8 -*-

import sys
import Foundation
import AppKit
import imp
import objc
import os
import os.path
import shutil
import StringIO
import traceback
import string

'''sys.path += [
            '/Library/Python'
            '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
            '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
            '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
            '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
            '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
            '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
            '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages',
            '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python',
            '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC'
            ]'''

VPPlugin = objc.lookUpClass('VPPlugin')

class VPPythonPlugin (VPPlugin):
    
    def didRegister(self):
        
        '''
        
        '''
        # self.copyDefaultScriptsToFolder()

        self.pluginManager().addPluginsMenuTitle_withSuperMenuTitle_target_action_keyEquivalent_keyEquivalentModifierMask_userObject_(
            'Run page as Python',
            'Python',
            self,
            'handleRunPageAsPythonPlugIn:',
            ';',
            AppKit.NSControlKeyMask | AppKit.NSCommandKeyMask | AppKit.NSShiftKeyMask,
            None
            )
        
        
        self.pluginManager().addPluginsMenuTitle_withSuperMenuTitle_target_action_keyEquivalent_keyEquivalentModifierMask_userObject_(
            u'Save page as Python PlugIn\u2026',
            'Python',
            self,
            'handleSavePageAsPythonPlugIn:',
            '',
            0,
            None
            )
        '''
        self.pluginManager().addPluginsMenuTitle_withSuperMenuTitle_target_action_keyEquivalent_keyEquivalentModifierMask_userObject_(
            u'Show Example Python PlugIns\u2026',
            'Python',
            self,
            'handleShowExamplePlugins:',
            '',
            0,
            None
            )
        '''
        self.plugins = {}
        self.loadPluginBundles()
        self.loadPlugins(self.scriptsDirectory)
        self.loadPlugins(self.pluginsDirectory)
        
        self.pluginManager().registerEventRunner_forLanguage_(self, "Python")
    
    
    def runScript(self, scriptBuffer, eventDictionary, eventName, windowController):
        
        if eventDictionary is None:
            eventDictionary = {'eventName': 'PythonPageRun', 'document': windowController.document(), 'windowController': windowController}
        else:
            
            if (eventDictionary.has_key('windowController')):
                windowController = eventDictionary['windowController']
            
            # legacy stuff.
            document            = eventDictionary['document']
            triggerDictionary   = eventDictionary
        
        vpconsole = AppKit.NSApplication.sharedApplication().delegate().console_
        
        outStringIO = StringIO.StringIO()
        errStringIO = StringIO.StringIO()
        
        theOldStdout = sys.stdout
        theOldStderr = sys.stderr
        
        # this seems to break in python 2.7:
        #sys.stdout = outStringIO
        #sys.stderr = errStringIO
        
        try:
            theCodeObject = compile(scriptBuffer, '__main__', 'exec')
            exec(theCodeObject)
        except Exception, e:
        
            type, value, tb = sys.exc_info()
            print ("\nTraceback (innermost last):\n%s" % string.join(traceback.format_tb(tb) + traceback.format_exception_only(type, value)))
        
        sys.stdout = theOldStdout
        sys.stderr = theOldStderr
        
        if (len(outStringIO.getvalue())):
            vpconsole(outStringIO.getvalue())
        
        if (len(errStringIO.getvalue())):
            vpconsole(errStringIO.getvalue())
        
        
    
    def runScript_forEvent_withEventDictionary_(self, scriptBuffer, eventName, eventDictionary):
        
        self.runScript(scriptBuffer, eventDictionary, eventName, None)
        
        return True
    
    def savePanelDidEndForSaveAsPython_returnCode_contextInfo_(self, savePanel, returnCode, contextInfo):
        
        if (returnCode == AppKit.NSOKButton):
            data = self.saveWindowHack.textView().string().dataUsingEncoding_(Foundation.NSUTF8StringEncoding)
            
            data.writeToFile_atomically_(savePanel.filename(), False)
            
            modName = os.path.basename(savePanel.filename())
            
            modName = os.path.splitext(modName)[0]
            
            self.loadPluginWithModuleNameAtPath(modName, savePanel.filename())
            
            # privateness, please ignore.
            self.pluginManager().sortMenu()
        
        self.saveWindowHack = None
        
    # lame.  We have to do some pyobjc trickery here.
    savePanelDidEndForSaveAsPython_returnCode_contextInfo_ = objc.selector(savePanelDidEndForSaveAsPython_returnCode_contextInfo_, signature="v@:@ii")

    def handleSavePageAsPythonPlugIn_(self, windowController):
        
        pageName    = windowController.item().displayName()
        scriptName  = pageName + u".py"
        
        savePanel   = AppKit.NSSavePanel.savePanel()
        
        savePanel.setPrompt_(Foundation.NSLocalizedString("Save", "Save"))
        savePanel.setTitle_(Foundation.NSLocalizedString("Save as Python Plugin", "Save as Python Plugin"))
        
        self.saveWindowHack = windowController
        
        savePanel.beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo_(self.pluginsDirectory, scriptName, windowController.window(), self, "savePanelDidEndForSaveAsPython:returnCode:contextInfo:", 0)
        
    def handleRunPageAsPythonPlugIn_(self, windowController):
        
        textStorage     = windowController.textView().textStorage()
        selectedRange   = windowController.textView().selectedRange()
        
        if selectedRange[1] == 0:
            scriptBuffer = textStorage.mutableString()
        else:
            scriptBuffer = textStorage.mutableString().substringWithRange_(selectedRange)
        
        
        self.runScript(scriptBuffer, None, None, windowController)
                
    def handleShowExamplePlugins_(self, windowController):
        
        AppKit.NSWorkspace.sharedWorkspace().openURL_(Foundation.NSURL.URLWithString_(u"http://flyingmeat.com/wikka/VoodooPadPythonScripts"))
        
        
    def validateAction_forPageUTI_userObject_(self, action, type, uo):
        return True


    def handleRunScript_userObject_(self, windowController, userObject):
        thePlugin = self.plugins[userObject]
        theModule = imp.load_module(thePlugin['name'], file(thePlugin['path']), thePlugin['path'], ('.py', 'U', 1),)
        vpconsole = AppKit.NSApplication.sharedApplication().delegate().console_
        
        outStringIO = StringIO.StringIO()
        errStringIO = StringIO.StringIO()
        
        theOldStdout = sys.stdout
        theOldStderr = sys.stderr
        
        sys.stdout = outStringIO
        sys.stderr = errStringIO
        
        
        try:
            theModule.main(windowController)
        
        except Exception, e:
            type, value, tb = sys.exc_info()
            print ("\nTraceback (innermost last):\n%s" % string.join(traceback.format_tb(tb) + traceback.format_exception_only(type, value)))
        
        sys.stdout = theOldStdout
        sys.stderr = theOldStderr
        
        if (len(outStringIO.getvalue())):
            vpconsole(outStringIO.getvalue())
        
        if (len(errStringIO.getvalue())):
            vpconsole(errStringIO.getvalue())
        
        
        
        
    def getScriptsDir(self):
        if not self.__dict__.has_key('_scriptsDirectory'):
            theScriptPluginDir = os.path.expanduser('~/Library/Application Support/VoodooPad/Script PlugIns')
            if not os.path.isdir(theScriptPluginDir):
                 os.makedirs(theScriptPluginDir)
            _scriptsDirectory = theScriptPluginDir
        return _scriptsDirectory
    scriptsDirectory = property(getScriptsDir)

    def getPluginsDir(self):
        if not self.__dict__.has_key('_pluginsDirectory'):
            thetPluginDir = os.path.expanduser('~/Library/Application Support/VoodooPad/PlugIns')
            if not os.path.isdir(thetPluginDir):
                 os.makedirs(thetPluginDir)
            _pluginsDirectory = thetPluginDir
        return _pluginsDirectory
    pluginsDirectory = property(getPluginsDir)
        
    def copyDefaultScriptsToFolder(self):
        try:
            thePluginBundle = Foundation.NSBundle.bundleForClass_(objc.lookUpClass('VPPythonPlugin'))
            theDefaultScriptsFolderPath = os.path.join(thePluginBundle.resourcePath(), 'Script PlugIns')
            for theScriptName in os.listdir(theDefaultScriptsFolderPath):
                if theScriptName[0] != '.':
                    if not os.path.exists(os.path.join(self.scriptsDirectory, theScriptName)):
                        theScriptPath = os.path.join(theDefaultScriptsFolderPath, theScriptName)
                        shutil.copy(theScriptPath, self.scriptsDirectory)
        except Exception, e:
            print e
            pass
    
    
    def loadPluginWithModuleNameAtPath(self, theModuleName, theFullPath):
        try:
            theModule           = imp.load_module(theModuleName, file(theFullPath), theFullPath, ('.py', 'U', 1),)
            
            theModule.__dict__['VPBundlePath'] = os.path.join(theFullPath)
            
            theMenuTitle        = None
            if theModule.__dict__.has_key('VPScriptMenuTitle'): theMenuTitle = theModule.VPScriptMenuTitle
            
            theSuperMenuTitle   = None
            if theModule.__dict__.has_key('VPScriptSuperMenuTitle'): theSuperMenuTitle = theModule.VPScriptSuperMenuTitle
            
            
            # thanks to Heesoo Lee for this improvement
            # get shortcut key (optional)
            try:
                theShortcutKey  = theModule.VPShortcutKey
                theShortcutMask = theModule.VPShortcutMask
                # set Modifier Flags
                try:
                    theShortcutMask = int(theShortcutMask)
                except:
                    theShortcutMask = self.decodeShortcutMask(theShortcutMask)
            except:
                theShortcutKey = ''
                theShortcutMask = 0
            
            thePluginDict = dict(
                name = theModuleName,
                path = theFullPath)

            self.plugins[theModuleName] = thePluginDict

            self.pluginManager().addPluginsMenuTitle_withSuperMenuTitle_target_action_keyEquivalent_keyEquivalentModifierMask_userObject_(
                theMenuTitle,
                theSuperMenuTitle,
                self,
                'handleRunScript:userObject:',
                theShortcutKey,
                theShortcutMask,
                theModuleName
                )



        except Exception, e:
            print 'Failed to load plugin: %s' % theFullPath
            print e
    
    def loadPlugins(self, theDirectory):
        
        for theFilename in os.listdir(theDirectory):
            if os.path.splitext(theFilename)[-1] == '.py':
                theModuleName = os.path.splitext(theFilename)[0]
                theFullPath = os.path.join(theDirectory, theFilename)
                
                self.loadPluginWithModuleNameAtPath(theModuleName, theFullPath)
    
    
    def loadPluginBundles(self):
        
        for theBundleFilename in os.listdir(self.pluginsDirectory):
            
            if os.path.splitext(theBundleFilename)[-1] == '.vppy':
                theModuleName = os.path.splitext(theBundleFilename)[0]
                
                theFullPath = os.path.join(self.pluginsDirectory, theBundleFilename, 'Contents', 'Resources', 'main.py')
                
                try:
                    
                    theModule           = imp.load_module(theModuleName, file(theFullPath), theFullPath, ('.vppy', 'U', 1),)
                    
                    theModule.__dict__['VPBundlePath'] = os.path.join(self.pluginsDirectory, theBundleFilename)
                    
                    theMenuTitle        = None
                    if theModule.__dict__.has_key('VPScriptMenuTitle'): theMenuTitle = theModule.VPScriptMenuTitle
                    
                    theSuperMenuTitle   = None
                    if theModule.__dict__.has_key('VPScriptSuperMenuTitle'): theSuperMenuTitle = theModule.VPScriptSuperMenuTitle
                    
                    
                    # thanks to Heesoo Lee for this improvement
                    # get shortcut key (optional)
                    try:
                        theShortcutKey  = theModule.VPShortcutKey
                        theShortcutMask = theModule.VPShortcutMask
                        # set Modifier Flags
                        try:
                            theShortcutMask = int(theShortcutMask)
                        except:
                            theShortcutMask = self.decodeShortcutMask(theShortcutMask)
                    except:
                        theShortcutKey = ''
                        theShortcutMask = 0
                    
                    
                    thePluginDict = dict(
                        name = theModuleName,
                        path = theFullPath)

                    self.plugins[theModuleName] = thePluginDict
                    
                    self.pluginManager().addPluginsMenuTitle_withSuperMenuTitle_target_action_keyEquivalent_keyEquivalentModifierMask_userObject_(
                        theMenuTitle,
                        theSuperMenuTitle,
                        self,
                        'handleRunScript:userObject:',
                        theShortcutKey,
                        theShortcutMask,
                        theModuleName
                        )
                
                except Exception, e:
                    print 'Failed to load plugin: %s' % theFullPath
                    print e
    
    
    def decodeShortcutMask(self,maskStr):
        shortcutMask = 0
        for mask in maskStr.split():
            if mask.lower() == "shift":
                shortcutMask += 1 << 17
            elif mask.lower() == "control" or mask.lower() == "ctrl":
                shortcutMask += 1 << 18
            elif mask.lower() == "alt" or mask.lower() == "opt" or mask.lower() == "option":
                shortcutMask += 1 << 19
            elif mask.lower() == "command":
                shortcutMask += 1 << 20
        return shortcutMask

#print("running the event loop..")
#AppHelper.runEventLoop()
