#include args.js
#include colour.js
#include utility.js
#include controls/tabs.js
#include colpick/tgrid.jsx
#include colpick/tpresets.jsx
#include colpick/tsliders.jsx
#include colpick/vhex.jsx
#include colpick/vraw.jsx

const MamiColourPicker = function(options) {
    options = MamiArguments.verify(options, [
        MamiArguments.filter('colour', 'number', 0, num => Math.min(0xFFFFFF, Math.max(0, num))),
        MamiArguments.type('posX', 'number', -1),
        MamiArguments.type('posY', 'number', -1),
        MamiArguments.type('presets', 'object', []),
        MamiArguments.type('showPresetsTab', 'boolean', options.presets.length > 0),
        MamiArguments.type('showGridTab', 'boolean', true),
        MamiArguments.type('showSlidersTab', 'boolean', true),
        MamiArguments.type('showHexValue', 'boolean', true),
        MamiArguments.type('showRawValue', 'boolean', true),
        MamiArguments.type('showDialogButtons', 'boolean', true),
    ]);

    let colour;
    const needsColour = [];

    let promiseResolve;
    const runResolve = () => {
        if(promiseResolve !== undefined)
            promiseResolve(colour);
        close();
    };

    let promiseReject;
    const runReject = () => {
        if(promiseReject !== undefined)
            promiseReject();
        close();
    };

    let tabsElem, tabsContainer, tabsList;
    let values, buttons;

    const html = <form class="colpick" style={{ zIndex: '9001' }} onsubmit={ev => { ev.preventDefault(); runResolve(); return false; }}>
        {tabsElem = <div class="colpick-tabbed">
            {tabsContainer = <div class="colpick-tabbed-container"/>}
            {tabsList = <div class="colpick-tabbed-list"/>}
        </div>}
        <div class="colpick-middle-row">
            <div class="colpick-colour-preview-container">
                <div class="colpick-colour-preview"/>
            </div>
            {values = <div class="colpick-values-container"/>}
        </div>
        <div class="colpick-buttons-container">
            {buttons = <div class="colpick-buttons-container-inner"/>}
        </div>
    </form>;

    const close = () => html.parentNode.removeChild(html);

    const setColour = (raw, mask) => {
        raw = typeof raw === 'number' ? (parseInt(raw) & 0xFFFFFF) : 0;
        mask = typeof mask === 'number' ? parseInt(mask) : ~0;

        colour = (colour & ~mask) | (raw & mask);

        const text = MamiColour.text(colour);
        html.style.setProperty('--colpick-colour', MamiColour.hex(colour));
        html.style.setProperty('--colpick-text', MamiColour.hex(text));

        for(const info of needsColour)
            if('updateColour' in info)
                info.updateColour(colour, text);
    };

    const setPosition = pos => {
        if(typeof pos !== 'object')
            throw 'pos must be an object';

        html.style.top = 'y' in pos && pos.y >= 0 ? `${pos.y}px` : null;
        html.style.left = 'x' in pos && pos.x >= 0 ? `${pos.x}px` : '';
    };

    const tabs = new MamiTabsControl({
        onAdd: ctx => {
            const name = ctx.info.getName(),
                containerName = `colpick-tab-${name}-container`,
                buttonName = `colpick-tab-${name}-button`;

            needsColour.push(ctx.info);
            ctx.info.onChange(setColour);

            ctx.elem.className = `colpick-tab-container ${containerName} colpick-tab-container-inactive`;
            tabsContainer.appendChild(ctx.elem);

            tabsList.appendChild(<input type="button" value={ctx.title}
                class={['colpick-tab-button', buttonName]}
                onclick={ctx.onClick}/>);
        },
        onRemove: ctx => {
            const name = ctx.info.getName();
            $rq(`.colpick-tab-${name}-button`);
            $rq(`.colpick-tab-${name}-container`);
        },
        onSwitch: ctx => {
            if(ctx.from !== undefined) {
                ctx.from.elem.classList.toggle('colpick-tab-container-inactive', true);
                $q(`.colpick-tab-${ctx.from.info.getName()}-button`).classList.toggle('colpick-tab-button-active', false);
            }

            ctx.elem.classList.toggle('colpick-tab-container-inactive', false);
            $q(`.colpick-tab-${ctx.info.getName()}-button`).classList.toggle('colpick-tab-button-active', true);
        },
    });

    if(options.showPresetsTab)
        tabs.add(new MamiColourPickerPresetsTab(options.presets));
    if(options.showGridTab)
        tabs.add(new MamiColourPickerGridTab);
    if(options.showSlidersTab)
        tabs.add(new MamiColourPickerSlidersTab);

    if(tabs.count() < 1)
        html.removeChild(tabsElem);

    const addValue = (id, name, valueInfo) => {
        needsColour.push(valueInfo);
        valueInfo.onChange(setColour);
        values.appendChild(<label class={['colpick-values-child', `colpick-${id}-value`]}>
            <div class={['colpick-values-child-label', `colpick-${id}-value-label`]}>{name}</div>
            {valueInfo}
        </label>);
    };

    if(options.showHexValue)
        addValue('hex', 'Hex', new MamiColourPickerValueHex);
    if(options.showRawValue)
        addValue('raw', 'Raw', new MamiColourPickerValueRaw);

    const addButton = (id, name, action) => {
        const button = <input class={['colpick-buttons-button', `colpick-buttons-${id}-button`]} value={name}/>;

        if(action === undefined) {
            button.classList.add('colpick-buttons-button-submit');
            button.type = 'submit';
        } else {
            button.onclick = () => action();
            button.type = 'button';
        }

        buttons.appendChild(button);
    };

    if(options.showDialogButtons) {
        addButton('cancel', 'Cancel', runReject);
        addButton('apply', 'Apply');
    }

    setPosition({ x: options.posX, y: options.posY });
    setColour(options.colour);

    return {
        getElement: () => html,
        getColour: () => colour,
        setColour: setColour,
        setPosition: setPosition,
        close: close,
        dialog: pos => {
            if(pos !== undefined)
                setPosition(pos);

            return new Promise((resolve, reject) => {
                promiseResolve = resolve;
                promiseReject = reject;
            });
        },
        suggestPosition: mouseEvent => {
            let x = 10, y = 10;

            if(html.parentNode.clientWidth > 340) {
                x = mouseEvent.clientX;
                y = mouseEvent.clientY;

                const bb = html.getBoundingClientRect();

                if(y > bb.height + 20)
                    y -= bb.height;
                if(x > html.parentNode.clientWidth - bb.width - 20)
                    x -= bb.width;
            }

            return { x: x, y: y };
        },
    };
};
