import * as Helpers from "../helpers";
import jQuery from "jquery";
import * as Config from "../../config";

export { NodeNeighborOverlay };

/**
 * Displays an overlay showing the neighbors of a node divided by the link type
 * that connects them.
 */
class NodeNeighborOverlay {
    constructor(graph, parentNode, infoOverlay) {
        this.graph = graph;
        this.parentNode = parentNode;
        this.infoOverlay = infoOverlay;

        this.activeTabNav = null; // The currently selected tab handle
        this.activeTabContent = null; // The currently selected tab content

        this.tabContentPages = {};
    }

    /**
     * Creates the visible elements of the overlay.
     * Must be called after the graph has been initialized.
     */
    create() {
        const bottomContainerDiv = Helpers.createDiv(
            "bottom-container",
            this.parentNode
        );
        const bottomContainerNavDiv = Helpers.createDiv(
            "bottom-container-nav",
            bottomContainerDiv
        );
        const bottomContainerLinkDiv = Helpers.createDiv(
            "bottom-container-links",
            bottomContainerDiv
        );

        for (const [cls, color] of Object.entries(this.graph.edgeColors)) {
            const navTab = Helpers.createDiv(
                "bottom-container-nav-tab",
                bottomContainerNavDiv
            );
            navTab.innerText = cls.slice(0, 3);
            navTab.style.backgroundColor = color;
            navTab.edgeType = cls; // Attach the edge type to the DOM object to retrieve it during click events
            jQuery(navTab).click((event) => this.openTab(event));

            const tabContent = Helpers.createDiv(
                "bottom-container-tab-content",
                bottomContainerLinkDiv
            );
            tabContent.style.backgroundColor = color;
            this.tabContentPages[cls] = tabContent;
        }
        this.initializeActive(bottomContainerNavDiv, bottomContainerLinkDiv);
    }

    /**
     * Initializes the activeTabNav and activeTabContent variables to a random edge type.
     * @param {Element} bottomContainerNavDiv
     * @param {Element} bottomContainerLinkDiv
     */
    initializeActive(bottomContainerNavDiv, bottomContainerLinkDiv) {
        this.activeTabNav = bottomContainerNavDiv.firstChild;
        this.activeTabContent = bottomContainerLinkDiv.firstChild;

        this.activeTabContent.classList.add("active-tab-content");
        this.activeTabNav.classList.add("active-tab-nav");
        this.activeTabNav.innerText = this.activeTabNav.edgeType;
    }

    /**
     * Click event handler for the tab headers of the bottom menu.
     * @param event
     */
    openTab(event) {
        const navTab = event.target;
        const cls = navTab.edgeType;

        this.activeTabNav.classList.remove("active-tab-nav");
        this.activeTabNav.innerText = this.activeTabNav.innerText.slice(0, 3);
        navTab.classList.add("active-tab-nav");
        navTab.innerText = cls;

        this.activeTabContent.classList.remove("active-tab-content");
        this.tabContentPages[cls].classList.add("active-tab-content");

        this.activeTabNav = navTab;
        this.activeTabContent = this.tabContentPages[cls];
    }

    /**
     * Clears the images from all tab content pages.
     */
    clearTabContentPages() {
        for (const page of Object.values(this.tabContentPages)) {
            jQuery(page).empty();
        }
    }

    /**
     * Creates a new image (with link) for the given target node.
     * @param target
     * @returns {HTMLDivElement}
     */
    createReference(target) {
        const linkDiv = document.createElement("div");
        linkDiv.className = "link-img";

        if ("image" in target) {
            const linkImage = document.createElement("img");
            linkImage.src =
                Config.PLUGIN_PATH + "datasets/images/" + target.image;
            linkDiv.appendChild(linkImage);
        }

        jQuery(linkDiv).on("click", () => {
            this.graph.focusOnNode(target);
            this.infoOverlay.updateInfoOverlay(target);
        });
        return linkDiv;
    }

    /**
     * Updates all tabs to have content matching the given node.
     * @param node
     */
    updateTabs(node) {
        this.clearTabContentPages();

        for (const link of node.links) {
            const target = link.source == node ? link.target : link.source;
            const reference = this.createReference(target);
            this.tabContentPages[link.type].appendChild(reference);
        }
    }
}