const TOOLS = {
    select: new SelectTool("select"),
    collect: new CollectTool("collect"),
    delete: new DeleteTool("delete"),
    addnode: new AddNodeTool("addnode"),
    connect: new ConnectTool("connect"),
};

const CONTEXT = {
    node: "node",
    link: "link",
    mixed: "mixed",
};

class State extends Tool {
    constructor() {
        super("State");

        this.display = new Display(TOOLS);

        this.tool = undefined;
        this.setTool(TOOLS.select);

        // Shared variables
        this.selectedItem = undefined;
        this.selectedItems = new Set();
        this.itemsContext = undefined;

        this.keyStates = {};
    }

    setTool(tool) {
        if (this.tool === tool) {
            return;
        }

        this.tool.onToolDeactivate(tool);

        this.previousTool = this.tool;
        this.tool = tool;
        this.display.setSelectedTool(tool);

        this.tool.onToolActivate();
    }

    setSelectedItem(item) {
        this.selectedItem = item;
        this.display.setSelectedItem(item);
    }

    addSelectedItem(item) {
        this.selectedItems.add(item);
        this.display.setSelectedItems(this.selectedItems, this.itemsContext);
    }

    removeSelectedItem(item) {
        this.selectedItems.delete(item);
        this.display.setSelectedItems(this.selectedItems, this.itemsContext);
    }

    clearSelectedItems() {
        this.selectedItems.clear();
        this.itemsContext = undefined;
        this.display.setSelectedItems(this.selectedItems, this.itemsContext);
    }

    onNodeClick(node) {
        this.tool.onNodeClick(node);
    }

    onLinkClick(link) {
        this.tool.onLinkClick(link);
    }

    onKeyDown(key) {
        var id = this.getKeyId(key);
        var previous = this.keyStates[id];

        this.keyStates[id] = true;

        if (previous !== true) {
            this.tool.onKeyDown(key);
        }
    }

    onKeyUp(key) {
        var id = this.getKeyId(key);
        var previous = this.keyStates[id];

        this.keyStates[id] = false;

        if (previous !== false) {
            this.tool.onKeyUp(key);
        }
    }

    getKeyId(key) {
        return key.keyCode;
    }

    nodeCanvasObject(node, ctx) {
        var toolValue = this.tool.nodeCanvasObject(node, ctx);

        if (toolValue !== undefined) {
            return toolValue;
        }

        // TODO: Clean up function

        // add ring just for highlighted nodes
        if (this.selectedItem === node || this.selectedItems.has(node)) {
            ctx.beginPath();
            ctx.arc(node.x, node.y, 5 * 1.4, 0, 2 * Math.PI, false);
            ctx.fillStyle = this.selectedItem === node ? "red" : "green";
            ctx.fill();
        }

        // Draw image
        if (node[NODE_IMAGE] !== undefined) {
            var path = IMAGE_SRC + node[NODE_IMAGE];
            var img = new Image();
            img.src = path;

            ctx.drawImage(
                img,
                node.x - IMAGE_SIZE / 2,
                node.y - IMAGE_SIZE / 2,
                IMAGE_SIZE,
                IMAGE_SIZE
            );
        }

        // TODO: Render label as always visible
    }

    nodePointerAreaPaint(node, color, ctx) {
        var toolValue = this.tool.nodePointerAreaPaint(node, color, ctx);

        if (toolValue !== undefined) {
            return toolValue;
        }

        ctx.fillStyle = color;
        ctx.fillRect(
            node.x - IMAGE_SIZE / 2,
            node.y - IMAGE_SIZE / 2,
            IMAGE_SIZE,
            IMAGE_SIZE
        ); // draw square as pointer trap
    }

    nodeCanvasObjectMode(node) {
        var toolValue = this.tool.nodeCanvasObjectMode(node);

        if (toolValue !== undefined) {
            return toolValue;
        }

        return "after";
    }

    linkWidth(link) {
        var toolValue = this.tool.linkWidth(link);

        if (toolValue !== undefined) {
            return toolValue;
        }

        return this.isLinkHighlighted(link) ? 5 : 1;
    }

    linkDirectionalParticles() {
        var toolValue = this.tool.linkDirectionalParticles();

        if (toolValue !== undefined) {
            return toolValue;
        }

        return 4;
    }

    linkDirectionalParticleWidth(link) {
        var toolValue = this.tool.linkDirectionalParticleWidth(link);

        if (toolValue !== undefined) {
            return toolValue;
        }

        return this.isLinkHighlighted(link) ? LINK_PARTICLE_COUNT : 0;
    }

    onBackgroundClick(event, positions) {
        this.tool.onBackgroundClick(event, positions);
    }

    redraw() {
        this.display.setSelectedTool(this.tool);
        this.display.setSelectedItem(this.selectedItem);
        this.display.setSelectedItems(this.selectedItems, this.itemsContext);
    }

    isLinkHighlighted(link) {
        return (
            this.selectedItem === link ||
            graph.isLinkOnNode(link, state.selectedItem)
        );
    }
}