/**
 * @file Miscellaneous JS definitions for <tt>k-fet</tt> app.
 * @copyright 2017 cof-geek
 * @license MIT
 */

/**
 * String method
 * @memberof String
 * @return  {String} String formatted as trigramme
 */
String.prototype.formatTri = function() {
    return this.toUpperCase().substr(0, 3);
}


/**
 * String method
 * @global
 * @return  {Boolean} true iff String follows trigramme pattern
 */
String.prototype.isValidTri = function() {
    var pattern = /^[^a-z]{3}$/;
    return pattern.test(this);
}


function intCheck(v) {
    return Number.parseInt(v);
}

function floatCheck(v) {
    if (typeof v === 'number')
        return v;
    return Number.parseFloat(v);
}

function booleanCheck(v) {
    return v == true;
}


/**
 * Short: Equivalent to python str format.
 * Source: [MDN]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals}.
 * @example
 * var t1Closure = template`${0}${1}${0}!`;
 * t1Closure('Y', 'A');  // "YAY!"
 * @example
 * var t2Closure = template`${0} ${'foo'}!`;
 * t2Closure('Hello', {foo: 'World'});  // "Hello World!"
 */
function template(strings, ...keys) {
    return (function(...values) {
        var dict = values[values.length - 1] || {};
        var result = [strings[0]];
        keys.forEach(function(key, i) {
            var value = Number.isInteger(key) ? values[key] : dict[key];
            result.push(value, strings[i + 1]);
        });
        return result.join('');
    });
}


/**
 * Get and store K-Psul config from API.
 * <br><br>
 *
 * Config should be accessed statically only.
 */
class Config {

    /**
     * Get or create config object.
     * @private
     * @return  {object} object - config keys/values
     */
    static _get_or_create_config() {
        if (window.config === undefined)
            window.config = {};
        return window.config;
    }

    /**
     * Get config from API.
     * @param   {jQueryAjaxComplete} [callback] - A function to be called when
     *                               the request finishes.
     */
    static reset(callback) {
        $.getJSON(Urls['kfet.kpsul.get_settings']())
            .done(function(data) {
                for (var key in data) {
                    Config.set(key, data[key]);
                }
            })
            .always(callback);
    }

    /**
     * Get value for key in config.
     * @param   {string} key
     */
    static get(key) {
        return this._get_or_create_config()[key];
    }

    /**
     * Set value for key in config.
     * @param   {string} key
     * @param   {*} value
     */
    static set(key, value) {
        // API currently returns string for Decimal type
        if (['addcost_amount', 'subvention_cof'].indexOf(key) > -1)
            value = floatCheck(value);
        this._get_or_create_config()[key] = value;
    }

}


$(document).ready(function() {
    $(window).scroll(function() {
        if ($(window).width() >= 768 && $(this).scrollTop() > 72.6) {
            $('.col-content-left').css({'position':'fixed', 'top':'50px'});
            $('.col-content-right').addClass('col-sm-offset-4 col-md-offset-3');
        } else {
            $('.col-content-left').css({'position':'relative', 'top':'0'});
            $('.col-content-right').removeClass('col-sm-offset-4 col-md-offset-3');
        }
    });

    if (typeof Cookies !== 'undefined') {
        // Retrieving csrf token
        csrftoken = Cookies.get('csrftoken');
        // Appending csrf token to ajax post requests
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
    }

});

/*
 * Capslock management
 */

window.capslock = -1;
$(document).on('keypress', function(e) {
    var s = String.fromCharCode(e.which);
    if ((s.toUpperCase() === s && s.toLowerCase() !== s && !e.shiftKey)|| //caps on, shift off
        (s.toUpperCase() !== s && s.toLowerCase() === s && e.shiftKey)) { //caps on, shift on
            $('body').addClass('capslock_on')
    } else if ((s.toLowerCase() === s && s.toUpperCase() !== s && !e.shiftKey)|| //caps off, shift off
               (s.toLowerCase() !== s && s.toUpperCase() === s && e.shiftKey)) { //caps off, shift on
            $('body').removeClass('capslock_on')
    }
});

$(document).on('keydown', function(e) {
    if (e.which == 20) {
        $('body').toggleClass('capslock_on')
    }
});


/*
 * Generic Websocket class and k-psul ws instanciation
 */

class KfetWebsocket {

    static get defaults() {
        return {"relative_url": "", "default_msg": {}, "handlers": []};
    }

    constructor(data) {
        $.extend(this, this.constructor.defaults, data);
    }

    get url() {
        var websocket_protocol = window.location.protocol == 'https:' ? 'wss' : 'ws';
        var location_host = window.location.host;
        var location_url = window.location.pathname.startsWith('/gestion/') ? location_host + '/gestion' : location_host;

        return websocket_protocol+"://" + location_url + this.relative_url ;
    }

    add_handler(handler) {
        if (!this.socket)
            this.listen();

        this.handlers.push(handler);
    }

    listen() {
        var that = this;
        this.socket = new ReconnectingWebSocket(this.url);

        this.socket.onmessage = function(e) {
            var data = $.extend({}, that.default_msg, JSON.parse(e.data));
            for (let handler of that.handlers) {
                handler(data);
            }
        }
    }
}

