import { Toolbox } from "./Toolbox";
import { TextToolbox } from "./TextToolbox";
import { IconToolbox, IShapeIconToolboxOptions } from "./IconToolbox";
import { IShapeDescriptionManager } from "../../Model/Shapes/Descriptions/ShapeDescriptionManager";
import { ITextMeasurer } from "../Measurer/ITextMeasurer";
import { TextMeasurer } from "../Measurer/TextMeasurer";
import { MathUtils } from "@devexpress/utils/lib/utils/math";

export class ToolboxManager {
    private toolboxes: Toolbox[] = [];
    private measurers: { [id: string]: ITextMeasurer } = {};

    constructor(protected shapeDescriptionManager: IShapeDescriptionManager) { }

    create(parent: HTMLElement, readOnly: boolean, allowDragging: boolean, renderAsText: boolean,
        shapes: string | string[], getAllowedShapeTypes: (shapes: string[]) => string[],
        options?: IShapeIconToolboxOptions) {
        const shapeTypes = Array.isArray(shapes) ? shapes : this.shapeDescriptionManager.getTypesByCategory(shapes);
        const toolbox = renderAsText ?
            new TextToolbox(parent, readOnly, allowDragging, this.shapeDescriptionManager,
                shapeTypes, getAllowedShapeTypes) :
            new IconToolbox(parent, readOnly, allowDragging, this.shapeDescriptionManager,
                shapeTypes, getAllowedShapeTypes, options, this.getOrCreateMeasurer(parent));
        toolbox.render();
        this.toolboxes.push(toolbox);
        return toolbox;
    }

    clean(removeElement?: (element: HTMLElement) => void, toolbox?: Toolbox) {
        if(toolbox) {
            toolbox.clean(removeElement);
            this.toolboxes.splice(this.toolboxes.indexOf(toolbox), 1);
            Object.keys(this.measurers).forEach(key => {
                if(this.measurers[key] === toolbox.measurer)
                    delete this.measurers[key];
            });
        }
        else {
            for(let i = 0; i < this.toolboxes.length; i++)
                this.toolboxes[i].clean(removeElement);
            this.toolboxes = [];
            this.measurers = {};
        }
    }

    refresh(toolboxes?: number[] | number): void {
        this.toolboxes.forEach((toolbox, index) => {
            if(!toolboxes || (Array.isArray(toolboxes) && toolboxes.indexOf(index) > -1) || index === toolboxes)
                toolbox.render();
        });
    }

    applyFilter(str: string, toolboxes?: number[] | number): number[] {
        return this.toolboxes.reduce((aggr, toolbox, index) => {
            if(!toolboxes || (Array.isArray(toolboxes) && toolboxes.indexOf(index) > -1) || index === toolboxes)
                toolbox.render(shapeType => this.searchFilter(shapeType, str, index)) && aggr.push(index);
            return aggr;
        }, []);
    }

    protected searchFilter(shapeType: string, str: string, toolboxIndex: number, filteringToolboxes?: number[]): boolean {
        if(!str || (filteringToolboxes && filteringToolboxes.indexOf(toolboxIndex) === -1)) return true;
        str = str.toLowerCase();
        const shapeDescription = this.shapeDescriptionManager.get(shapeType);
        return shapeDescription.getTitle().toLowerCase().indexOf(str) > -1 ||
            shapeDescription.getDefaultText().toLowerCase().indexOf(str) > -1;
    }
    private getOrCreateMeasurer(parent: HTMLElement): ITextMeasurer {
        let id = parent.getAttribute("data-dxdiMeasurerID");
        if(!id || !this.measurers[id]) {
            id = MathUtils.generateGuid();
            this.measurers[id] = new TextMeasurer(parent);
            parent.setAttribute("data-dxdiMeasurerID", id);
        }
        return this.measurers[id];
    }
}
