/**
 * @file K-Psul JS
 * @copyright 2017 cof-geek
 * @license MIT
 */


class KPsulManager {

    constructor(env) {
        this._env = env;
        this.account_manager = new AccountManager(this);
        this.checkout_manager = new CheckoutManager(this);
        this.article_manager = new ArticleManager(this);
    }

    reset(soft) {
        soft = soft || false;

        this.account_manager.reset();
        this.article_manager.reset();

        if (!soft) {
            this.checkout_manager.reset();
            this.article_manager.reset_data();
        }
    }

    focus() {
        if (this.checkout_manager.is_empty())
            this.checkout_manager.focus();
        else if (this.account_manager.is_empty())
            this.account_manager.focus();
        else
            this.article_manager.focus();

        return this;
    }

}


class AccountManager {

    constructor() {
        this._$container = $('#account');

        this.account   = new Account();
        this.selection = new AccountSelection(this);
        this.search    = new AccountSearch(this);

        // buttons: search, read or create
        this._$buttons_container = this._$container.find('.buttons');
        this._buttons_templates = {
            create: template`<a href="${'url'}" class="btn btn-primary" target="_blank" title="Créer ce compte"><span class="glyphicon glyphicon-plus"></span></a>`,
            read: template`<a href="${'url'}" class="btn btn-primary" target="_blank" title="Détails du compte"><span class="glyphicon glyphicon-info-sign"></span></a>`,
            search: template`<button class="btn btn-primary search" title="Rechercher"><span class="glyphicon glyphicon-search"></span></button>`,
        }

    }

    is_empty() { return this.account.is_empty(); }

    display() {
        this._display_data();
        this._display_buttons();
    }

    _display_data() {
        this.account.display(this._$container, {
            'prefix_prop': '#account-',
        });
    }

    _display_buttons() {
        var buttons;

        if (this.is_empty()) {
            var trigramme = this.selection.get();
            if (trigramme.isValidTri()) {
                var url = Account.url_create(trigramme);
                buttons = this._buttons_templates['create']({url: url});
            } else {  /* trigramme input is empty or invalid */
                buttons = this._buttons_templates['search']();
            }
        } else {  /* an account is loaded */
            var url = this.account.url_read;
            buttons = this._buttons_templates['read']({url: url});
        }

        this._$buttons_container.html(buttons);
    }

    update(trigramme) {
        if (trigramme !== undefined)
            this.selection.set(trigramme);

        trigramme = trigramme || this.selection.get();

        if (trigramme.isValidTri()) {
            this.account.get_by_apipk(trigramme)
                .done( () => this._update_on_success() )
                .fail( () => this.reset_data() );
        } else {
            this.reset_data();
        }
    }

    _update_on_success() {
        $('#id_on_acc').val(this.account.id);
        this.display();

        kpsul.focus();
        kpsul._env.updateBasketAmount();
        kpsul._env.updateBasketRel();
    }

    reset() {
        $('#id_on_acc').val(0);
        this.selection.reset();
        this.search.reset();
        this.reset_data();
    }

    reset_data() {
        this.account.clear();
        this.display();
    }

    focus() {
        this.selection.focus();
        return this;
    }

}


class AccountSelection {

    constructor(manager) {
        this.manager = manager;
        this._$input = $('#id_trigramme');

        this._init_events();
    }

    _init_events() {
        var that = this;

        // user change trigramme
        this._$input
            .on('input', () => this.manager.update());

        // LIQ shortcuts
        this._$input
            .on('keydown', function(e) {
                // keys: 13:Enter|40:Arrow-Down
                if (e.keyCode == 13 || e.keyCode == 40)
                    that.manager.update('LIQ');
            });
    }

    get() {
        return this._$input.val().formatTri();
    }

    set(v) {
        this._$input.val(v);
    }

    focus() {
        this._$input.focus();
    }

    reset() {
        this.set('');
    }

}


class AccountSearch {

    constructor(manager) {
        this.manager = manager;

        this._content = '<input type="text" name="q" id="search_autocomplete" autocomplete="off" spellcheck="false" autofocus><div id="account_results"></div>' ;
        this._input = '#search_autocomplete';
        this._results_container = '#account_results';

        this._init_outer_events();
    }

    open() {
        var that = this;
        this._$dialog = $.dialog({
            title: 'Recherche de compte',
            content: this._content,
            backgroundDismiss: true,
            animation: 'top',
            closeAnimation: 'bottom',
            keyboardEnabled: true,
            onOpen: function() {
                that._$input = $(that._input);
                that._$results_container = $(that._results_container);
                that._init_form()
                    ._init_inner_events();
            },
        });
    }

    _init_form() {
        var that = this;

        this._$input.yourlabsAutocomplete({
            url: Urls['kfet.account.search.autocomplete'](),
            minimumCharacters: 2,
            id: 'search_autocomplete',
            choiceSelector: '.choice',
            placeholder: "Chercher un utilisateur K-Fêt",
            container: that._$results_container,
            box: that._$results_container,
            fixPosition: function() {},
        });

        return this;
    }

