/* global angular */

/**
 * angular-$uhttp - v2.11 - 2022-06-22
 * @author UNION DNC cvillegas
 */
'use strict';
angular.module('$uhttp', []).provider('$uhttp', function () {
    var notifications = {
        message_wrapper: 'message',
        severity_wrapper: 'severity',
        time_wrapper: 'time',
        title_wrapper: 'title',
        process_wrapper: 'process',
        default_severity: {
            201: 'success'
                    //400: 'warning',
                    //404: 'warning'
        },
        default_titles: {
            //401: 'Atención',
            //403: 'Atención'
        },
        default_messages: {
            201: 'Informaci&oacute;n almacenada correctamente',
            500: 'Error al realizar la petici&oacute;n al servidor'
        },
        status_callbacks: {
        },
        process_loader_start: undefined,
        process_loader_update: undefined,
        process_loader_done: undefined,
        full_screen_loader_start: undefined,
        full_screen_loader_done: undefined,
        small_loader_start: undefined,
        small_loader_done: undefined,
        alert: undefined,
        error: undefined,
        info: undefined,
        success: undefined,
        warning: undefined,
        debug: undefined,
        close_debug: undefined
    };
    var hooks = {
        pre_request: {
            evaluate: undefined,
            error_mesage: undefined
        },
        add_params: null
    };
    var active_processes = {"small": 0, "full_screen": 0, 'process': 0};
    var actual_process = 0;
    //metodo que generara las notificaciones al usuario
    function resolve_notifications(status, data) {
        //aseguramos que data este definido para evitar errores
        if (data === undefined) {
            data = {};
        }
        //variables que seran establecidas
        var severity = '';
        var time = 2000;
        var title = '';
        var message = '';
        //define severity para la notifiacion
        if (data[notifications.severity_wrapper] !== undefined) {
            //evalua si la respuesta contiene un valor para severity
            severity = data[notifications.severity_wrapper];
        } else {
            //si no viene del servidor intenta obtenerla desde la configuración
            if (notifications.default_severity[status] !== undefined) {
                severity = notifications.default_severity[status];
            } else {
                //si no se establece de acuerdo a rangos
                if (status >= 200 && status <= 299) {
                    severity = 'success';
                } else if (status <= 499) {
                    //incluye a los 100's, 300's, 400',s
                    severity = 'warning';
                    message = data.toString();
                    time = 3000;
                } else {
                    //incluye a los 500's y cualquier otro
                    severity = 'error';
                    message = data.toString();
                    time = 5000;
                }
            }
        }
        //define time para la notifiacion en caso de venir en la respuesta
        if (data[notifications.time_wrapper] !== undefined) {
            //evalua si la respuesta contiene un valor para time
            time = data[notifications.time_wrapper];
        }
        //define el titulo para la notificacion
        if (data[notifications.title_wrapper] !== undefined) {
            //evalua si la respuesta contiene un valor para title
            title = data[notifications.title_wrapper];
        } else {
            //se asigna el valor desde la configuracion
            if (notifications.default_titles[status] !== undefined) {
                title = notifications.default_titles[status];
            }
        }
        //evalua si existe lavariable message
        if (data[notifications.message_wrapper] !== undefined) {
            //se asegura que haya un mensaje en la respuesta
            message = data[notifications.message_wrapper];
        } else {
            //en caso de que no exista un valor en la respuesta
            //se intenta identificar si hay un mensaje predefino para este status
            if (notifications.default_messages[status] !== undefined) {
                message = notifications.default_messages[status];
            }
        }
        //realiza el proceso de ejecucion de funciones de acuerdo al elemento severity
        if (typeof message === "string" && message !== '') {
            if (typeof notifications[severity] === 'function') {
                notifications[severity].call(this, message, time, title);
            } else {
                alert(message);
            }
        }
    }
    //inicia el loader
    function start_loader(loader) {
        if (loader === 'small' || loader === 'full_screen' || loader === 'process') {
            if (active_processes[loader] === 0) {
                if (typeof (notifications[loader + '_loader_start']) === 'function') {
                    notifications[loader + '_loader_start'].call(this);
                }
            }
            active_processes[loader]++;
        }
    }
    //cierra el loader
    function close_loader(loader) {
        if (loader === 'small' || loader === 'full_screen' || loader === 'process') {
            active_processes[loader]--;
            if (active_processes[loader] < 1) {
                if (typeof (notifications[loader + '_loader_done']) === 'function') {
                    notifications[loader + '_loader_done'].call(this);
                }
            }
        }
    }
    return {
        setNotifications: function (new_notifications) {
            notifications = angular.extend(notifications, new_notifications);
        },
        setHooks: function (new_hooks) {
            hooks = angular.extend(hooks, new_hooks);
        },
        $get: [
            '$http',
            '$q',
            function ($http, $q) {
                return function (options) {
                    var defered = $q.defer();
                    var requested_process;
                    //evaluara un requerimiento para realizar todas las peticiones
                    if (typeof (hooks.pre_request.evaluate) === 'function') {
                        if (!hooks.pre_request['evaluate'].call(this)) {
                            if (typeof (hooks.pre_request.message) !== 'undefined') {
                                defered.reject();
                            } else {
                                window.console.warn('Hook message is missing');
                            }
                        } else {
                            //continuará
                        }
                    }
                    var defaults = {
                        headers: {
                            'X-Requested-With': 'XMLHttpRequest', // para que PHP(servidor) lo identifique como ajax
                            'Content-Type': undefined // para que PHP(servidor) lo interprete
                        },
                        process_url: '',
                        method: 'GET',
                        show_success_notifications: true,
                        show_error_notifications: true
                    };
                    //default setting are override
                    var o = angular.extend(defaults, options);
                    if (typeof (hooks.add_params) === 'function') {
                        var params_to_add = hooks.add_params();
                        o.params = angular.extend(params_to_add, o.params);
                    }
                    if (typeof (o.params) !== 'undefined') {
                        if (o.url[(o.url.length) - 1] !== '/') {
                            o.url += '/';
                        }
                        Object.keys(o.params).forEach(function (key) {
                            o.url += key + '/' + o.params[key] + '/';
                        });
                        o.params = undefined;
                    }
                    if (typeof o.data !== 'undefined') {
                        o.data = toFormData(o.data);
                    }
                    //inicia loader
                    //loader: // none = sin loader, small = Loader chico, full_screen = Pantalla completa, process = Procesamiento con porcentaje
                    if (typeof (o.loader) === 'undefined') {
                        if (o.method.toUpperCase() === 'POST') {
                            o.loader = 'full_screen';
                        } else {
                            o.loader = 'small';
                        }
                    } else {
                        //para trabajar con procesos
                        if (o.loader === 'process' && o.process_url !== undefined) {
                            actual_process = 0;
                        }
                    }
                    start_loader(o.loader);
                    if (typeof (notifications['close_debug']) === 'function') {
                        notifications['close_debug'].call(this);
                    }
                    $http(o).then(function (response) {
                        //si se esta ejecutando un proceso
                        if (o.loader === 'process' && o.process_url !== undefined) {
                            window.clearInterval(requested_process);
                        }
                        //cerramos el loader
                        close_loader(o.loader);
                        //para impresion del debug
                        if (response.data !== null) {
                            if (typeof (response.data.debug) !== 'undefined') {
                                if (typeof notifications['debug'] === 'function') {
                                    notifications['debug'].call(this, response.data.debug);
                                } else {
                                    alert(response.data.debug);
                                }
                            }
                        } else {
                            window.console.warn('Not a formated JSON in response');
                        }
                        //se obtiene el status
                        var status = parseInt(response.status);
                        var continue_after_callback = true;
                        //tareas especificas para los casos de falta de autenticacion o bien permisos, etc
                        if (typeof notifications.status_callbacks[status] === 'function') {
                            continue_after_callback = notifications.status_callbacks[status].call(this, response);
                        }
                        if (continue_after_callback) {
                            if (response.data !== null) {
                                if (o.show_success_notifications) {
                                    //se identificará si el valor del mensaje esta en la respuesta
                                    //puede venir desde el servidor o seteado anteriormente en la configuracion de acuerdo al status
                                    resolve_notifications(status, response.data);
                                }
                            }
                            //se devuelve la promesa incluyendo el valor del data
                            defered.resolve(response.data);
                        }
                    }, function (response) {
                        //si se esta ejecutando un proceso
                        if (o.loader === 'process' && o.process_url !== undefined) {
                            window.clearInterval(requested_process);
                        }
                        //cerramos el loader
                        close_loader(o.loader);
                        //para impresion del debug
                        if (response.data !== null) {
                            if (typeof (response.data.debug) !== 'undefined') {
                                if (typeof notifications['debug'] === 'function') {
                                    notifications['debug'].call(this, response.data.debug);
                                } else {
                                    alert(response.data.debug);
                                }
                            }
                        } else {
                            window.console.warn('Not a formated JSON in response');
                        }
                        //se obtiene el status
                        var status = parseInt(response.status);
                        var continue_after_callback = true;
                        //tareas especificas para los casos de falta de autenticacion o bien permisos, etc
                        if (typeof notifications.status_callbacks[status] === 'function') {
                            continue_after_callback = notifications.status_callbacks[status].call(this, response);
                        }
                        if (continue_after_callback) {
                            if (response.data !== null) {
                                //se identificara si el valor del mensaje esta en la respuesta
                                //puede venir desde el servidor o seteado anteriormente en la configuracion de acuerdo al status
                                if (o.show_error_notifications) {
                                    resolve_notifications(status, response.data);
                                }
                            }
                            //se devuelve la promesa incluyendo el valor del data
                            defered.reject(response.data);
                        }
                    });
                    //para el caso del procesamiento
                    if (o.loader === 'process' && o.process_url !== undefined && typeof (notifications.process_loader_update) === 'function') {
                        var loader_delay = 1000;
                        if (typeof (o.process_loader_delay) !== undefined && o.process_loader_delay > 0) {
                            loader_delay = o.process_loader_delay;
                        }
                        requested_process = window.setInterval(function () {
                            $http({
                                headers: {'Content-Type': undefined}, // para que PHP lo interprete
                                url: o.process_url,
                                method: 'GET'
                            }).then(function (response) {
                                if (response.data !== undefined && response.data[notifications['process_wrapper']]) {
                                    if (actual_process < response.data[notifications['process_wrapper']]) {
                                        actual_process = response.data[notifications['process_wrapper']];
                                        notifications.process_loader_update.call(this, actual_process);
                                    }
                                }
                            });
                        }, loader_delay);
                    }
                    return defered.promise;
                };
            }
        ]
    };
});
function toFormData(object, form, namespace) {
    var formData = form || new FormData();
    var formKey;
    if (object instanceof File) {
        formData.append(namespace, object);
    } else if (typeof (object) === "object") {
        for (var property in object) {
            if (object.hasOwnProperty(property)) {
                if (namespace) {
                    formKey = namespace + '[' + property + ']';
                } else {
                    formKey = property;
                }
                //si la propiedad es un objeto pero no es un archivo se usa recursivamente
                if (object[property] instanceof Date) {
                    formData.append(formKey, object[property].toISOString());
                } else if (object[property] instanceof Array) {
                    object[property].forEach(function (element, index) {
                        var tempFormKey = formKey + '[' + index + ']';
                        toFormData(element, formData, tempFormKey);
                    });
                } else if (object[property] instanceof File) {
                    formData.append(formKey, object[property]);
                } else if (typeof object[property] === 'object') {
                    toFormData(object[property], formData, formKey);
                } else {
                    formData.append(formKey, object[property]);
                }
            }
        }
    } else {
        formData.append(namespace, object);
    }
    return formData;
}