/*
    UI functions.
*/
function getProgress(min, max, value, class_names) {
    return $('<div class="progress ' + class_names + '"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="' + value + '" aria-valuemin="' + min + '" aria-valuemax="' + max + '" style="width: ' + (value/max*100) + '%"></div></div>')
}

function getLoading() {
    return $('<div class="loading"><div class="spinner-border text-primary" role="status"><span class="sr-only">Loading...</span></div></div>');
}

function showConfirmation($item, danger, callback) {
    var title = $item.attr('title');
    var cancelTitle = $item.attr('data-confirmation-cancel');
    var validateTitle = $item.attr('data-confirmation-validate');

    if (_.isUndefined(title) || title.length == 0 || _.isUndefined(cancelTitle) || cancelTitle.length == 0 || _.isUndefined(validateTitle) || validateTitle.length == 0) {
        callback();
        return;
    }

    $confirmation = $('#confirmation');
    if ($confirmation.length == 0) {
        $confirmation = $(
            '<div id="confirmation" class="modal fade" tabindex="-1" role="dialog">'+
                '<div class="modal-dialog" role="document">'+
                    '<div class="modal-content">'+
                        '<div class="modal-header">'+
                            '<h5 class="modal-title"></h5>'+
                            '<button type="button" class="close" data-dismiss="modal" aria-label="Close">'+
                            '<span aria-hidden="true">&times;</span>'+
                            '</button>'+
                        '</div>'+
                        '<div class="modal-footer">'+
                            '<button type="button" class="btn btn-secondary" data-dismiss="modal"></button>'+
                            '<button type="button" class="btn btn-primary"></button>'+
                        '</div>'+
                    '</div>'+
                '</div>'+
            '</div>'
        ).appendTo('body');
    }

    $('.modal-title', $confirmation).text(title);
    $('.btn[data-dismiss=modal]', $confirmation).text(cancelTitle);
    var $button = $('.btn:not([data-dismiss=modal])', $confirmation).text(validateTitle).off('click').on('click', function(e) {
        e.preventDefault();
        $confirmation.modal('hide');
        callback();
    });

    if (danger) {
        $button.removeClass('btn-primary').addClass('btn-danger');
    } else {
        $button.removeClass('btn-danger').addClass('btn-primary');
    }

    $confirmation.modal('show');
}

/*
    These following methods are useful to retrieve the data from an API error.
*/
function errorMessage(xhr) {
    if (typeof(xhr)=="string") return xhr;

    if (xhr.responseJSON) {
        return xhr.responseJSON.error.message;
    }

    return undefined
}

function errorReason(xhr) {
    if (xhr.responseJSON) {
        return xhr.responseJSON.error.reason;
    }

    return undefined
}

function errorRecovery(xhr) {
    if (xhr.responseJSON) {
        return xhr.responseJSON.error.recovery;
    }

    return undefined
}

function errorField(xhr) {
    if (xhr.responseJSON) {
        return xhr.responseJSON.error.field;
    }

    return undefined
}

function errorDomain(xhr) {
    if (xhr.responseJSON) {
        return xhr.responseJSON.error.domain;
    }

    return undefined
}

function errorCode(xhr) {
    if (xhr.responseJSON) {
        return xhr.responseJSON.error.code;
    }

    return undefined
}

/*
    JSON response handlers.
*/
function handleJSONError(xhr) {
    if (xhr.responseJSON) {
        var domain = errorDomain(xhr);
        var code = errorCode(xhr);
        var attr = '';

        if (domain == 'auth') {
            switch (code) {
                case 2:
                attr = 'data-authentication-invalid';
                break;
                case 3:
                attr = 'data-authentication-expired';
                break;
                case 4:
                attr = 'data-authentication-revoked';
                break;
                case 5:
                //attr = 'data-unauthorized';
                break;
            }
        }

        if (attr.length > 0) {
            var url = $('meta[name=application-config]').attr(attr);
            if (!_.isUndefined(url)) {
                window.location.href = url;
                return true;
            }
        }
    }

    return false;
}