    _init_outer_events() {
        var that = this;

        /* open search on button click */
        this.manager._$container
            .on('click', '.search', () => this.open());

        /* open search on Ctrl-F */
        this.manager._$container
            .on('keydown', function(e) {
                if (e.which == 70 && e.ctrlKey) {
                    that.open();
                    e.preventDefault() ;
                }
            });
    }

    _init_inner_events() {
        this._$input.bind('selectChoice',
                (e, choice, autocomplete) => this._on_select(e, choice, autocomplete));
        return this;
    }

    _on_select(e, choice, autocomplete) {
        this.manager.update(choice.find('.trigramme').text());
        this.reset();
    }

    reset() {
        if (this._$dialog !== undefined) {
            this._$dialog.close();
        }
    }
}


class CheckoutManager {

    constructor() {
        this._$container = $('#checkout');
        this.display_prefix = '#checkout-';

        this.checkout = new Checkout();
        this.selection = new CheckoutSelection(this);

        this._$laststatement_container = $('#last_statement');
        this.laststatement = new Statement();
        this.laststatement_display_prefix = '#checkout-last_statement_';

        this._$buttons_container = this._$container.find('.buttons');
        this._buttons_templates = {
            read: template`<a class="btn btn-primary" href="${'url'}" title="En savoir plus" target="_blank"><span class="glyphicon glyphicon-info-sign"></span></a>`,
            statement_create: template`<a href="${'url'}" title="Effectuer un relevé" class="btn btn-primary" target="_blank"><span class="glyphicon glyphicon-euro"></span></a>`,
        }
    }

    update(id) {
        if (id !== undefined)
            this.selection.set(id);

        id = id || this.selection.get();

        var api_options = {
            'last_statement': true,
        };

        this.checkout.get_by_apipk(id, api_options)
            .done( (data) => this._update_on_success(data) )
            .fail( () => this.reset_data() );

        kpsul.focus();
    }

    _update_on_success(data) {
        if (data['laststatement'] !== undefined)
            this.laststatement.from(data['laststatement']);

        $('#id_checkout').val(this.checkout.id);
        this.display();

    }

    is_empty() { return this.checkout.is_empty(); }

    display() {
        this._display_data();
        this._display_laststatement();
        this._display_buttons();
    }

    _display_data() {
        this.checkout.display(this._$container, {
            'prefix_prop': this.display_prefix,
        });
    }

    _display_laststatement() {
        if (this.laststatement.is_empty()) {
            this._$laststatement_container.hide();
        } else {
            this.laststatement.display(this._$laststatement_container, {
               'prefix_prop': this.laststatement_display_prefix
            });
            this._$laststatement_container.show();
        }
    }

    _display_buttons() {
        var buttons = '';
        if (!this.is_empty()) {
            var url_newcheckout = Statement.url_create(this.checkout.id);
            buttons += this._buttons_templates['statement_create']({
                url: url_newcheckout});
            var url_read = this.checkout.url_read;
            buttons += this._buttons_templates['read']({url: url_read});
        }
        this._$buttons_container.html(buttons);
    }

    reset() {
        $('#id_checkout').val(0);

        this.selection.reset();
        this.reset_data();

        if (this.selection.choices.length == 1)
            this.update(this.selection.choices[0]);
    }

    reset_data() {
        this.checkout.clear();
        this.laststatement.clear();

        this.display();
    }

    focus() {
        this.selection.focus();
        return this;
    }
}


class CheckoutSelection {

    constructor(manager) {
        this.manager = manager;
        this._$input = $('#id_checkout_select');

        this._init_events();

        this.choices = this._$input.find('option[value!=""]').toArray()
            .map(function(opt) {
                return parseInt($(opt).attr('value'));
            });
    }

    _init_events() {
        this._$input.on('change', () => this.manager.update());
    }

    get() {
        return this._$input.val() || 0;
    }

    set(v) {
        this._$input.find('option[value='+ v +']').prop('selected', true);
    }

    reset() {
        this._$input.find('option:first').prop('selected', true);
    }

    focus() {
        this._$input.focus();
        return this;
    }
}

class ArticleManager {

    constructor(env) {
        this._env = env; // Global K-Psul Manager

        this._$container = $('#articles_data');
        this._$input = $('#article_autocomplete'); 
        this._$nb = $('#article_number');
        this._$stock = $('#article_stock');
        this.templates = {'category': '<div class="category"><span class="name"></span></div>',
                          'article' : '<div class="article"><span class="name"></span><span class="price"></span><span class="stock"></span></div>'}

        this.selected = new Article() ;
        this.list = new ArticleList() ;
        this.autocomplete = new ArticleAutocomplete(this);

        this._init_events();
    }

    get nb() {
        return this._$nb.val() ;
    }

