"""This module contains the DirectAutoSizer class."""

__all__ = ['DirectAutoSizer']

import inspect
from panda3d.core import *
from direct.gui import DirectGuiGlobals as DGG
from direct.gui.DirectFrame import DirectFrame
from direct.gui.DirectGuiBase import DirectGuiWidget
from . import DirectGuiHelper as DGH
from direct.showbase import ShowBaseGlobal

class DirectAutoSizer(DirectFrame):
    """
    A frame to Automatically resize the given other DirectGui element
    """
    def __init__(self, parent = None, child = None, **kw):
        optiondefs = (
            ('extendHorizontal', True,      None),
            ('extendVertical',   True,      None),
            ('minSize',          (0, 0, 0, 0), self.refresh),
            ('maxSize',          (0, 0, 0, 0), self.refresh),
            ('updateOnWindowResize', True,  self.setUpdateOnWindowResize),
            ('childUpdateSizeFunc', None,   None),
            ('parentGetSizeFunction', None, None),
            ('parentGetSizeExtraArgs', None, None),

            ('suppressMouse',  0,           None),
            )
        # Merge keyword options with default options
        self.defineoptions(kw, optiondefs)

        # Initialize superclasses
        DirectFrame.__init__(self, parent)

        self.parentObject = parent
        self.child = child
        if child is not None:
            child.reparentTo(self)

        # Call option initialization functions
        self.initialiseoptions(DirectAutoSizer)

    def setChild(self, child):
        if self.child is not None:
            self.child.detachNode()
        self.child = child
        self.child.reparentTo(self)
        self.refresh()

    def removeChild(self):
        if self.child is not None:
            self.child.detachNode()
        self.child = None

    def setUpdateOnWindowResize(self):
        if self['updateOnWindowResize']:
            # Make sure the sizer scales with window size changes
            self.screenSize = base.getSize()
            self.accept('window-event', self.windowEventHandler)
        else:
            # stop updating on window resize events
            self.ignore('window-event')
            self.screenSize = None

    def windowEventHandler(self, window=None):
        if window != base.win:
            # This event isn't about our window.
            return

        #if window is not None: # window is none if panda3d is not started
        #    if self.screenSize == base.getSize():
        #        return
        #self.screenSize = base.getSize()
        taskMgr.doMethodLater(0.25, self.refresh, "delayed sizer refresh", extraArgs=[])
        #self.refresh()

    def refresh(self):
        """Resize the sizer and its child element"""
        if self.child is None:
            return

        # store left/right/bottom/top
        l=r=b=t=0

        # dependent on our parent, make sure the size values are set correct
        if self["parentGetSizeFunction"] is not None:
            # we have a user defined way to get the size, this should be treated
            # most important
            size = self["parentGetSizeFunction"](*self["parentGetSizeExtraArgs"])

            l=size[0]
            r=size[1]
            b=size[2]
            t=size[3]
        elif self.parentObject is None or self.parentObject == ShowBaseGlobal.aspect2d:
            # the default parent of directGui widgets
            l = base.a2dLeft
            r = base.a2dRight
            b = base.a2dBottom
            t = base.a2dTop
        elif self.parentObject == base.pixel2d:
            # we are parented to pixel2d
            xsize, ysize = base.getSize()
            l = 0
            r = xsize
            b = -ysize
            t = 0
        elif DirectGuiWidget in inspect.getmro(type(self.parentObject)):
            # We have a "normal" DirectGui widget here
            bounds = self.parentObject.bounds
            l, r, b, t = bounds
        else:
            # We are parented to something else, probably a nodepath
            self.parentObject.node().setBoundsType(BoundingVolume.BT_box)

            ll = LPoint3()
            ur = LPoint3()

            self.parentObject.calcTightBounds(ll, ur, render)

            l=ll.getX()
            r=ur.getX()
            b=ll.getZ()
            t=ur.getZ()

        childSize = self.child['frameSize']
        if childSize is None:
            childSize = self.child.getBounds()

        if type(self.child["scale"]) == LVecBase3f:
            childScale = self.child["scale"]
        elif self.child["scale"] is not None:
            try:
                childScale = LVecBase3f(self.child["scale"])
            except:
                childScale = self.child["scale"]
        else:
            childScale = LVecBase3f(1.0)

        if not self['extendHorizontal']:
            l = childSize[0] * childScale.getX()
            r = childSize[1] * childScale.getX()

        if not self['extendVertical']:
            b = childSize[2] * childScale.getY()
            t = childSize[3] * childScale.getY()

        #TODO: Better check for positive/negative numbers
        if l > self['minSize'][0]: l = self['minSize'][0]
        if r < self['minSize'][1]: r = self['minSize'][1]
        if b > self['minSize'][2]: b = self['minSize'][2]
        if t < self['minSize'][3]: t = self['minSize'][3]

        if self['maxSize'] is not None and self['maxSize'] != (0, 0, 0, 0):
            if l < self['maxSize'][0]: l = self['maxSize'][0]
            if r > self['maxSize'][1]: r = self['maxSize'][1]
            if b < self['maxSize'][2]: b = self['maxSize'][2]
            if t > self['maxSize'][3]: t = self['maxSize'][3]

        # recalculate size according to position
        l -= self.child.getX()
        r += self.child.getX()
        b -= self.child.getZ()
        t += self.child.getZ()

        # actual resizing of our child element
        self.child["frameSize"] = [l/childScale.getX(),r/childScale.getX(),b/childScale.getY(),t/childScale.getY()]
        self["frameSize"] = self.child["frameSize"]

        base.messenger.send(self.uniqueName("update-size"))
        if self['childUpdateSizeFunc'] is not None:
            self['childUpdateSizeFunc']()
