"""Subclass of MethodPane, which is generated by wxFormBuilder."""

import wx
import wx.stc
import app
from ctx import theContext as context
import tran
from app.ui import pane
from activity.models.ui import ui as ui
from activity.models.ui.dlg.cc import NavigatorDialog
from model import cc
from analytic.cppparse import gather_vars

CLOSE_PANE_ID = wx.ID_HIGHEST + 100


# Implementing MethodPane
class MethodPane(ui.MethodPane):
    """Implements method pane editor"""
    # command ids:
    _saveCode = wx.Window.NewControlId()
    _undoCode = wx.Window.NewControlId()
    _redoCode = wx.Window.NewControlId()
    _copyCode = wx.Window.NewControlId()
    _cutCode = wx.Window.NewControlId()
    _pasteCode = wx.Window.NewControlId()
    _deleteCode = wx.Window.NewControlId()
    _toggleFull = wx.Window.NewControlId()
    _navigator = wx.Window.NewControlId()

    def _create_toolbars(self):
        """Create custom toolbar"""
        self.m_localToolbar = wx.aui.AuiToolBar(self, wx.ID_ANY, wx.DefaultPosition,
            wx.DefaultSize, wx.aui.AUI_TB_HORZ_LAYOUT)
        self.m_save = self.m_localToolbar.AddTool(self._saveCode,
            u"save code", wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR),
            wx.NullBitmap, wx.ITEM_NORMAL, u"Save", wx.EmptyString, None)
        self.m_localToolbar.AddSeparator()
        self.m_undo = self.m_localToolbar.AddTool(self._undoCode, u"tool",
            wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR), wx.NullBitmap, wx.ITEM_NORMAL,
            u"Undo", wx.EmptyString, None)
        self.m_redo = self.m_localToolbar.AddTool(self._redoCode, u"tool",
            wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_TOOLBAR), wx.NullBitmap, wx.ITEM_NORMAL,
            u"Redo", wx.EmptyString, None)
        self.m_localToolbar.AddSeparator()
        self.m_copy = self.m_localToolbar.AddTool(self._copyCode, u"copy",
            wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR), wx.NullBitmap, wx.ITEM_NORMAL,
            u"Copy", wx.EmptyString, None)
        self.m_cut = self.m_localToolbar.AddTool(self._cutCode, u"cut", wx.ArtProvider.GetBitmap(
            wx.ART_CUT, wx.ART_TOOLBAR), wx.NullBitmap, wx.ITEM_NORMAL, u"Cut", wx.EmptyString, None)
        self.m_paste = self.m_localToolbar.AddTool(self._pasteCode, u"paste",
            wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR), wx.NullBitmap,
            wx.ITEM_NORMAL, u"Paste", wx.EmptyString, None)
        self.m_localToolbar.AddSeparator()
        self.m_delete = self.m_localToolbar.AddTool(self._deleteCode, u"delete",
            wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_TOOLBAR), wx.NullBitmap, wx.ITEM_NORMAL,
            u"Delete", wx.EmptyString, None)
        self.m_localToolbar.AddSeparator()
        self.m_fullScreen = self.m_localToolbar.AddTool(self._toggleFull, u"tool",
            wx.ArtProvider.GetBitmap(u"gtk-fullscreen", wx.ART_TOOLBAR), wx.NullBitmap, wx.ITEM_NORMAL,
            u"Toggle fullscreen", wx.EmptyString, None)
        self.m_localToolbar.AddSeparator()
        self.m_navigator = self.m_localToolbar.AddTool(self._navigator, u"tool", wx.Bitmap(u"app/res/method.xpm",
            wx.BITMAP_TYPE_ANY), wx.NullBitmap, wx.ITEM_NORMAL, u"insert call", wx.EmptyString, None)
        self.m_localToolbar.Realize()
        self.m_toolbarSizer.Add(self.m_localToolbar, 0, wx.ALL, 5)
        self.Layout()
        # Connect Events
        self.m_editor.Bind(wx.EVT_KILL_FOCUS, self.OnLeaveFocus)
        self.m_editor.Bind(wx.EVT_SET_FOCUS, self.OnGetFocus)

    def __init__(self, parent, mainframe, method):
        """Intialization of method editor"""
        super(MethodPane, self).__init__(parent)
        self._mainframe = mainframe
        self._object = method
        #self._types = dict([(x._name, x) for x in method.types])
        self._notebook = parent

        container = method.inner_member_container
        container_cls = container.inner_class
        if container_cls:
            s = [container_cls.scoped]
            scoped = lambda x: (hasattr(x, 'scoped_str') and x.scoped_str(s)
            ) or (hasattr(x, 'scoped') and x.scoped) or x.name
            self._types = dict([scoped(x), x] for x in container.types)
        else:
            self._types = dict([scoped(x), x] for x in container.types)
            scoped = lambda x: (hasattr(x, 'scoped') and x.scoped) or x.name
            self._types = dict([scoped(x), x] for x in container.types)

        if '@' in self._types:
            del self._types['@']
        self.m_editor.SetText(method._content)
        self.m_editor.Initialize(self._types)
        """
        if method._note:
            self.m_editor.AnnotationSetVisible(wx.stc.STC_ANNOTATION_BOXED)
            self.m_editor.AnnotationSetText(0, method.note)"""
        self.m_editor.SetReadOnly(method._readOnly)
        #self.m_editor.SendMsg(2540, wp="Prueba de anotacion", lp=long(0))
        #self.m_editor.SendMsg(2548, wp=1, lp=long(0))
        self.Layout()
        self._create_toolbars()

        wx.stc.EVT_STC_CHANGE(self.m_editor,
            self.m_editor.GetId(), self.OnEditorChange)

        #self.Bind(EVT_STC_STYLENEEDED, self.handleStyleNeeded,
        #id=self.m_editor.GetId())
        frame = context.frame

        #bind some messages to this frame
        self.Bind(wx.EVT_MENU, frame.CloseCurrentDocPane, id=CLOSE_PANE_ID)
        self.Bind(wx.EVT_MENU, self.OnDeleteCode, id=self._deleteCode)
        self.Bind(wx.EVT_MENU, self.OnUndoCode, id=self._undoCode)
        self.Bind(wx.EVT_MENU, self.OnRedoCode, id=self._redoCode)
        self.Bind(wx.EVT_MENU, self.OnCopyCode, id=self._copyCode)
        self.Bind(wx.EVT_MENU, self.OnPasteCode, id=self._pasteCode)
        self.Bind(wx.EVT_MENU, self.OnCutCode, id=self._cutCode)
        self.Bind(wx.EVT_MENU, self.OnSaveCode, id=self._saveCode)
        self.Bind(wx.EVT_MENU, self.OnFullScreen, id=self._toggleFull)
        self.Bind(wx.EVT_MENU, self.OnNavigator, id=self._navigator)

        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateDeleteCode, id=self._deleteCode)
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUndoCode, id=self._undoCode)
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateRedoCode, id=self._redoCode)
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateCopyCode, id=self._copyCode)
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdatePasteCode, id=self._pasteCode)
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateCutCode, id=self._cutCode)
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateSaveCode, id=self._saveCode)

        self.m_editor.popup_handler = self
        self._fullScreen = None

        aTable = wx.AcceleratorTable([
            wx.AcceleratorEntry(wx.ACCEL_ALT | wx.ACCEL_CTRL, ord('F'), ui.ID_TOGGLE_FULLSCREEN),
            wx.AcceleratorEntry(wx.ACCEL_CTRL, ord('W'), CLOSE_PANE_ID),
            wx.AcceleratorEntry(wx.ACCEL_CTRL, ord('S'), self._saveCode),
            wx.AcceleratorEntry(wx.ACCEL_NORMAL, wx.WXK_DELETE, self._deleteCode)
        ])
        self.SetAcceleratorTable(aTable)

    def Refresh(self):
        """Update editor from external changes (like undo/redo)"""
        line = self.m_editor.GetFirstVisibleLine()
        pos = self.m_editor.GetCurrentPos()
        self.m_editor.Freeze()
        self.m_editor.SetText(self._object._content)
        self.m_editor.SetModified(False)
        try:
            self.m_editor.SetFirstVisibleLine(line)
            self.m_editor.SetCurrentPos(pos)
        except:
            pass
        self.m_editor.Thaw()

    def PreDelete(self):
        """Remove toolbar first in order to avoid gtk-collision at close"""
        #self.m_editor.Destroy()
        self.m_localToolbar.Destroy()

    def Popup(self, editor, text=None):
        """Shows a custom popup"""
        pos = editor.GetCurrentPos()
        code = editor.GetText()[:pos]
        if text:
            # in the future, we need to show a complete floating dialog here
            # we receive "this->" or "object." here ..
            _vars = gather_vars(code, self._types)
            if not _vars:
                return
            if text not in _vars:
                return
            var = _vars[text]
            _type = var['type']
            if type(_type) is cc.Class:
                pos = editor.GetCurrentPos()
                p = editor.PointFromPosition(pos)
                p = editor.ClientToScreen(p)
                dlg = NavigatorDialog(editor, _type, p)
                if dlg.ShowModal() == wx.ID_OK:
                    editor.AddText(dlg.value)
            return
        else:
            menu = wx.Menu()
            menu.Append(self._mainframe.editProperties.GetId(),
                "test menu", "Edit relation properties")
            pos = editor.GetCurrentPos()
            p = editor.PointFromPosition(pos)
            editor.PopupMenu(menu, p)
            menu.Destroy()

    def OnNavigator(self, event):
        """Navigate throug the class structure"""
        pos = self.m_editor.GetCurrentPos()
        p = self.m_editor.PointFromPosition(pos)
        p = self.m_editor.ClientToScreen(p)
        dialog = app.ui.dlg.CodeNavigator(self, self._object)
        dialog.Move(p)
        if dialog.ShowModal() != wx.ID_OK:
            return
        pass

    def OnUndoCode(self, event):
        """Edit undo"""
        self.m_editor.Undo()

    def OnRedoCode(self, event):
        """Edit redo"""
        self.m_editor.Redo()

    def OnUpdatePasteCode(self, event):
        """Edit paste?"""
        event.Enable(self.m_editor.CanPaste())

    def OnUpdateCopyCode(self, event):
        """Edit copy?"""
        (b, e) = self.m_editor.GetSelection()
        event.Enable(b != e)

    def OnUpdateCutCode(self, event):
        """Edit cut?"""
        if self._object._readOnly:
            event.Enable(False)
        else:
            (b, e) = self.m_editor.GetSelection()
            event.Enable(b != e)

    def OnUpdateRedoCode(self, event):
        """Edit redo?"""
        if self.m_editor.CanRedo():
            event.SetText("Redo edit")
            event.Enable(True)
        else:
            event.SetText("Can't redo")
            event.Enable(False)

    def OnUpdateUndoCode(self, event):
        """Edit undo?"""
        if self.m_editor.CanUndo():
            event.SetText("Undo edit")
            event.Enable(True)
        else:
            event.SetText("Can't undo")
            event.Enable(False)

    def OnUpdateDeleteCode(self, event):
        """Edit delete?"""
        event.Enable(not self._object._readOnly)

    def Enabled(self, event):
        """Joker event"""
        event.Enable(True)

    def Disabled(self, event):
        """Joker event"""
        event.Enable(False)

    def UpdateModifiedTitle(self):
        """Update the tile after modifications"""
        if not self._fullScreen:
            i = self._notebook.GetPageIndex(self)
            s = self._notebook.GetPageText(i)
            m = '[modified] '
            if self.m_editor.IsModified():
                if s.find(m) == wx.NOT_FOUND:
                    self._notebook.SetPageText(i, m + s)
            else:
                if s.find(m) != wx.NOT_FOUND:
                    s = s.replace(m, '')
                    self._notebook.SetPageText(i, s)

    def OnEditorChange(self, event):
        """Called when editor status change"""
        if not self._fullScreen:
            self.UpdateModifiedTitle()

    @tran.TransactionalMethod('edit method')
    def Commit(self):
        """Update document"""
        text = self.m_editor.GetText()
        if text == self._object._content:
            return False
        o = self._object
        o.SaveState()
        o._content = text
        o.project.SetModified(True)
        k = o.outer_class or o.outer_module
        if k:
            k.ExportCppCodeFiles(force=True)

        return True

    def OnDeleteCode(self, event):
        """Handle delete key"""
        (b, e) = self.m_editor.GetSelection()
        if b == e:
            self.m_editor.CharRight()
        self.m_editor.DeleteBack()

    def OnCopyCode(self, event):
        """Handle a copy event"""
        self.m_editor.Copy()

    def OnPasteCode(self, event):
        """Handle a paste event"""
        self.m_editor.Paste()

    def OnCutCode(self, event):
        """Handle a paste event"""
        self.m_editor.Cut()

    def OnUpdateSaveCode(self, event):
        """Handles update event"""
        event.Enable(self.m_editor.IsModified())

    def OnSaveCode(self, event):
        """Handles save event"""
        self.Commit()
        self.m_editor.ResetModified()
        self.UpdateModifiedTitle()

    def OnFullScreen(self, event):
        """ShowFullscreen"""
        if self._fullScreen:
            self._fullScreen.LeaveFullScreen()
            self._fullScreen.Destroy()
            self._fullScreen = None
            self.UpdateModifiedTitle()
        else:
            self._fullScreen = pane.FullScreen(self)
        self.m_editor.SetFocus()

    def handleStyleNeeded(self, event):
        """Handle scintylla events"""
        wnd = self.m_editor
        pos = wnd.GetCurrentPos()
        if pos == 0:
            return
        if wnd.GetCharAt(pos - 1) == wx.T(':'):
            lnno = wnd.GetCurrentLine()
            iden = wnd.GetLineIndentation(lnno - 1)
            wnd.SetLineIndentation(lnno, iden)

            # = self.m_editor.GetFoldLevel(lnno - 1)
        # if this is not a normal line
        #self.m_editor.SetFoldLevel(lnno,LastIndent)
        #pass


