/**
 * @category MyEic
 * @subcategory Libraries
 * @extends Controller
 */
class WindozController extends Controller {

    constructor() { 
        super(); 
        this.view2url = {};
    }
    
    getViewByClass(className) { 
        let content = Controller._contents.find(o => o.view._className == className)
        return content ? content.view: null; 
    }

    getViewByURL(url) { 
        let content = Controller._contents.find(o => o.view._url == url)
        return content ? content.view: null; 
    }

    loadContent(name, options, data) {
        options = options || {};
        options.onContentLoaded = this.createContent;
        return super.loadView(name, options, data);
    }

    createContent(options, data, html) {
        
        let container = ui.create('<div></div>');
        container.innerHTML = Controller.processTemplate(options.name, html, data);

        let view = new app.LoadedClasses[options.className](options);
        view._className = options.name.replace('.html', '');
        view._controller = this;
        view.el = container;
        view.DOMContentLoaded(data);
        
        container.setAttribute('sparc-id', view._sparcId);

        return view;
    }

    loadWindow(name, options, data) {
        let url = app.Router.currentRoute.realUrl;
        options = options || {};
        // if static, redirect to existing instance 
        if(options.static) {
            /* 
                MFA:    
                    Using stored real url instead of classname allows different instance of window based on parameter:
                    eg: 
                        having route "/window/{id}", calling "/window/345" won't replace "/window/123"
                    
                    Makes me wonder: shouldn't all windows be static anyway then ?
            */
            //let existing = this.getViewByClass(name);
            let existing = this.getViewByURL(url);
            
            if(existing) {
                this.focus(existing._sparcId, data);              
                return;
            }
        }
        options.onContentLoaded = this.createWindow;
        super.loadView(name, options, data).then(
            view => { 
                this.view2url[view._sparcId] = url; 
                view._url = url
            }
        );
    }

    createWindow(options, data, html) {
        
        if(!(options.className in app.LoadedClasses)){
            console.error(`Missing view ${options.className} !\nLoad explicitely it from your controller, or as set it as a dependency...`);
            return null; 
        }

        let view = new app.LoadedClasses[options.className]();
        view._className = options.name.replace('.html', '');
        view._controller = this;

        Controller._contents.push({
            view: view, 
            type: 'window', 
            expanded: options.expanded || false,
            visible: true,
            active: false
        });

        let settingsMarkup = ''
        if(options.withSettings){
            settingsMarkup=`
                <div eicdropdown>
                    <button eicbutton data-id="${view._sparcId}" basic primary rounded xsmall class="icon-cog settings" title="settings"></button>
                    <menu eicmenu data-output="settingsMenu"></menu>
                </div>
            `
        }
        let content = ui.create(`<div class="window">
            <header class="cols-2 right">
                <h1>${options.title || ''}</h1>
                <div class="controls">
                    ${settingsMarkup}
                    <button eicbutton data-id="${view._sparcId}" basic primary rounded xsmall class="icon-copy shrink" title="shrink"></button>
                    <button eicbutton data-id="${view._sparcId}" basic primary rounded xsmall class="icon-square-o expand" title="expand"></button>
                    <button eicbutton data-id="${view._sparcId}" basic primary rounded xsmall class="icon-cancel close" title="close"></button>
                </div>
                </header>
            <section></section>
            <div class="handle" data-side="nw"></div>
            <div class="handle" data-side="n"></div>
            <div class="handle" data-side="ne"></div>
            <div class="handle" data-side="e"></div>
            <div class="handle" data-side="se"></div>
            <div class="handle" data-side="s"></div>
            <div class="handle" data-side="sw"></div>
            <div class="handle" data-side="w"></div>
        </div>`);
        if(options.expanded) content.setAttribute('expanded','');
        if(options.windowStyle){
            for(const k in options.windowStyle){
                content.style[k] = options.windowStyle[k]
            }
        }

        let container = content.querySelector('section');
        container.innerHTML = Controller.processTemplate(options.name, html, data);

        view.el = content;
        
        // setting up window controls
        let expand = content.querySelector('header button.expand');
        expand.addEventListener('click', view.expand.bind(view));

        let shrink = content.querySelector('header button.shrink');
        shrink.addEventListener('click', view.shrink.bind(view));
        
        let close = content.querySelector('header button.close');
        close.addEventListener('click', this.onclose.bind(this));
        
        content.addEventListener('click', this.onFocusRequest.bind(this));
        content.addEventListener('expanded', this.onFocusRequest.bind(this));
        content.addEventListener('shrinked', this.onFocusRequest.bind(this));
        
        if(options.withSettings && (typeof(view.settings) == 'function')){
            let settings = content.querySelector('header button.settings');
            settings.addEventListener('click', view.settings.bind(view));
        }

        content.setAttribute('sparc-id', view._sparcId);

        let parent = Controller._template.view.find('.app-workspace');
        parent.appendChild(content);
        
        this.addThesaurus(view._sparcId, options.title || 'a window')

        view.DOMContentLoaded(data);
        view.initWindowEvents();
        this.focus(view._sparcId);

        return view;
    }

