var HL = HL || {};

/** TODO
 * sentence type logic
 * flip between cfg and edit
 * upload
 * conditionals - hide not needed on load
 * strip out spans without highlight from answer
 * ARIA - where highlight ends at end of block should ARIA be applied on next span or an empty span added within block?
 * add button to set static (unhighlightable) text
 */

HL.configure = (function(utils) {
    var container = OU.utils.createElement('div'),
        cfg = {};

    cfg.tool = {
        debug: true,
        prehighlight: false,
        static: false,
        type: {
            curr: '',
            prev: ''
        },
        pens: [
            'yellow',
            'green',
            'pink',
            'blue',
            'orange',
            'red',
            'aqua',
            'purple',
            'slate',
            'brown'
        ],
        languages: ['en', 'fr', 'it', 'es', 'de']
    };

    cfg.activity = {
        options: [
            {
                id: 'type',
                input: {
                    type: 'select',
                    label: {
                        prefix: 'Type:'
                    },
                    options: [
                        {
                            label: 'Character',
                            value: 'character'
                        },
                        {
                            label: 'Word',
                            value: 'word'
                        },
                        {
                            label: 'Sentence',
                            value: 'sentence',
                            disabled: true
                        },
                        {
                            label: 'Paragraph',
                            value: 'paragraph',
                            disabled: true
                        },
                        {
                            label: 'Custom',
                            value: 'custom'
                        }
                    ]
                },
                update: function (value, prev) {
                    cfg.tool.type.prev = prev;
                },
                conditional: [
                    ['splitWord', 'word'],
                    ['background', 'custom']
                ]
            },
            {
                id: 'lang',
                panel: 'general',
                input: {
                    type: 'select',
                    label: {
                        prefix: 'Language:'
                    },
                    options: cfg.tool.languages.map(function(lang) {
                        return {
                            label: lang,
                            value: lang,
                            selected: (lang == 'en')
                        };
                    })
                }
            },
            {
                id: 'splitWord',
                panel: 'type',
                input: {
                    type: 'checkbox',
                    label: 'Split on punctuation'
                }
            },
            {
                id: 'background',
                panel: 'type',
                input: {
                    type: 'checkbox',
                    label: 'Apply grey background'
                }
            },
            {
                id: 'dragging',
                options: [
                    {
                        id: 'enabled',
                        input: {
                            type: 'checkbox',
                            label: 'Enable'
                        },
                        conditional: [
                            ['selection', true]
                        ]
                    },
                    {
                        id: 'selection',
                        input: {
                            type: 'checkbox',
                            label: 'Simulate selection'
                        }

                    }
                ]
            },
            {
                id: 'pens',
                options: cfg.tool.pens.map(function(colour) {
                    return {
                        id: colour,
                        options: [
                            {
                                id: 'label',
                                input: {
                                    type: 'textarea',
                                    label: {
                                        prefix: 'Label:'
                                    }
                                },
                                update: function(value) {
                                    activity.pens.selected.setLabel(value);
                                }
                            },
                            {
                                id: 'index',
                                input: {
                                    type: 'select',
                                    label: {
                                        prefix: 'Position:'
                                    },
                                    placeholder: false,
                                    options: cfg.tool.pens.map(function(pen, i) {
                                        return {
                                            label: i + 1
                                        };
                                    })
                                },
                                update: function() {
                                    updatePenPosition.apply(this, arguments);
                                    //options.set();
                                }
                            }
                        ]
                    };
                })
            },
            {
                id: 'spaces',
                options: [
                    {
                        id: 'selectable',
                        input: {
                            type: 'checkbox',
                            label: 'Selectable'
                        },
                        conditional: [
                            ['spaces:mark', true]
                        ]
                    },
                    {
                        id: 'mark',
                        input: {
                            type: 'checkbox',
                            label: 'Include when marking',
                            disabled: true
                        }
                    }
                ]
            },
            {
                id: 'punctuation',
                options: [
                    {
                        id: 'selectable',
                        input: {
                            type: 'checkbox',
                            label: 'Selectable'
                        },
                        conditional: [
                            ['punctuation:mark', true]
                        ]
                    },
                    {
                        id: 'mark',
                        input: {
                            type: 'checkbox',
                            label: 'Include when marking',
                            disabled: true
                        }
                    }
                ]
            },
            {
                id: 'buttons',
                options: [
                    {
                        id: 'check',
                        input: {
                            type: 'checkbox',
                            label: 'Check',
                            value: 'check',
                            disabled: true
                        }
                    },
                    {
                        id: 'reveal',
                        input: {
                            type: 'checkbox',
                            label: 'Reveal',
                            value: 'reveal'
                        }
                    },
                    {
                        id: 'save',
                        input: {
                            type: 'checkbox',
                            label: 'Save',
                            value: 'save'
                        }
                    },
                    {
                        id: 'reset',
                        input: {
                            type: 'checkbox',
                            label: 'Reset',
                            value: 'reset'
                        }
                    }
                ]
            },
            {
                id: 'answer',
                options: [
                    {
                        id: 'overlay',
                        input: {
                            type: 'checkbox',
                            label: {
                                suffix: 'Overlay'
                            }
                        }
                    }
                ]
            }
        ]
    };

    var panels = [
        {
            id: 'type',
            heading: 'Type',
            buttons: [
                {
                    type: 'create-activity',
                    html: 'Create activity',
                    classes: ['osep']
                }
            ]
        },
        {
            id: 'dragging',
            heading: 'Dragging',
            hidden: true
        },
        {
            id: 'pens',
            heading: 'Selected pen',
            hidden: true
        },
        {
            id: 'spaces',
            heading: 'Spaces',
            hidden: true
        },
        {
            id: 'punctuation',
            heading: 'Punctuation',
            hidden: true
        },
        {
            id: 'buttons',
            heading: 'Buttons',
            hidden: true
        },
        {
            id: 'answer',
            heading: 'Answer',
            hidden: true
        },
        {
            id: 'general',
            heading: 'General',
            hidden: true
        }
    ];

    var activity = null,
        options = null,
        buttons;

    var init = function() {
        createActivity();
        initOptions();
        createPanels();
        createOptions(options);

        options.setConditions(); //hide conditionals
        container.addEventListener('create-activity', initActivity);
        // container.addEventListener('create-activity', updateActivityType);
        // container.addEventListener('pen-selected', handlePenSelection);
        // container.addEventListener('highlight-updated', handleStatic);
        // container.addEventListener('highlight-undone', undoStatic);
    };

    var createActivity = function() {
        activity = HL.activity.construct();
        api.activity = activity;

        activity.setCfg({
            pens: cfg.tool.pens.reduce(function(prev, curr, i) {
                prev[curr] = {
                    label: curr + ' pen',
                    index: i
                };
                return prev;
            }, {})
        });
    };

    var initActivity = function initActivity(e) {
        if (!activity.cfg.type) {
            e.stopPropagation();
            e.stopImmediatePropagation();
            return;
        }
    
        console.log(activity);

        // activity.load({
        //     // need to wait for this to be finished
        //     ready: function () {
        container.addEventListener('activity-loaded', function () {
            console.log('ready bitches........................');
            activity.inTool = true; // used in utils

            initSpans();
            updatePenOptions(activity.pens.selected);
            showHiddenPanels();
            initButtons();
            setOptions();

            container.addEventListener('create-activity', updateActivityType);
            container.addEventListener('pen-selected', handlePenSelection);
            container.addEventListener('highlight-updated', handleStatic);
            container.addEventListener('highlight-undone', undoStatic);
        });

        container.appendChild(activity.container);
        container.removeEventListener('create-activity', initActivity); //make sure this is only called the once
        activity.load({});
    };

    var initButtons = function () {
        buttons = OU.buttons.create([
            {
                type: 'prefill',
                html: 'PREFILL',
                classes: ['btn-no-style'],
                toggle: true,
                click: handleStaticSelection
            },
            {
                type: 'static',
                html: 'STATIC',
                classes: ['btn-no-style'],
                toggle: true,
                click: handleStaticSelection
            }
        ]);

        OU.utils.addClass(buttons.group, 'cfg-hl-controls');
        OU.utils.forIn(activity.buttons.buttons, function (btn) {
            if (btn.type !== 'reset') {
                // console.log(activity.buttons, btn);
                activity.buttons.group.removeChild(btn.el); // no use in tool so remove
            }
        });

        activity.container.insertBefore(buttons.group, activity.content);
    };

    var showHiddenPanels = function () {
        panels.forEach(function(data) {
            if (data.hidden) {
                data.el.style.display = 'block';
                data.hidden = false;
            }
        });
    };

    var updateActivityType = function () {
        if (activity.loaded) {
            if (confirm('Changing type now may remove highlights already applied. Continue?')) {
                //TODO reset history so one click removes all highlights??
            }
            else {
                //reset data and input if cancelled
                options.get('type').setData(cfg.tool.type.prev);
                options.get('type').setInput(cfg.tool.type.prev);
                return;
            }
        }

        updateActivityContent();
    };

    /**
     * replace activity content after update
     */
    var updateActivityContent = function () {
        activity.updateContent();
        initSpans();
    };

    /**
     * show highlights and set static property on span data
     */
    var initSpans = function () {
        activity.spans.forEach(function (data) {
            data.static = utils.isStatic(data.el);

            if (data.answer) {
                activity.applyHighlight(data, data.answer);
            }
        });
    };

    /**
     * update activity after import
     */
    var importCfg = function () {
        var pens, i;

        pens = activity.getPensInUse();
        i = pens.length;

        //update pens
        activity.pens.forEach(function(pen) {
            if (pens.indexOf(pen) < 0) { //data not imported
                pen.index = i++; //push to end
            }
            else {
                pen.setLabel(activity.cfg.pens[pen.colour].label);
                pen.index = activity.cfg.pens[pen.colour].index;
            }
        });

        //sort pens
        activity.pens.sort(function(a, b) {
            return a.index - b.index;
        });

        //reorder pen elements (reverse and insert due to undo button)
        activity.pens.slice(0).reverse().forEach(function(pen) {
            activity.pens.group.insertBefore(pen.el, activity.pens.undo.nextSibling);
        });

        updatePenOptions(activity.pens.selected);
        updateActivityContent();
        setOptions();
    };

    var handlePenSelection = function(e) {
        updatePenOptions(e.detail.current, e.detail.prev);

        if (buttons.static.getAttribute('aria-pressed') == 'true') {
            OU.utils.triggerCustomEvent(buttons.static, 'click');
        }
    };

    var handleStaticSelection = function(e) {
        //set to e.target state as other button may already be active...
        cfg.tool.static = (e.target.getAttribute('aria-pressed') == 'false');

        //allow prefill/static to be pressed, not both
        if (e.target == buttons.prefill) {
            if (buttons.static.getAttribute('aria-pressed') == 'true') {
                buttons.static.setAttribute('aria-pressed', 'false');
            }
        }
        else {
            if (buttons.prefill.getAttribute('aria-pressed') == 'true') {
                buttons.prefill.setAttribute('aria-pressed', 'false');
            }
        }

        if (cfg.tool.static && e.target == buttons.static) {
            activity.pens.previous = activity.pens.selected;
            activity.pens.selected.deselect();
            activity.pens.selected = null;
        }
        else {
            if (!activity.pens.selected) {
                activity.selectPen(activity.pens.previous);
                activity.pens.previous = null;
            }
        }

        e.target.setAttribute('aria-pressed', cfg.tool.static.toString());
    };

    var handleStatic = function(e) {
        var data = e.detail.target;

        if (cfg.tool.static && !data.static) {
            applyStatic(data);
        }
        else {
            removeStatic(data);
        }
    };

    var applyStatic = function(data) {
        if (!data.static) {
            data.static = true;
            OU.utils.addClass(data.el, 'static');
        }
    };

    var removeStatic = function(data) {
        if (data.static) {
            data.static = false;
            OU.utils.removeClass(data.el, 'static');
        }
    };

    var undoStatic = function(e) {
        e.detail.data.forEach(function (data) {
            removeStatic(data);
        });
    };

    var initOptions = function() {
        //link inputs and activity.cfg
        options = OU.cfg.construct({
            id: 'cfg',
            options: cfg.activity.options
        }, activity.cfg);
    };

    var setOptions = function() {
        //normalise button data before setting cfg view
        options.get('buttons').data.enabled.forEach(function(name) {
            options.get('buttons').data[name] = true;
        });

        options.set();
    };

    var createPanels = function() {
        var panelContainer = OU.utils.createElement('div', 'cfg-panel-container'),
            panel;

        panels.forEach(function(data) {
            data.el = OU.utils.createElement('div', 'cfg-panel');
            data.body = OU.utils.createElement('div', 'cfg-panel-body');

            data.el.insertAdjacentHTML('beforeend', '<h2>' + data.heading + '</h2>');
            data.el.appendChild(data.body);

            if (data.buttons) {
                data.buttons = OU.buttons.create(data.buttons);
                data.el.appendChild(data.buttons.group);
            }

            if (data.id) {
                panels[data.id] = data;
            }

            if (data.hidden) {
                data.el.style.display = 'none';
            }

            panelContainer.appendChild(data.el);
        });

        container.appendChild(panelContainer);
    };

    /**
     *
     * @param {object} obj
     * @param {string} obj.id
     * @param {string} [obj.heading]
     * @param {string} [obj.label]
     * @param {object[]} [obj.input] - array of input data objects
     * @param {object[]} [obj.options] - options array (called recursively)
     * @param {object[]} [obj.buttons] - button array
     * @returns {Element}
     */
    var createOptions = function(obj) {
        obj.options.forEach(function(obj) {
            obj.el = OU.utils.createElement('div', 'cfg-options', 'cfg-' + obj.id);

            if (obj.label) {
                obj.el.insertAdjacentHTML('beforeend', '<p>' + obj.label + '</p>');
            }

            if (obj.input) {
                obj.el.appendChild(obj.input.group);
            }

            if (obj.parent.el) {
                obj.parent.el.appendChild(obj.el);
            }
            else {
                obj.panel = obj.panel || (panels[obj.id] ? obj.id : obj.parent.id);

                if (panels[obj.panel]) {
                    panels[obj.panel].body.appendChild(obj.el);
                }
            }

            if (obj.options) {
                createOptions(obj);
            }
        });
    };

    var updatePenOptions = function(selected, prev) {
        var data = options.get('pens:' + selected.colour);

        data.options.forEach(function(opt) {
            switch (opt.id) {
                case 'label':
                    opt.input[0].el.value = selected.label.text;
                    break;
                case 'position':
                    opt.input[0].el.selectedIndex = selected.index + 1;
            }
        });

        if (prev && prev.el) {
            options.get('pens:' + prev.colour).el.style.display = 'none';
        }

        data.el.style.display = 'block';
    };

    var updatePenPosition = function(value, prev) {
        if (value == prev) {
            return;
        }

        var target = activity.pens[value].el,
            selected = activity.pens[prev].el;

        activity.pens.forEach(function(pen) {
            if (pen.index == prev) {
                pen.index = value;
                return;
            }

            if (value > prev) { //forward
                if (pen.index > prev && pen.index <= value) {
                    pen.index--;
                    activity.cfg.pens[pen.colour].index--;
                }
            }
            else { //backward
                if (pen.index >= value && pen.index < prev) {
                    pen.index++;
                    activity.cfg.pens[pen.colour].index++;
                }
            }
        });

        options.get('pens').set(); //update the inputs not selected
        selected.parentNode.insertBefore(selected, (value < prev) ? target : target.nextSibling);
        OU.utils.arrayMove(activity.pens, prev, value);
    };

    /**
     * output activity cfg
     * TODO remove default values!!
     * TODO possible bug - type may have been change but content not processed
     * @returns {object}
     */
    var getCfg = function() {
        var obj = {},
            pens = activity.getPensInUse();

        OU.utils.extendDeep(obj, activity.cfg);

        obj.pens = pens.reduce(function(prev, curr, i) {
            prev[curr.colour] = {
                label: curr.label.text,
                index: i
            };
            return prev;
        }, {});

        obj.content = getContent();

        //restructure data for buttons.js - array of enabled, not [button] = true
        obj.buttons.enabled.splice(0);

        options.get('buttons').options.forEach(function(btn) {
            if (obj.buttons.hasOwnProperty(btn.id) && obj.buttons[btn.id]) {
                obj.buttons.enabled.push(btn.id);
                delete obj.buttons[btn.id];
            }
        });

        delete obj.buttons.data;

        if (obj.images.length === 0) {
            delete obj.images;
        }

        return obj;
    };

    var getContent = function() {
        var content = activity.question.cloneNode(true),
            blocks = getBlockFragments(),
            prev;

        //container.appendChild(content);

        OU.utils.toArray(content.querySelectorAll('span[data-hl]')).forEach(function(el) {
            var data = activity.getSpanData(el),
                ref = (data.colour ? data.colour : (data.static ? 'static' : false)),
                related, block, child;

            if (ref) {
                if (prev) {
                    related = OU.utils.firstBlockParent(data.el) == OU.utils.firstBlockParent(prev.el);
                }

                if (!prev || ref != prev.ref || !related) { //start
                    block = blocks[ref].shift();

                    if (block.span.children.length === 0 || block.span.firstChild.nodeType == 3) {
                        el.parentNode.insertBefore(block.span, el);
                    }
                    else {
                        child = el.parentNode;

                        while (child) {
                            if (child.parentNode.nodeName == block.parent.nodeName) {
                                child.parentNode.insertBefore(block.span, child.nextSibling);
                                break;
                            }
                            child = child.parentNode;
                        }
                    }
                }

                utils.removeSpan(el);
            }
            else {
                utils.unwrapElement(el);
            }

            prev = {
                el: data.el,
                ref: ref
            };
        });

        return content.outerHTML.replace(/^(.*?)>/, '').replace(/<\/div>$/, '');
    };

    var getBlockFragments = function () {
        var blocks = HL.utils.getBlocks(activity.spans);

        OU.utils.forIn(blocks, function (blocks) {
            blocks.forEach(function (block, i) {
                var indices = block.map(function (obj) { return obj.index; }),
                    elements = block.map(function (span) { return span.el; }),
                    parent = OU.utils.firstBlockParent(block[0].el),
                    clone = parent.cloneNode(true),
                    span = document.createElement('span');

                //strip out everything except highlighted spans in block
                OU.utils.toArray(clone.querySelectorAll('span[data-hl]')).forEach(function (el) {
                    var data = activity.getSpanData(el),
                        index = indices.indexOf(data.index);

                    if (index > -1) {
                        utils.unwrapElement(el);
                    }
                    else {
                        utils.removeSpan(el);
                    }

                    /*if (index > -1) {
                        if (index === 0) {
                            while (el.previousSibling) {
                                el.parentNode.removeChild(el.previousSibling);
                            }
                        }
                        if (index == indices.length - 1) {
                            while (el.nextSibling) {
                                el.parentNode.removeChild(el.nextSibling);
                            }
                        }

                        utils.unwrapElement(el);
                    }
                    else {
                        if (clone.contains(el)) { //check as may have already been removed
                            utils.removeSpan(el);
                        }
                    }*/
                });

                if (block[0].static) {
                    OU.utils.addClass(span, 'static');
                }
                else {
                    span.setAttribute('data-hl', '');
                }

                if (block[0].colour) {
                    OU.utils.addClass(span, block[0].colour);
                }

                if (sameParent(elements) && clone.firstChild.nodeType == 1) {
                    utils.unwrapElementTo(clone.firstChild, span);
                }
                else {
                    utils.unwrapElementTo(clone, span);
                }

                blocks[i] = {
                    span: span,
                    parent: parent
                };
            });
        });

        return blocks;
    };

    var sameParent = function(elements) {
        return elements.every(function (el) {
            //console.log(el.parentNode, elements[0].parentNode);
            if (el.parentNode == elements[0].parentNode) {
                return true;
            }
        });
    };

    var api = {
        container: container,
        init: init,
        updateActivityContent: updateActivityContent,
        getCfg: getCfg,
        importCfg: importCfg,
        getContent: getContent,
        cfg: {
            activity: null,
            tool: cfg.tool
        },
        options: options,
        activity: activity
    };

    return api;
})(HL.utils);