import Tool from "./tool";
import * as Graph from "../graph";
import jquery from "jquery";
import ToolMenu from "./menus/toolmenu";
import DeleteIcon from "../../images/tools/delete.png";
import { Editor } from "../components/editor";

const BOX_SELECT_LAYER_ID = "#box-select-layer";
const BOX_SELECT_ID_WH = "box-select";
const SELECT_BOX_SELECTOR = BOX_SELECT_LAYER_ID + " #" + BOX_SELECT_ID_WH;

/**
 * Only one instance of this should exist, since box-delete has to work on a global scale.
 */
var deleteToolInstance = undefined; // Used for box delete
export default class DeleteTool extends Tool {
    constructor(key) {
        super("Delete", DeleteIcon, key, new ToolMenu());
        this.setupBoxSelect();
        this.isActive = false;

        if (deleteToolInstance === undefined) {
            deleteToolInstance = this;
        }
    }

    onBoxSelect(left, bottom, top, right) {
        // Filter out selected nodes
        const selectedNodes = [];
        const tl = Editor.globalRenderer.screen2GraphCoords(left, top);
        const br = Editor.globalRenderer.screen2GraphCoords(right, bottom);
        Editor.globalGraph.data[Graph.GRAPH_NODES].forEach((node) => {
            if (
                tl.x < node.x &&
                node.x < br.x &&
                br.y > node.y &&
                node.y > tl.y
            ) {
                selectedNodes.push(node);
            }
        });

        // Was anything even selected?
        if (selectedNodes.length <= 0) {
            return;
        }

        // Ask for confirmation to delete
        var nodeNames = selectedNodes.map((n) => n[Graph.NODE_LABEL]);
        //! Problem: If browser is not actually showing the alerts, it always returns false!
        var shouldDelete = confirm(
            "Are you sure you want to delete all these nodes?\n\n" +
                nodeNames.join("\n")
        );

        // Delete if confirmed
        if (shouldDelete) {
            var nodeIds = selectedNodes.map((n) => n[Graph.NODE_ID]);
            Editor.globalGraph.deleteNodes(nodeIds);
        }
    }

    onNodeClick(node) {
        Editor.globalGraph.deleteNode(node[Graph.NODE_ID]);

        if (Editor.globalState.selectedItem == node) {
            Editor.globalState.setSelectedItem(undefined);
        }
    }

    onLinkClick(link) {
        Editor.globalGraph.deleteLink(
            link[Graph.LINK_SOURCE][Graph.NODE_ID],
            link[Graph.LINK_TARGET][Graph.NODE_ID]
        );

        if (Editor.globalState.selectedItem == link) {
            Editor.globalState.setSelectedItem(undefined);
        }
    }

    setupBoxSelect() {
        window.addEventListener("load", () => {
            // Source: https://github.com/vasturiano/force-graph/issues/151#issuecomment-735850938

            // forceGraph element is the element provided to the Force Graph Library
            jquery("#2d-graph").on("pointerdown", this.boxSelectOnPointerDown);
            jquery("#2d-graph").on("pointermove", this.boxSelectOnPointerMove);
            jquery("#2d-graph").on("pointerup", this.boxSelectOnPointerUp);
        });
    }

    boxSelectOnPointerDown(e) {
        // Only do anything if delete tool is also active
        if (
            deleteToolInstance === undefined ||
            deleteToolInstance.isActive == false
        ) {
            return;
        }

        if (!e.shiftKey) {
            return;
        }

        e.preventDefault();
        this.boxSelect = document.createElement("div");
        this.boxSelect.id = BOX_SELECT_ID_WH;
        this.boxSelect.style.left = e.offsetX.toString() + "px";
        this.boxSelect.style.top = e.offsetY.toString() + "px";
        this.boxSelectStart = {
            x: e.offsetX,
            y: e.offsetY,
        };
        // app element is the element just above the forceGraph element.
        jquery(BOX_SELECT_LAYER_ID).append(this.boxSelect);
    }

    boxSelectOnPointerMove(e) {
        if (!this.boxSelect) {
            return;
        }

        if (!e.shiftKey) {
            jquery(SELECT_BOX_SELECTOR).remove();
            return;
        }

        e.preventDefault();
        if (e.offsetX < this.boxSelectStart.x) {
            this.boxSelect.style.left = e.offsetX.toString() + "px";
            this.boxSelect.style.width =
                (this.boxSelectStart.x - e.offsetX).toString() + "px";
        } else {
            this.boxSelect.style.left = this.boxSelectStart.x.toString() + "px";
            this.boxSelect.style.width =
                (e.offsetX - this.boxSelectStart.x).toString() + "px";
        }
        if (e.offsetY < this.boxSelectStart.y) {
            this.boxSelect.style.top = e.offsetY.toString() + "px";
            this.boxSelect.style.height =
                (this.boxSelectStart.y - e.offsetY).toString() + "px";
        } else {
            this.boxSelect.style.top = this.boxSelectStart.y.toString() + "px";
            this.boxSelect.style.height =
                (e.offsetY - this.boxSelectStart.y).toString() + "px";
        }
    }

    boxSelectOnPointerUp(e) {
        if (!this.boxSelect) {
            return;
        }

        if (!e.shiftKey) {
            jquery(SELECT_BOX_SELECTOR).remove();
            return;
        }

        e.preventDefault();
        let left, bottom, top, right;
        if (e.offsetX < this.boxSelectStart.x) {
            left = e.offsetX;
            right = this.boxSelectStart.x;
        } else {
            left = this.boxSelectStart.x;
            right = e.offsetX;
        }
        if (e.offsetY < this.boxSelectStart.y) {
            top = e.offsetY;
            bottom = this.boxSelectStart.y;
        } else {
            top = this.boxSelectStart.y;
            bottom = e.offsetY;
        }
        this.boxSelect.remove();
        deleteToolInstance.onBoxSelect(left, bottom, top, right);
    }
}