var OperationWebSocket = new KfetWebsocket({
    'relative_url': '/ws/k-fet/k-psul/',
    'default_msg': {'opegroups':[],'opes':[],'checkouts':[],'articles':[]},
});

function dateUTCToParis(date) {
    return moment.tz(date, 'UTC').tz('Europe/Paris');
}

function amountDisplay(amount, is_cof=false, tri='') {
    if (tri == 'LIQ')
        return (- amount).toFixed(2) +'€';
    return amountToUKF(amount, is_cof);
}

function amountToUKF(amount, is_cof=false, account=false) {
    var rounding = account ? Math.floor : Math.round ;
    var coef_cof = is_cof ? 1 + Config.get('subvention_cof') / 100 : 1;
    return rounding(amount * coef_cof * 10);
}

function isValidTrigramme(trigramme) {
    var pattern = /^[^a-z]{3}$/;
    return trigramme.match(pattern);
}

/**
 * Dialogs with user via jconfirm
 */

class UserDialog {

    static get defaults() {
        return {'title': '', 'content': ''};
    }

    constructor(data) {
        $.extend(this, this.constructor.defaults, data);
    }

    open(settings) {
        // Arg management
        var pre_content = settings.pre_content || '';
        var post_content = settings.post_content || '';
        var callback = settings.callback || $.noop;

        var that = this;
        $.confirm({
            title: this.title,
            content: pre_content + this.content + post_content,
            backgroundDismiss: true,
            animation:'top',
            closeAnimation:'bottom',
            keyboardEnabled: true,
            confirm: function() {
                var inputs = {};
                this.$content.find('input').each(function () {
                    inputs[$(this).attr('name')] = $(this).val();
                });
                if (Object.keys(inputs).length > 1)
                    return callback(inputs);
                else
                    return callback(inputs[Object.keys(inputs)[0]]);
            },
            onOpen: function() {
                var that = this
                this.$content.find('input').on('keydown', function(e) {
                    if (e.keyCode == 13) {
                        e.preventDefault();
                        that.$confirmButton.click();
                    }
                });
            },
            onClose: function() { if (settings.next_focus) { this._lastFocused = settings.next_focus; } }
        });
    }
}

function getErrorsHtml(data) {
    var content = '';
    if (!data)
        return "L'utilisateur n'est pas dans l'équipe";
    if ('operation_group' in data['errors']) {
        content += 'Général';
        content += '<ul>';
        if (data['errors']['operation_group'].indexOf('on_acc') != -1)
            content += '<li>Pas de compte sélectionné</li>';
        if (data['errors']['operation_group'].indexOf('checkout') != -1)
            content += '<li>Pas de caisse sélectionnée</li>';
        content += '</ul>';
    }
    if ('missing_perms' in data['errors']) {
        content += 'Permissions manquantes';
        content += '<ul>';
        for (var i=0; i<data['errors']['missing_perms'].length; i++)
            content += '<li>'+data['errors']['missing_perms'][i]+'</li>';
        content += '</ul>';
    }
    if ('negative' in data['errors']) {
        if (window.location.pathname.startsWith('/gestion/')) {
            var url_base = '/gestion/k-fet/accounts/';
        } else {
            var url_base = '/k-fet/accounts/';
        }
        for (var i=0; i<data['errors']['negative'].length; i++) {
            content += '<a class="btn btn-primary" href="'+url_base+data['errors']['negative'][i]+'/edit" target="_blank" style="width:100%">Autorisation de négatif requise pour '+data['errors']['negative'][i]+'</a>';
        }
    }
    if ('addcost' in data['errors']) {
        content += '<ul>';
        if (data['errors']['addcost'].indexOf('__all__') != -1)
            content += '<li>Compte invalide</li>';
        if (data['errors']['addcost'].indexOf('amount') != -1)
            content += '<li>Montant invalide</li>';
        content += '</ul>';
    }
    if ('account' in data['errors']) {
        content += 'Général';
        content += '<ul>';
        content += '<li>Opération invalide sur le compte '+data['errors']['account']+'</li>';
        content += '</ul>';
    }
    return content;
}

var authDialog = new UserDialog({
    'title': 'Authentification requise',
    'content': '<div class="capslock"><span class="glyphicon glyphicon-lock"></span><input type="password" name="password" autofocus><div>',
});

function api_with_auth(settings, password) {
    if (window.api_lock == 1)
        return false;
    window.api_lock = 1;

    var url = settings.url;
    if (!url)
        return false;
    var data = settings.data || {} ;
    var on_success = settings.on_success || $.noop ;
    var on_400 = settings.on_400 || $.noop ;

    $.ajax({
        dataType: "json",
        url: url,
        method: "POST",
        data: data,
        beforeSend: function ($xhr) {
            $xhr.setRequestHeader("X-CSRFToken", csrftoken);
            if (password)
                $xhr.setRequestHeader("KFetPassword", password);
        },
    })
    .done(function(data) {
        on_success(data);
    })
    .fail(function($xhr) {
        var response = $xhr.responseJSON;
        switch ($xhr.status) {
            case 403:
                authDialog.open({
                    callback: function(password) {
                        api_with_auth(settings, password)
                    },
                    pre_content: getErrorsHtml(response),
                    next_focus: settings.next_focus,
                });
                break;
            case 400:
                on_400(response);
                break;
        }
    })
    .always(function() {
        window.api_lock = 0;
    });
}
