#!/usr/bin/env python3
import tkinter as tk
from math import ceil
try:
    from src.Perimeter import inside, convex
except Exception as E:
    print(E)

    convex = inside = lambda *x: 0.0

class ShapeEditorApp:
    def _center(self, objid):
        x0, y0, x1, y1 = self.canvas.coords(objid)
        return (x1 + x0) / 2, (y1 + y0) / 2

    def _oval(self, x, y):
        return x - self.radius, y - self.radius, x + self.radius, y + self.radius

    def _float(self, xy):
        return [float(c) for c in xy.split(",")]

    def _load(self, file):
        with open(file, "rt") as f:
            dots = [self._float(dot) for dot in f.readline().split()]
            single = self._float(f.readline())
        return dots, single

    def __init__(self, root, file=None):
        self.root = root
        self.root.title("Shape Editor")
        self.root.rowconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        self.root.columnconfigure(0, weight=1)

        # Create Canvas widget
        self.canvas = tk.Canvas(root, bg="linen")
        self.canvas.grid(column=0, row=0, sticky="NEWS")
        self.info = tk.StringVar()
        self.dump = tk.Label(self.root, textvariable=self.info, justify=tk.LEFT)
        self.dump.grid(column=0, row=1, sticky="NEWS")

        self.dots, self.singledot, self.line, self.closeline, self.moving = [], None, None, None, None
        self.one = float(self.canvas["height"]) // 100
        self.width, self.radius = ceil(self.one / 2), self.one * 1.5

        self.canvas.bind("<Button-1>", self.next)
        self.canvas.bind("<Button-3>", self.next)
        self.canvas.bind("<Motion>", self.move)
        self.root.bind("<Any-KeyPress>", self.control)

        self.inspect = False

        if file:
            dots, (sx, sy) = self._load(file)
            for x, y in dots:
                self.next(type("event", (), {"x": x, "y": y, "num": 1}))
            self.canvas.event_generate("<Button-2>", x=sx, y=sy)

    def control(self, event):
        # print(event)
        match event.keysym:
            case "Escape" | "q":
                root.quit()
            case "space":
                self.canvas.event_generate("<Button-2>", x=event.x, y=event.y)
            case "Delete" | "BackSpace":
                if self.dots:
                    self.moving = self.dots[-1]

    def move(self, event):
        if self.moving:
            oval = self._oval(event.x, event.y)
            self.canvas.coords(self.moving, *oval)
            newline = [self._center(obj) for obj in self.dots]
            self.canvas.coords(self.line, *newline)
            self.canvas.coords(self.closeline, *self._center(self.dots[0]), *self._center(self.dots[-1]))

    def has_dot(self, x, y, *sets):
        res = set(self.canvas.find_overlapping(x, y, x, y)) & set.union(*map(set, sets))
        return res.pop() if res else None

    def next(self, event):
        c = self.canvas
        oval = self._oval(event.x, event.y)
        if obj := self.has_dot(event.x, event.y, self.dots, {self.singledot}):
            if self.moving:
                self.moving = None
            else:
                self.moving = obj
        elif event.num != 1:
            self.moving = None
            if self.singledot:
                c.coords(self.singledot, oval)
            else:
                self.singledot = c.create_oval(*oval, fill="firebrick")
        else:
            self.moving = None
            self.dump["wraplength"] = self.root.grid_bbox(0, 0, 1, 1)[2]
            self.dots.append(c.create_oval(*oval, fill="black"))
            if len(self.dots) < 2:
                return
            (x0, y0), (x1, y1) = self._center(self.dots[0]), self._center(self.dots[-1])
            if len(self.dots) == 2:
                self.line = c.create_line(x0, y0, x1, y1, fill="grey", width=self.width)
            else:
                c.coords(self.line, *c.coords(self.line), x1, y1)
            if len(self.dots) == 3:
                self.closeline = c.create_line(x1, y1, x0, y0, fill="grey66", width=self.width, dash=self.width)
            if len(self.dots) > 3:
                c.coords(self.closeline, x1, y1, x0, y0)
        longstr = " ".join(f"{c[0]},{c[1]}" for c in (self._center(dot) for dot in self.dots))
        if self.singledot:
            x, y = self._center(self.singledot)
            longstr += f"\n{x},{y}"
            if self.dots:
                c.itemconfigure(self.line, fill="darkgreen" if convex(map(self._center, self.dots)) else "firebrick")
                internal = inside(self._center(self.singledot), map(self._center, self.dots))
                c.itemconfigure(self.singledot, fill="darkgreen" if internal else "firebrick")

        self.info.set(longstr)
        self.root.clipboard_clear()
        self.root.clipboard_append(longstr)
        root.update()


if __name__ == "__main__":
    import sys
    root = tk.Tk()
    app = ShapeEditorApp(root, sys.argv[1] if len(sys.argv) > 1 else None)
    root.mainloop()
    print(app.info.get())
