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

#import wx


MARGIN_LINE_NUMBERS = 0
MARGIN_FOLD = 1

import wx
import wx.stc
import wx.lib.newevent
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


#define update sash required event
UglySashEvent, EVT_UGLY_SASH = wx.lib.newevent.NewEvent()

LocalCommand, EVT_LOCAL_COMMAND_EVENT = wx.lib.newevent.NewCommandEvent()

CLOSE_PANE_ID = wx.ID_HIGHEST + 100


# Implementing ConstructorPane
class ConstructorPane(ui.ConstructorPane):
    """Pane for constructor edition"""
    def __init__(self, parent, mainframe, constructor):
        """Initialization"""
        super(ConstructorPane, self).__init__(parent)
        self._mainframe = mainframe
        self._object = constructor
        self._notebook = parent
        container = constructor.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._bodyTouched = False

        self.m_editor.SetText(constructor._content)
        self.m_init.SetText(constructor._init)
        self.m_editor.Initialize(self._types)
        self.m_init.Initialize(self._types)
        self.RecalcSashPos()

        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.m_delete.GetId())
        self.Bind(wx.EVT_MENU, self.OnUndoCode, id=frame.undo.GetId())
        self.Bind(wx.EVT_MENU, self.OnRedoCode, id=frame.redo.GetId())
        self.Bind(wx.EVT_MENU, self.OnCopyCode, id=frame.copy.GetId())
        self.Bind(wx.EVT_MENU, self.OnPasteCode, id=frame.paste.GetId())
        self.Bind(wx.EVT_MENU, self.OnCutCode, id=frame.cut.GetId())
        self.Bind(wx.EVT_MENU, self.OnSaveCode, id=frame.saveProject.GetId())

        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateDeleteCode, id=self.m_delete.GetId())
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUndoCode, id=frame.undo.GetId())
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateRedoCode, id=frame.redo.GetId())
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateCopyCode, id=frame.copy.GetId())
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdatePasteCode, id=frame.paste.GetId())
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateCutCode, id=frame.cut.GetId())
        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateSaveCode, id=frame.saveProject.GetId())

        self._selected = None
        self.m_editor.popup_handler = self
        self.m_init.popup_handler = self
        self._fullScreen = None

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

        wx.stc.EVT_STC_ZOOM(self.m_editor, self.m_editor.GetId(),
            self.OnEditorZoomed)
        wx.stc.EVT_STC_ZOOM(self.m_init, self.m_init.GetId(),
            self.OnInitZoomed)

        EVT_UGLY_SASH(self, self.OnUglySash)

        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'), frame.saveProject.GetId()),
            wx.AcceleratorEntry(wx.ACCEL_NORMAL, wx.WXK_DELETE, self.m_delete.GetId())
        ])
        self.SetAcceleratorTable(aTable)

    def Refresh(self):
        """Update editor from external changes (like undo/redo)"""
        line = self.m_init.GetFirstVisibleLine()
        pos = self.m_init.GetCurrentPos()
        self.m_init.Freeze()
        self.m_init.SetText(self._object._init)
        self.m_init.SetModified(False)
        try:
            self.m_init.SetFirstVisibleLine(line)
            self.m_init.SetCurrentPos(pos)
        except:
            pass
        self.m_init.Thaw()
        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_init.Destroy()
        self.m_auiToolBar5.Destroy()

    def Popup(self, editor, text=None):
        """Called from editor to show user menus"""
        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 OnInitPane(self):
        """Initialization"""
        self.RecalcSashPos()

    def RecalcSashPos(self):
        """Take amodelount of init section and recalc sash"""
        h = 10
        if self.m_init.GetLineCount():
            h += (self.m_init.GetLineCount() + 1) * (self.m_init.TextHeight(0) +
                self.m_init.GetExtraAscent() +
                self.m_init.GetExtraDescent())
        #self.m_splitter2.SetMinimumPaneSize(h)
        self.m_splitter2.SetSashPosition(h, True)
        self.Layout()
        self.m_splitter2.UpdateSize()

    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() or self.m_init.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"""
        self.UpdateModifiedTitle()

    def OnInitChange(self, event):
        """Called when editor status change"""
        self.RecalcSashPos()
        self.UpdateModifiedTitle()

    def OnUglySash(self, event):
        """Recalc sash"""
        sz = event.source.GetZoom()
        tz = event.target.GetZoom()
        if sz != tz:
            event.target.SetZoom(sz)
            wx.PostEvent(self, event)
        else:
            self.RecalcSashPos()

    def OnEditorZoomed(self, event):
        """Called when the UI of the editor changes"""
        e = UglySashEvent(source=self.m_editor, target=self.m_init)
        wx.PostEvent(self, e)
        event.Skip()

    def OnInitZoomed(self, event):
        """Called when the UI of the init par changes"""
        e = UglySashEvent(source=self.m_init, target=self.m_editor)
        wx.PostEvent(self, e)
        event.Skip()

    @tran.TransactionalMethod('edit constructor')
    def Commit(self):
        """Update document"""
        text = self.m_editor.GetText()
        init = self.m_init.GetText()
        o = self._object
        if text == o._content and init == o._init:
            return False
        if text != o._content:
            o._bodyTouched = True
        if init != o._content:
            o._initTouched = True
        o.SaveState()
        o._content = text
        o._init = init
        o.project.SetModified(True)
        k = o.outer_class or o.outer_module
        if k:
            k.ExportCppCodeFiles(force=True)
        return True

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

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

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

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

    def OnUpdateCopyCode(self, event):
        """Edit copy?"""
        if self._selected:
            (b, e) = self._selected.GetSelection()
            event.Enable(b != e)
        else:
            event.Enable(False)

    def OnUpdatePasteCode(self, event):
        """Edit paste?"""
        event.Enable(bool(self._selected and self._selected.CanPaste()))

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

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

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

    def OnDeleteCode(self, event):
        """Handle delete for focus editor"""
        if self._selected is None:
            return
        (b, e) = self._selected.GetSelection()
        if b == e:
            self._selected.CharRight()
        self._selected.DeleteBack()

    def OnCopyCode(self, event):
        """Handle copy for focus editor"""
        if self._selected is None:
            return
        self._selected.Copy()

    def OnPasteCode(self, event):
        """Handle paste for focus editor"""
        if self._selected is None:
            return
        self._selected.Paste()

    def OnCutCode(self, event):
        """Handle paste for focus editor"""
        if self._selected is None:
            return
        self._selected.Cut()

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

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

    def OnInitLeaveFocus(self, event):
        "Handle LeaveFocus event for init"
        self._selected = None
        event.Skip()

    def OnInitGetFocus(self, event):
        "Handle GetFocus event for init"
        self._selected = self.m_init
        event.Skip()

    def OnEditorLeaveFocus(self, event):
        "Handle LeaveFocus event for editor"
        self._selected = None
        event.Skip()

    def OnEditorGetFocus(self, event):
        "Handle GetFocus event for editor"
        self._selected = self.m_editor
        event.Skip()

