from math import ceil as float_ceil, pi
import cairo

from gi.repository import Gtk, Gdk, GObject

from .OverlayWindow import OverlayWindow

# ceil = lambda f: int(float_ceil(f))


def ceil(num):
    return int(float_ceil(num))


POSITIONS_COUNT = 5
NORTH, EAST, SOUTH, WEST, CENTER = range(POSITIONS_COUNT)
DX_DY = ((0, -1), (1, 0), (0, 1), (-1, 0), (0, 0))
PADDING_X = 0.2  # Amount of button width
PADDING_Y = 0.4  # Amount of button height


class StarArrowButton(OverlayWindow):
    __gsignals__ = {
        "dropped": (GObject.SignalFlags.RUN_FIRST, None, (int, object)),
        "hovered": (GObject.SignalFlags.RUN_FIRST, None, (int, object)),
        "left": (GObject.SignalFlags.RUN_FIRST, None, ()),
    }

    def __init__(self, parent, northSvg, eastSvg, southSvg, westSvg, centerSvg, bgSvg):
        OverlayWindow.__init__(self, parent)

        self.svgs = (northSvg, eastSvg, southSvg, westSvg, centerSvg)
        self.bgSvg = bgSvg
        self.size = ()
        self.currentHovered = -1

        # targets = [("GTK_NOTEBOOK_TAB", Gtk.TargetFlags.SAME_APP, 0xbadbeef)]
        targets = [
            Gtk.TargetEntry.new("GTK_NOTEBOOK_TAB", Gtk.TargetFlags.SAME_APP, 0xBADBEEF)
        ]
        self.drag_dest_set(
            Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION,
            targets,
            Gdk.DragAction.MOVE,
        )
        self.drag_dest_set_track_motion(True)
        self.myparent.button_cids += [
            self.connect("drag-motion", self.__onDragMotion),
            self.connect("drag-leave", self.__onDragLeave),
            self.connect("drag-drop", self.__onDragDrop),
            self.connect_after("draw", self.__onExposeEvent),
        ]
        self.myparentAlloc = None
        self.myparentPos = None
        self.hasHole = False
        self.size = ()

    def _calcSize(self):
        parentAlloc = self.myparent.get_allocation()

        if (
            self.myparentAlloc is None
            or parentAlloc.width != self.myparentAlloc.width
            or parentAlloc.height != self.myparentAlloc.height
        ):
            starWidth, starHeight = self.getSizeOfSvg(self.bgSvg)
            scale = min(
                1,
                parentAlloc.width / float(starWidth),
                parentAlloc.height / float(starHeight),
            )
            self.size = list(map(int, (starWidth * scale, starHeight * scale)))
            self.resize(self.size[0], self.size[1])

            if self.get_window():
                self.hasHole = True
                self.digAHole(self.bgSvg, self.size[0], self.size[1])

        elif not self.hasHole:
            self.hasHole = True
            self.digAHole(self.bgSvg, self.size[0], self.size[1])

        if self.myparent.get_window():
            x_loc, y_loc = self.translateCoords(
                int(parentAlloc.width / 2.0 - self.size[0] / 2.0),
                int(parentAlloc.height / 2.0 - self.size[1] / 2.0),
            )
            if (x_loc, y_loc) != self.get_position():
                self.move(x_loc, y_loc)

            self.myparentPos = self.myparent.get_window().get_position()
        self.myparentAlloc = parentAlloc

    def __onExposeEvent(self, self_, ctx):
        self._calcSize()

        context = self.get_window().cairo_create()
        self.paintTransparent(context)
        surface = self.getSurfaceFromSvg(self.bgSvg, self.size[0], self.size[1])
        context.set_source_surface(surface, 0, 0)
        context.paint()

        for position in range(POSITIONS_COUNT):
            rect = self.__getButtonRectangle(position)

            context = self.get_window().cairo_create()
            surface = self.getSurfaceFromSvg(
                self.svgs[position], rect.width, rect.height
            )
            context.set_source_surface(surface, rect.x, rect.y)
            context.paint()

    def __getButtonRectangle(self, position):
        starWidth, starHeight = self.getSizeOfSvg(self.bgSvg)
        buttonWidth, buttonHeight = self.getSizeOfSvg(self.svgs[position])

        buttonWidth = buttonWidth * self.size[0] / float(starWidth)
        buttonHeight = buttonHeight * self.size[1] / float(starHeight)
        dx_loc, dy_loc = DX_DY[position]
        x_loc = ceil(
            dx_loc * (1 + PADDING_X) * buttonWidth
            - buttonWidth / 2.0
            + self.size[0] / 2.0
        )
        y_loc = ceil(
            dy_loc * (1 + PADDING_Y) * buttonHeight
            - buttonHeight / 2.0
            + self.size[1] / 2.0
        )

        rect = Gdk.Rectangle()
        rect.x, rect.y, rect.width, rect.height = (
            x_loc,
            y_loc,
            ceil(buttonWidth),
            ceil(buttonHeight),
        )
        return rect

    def __getButtonAtPoint(self, x, y):
        for position in range(POSITIONS_COUNT):
            rect = Gdk.Rectangle()
            rect.x, rect.y, rect.width, rect.height = (x, y, 1, 1)

            inside, dest = Gdk.rectangle_intersect(
                self.__getButtonRectangle(position), rect
            )
            if inside:
                return position
        return -1

    def __onDragMotion(self, arrow, context, x, y, timestamp):
        position = self.__getButtonAtPoint(x, y)
        if self.currentHovered != position:
            self.currentHovered = position
            if position > -1:
                self.emit("hovered", position, Gtk.drag_get_source_widget(context))
            else:
                self.emit("left")

        if position > -1:
            Gdk.drag_status(context, Gdk.DragAction.MOVE, timestamp)
            return True
        Gdk.drag_status(context, Gdk.DragAction.DEFAULT, timestamp)

    def __onDragLeave(self, arrow, context, timestamp):
        if self.currentHovered != -1:
            self.currentHovered = -1
            self.emit("left")

    def __onDragDrop(self, arrow, context, x, y, timestamp):
        position = self.__getButtonAtPoint(x, y)
        if position > -1:
            self.emit("dropped", position, Gtk.drag_get_source_widget(context))
            context.finish(True, True, timestamp)
            return True