    openDialog(view) {
        
        let promise = new Promise(function(resolve) {
            if(typeof view === 'string') {
                let message = view;
                view = new WindozDialogContent();
                view.el = message;
            }

            let dialog = WindozController.createDialog(view);

            function commit(result) {
                WindozController.closeDialog(view._sparcId);
                resolve(result);
            }

            function abort(result) {
                WindozController.closeDialog(view._sparcId);
                resolve(result);
            }

            view.commit = commit;
            view.abort = abort;
            view.buttons.forEach(function(button) { 
                dialog.querySelector('[eicdialog] > [eiccard] > footer').append(button.el); 
            });
            
            view.DOMContentFocused();
        });

        return promise;
    }
    
    /**
     * Used by a view that needs to change the current URL 
     * Typically happens when the view allows you to switch to another instance of the business-object
     * handled by this controiller. Doinbg a  history.replaceState in the view is not enough, because 
     * the controller needs to keep track of his current URL (in view2url) for changing 
     * the Browser URL bar when -later- changing window focus.
     * @param {string} newUrl
     */
    changeUrl(view, newUrl) {
        history.replaceState(null, null, newUrl)
        this.view2url[view._sparcId] = newUrl
        view._url = newUrl
    }

    static createDialog(dialog, options) {
        
        options = options || {};
        
        let container = ui.create(`<div eicdialog sparc-id="${dialog._sparcId}">
            <article eiccard ${ options.closable || ''}>
                ${ dialog.options.title ? `<header><h1>${dialog.options.title}</h1>${dialog.options.subtitle ? `<h2>${dialog.options.subtitle}</h2>`: '' }</header>`: ''}
                <section></section>
                <footer></footer>
            </article>
        </div>`);
        
        ui.eicfy(container);

        container.querySelector('[eiccard] section').append(dialog.el);
        dialog.parentContainer = container;

        document.body.append(container)
        
        return container;
    }

    static closeDialog(id) { document.body.querySelector(`[sparc-id="${id}"]`).remove(); }

    addThesaurus(id, title) {
        let container = Controller._template.view.find('.app-content-thesaurus');
        container.querySelectorAll('[eicchip]').forEach(el => el.setAttribute('secondary', ''))
        
        let chip = new Chip(null, {label: title, destroyable: true});
        chip.el.setAttribute('data-id', id);
        chip.addEventListener('click', this.onSelectThesaurus.bind(this));
        chip.addEventListener('destroy', this.onRemoveThesaurus.bind(this));
        
        container.append(chip.el);
    }

