from abc import ABC, abstractmethod

from browser import document
from visualife.core import HtmlViewport


class AbstractWindow(ABC):

    @abstractmethod
    def draw(self, viewport): pass

    @property
    @abstractmethod
    def x(self): pass

    @property
    @abstractmethod
    def y(self): pass

    @property
    @abstractmethod
    def w(self): pass

    @property
    @abstractmethod
    def h(self): pass


class SimpleWindow(AbstractWindow):
    def __init__(self, x, y, w, h):
        self.__x, self.__y = x, y
        self.__w, self.__h = w, h
        self.fill = "white"
        self.stroke = "black"

    @property
    def x(self): return self.__x

    @property
    def y(self): return self.__y

    @property
    def w(self): return self.__w

    @property
    def h(self): return self.__h

    def draw(self, viewport):
        viewport.rect("", self.x, self.y, self.w, self.h, fill=self.fill, stroke=self.stroke, stroke_width=1)


class AbstractDecorator(AbstractWindow):

    def __init__(self, decorated: AbstractWindow):
        self._decorated = decorated

    @abstractmethod
    def draw(self, viewport): pass

    @property
    def x(self): return self._decorated.x

    @property
    def y(self): return self._decorated.y

    @property
    def w(self): return self._decorated.w

    @property
    def h(self): return self._decorated.h


class TitlebarWindow(AbstractDecorator):

    def __init__(self, a_window, bar_height=10):
        super().__init__(a_window)
        self.bar_height = bar_height

    def draw(self, viewport):
        # --- draw the simple window
        self._decorated.draw(viewport)
        # --- and draw the decoration - a title bar and the title itself
        viewport.rect("", self.x, self.y, self.w, self.bar_height, stroke_width=1)
        viewport.text("", self.x+30, self.y+8, "window title", stroke_width=0, fill="white", text_anchor="start")


class DropShadow(AbstractDecorator):

    def __init__(self, a_window):
        super().__init__(a_window)

    def draw(self, viewport):
        # --- draw the shadow first
        viewport.rect("", self.x+5, self.y+5, self.w, self.h, fill="lightgray", stroke_width=0)
        # --- and draw the main window
        self._decorated.draw(viewport)


class MenuBar(AbstractDecorator):

    def __init__(self, a_window, menu_items):
        super().__init__(a_window)
        self.__items = menu_items

    def draw(self, viewport):
        # --- draw the simple window
        self._decorated.draw(viewport)
        # --- add the menu
        for i, el in enumerate(self.__items):
            viewport.text("", self.x+i*40+10, self.y+20, el, stroke_width=0, fill="black", text_anchor="start")


class MacButtons(AbstractDecorator):

    def __init__(self, a_window):
        super().__init__(a_window)

    def draw(self, viewport):
        # --- draw the simple window
        self._decorated.draw(viewport)
        # --- and draw the decoration - a title bar and the title itself
        viewport.circle("", self.x+5, self.y+5, 3, fill="red", stroke_width=1, stroke="darker")
        viewport.circle("", self.x+15, self.y+5, 3, fill="yellow", stroke_width=1, stroke="darker")
        viewport.circle("", self.x+25, self.y+5, 3, fill="green", stroke_width=1, stroke="darker")


def build_window(x, y, if_shadow, if_title, if_menu, if_icons):
    w = SimpleWindow(x, y, 150, 80)
    if if_shadow:
        w = DropShadow(w)
    if if_title:
        w = TitlebarWindow(w)
    if if_icons:
        w = MacButtons(w)
    if if_menu:
        w = MenuBar(w, ["File", "Edit", "Help"])
    return w


def click_evt(event):
    global drawing

    x, y = event.clientX, event.clientY
    rect = document["drawing"].getBoundingClientRect()
    w = build_window(x-rect.left, y-rect.top, document["shadow"].checked, document["title"].checked,
                     document["menu"].checked, document["icons"].checked)
    w.draw(drawing)
    drawing.close()

def clear_evt(event):
    global drawing
    drawing.clear()
    drawing.rect("", 0, 0, 499, 399, stroke_width=1, fill="white")
    drawing.close()

drawing = HtmlViewport(document['drawing'], 500, 400)
drawing.rect("", 0, 0, 499, 399, stroke_width=1, fill="white")
drawing.close()

document["drawing"].bind("click", click_evt)
document["clear"].bind("click", clear_evt)