import wx
from wx.lib.agw import fourwaysplitter as FWS

from panda3d.core import *
from direct.showbase.ShowBase import *
from direct.directtools.DirectGlobals import *

try:
    base
except NameError:
    base = ShowBase(False, windowType = 'none')

from .WxAppShell import *
from .ViewPort import *

ID_FOUR_VIEW = 401
ID_TOP_VIEW = 402
ID_FRONT_VIEW = 403
ID_LEFT_VIEW = 404
ID_PERSP_VIEW = 405

class WxPandaShell(WxAppShell):
    """ Class for Panda3D LevelEditor """
    frameWidth = 800
    frameHeight = 600
    appversion      = '1.0'
    appname         = 'Panda3D Generic WX Frame'
    copyright       = ('Copyright 2010 Disney Online Studios.' +
                       '\nAll Rights Reserved.')

    MENU_TEXTS = {
        ID_FOUR_VIEW : ("Four Views", None),
        ID_TOP_VIEW : ("Top View", None),
        ID_FRONT_VIEW : ("Front View", None),
        ID_LEFT_VIEW : ("Left View", None),
        ID_PERSP_VIEW : ("Persp View", None),
        }

    def __init__(self, fStartDirect = False):
        fDirect = (base.config.GetBool('want-directtools', 0) or
                   (base.config.GetString("cluster-mode", '') != ''))

        self.fStartDirect = fStartDirect or fDirect

        # Create the Wx app
        self.wxApp = wx.App(redirect = False)
        self.wxApp.SetAppName(self.appname)
        WxAppShell.__init__(self, size=wx.Size(self.frameWidth, self.frameHeight))
        self.initialize()

    def createMenu(self):
        self.menuView = wx.Menu()
        self.menuBar.Insert(self.menuBar.GetMenuCount() - 1, self.menuView, "&View")

        menuItem = self.menuView.AppendRadioItem(ID_FOUR_VIEW, self.MENU_TEXTS[ID_FOUR_VIEW][0])
        self.Bind(wx.EVT_MENU, lambda p0=None, p1=-1:self.onViewChange(p0, p1), menuItem)

        menuItem = self.menuView.AppendRadioItem(ID_TOP_VIEW, self.MENU_TEXTS[ID_TOP_VIEW][0])
        self.Bind(wx.EVT_MENU, lambda p0=None, p1=0:self.onViewChange(p0, p1), menuItem)

        menuItem = self.menuView.AppendRadioItem(ID_FRONT_VIEW, self.MENU_TEXTS[ID_FRONT_VIEW][0])
        self.Bind(wx.EVT_MENU, lambda p0=None, p1=1:self.onViewChange(p0, p1), menuItem)

        menuItem = self.menuView.AppendRadioItem(ID_LEFT_VIEW, self.MENU_TEXTS[ID_LEFT_VIEW][0])
        self.Bind(wx.EVT_MENU, lambda p0=None, p1=2:self.onViewChange(p0, p1), menuItem)

        self.perspViewMenuItem = self.menuView.AppendRadioItem(ID_PERSP_VIEW, self.MENU_TEXTS[ID_PERSP_VIEW][0])
        self.Bind(wx.EVT_MENU, lambda p0=None, p1=3:self.onViewChange(p0, p1), self.perspViewMenuItem)

    def createInterface(self):
        self.createMenu()
        self.mainFrame = wx.SplitterWindow(self, style = wx.SP_3D | wx.SP_BORDER)
        self.leftFrame = wx.SplitterWindow(self.mainFrame, style = wx.SP_3D | wx.SP_BORDER)
        self.baseFrame = wx.SplitterWindow(self.mainFrame, style = wx.SP_3D | wx.SP_BORDER)
        self.viewFrame = FWS.FourWaySplitter(self.baseFrame, style=wx.SP_LIVE_UPDATE)
        self.rightFrame = wx.SplitterWindow(self.baseFrame, style = wx.SP_3D | wx.SP_BORDER)

        self.topView = Viewport.makeTop(self.viewFrame)
        self.viewFrame.AppendWindow(self.topView)

        self.frontView = Viewport.makeFront(self.viewFrame)
        self.viewFrame.AppendWindow(self.frontView)

        self.leftView = Viewport.makeLeft(self.viewFrame)
        self.viewFrame.AppendWindow(self.leftView)

        self.perspView = Viewport.makePerspective(self.viewFrame)
        self.viewFrame.AppendWindow(self.perspView)

        self.leftBarUpPane = wx.Panel(self.leftFrame)
        self.leftBarDownPane = wx.Panel(self.leftFrame)
        self.rightBarUpPane = wx.Panel(self.rightFrame)
        self.rightBarDownPane = wx.Panel(self.rightFrame)

        self.leftFrame.SplitHorizontally(self.leftBarUpPane, self.leftBarDownPane)
        self.rightFrame.SplitHorizontally(self.rightBarUpPane, self.rightBarDownPane)
        self.mainFrame.SplitVertically(self.leftFrame, self.baseFrame, 200)
        self.baseFrame.SplitVertically(self.viewFrame, self.rightFrame, 600)

        self.leftFrame.SetSashGravity(0.5)
        self.rightFrame.SetSashGravity(0.5)
        self.baseFrame.SetSashGravity(1.0)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.mainFrame, 1, wx.EXPAND, 0)
        self.SetSizer(sizer); self.Layout()

    def initialize(self):
        """Initializes the viewports and editor."""
        self.Update()
        ViewportManager.updateAll()
        self.wxStep()
        ViewportManager.initializeAll()
        # Position the camera
        if base.trackball != None:
          base.trackball.node().setPos(0, 30, 0)
          base.trackball.node().setHpr(0, 15, 0)

        # to make persp view as default
        self.perspViewMenuItem.Toggle()
        self.onViewChange(None, 3)

        # initializing direct
        if self.fStartDirect:
            base.startDirect(fWantTk = 0, fWantWx = 0)

            base.direct.disableMouseEvents()
            newMouseEvents = ["_le_per_%s"%x for x in base.direct.mouseEvents] +\
                             ["_le_fro_%s"%x for x in base.direct.mouseEvents] +\
                             ["_le_lef_%s"%x for x in base.direct.mouseEvents] +\
                             ["_le_top_%s"%x for x in base.direct.mouseEvents]
            base.direct.mouseEvents = newMouseEvents
            base.direct.enableMouseEvents()

            base.direct.disableKeyEvents()
            keyEvents = ["_le_per_%s"%x for x in base.direct.keyEvents] +\
                             ["_le_fro_%s"%x for x in base.direct.keyEvents] +\
                             ["_le_lef_%s"%x for x in base.direct.keyEvents] +\
                             ["_le_top_%s"%x for x in base.direct.keyEvents]
            base.direct.keyEvents = keyEvents
            base.direct.enableKeyEvents()

            base.direct.disableModifierEvents()
            modifierEvents = ["_le_per_%s"%x for x in base.direct.modifierEvents] +\
                             ["_le_fro_%s"%x for x in base.direct.modifierEvents] +\
                             ["_le_lef_%s"%x for x in base.direct.modifierEvents] +\
                             ["_le_top_%s"%x for x in base.direct.modifierEvents]
            base.direct.modifierEvents = modifierEvents
            base.direct.enableModifierEvents()

            base.direct.cameraControl.lockRoll = True
            base.direct.setFScaleWidgetByCam(1)

            unpickables = [
                "z-guide",
                "y-guide",
                "x-guide",
                "x-disc-geom",
                "x-ring-line",
                "x-post-line",
                "y-disc-geom",
                "y-ring-line",
                "y-post-line",
                "z-disc-geom",
                "z-ring-line",
                "z-post-line",
                "centerLines",
                "majorLines",
                "minorLines",
                "Sphere",]

            for unpickable in unpickables:
                base.direct.addUnpickable(unpickable)

            base.direct.manipulationControl.optionalSkipFlags |= SKIP_UNPICKABLE
            base.direct.manipulationControl.fAllowMarquee = 1
            base.direct.manipulationControl.supportMultiView()
            base.direct.cameraControl.useMayaCamControls = 1
            base.direct.cameraControl.perspCollPlane = self.perspView.collPlane
            base.direct.cameraControl.perspCollPlane2 = self.perspView.collPlane2

            for widget in base.direct.manipulationControl.widgetList:
                widget.setBin('gui-popup', 0)
                widget.setDepthTest(0)

            # [gjeon] to intercept messages here
            base.direct.ignore('DIRECT-delete')
            base.direct.ignore('DIRECT-select')
            base.direct.ignore('DIRECT-preDeselectAll')
            base.direct.ignore('DIRECT-toggleWidgetVis')
            base.direct.fIgnoreDirectOnlyKeyMap = 1

            # [gjeon] do not use the old way of finding current DR
            base.direct.drList.tryToGetCurrentDr = False

        else:
            base.direct=None
        #base.closeWindow(base.win)
        base.win = base.winList[3]

    def wxStep(self, task = None):
        """A step in the WX event loop. You can either call this yourself or use as task."""
        while self.evtLoop.Pending():
          self.evtLoop.Dispatch()
        self.wxApp.ProcessIdle()
        if task != None: return task.cont

    def appInit(self):
        """Overridden from WxAppShell.py."""
        # Create a new event loop (to overide default wxEventLoop)
        self.evtLoop = wx.EventLoop()
        self.oldLoop = wx.EventLoop.GetActive()
        wx.EventLoop.SetActive(self.evtLoop)
        taskMgr.add(self.wxStep, "evtLoopTask")

    def onViewChange(self, evt, viewIdx):
        for i in range(4):
            if viewIdx >=0 and\
               i != viewIdx:
                base.winList[i].setActive(0)
            else:
                base.winList[i].setActive(1)

        self.viewFrame.SetExpanded(viewIdx)

    def getCurrentView(self):
        """Function for get the current Viewport"""
        if self.viewFrame._expanded == -1: #four view
            self.currentView = None
        if self.viewFrame._expanded == 0: #top view
            self.currentView = self.topView
        if self.viewFrame._expanded == 1: #front view
            self.currentView = self.frontView
        if self.viewFrame._expanded == 2: #left view
            self.currentView = self.leftView
        if self.viewFrame._expanded == 3: #perspect view
            self.currentView = self.perspView

        return self.currentView


