"""
"""
import pygame

from . import style


class Widget:
    """Template object - base for all widgets.

    <pre>Widget(**params)</pre>

    <p>A number of optional params may be passed to the Widget initializer.</p>

    <dl>
    <dt>decorate<dd>defaults to True.  If true, will call <tt>theme.decorate(self)</tt> to allow the theme a chance to decorate the widget.
    <dt>style<dd>a dict of style parameters.
    <dt>x, y, width, height<dd>position and size parameters, passed along to style
    <dt>align, valign<dd>alignment parameters, passed along to style
    <dt>font, color, background<dd>other common parameters that are passed along to style
    <dt>cls<dd>class name as used by Theme
    <dt>name<dd>name of widget as used by Form.  If set, will call <tt>form.add(self,name)</tt> to add the widget to the most recently created Form.
    <dt>focusable<dd>True if this widget can receive focus.  Defaults to True.
    <dt>disabled<dd>True of this widget is disabled.  Defaults to False.
    <dt>value<dd>initial value
    </dl>

    <strong>Example - Creating your own Widget</strong>
    <p>This example shows which methods are template methods.</p>
    <code>
    class Draw(gui.Widget):
        def paint(self,s):
            #paint the pygame.Surface
            return

        def update(self,s):
            #update the pygame.Surface and return the update rects
            return [pygame.Rect(0,0,self.rect.w,self.rect.h)]

        def event(self,e):
            #handle the pygame.Event
            return

        def resize(self,width=None,height=None):
            #return the width and height of this widget
            return 256,256
    </code>
    """

    def __init__(self, **params):
        # object.Object.__init__(self)
        self.connects = {}
        params.setdefault("decorate", True)
        params.setdefault("style", {})
        params.setdefault("focusable", True)
        params.setdefault("disabled", False)

        self.focusable = params["focusable"]
        self.disabled = params["disabled"]

        self.rect = pygame.Rect(
            params.get("x", 0),
            params.get("y", 0),
            params.get("width", 0),
            params.get("height", 0),
        )

        s = params["style"]
        # some of this is a bit "theme-ish" but it is very handy, so these
        # things don't have to be put directly into the style.
        for att in (
            "align",
            "valign",
            "x",
            "y",
            "width",
            "height",
            "color",
            "font",
            "background",
        ):
            if att in params:
                s[att] = params[att]
        self.style = style.Style(self, s)

        self.cls = "default"
        if "cls" in params:
            self.cls = params["cls"]
        if "name" in params:
            from . import form

            self.name = params["name"]
            if hasattr(form.Form, "form") and form.Form.form != None:
                form.Form.form.add(self)
                self.form = form.Form.form
        if "value" in params:
            self.value = params["value"]
        self.pcls = ""

        if params["decorate"] != False:
            from . import app

            if not hasattr(app.App, "app"):
                print("gui.widget: creating an App")
                app.App.app = app.App()
            app.App.app.theme.decorate(self, params["decorate"])

    def focus(self):
        """Focus this Widget.

        <pre>Widget.focus()</pre>
        """
        if getattr(self, "container", None) != None:
            if self.container.myfocus != self:  ## by Gal Koren
                self.container.focus(self)

    def blur(self):
        """Blur this Widget.

        <pre>Widget.blur()</pre>
        """
        if getattr(self, "container", None) != None:
            self.container.blur(self)

    def open(self):
        """Open this Widget as a modal dialog.

        <pre>Widget.open()</pre>
        """
        if getattr(self, "container", None) != None:
            self.container.open(self)

    def close(self):
        """Close this Widget (if it is a modal dialog.)

        <pre>Widget.close()</pre>
        """
        if getattr(self, "container", None) != None:
            self.container.close(self)

    def resize(self, width=None, height=None):
        """Template method - return the size and width of this widget.

        <p>Responsible for also resizing all sub-widgets.</p>

        <pre>Widget.resize(width,height): return width,height</pre>

        <dl>
        <dt>width<dd>suggested width
        <dt>height<dd>suggested height
        </dl>

        <p>If not overridden, will return self.style.width, self.style.height</p>
        """
        return self.style.width, self.style.height

    def chsize(self):
        """Change the size of this widget.

        <p>Calling this method will cause a resize on all the widgets,
        including this one.</p>

        <pre>Widget.chsize()</pre>
        """
        if not hasattr(self, "container"):
            return
        from . import app

        if hasattr(app.App, "app"):
            if app.App.app._chsize:
                return
            app.App.app.chsize()
            return

        # if hasattr(app.App,'app'):
        #    w,h = self.rect.w,self.rect.h
        #    w2,h2 = self.resize()
        #    if w2 != w or h2 != h:
        #        app.App.app.chsize()
        #    else:
        #        self.repaint()

    def update(self, s):
        """Template method - update the surface

        <pre>Widget.update(s): return list of pygame.Rect(s)</pre>

        <dl>
        <dt>s<dd>pygame.Surface to update
        </dl>

        <p>return - a list of the updated areas as pygame.Rect(s).</p>
        """
        return

    def paint(self, s):
        """Template method - paint the surface

        <pre>Widget.paint(s)</pre>

        <dl>
        <dt>s<dd>pygame.Surface to paint
        </dl>
        """
        return

    def repaint(self):
        """Request a repaint of this Widget.

        <pre>Widget.repaint()</pre>
        """
        if getattr(self, "container", None) != None:
            self.container.repaint(self)

    def repaintall(self):
        """Request a repaint of all Widgets.

        <pre>Widget.repaintall()</pre>
        """
        if getattr(self, "container", None) != None:
            self.container.repaintall()

    def reupdate(self):
        """Request a reupdate of this Widget

        <pre>Widget.reupdate()</pre>
        """
        if getattr(self, "container", None) != None:
            self.container.reupdate(self)

    def __next__(self):
        """Pass focus to next Widget.

        <p>Widget order determined by the order they were added to their container.</p>

        <pre>Widget.next()</pre>
        """
        if getattr(self, "container", None) != None:
            self.container.next(self)

    def previous(self):
        """Pass focus to previous Widget.

        <p>Widget order determined by the order they were added to their container.</p>

        <pre>Widget.previous()</pre>
        """

        if getattr(self, "container", None) != None:
            self.container.previous(self)

    def get_abs_rect(self):
        """Get the absolute rect of this widget on the App screen

        <pre>Widget.get_abs_rect(): return pygame.Rect</pre>
        """
        x, y = self.rect[:2]
        c = getattr(self, "container", None)
        while c:
            x += c.rect[0]
            y += c.rect[1]
            c = getattr(c, "container", None)
        return pygame.Rect(x, y, self.rect.w, self.rect.h)

    def connect(self, code, fnc, *values):
        """Connect a event code to a callback function.

        <p>There may only be one callback per event code.</p>

        <pre>Object.connect(code,fnc,value)</pre>

        <dl>
        <dt>code<dd>event type [[gui-const]]
        <dt>fnc<dd>callback function
        <dt>*values<dd>values to pass to callback.  Please note that callbacks may also have "magicaly" parameters.  Such as:
            <dl>
            <dt>_event<dd>receive the event
            <dt>_code<dd>receive the event code
            <dt>_widget<dd>receive the sending widget
            </dl>
        </dl>

        <strong>Example</strong>
        <code>
        def onclick(value):
            print 'click',value

        w = Button("PGU!")
        w.connect(gui.CLICK,onclick,'PGU Button Clicked')
        </code>
        """

        self.connects[code] = {"fnc": fnc, "values": values}

    def send(self, code, event=None):
        """Send a code, event callback trigger.

        <pre>Object.send(code,event=None)</pre>

        <dl>
        <dt>code<dd>event code
        <dt>event<dd>event
        </dl>
        """
        if code in self.connects:
            con = self.connects[code]
            # con['fnc'](*con['values'])

            fnc = con["fnc"]
            values = list(con["values"])

            nargs = fnc.__code__.co_argcount
            names = list(fnc.__code__.co_varnames)[:nargs]
            if hasattr(fnc, "im_class"):
                names.pop(0)

            args = []
            magic = {"_event": event, "_code": code, "_widget": self}
            for name in names:
                if name in list(magic.keys()):
                    args.append(magic[name])
                elif len(values):
                    args.append(values.pop(0))
                else:
                    break
            args.extend(values)
            fnc(*args)

    def _event(self, e):
        if self.disabled:
            return
        self.send(e.type, e)
        self.event(e)
        return
        from . import app

        if hasattr(app.App, "app"):
            app.App.app.events.append((self, e))

    def event(self, e):
        """Template method - called when an event is passed to this object.

        <dl>
        <dt>e<dd>event
        </dl>
        """

        return