if __name__ == "__main__":
    w = Gtk.Window()
    w.connect("delete-event", Gtk.main_quit)
    sab = StarArrowButton(
        w,
        "/home/thomas/Programmering/workspace/pychess/glade/dock_top.svg",
        "/home/thomas/Programmering/workspace/pychess/glade/dock_right.svg",
        "/home/thomas/Programmering/workspace/pychess/glade/dock_bottom.svg",
        "/home/thomas/Programmering/workspace/pychess/glade/dock_left.svg",
        "/home/thomas/Programmering/workspace/pychess/glade/dock_center.svg",
        "/home/thomas/Programmering/workspace/pychess/glade/dock_star.svg",
    )

    def on_expose(widget, event):
        cairo_win = widget.window.cairo_create()
        cx_loc = cy_loc = 100
        radius = 50
        cairo_win.arc(cx_loc, cy_loc, radius - 1, 0, 2 * pi)
        cairo_win.set_source_rgba(1.0, 0.0, 0.0, 1.0)
        cairo_win.set_operator(cairo.OPERATOR_OVER)
        cairo_win.fill()

    # w.connect("e)
    w.show_all()
    sab.show_all()
    Gtk.main()

# if __name__ != "__main__":
#    w = Gtk.Window()
#    w.connect("delete-event", Gtk.main_quit)
#    hbox = Gtk.HBox()
#
#    l = Gtk.Layout()
#    l.set_size_request(200,200)
#    sab = StarArrowButton("/home/thomas/Programmering/workspace/pychess/glade/dock_top.svg",
#                          "/home/thomas/Programmering/workspace/pychess/glade/dock_right.svg",
#                          "/home/thomas/Programmering/workspace/pychess/glade/dock_bottom.svg",
#                          "/home/thomas/Programmering/workspace/pychess/glade/dock_left.svg",
#                          "/home/thomas/Programmering/workspace/pychess/glade/dock_center.svg",
#                          "/home/thomas/Programmering/workspace/pychess/glade/dock_star.svg")
#    sab.set_size_request(200,200)
#    l.put(sab, 0, 0)
#    hbox.add(l)
#    def handle (*args):
#        sab.showAt(l, CENTER)
#    l.connect("button-press-event", handle)
#
#    nb = Gtk.Notebook()
#    label = Gtk.Label(label="hi")
#    nb.append_page(label)
#    nb.set_tab_detachable(label, True)
#    hbox.add(nb)
#    w.add(hbox)
#    w.show_all()
#    Gtk.main()