    removeThesaurus(id) {
        let container = Controller._template.view.find('.app-content-thesaurus');

        let chip = container.querySelector(`[data-id="${id}"]`)
        if(chip) chip.remove();

        let remaining = container.querySelectorAll('[eicchip]');
        
        if(remaining.length > 0) {
            remaining.item(remaining.length - 1).dispatchEvent(new MouseEvent('click'));
        }
    }

    close(id) {
        this.removeThesaurus(id);
        this.unloadView(Controller.getContentById(id));
        if(this.view2url.hasOwnProperty(id)) delete(this.view2url[id]);
    }

    focus(id, data) {
        this.selectThesaurus(id);
        let curUrl = new URL(document.location.href).pathname 
        if(this.view2url.hasOwnProperty(id)) {
            history.replaceState(null, null, this.view2url[id]);
            curUrl = this.view2url[id]
        }

        if(app.matomo) app.matomo.logAction('Focus window / '+curUrl)

        let next = Controller.getContentById(id);

        if(Controller._currentContent) {
            if(next.expanded) {
                this.blur(Controller._currentContent);
                Controller._contents.filter(item => item.type == 'window').forEach(item => this.desactivate(item));
                Controller._contents.filter(item => !item.expanded).forEach(item => this.blur(item));
            } else {
                Controller._contents.filter(item => !item.expanded && item.type == 'window').forEach(item => this.attach(item));
                this.attach(Controller._currentContent);

                let altexpand = Controller._contents.filter(item => item.expanded && item.visible && item.type == 'window');
                
                if(altexpand.length == 0) {
                    let latest = Controller._contents.reverse().find(item => item.expanded);
                    if(latest) { this.attach(latest); }
                }
            }
        }
        Controller._currentContent = next;
        this.activate(Controller._currentContent, data);
        Controller._currentContent.view.DOMContentResized();   
    }
    
    desactivate(content) {
        content.view.el.classList.remove('active');
        content.active = false;
        if(content.expanded) this.blur(content);
    }

    activate(content, data) {
        Controller._contents.forEach(o => o.active = false);
        Controller._contents.forEach(o => o.view.el.classList.remove('active'));
        content.view.el.classList.add('active');
        content.active = true;
        
        if(!content.visible) this.attach(content);

        content.view.DOMContentFocused(data);
    }

    attach(content) {
        //ui.show(content.view.el,!content.expanded ? 'grid': 'block');
        ui.show(content.view.el, 'flex');
        content.visible = true;
    }

    blur(content) {
        ui.hide(content.view.el);
        content.visible = false;
        content.active = false;
        content.view.DOMContentBlured();
    }

    onclose(event) {
        event.preventDefault();
        event.stopPropagation();

        this.close(event.currentTarget.dataset.id)
    }

    onSelectThesaurus(event) {
        event.stopPropagation();
        event.preventDefault();

        this.focus(event.currentTarget.dataset.id);
    }

    selectThesaurus(id) {
        let container = Controller._template.view.find('.app-content-thesaurus');
        container.querySelectorAll('[eicchip]').forEach(el => el.setAttribute('secondary', ''))
        container.querySelector(`[eicchip][data-id="${id}"]`).removeAttribute('secondary');
    }
    onRemoveThesaurus(event) {
        event.stopPropagation();
        event.preventDefault();

        this.close(event.currentTarget.dataset.id);        
    }

    onFocusRequest(event) {

        let view = event.currentTarget;
        while(!view.hasAttribute('sparc-id') && !view.classList.contains('window')) view = view.parentElement;
        let content = Controller.getContentById(view.getAttribute('sparc-id'));
        if(!content.active || content.expanded != content.view.expanded || (Controller._currentContent.view._sparcId != content.view._sparcId)) {
            content.expanded = content.view.expanded;
            this.focus(view.getAttribute('sparc-id'));
        }   
    }

    static resize() {
        Controller._contents.forEach(item => item.view.DOMContentResized())
    }

}

app.registerClass('WindozController', WindozController);