/*
    These functions define common behaviours in the entire application.
*/
$.fn.extend({
    disappear: function(callback) {
        return this.each(function() {
            $(this).fadeOut(500, function() {
                $(this).remove();
                if (!_.isUndefined(callback)) {
                    callback();
                }
            });
        });
    },

    appear: function() {
        return this.each(function() {
            $(this).fadeIn(500);
        });
    },

    startLoading: function() {
        return this.each(function() {
            var $this = $(this);

            var $loadingItem = $this.nextAll('.loading:first');
            if ($loadingItem.length == 0) {
                $loadingItem = getLoading().insertAfter($this);
            }

            if ($this.attr('data-reload-loading-height') != 'auto') {
                var height = $this.height();
                if (height > 0) {
                    $loadingItem.css('height', height+'px');
                } else {
                    $loadingItem.css('height', '');
                }
            }
            
            if ($this.attr('data-reload-loading-width') != 'auto') {
                var width = $this.width();
                if (width > 0) {
                    $loadingItem.css('width', width+'px');
                } else {
                    $loadingItem.css('width', '');
                }
            }

            $loadingItem.show();
            $this.hide();
        });
    },

    stopLoading: function() {
        return this.each(function() {
            $(this).show().nextAll('.loading:first').hide();
        });
    },

    reloadData: function(options) {
        var options = $.extend({
            complete: function(data){
            },
            success: function(data){
            },
            error: function(data){
            },
            page: 0,
        }, options);

        return this.each(function(){
            var $target = $(this);

            var url = $target.attr('data-reload-url');
            if (_.isUndefined(url)) {
                var $this = $(this).modal('hide');
                $target = $($this.attr('data-submit-callback-target'));
                url = $this.attr('data-submit-callback-url');
            }
            url += '?';

            var page = $target.attr('data-reload-page');
            if (options.page > 0) {
                page = options.page
            } else if (options.page < 0) {
                var countOfPages = parseInt($('*[data-pagination-count-pages]', $target).attr('data-pagination-count-pages'), 10);
                page = (countOfPages + options.page + 1);
            }
            if (!_.isUndefined(page)) {
                url += 'page=' + _.escape(page) + '&';
            }

            var params = $target.data('data-params');
            if (_.isMap(params)) {
                for (var [key, value] of params) {
                    url += key + '=' + _.escape(value) + '&';
                }
            }

            var loadingValue = $target.attr('data-reload-loading');
            var loading = false;
            var $loadingTag = undefined;
            if (loadingValue == 'true') {
                loading = true;
            } else if (!_.isUndefined(loadingValue) && loadingValue.length > 0) {
                $loadingTag = $(loadingValue);
            }
            
            if (loading && !$target.is(':hidden')) {
                $target.startLoading();
            } else if (!_.isUndefined($loadingTag)) {
                $target.hide();
                $loadingTag.show();
            }
            
            var callback = $target.attr('data-reload-callback');

            $.ajax({
                url: url,
                type: 'get',
                success: function(data) {
                    $target.html(data);
                    options.success(data);
                    $('[data-toggle="tooltip"]', $target).tooltip();

                    if (!_.isUndefined(callback)) {
                        eval(callback);
                    }
                },
                error: function(data){
                    options.error(data);
                },
                complete: function(data) {
                    if (loading) {
                        $target.stopLoading();
                    } else if (!_.isUndefined($loadingTag)) {
                        $loadingTag.hide();
                        $target.show();
                    }
                    options.complete(data);
                },
            });
        });
    },

    setParameter: function(key, value) {
        return this.each(function(){
            var $target = $(this);

            var params = $target.data('data-params');
            if (!_.isMap(params)) {
                params = new Map();
            }

            params.set(key, value);
            $target.data('data-params', params);
        });
    },
});

$.extend({
    switch: function(current, next, callback = undefined) {
        current.fadeOut(500, function() {
            next.fadeIn(500, function() {
                if (!_.isUndefined(callback)) {
                    callback();
                }
            });
        });
    }
});

/*
    Calls at the page loading.
*/
$(function() {
    // Default error handler for the JSON calls.
    $(document).ajaxError(function(event, xhr, settings, error) {
        if (!handleJSONError(xhr)) {
            notifyError(xhr);
        }
    });

    $.ajaxSetup({
        contentType: 'application/json',
    });

    // Load the content on show.
    $('.modal[data-load-on-shown]').on('shown.bs.modal', function() {
        $('*[data-reload-url]', $(this)).each(function(index, e){
            var $this = $(e);
            if ($this.children().length == 0) {
                $this.reloadData();
            }
        });
    });
    $('.dropdown-menu[data-load-on-shown]').parent().on('shown.bs.dropdown', function() {
        $('*[data-reload-url]', $(this)).each(function(index, e){
            var $this = $(e);
            if ($this.children().length == 0) {
                $this.reloadData();
            }
        });
    });

    // Show on page load.
    $('.modal[data-show-on-load="true"]').modal('show');

    // Refresh the content.
    $(document).on('click', '*[data-refresh]', function(e) {
        e.preventDefault();
        var $modal = $(e.target).closest('.modal');
        var $reload = $('*[data-reload-url]', $modal);
        $reload.reloadData();
    });

    // Enable the tooltips.
    $('[data-toggle="tooltip"]').tooltip();
});