# -*- 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 base64
import pickle

from ActionItem import ActionItem
from TreeItem import TreeItem



class PluginItem(ActionItem):
    xmlTag = "Plugin"
    icon = eg.Icons.PLUGIN_ICON
    isRenameable = False
    info = None

    def GetData(self):
        attr, text = TreeItem.GetData(self)
        del attr[0]
        attr.append(('Identifier', self.executable.info.evalName))
        guid = self.executable.info.guid
        if guid:
            attr.append(('Guid', guid))
        attr.append(('File', self.pluginName))
        text = base64.b64encode(pickle.dumps(self.info.args, 2))
        return attr, text


    @eg.AssertInActionThread
    def __init__(self, parent, node):
        TreeItem.__init__(self, parent, node)
        if node.text:
            try:
                args = pickle.loads(base64.b64decode(node.text))
            except AttributeError:
                args = ()
        else:
            args = ()
        evalName = node.attrib.get('identifier', None)
        self.pluginName = node.attrib.get('file', None)
        guid = node.attrib.get('guid', self.pluginName)
        self.info = info = eg.pluginManager.OpenPlugin(
            guid,
            evalName,
            args,
            self,
        )
        self.name = eg.text.General.pluginLabel % info.label
        if info.icon != self.icon:
            self.icon = eg.Icons.PluginSubIcon(info.icon)
        #self.icon = info.icon
        self.url = info.url ##########################################################################
        self.executable = info.instance


    def GetLabel(self):
        return self.name


    def GetTypeName(self):
        return self.executable.info.name


    @eg.LogIt
    def RestoreState(self):
        if self.isEnabled:
            eg.actionThread.Call(self.info.Start)


    def SetAttributes(self, tree, itemId):
        if self.info.lastException or self.info.initFailed:
            tree.SetItemTextColour(itemId, eg.colour.pluginError)


    @eg.AssertInActionThread
    def Execute(self):
        if not self.isEnabled:
            return None, None
        if eg.config.logActions:
            self.Print(self.name)
        if self.shouldSelectOnExecute:
            wx.CallAfter(self.Select)
        eg.indent += 1
        self.info.Start()
        eg.indent -= 1
        eg.result = self.executable
        return None, None


    @eg.AssertInActionThread
    def SetEnable(self, flag=True):
        ActionItem.SetEnable(self, flag)
        if flag:
            self.info.Start()
        else:
            self.info.Stop()


    @eg.AssertInActionThread
    def Delete(self):
        info = self.info
        def DoIt():
            info.Close()
            info.instance.OnDelete()
            info.RemovePluginInstance()
        eg.actionThread.Call(DoIt)
        ActionItem.Delete(self)
        self.executable = None
        self.info = None


    def AskDelete(self):
        actionItemCls = self.document.ActionItem
        def SearchFunc(obj):
            if obj.__class__ == actionItemCls:
                if obj.executable and obj.executable.plugin == self.executable:
                    return True
            return None
        if self.root.Traverse(SearchFunc) is not None:
            eg.MessageBox(
                eg.text.General.deletePlugin,
                eg.APP_NAME,
                wx.NO_DEFAULT|wx.OK|wx.ICON_EXCLAMATION
            )
            return False
        if not TreeItem.AskDelete(self):
            return False
        return True


    def AskCut(self):
        return self.AskDelete()


    def NeedsStartupConfiguration(self):
        """
        Returns True if the item wants to be configured after creation.

        Overrides ActionItem.NeedsStartupConfiguration()
        """
        # if the Configure method of the executable is overriden, we assume
        # the item wants to be configured after creation
        return (
            self.executable.Configure.im_func
            != eg.PluginBase.Configure.im_func
        )


    def GetBasePath(self):
        """
        Returns the filesystem path, where additional files (like pictures)
        should be found.

        Overrides ActionItem.GetBasePath()
        """
        return self.info.path


    # The Find function calls this from MainThread, so we can't restrict this
    # to the ActionThread
    #@eg.AssertInActionThread
    def GetArguments(self):
        return self.info.args


    @eg.LogIt
    @eg.AssertInActionThread
    def SetArguments(self, args):
        info = self.info
        if not info.lastException and args == self.info.args:
            return
        self.info.args = args
        label = info.instance.GetLabel(*args)
        if label != info.label:
            info.label = label
            self.name = eg.text.General.pluginLabel % label
            #eg.Notify("NodeChanged", self)
        self.RefreshAllVisibleActions()
        if self.isEnabled:
            eg.actionThread.Call(self.info.Stop)
            eg.actionThread.Call(self.info.Start)


    def RefreshAllVisibleActions(self):
        """
        Calls Refresh() for all currently visible actions of this plugin.
        """
        actionItemCls = self.document.ActionItem
        plugin = self.info.instance
        def Traverse(item):
            if item.__class__ == actionItemCls:
                if item.executable.plugin == plugin:
                    pass
                    #eg.Notify("NodeChanged", item)
            else:
                if item.childs and item in item.document.expandedNodes:
                    for child in item.childs:
                        Traverse(child)
        Traverse(self.root)