    display_list() {
        this.list.display(this._$container, this.templates) ;
    }

    validate(article) {
        this.selected.from(article) ;
        this._$input.val(article.name);
        this._$nb.val('1');
        this._$stock.text('/'+article.stock);
        this._$nb.focus().select();
    }

    unset() {
       this.selected.clear();
    }

    is_empty() {
        return this.selected.is_empty();
    }

    reset_data() {
        this._$container.html('');
        this.list.clear();
        this.list.fromAPI()
            .done( () => this.display_list() );
    }

    get_article(id) {
        return this.list.find('article', id);
    }

    update_data(data) {
        for (let article_dict of data.articles) {
            var article = this.get_article(article_dict.id);

            // For now, article additions are disregarded
            if (article) {
                article.stock = article_dict.stock;
                this._$container.find('#article-'+article.id+' .stock')
                                  .text(article.stock);
            }
        }
    }

    reset() {
       this.unset() ;
       this._$stock.text('');
       this._$nb.val('');
       this._$input.val('');
       this.autocomplete.showAll() ;
    }

    _init_events() {
        var that = this;

        // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12
        var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/;
        var arrowKeys = /^(37|38|39|40)$/;

        //Global input event (to merge ?)
        this._$input.on('keydown', function(e) {
            if (e.keyCode == 13 && that._$input.val() == '') {
                kpsul._env.performOperations();
            }
        });

        this._$container.on('click', '.article', function() {
            var id = $(this).parent().attr('id').split('-')[1];
            var article = that.list.find('article', id);
            if (article)
                that.validate(article);
        });

        this._$nb.on('keydown', function(e) {
            if (e.keyCode == 13 && that.constructor.check_nb(that.nb) && !that.is_empty()) {
               kpsul._env.addPurchase(that.selected, that.nb);
               that.reset();
               that.focus();
            }
            if (normalKeys.test(e.keyCode) || arrowKeys.test(e.KeyCode) || e.ctrlKey) {
               if (e.ctrlKey && e.charCode == 65)
                   that._$nb.val('');
               return true ;
            }
            if (that.constructor.check_nb(that.nb+e.key))
                return true;
            return false;

        });
    }

    focus() {
        if (this.is_empty())
            this._$input.focus();
        else
            this._$nb.focus();

        return this;
    }

    static check_nb(nb) {
        return /^[0-9]+$/.test(nb) && nb > 0 && nb <= 24 ;
    }
}

class ArticleAutocomplete {

    constructor(article_manager) {
        this.manager = article_manager;
        this._$container = article_manager._$container ;
        this._$input = $('#article_autocomplete');

        this.showAll() ;
        this._init_events();
    }

    _init_events() {
        var that = this ;

        // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12
        var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/;

        this._$input
            .on('keydown', function(e) {
                var text = that._$input.val() ;
                if (normalKeys.test(e.keyCode) || e.ctrlKey) {
                    // For the backspace key, we suppose the cursor is at the very end
                    if(e.keyCode == 8) {
                        that.update(text.substring(0, text.length-1), true);
                    }
                    return true ;
                }
                that.update(text+e.key, false);

                return false ;

            });

    }

    update(prefix, backspace) {

        this.resetMatch();
        var article_list = this.manager.list ;
        var lower = prefix.toLowerCase() ;
        var that = this ;

        article_list.traverse('article', function(article) {
            if (article.name.toLowerCase().startsWith(lower))
                that.matching.push(article);
        });

        if (this.matching.length == 1) {
            if (!backspace) {
                this.manager.validate(this.matching[0]) ;
                this.showAll() ;
            } else {
                this.manager.unset();
                this.updateDisplay();
            }
        } else if (this.matching.length > 1) {
            this.manager.unset();
            this.updateDisplay() ;
            if (!backspace)
                this.updatePrefix();
        }
    }

    updateDisplay() {
        var that = this;

        this.manager.list.traverse('category', function(category) {
            var is_active = false;
            for (let article of category.articles) {
                if (that.matching.indexOf(article) != -1) {
                    is_active = true;
                    that._$container.find('#article-'+article.id).show();
                } else { 
                    that._$container.find('#article-'+article.id).hide();
                }
            }

            if (is_active) {
                that._$container.find('#category-'+category.id).show();
            } else { 
                that._$container.find('#category-'+category.id).hide();
            }
        });
    }

    updatePrefix() {
        var lower = this.matching.map(function (article) {
            return article.name.toLowerCase() ;
       });

        lower.sort() ;
        var first = lower[0], last = lower[lower.length-1],
            length = first.length, i = 0;
        while (i < length && first.charAt(i) === last.charAt(i)) i++;

        this._$input.val(first.substring(0,i)) ;
    }

    showAll() {
        var that = this;
        this.resetMatch();
        this.manager.list.traverse('article', function(article) {
            that.matching.push(article);
        });
        this.updateDisplay();
    }

    resetMatch() {
        this.matching = [];
    }
}
