(function ($) {
    /**
     * @param options
     * @returns {*|HTMLElement}
     */
    $.fn.getPrototype = function (options) {
        var collectionHolder = $(this);

        var defaults = {
            prototype_name: '__name__',
            prototype_label: '__label__',
            prototype_class: ''
        }

        var options = $.extend(defaults, options);


        var index = collectionHolder.data('index');
        var prototype = collectionHolder.data('prototype');

        var regex_name = new RegExp(options.prototype_name, "g");
        var regex_label = new RegExp(options.prototype_name, "g");

        prototype = prototype.replace(regex_name, index).replace(regex_label, "");

        prototype = $('<div></div>').append(prototype).children();

        return $(prototype);
    };

    /**
     * @param options
     * @returns {*|HTMLElement}
     */
    $.fn.insertPrototype = function (options) {
        var collectionHolder = $(this);
        var prototype = collectionHolder.getPrototype(options);
        collectionHolder.prepend(prototype);
        collectionHolder.data('index', collectionHolder.data('index') + 1);

        return $(prototype);
    }

    /**
     * @param options
     * @returns {*|HTMLElement}
     */
    $.fn.setIndexValue = function (options) {
        var defaults = {
            filter: 'input[type="hidden"]',
            children: 'li'
        }

        var options = $.extend(defaults, options);

        $(this).each(function () {

            var parent_list = $(this);

            parent_list.find(options.children).each(function (index, element) {

                var list_element = $(element);

                // if not empty
                if (!list_element.is(':empty')) {
                    var value = $(options.children, parent_list).index(list_element) + 1;
                    list_element.find(options.filter).val(value);
                }
            });
        });

        return $(this);
    }

    /**
     * @param options
     * @returns {*|HTMLElement}
     */
    $.fn.updateProgress = function (options) {
        var defaults = {
            done: 0,
            max: 0,
            bar_selector: '.bar',
            callback: function () {
            }
            //total_text: 'Subida completa'
            //total: 0
        }

        var options = $.extend(defaults, options);

        var done = options.done;
        var total = options.total;

        $(this).each(function () {

            if (typeof(total) != 'undefined') {

                if (total == 0) {
                    $(this).hide();
                } else {

                    var progress = (done * 100) / total;
                    if (!$(this).is(':visible')) {
                        $(this).show();
                    }
                    $(options.bar_selector, $(this)).css('width', progress + '%').html(done + ' de ' + total + ' archivos subidos');

                }
            } else {

                var progress = done;

                if (!$(this).is(':visible')) {
                    $(this).show();
                }

                $(options.bar_selector, $(this)).css('width', progress + '%').html(done + '% subido');
            }

            if (progress >= 100) {
                $(this).removeClass('active');

                if (typeof(options.total_text) != 'undefined') {
                    $(options.bar_selector, $(this)).css('width', progress + '%').html(options.total_text);
                }

                options.callback();

            } else {
                $(this).addClass('active');
            }

        });

        return $(this);
    }

    /**
     * @param options
     * @returns {*|HTMLElement}
     */
    $.fn.asignIndex = function (options) {

        var collectionHolder = $(this);

        var defaults = {
            filter: 'span, li, div, p, tr, td',
            data: 'index'
        }

        var options = $.extend(defaults, options);

        var indexes = Array();
        indexes.push(-1); // Valor por defecto

        $(collectionHolder).find(options.filter).each(function (index, element) {

            var child_index = $(this).getCollectionId();

            if (child_index != null) {
                indexes.push(child_index);
            }

        });

        collectionHolder.data(options.data, Math.max.apply(null, indexes) + 1);

        return $(this);
    }

    /**
     *
     * @returns {*}
     */
    $.fn.getCollectionId = function () {
        var id = $(this).attr('id');
        if (typeof(id) != 'undefined') {
            var child_index = Number(id.substring(id.lastIndexOf('_') + 1));
            if (!isNaN(child_index)) {
                return child_index;
            }
        }

        return null;
    }

    /**
     *
     * @param options
     * @returns {*}
     */
    $.fn.getCollection = function (options) {

        var collectionHolder = $(this);
        var defaults = {
            filter: 'span, li, div, p, tr, td',
            data: 'index'
        };

        options = $.extend(defaults, options);

        var indexes = Array();

        $(collectionHolder).find(options.filter).each(function (index, element) {

            var id = $(this).attr('id');
            if (typeof(id) != 'undefined') {
                var child_index = Number(id.substring(id.lastIndexOf('_') + 1));
                if (!isNaN(child_index)) {
                    indexes.push($(this));
                }
            }
        });

        return indexes;
    }

    /**
     * @param options
     * @returns {*}
     */
    $.fn.getCollectionChildren = function (options) {
        return $(this).getCollection(options).length;
    }

    /**
     * @param options
     * @returns {*|HTMLElement}
     */
    $.fn.incrementIndex = function (options) {
        var defaults = {
            data: 'index'
        }

        var options = $.extend(defaults, options);

        $(this).data(options.data, $(this).data(options.data) + 1);
        return $(this);
    }

    /**
     * @param options
     * @returns {*|HTMLElement}
     */
    $.fn.decrementIndex = function (options) {
        var defaults = {
            data: 'index'
        }

        var options = $.extend(defaults, options);

        $(this).data(options.data, $(this).data(options.data) - 1);
        return $(this);
    }

    /**
     * @param options
     * @returns {number}
     */
    $.fn.getEmptyIndex = function (options) {

        var collectionHolder = $(this);

        var defaults = {
            filter: 'span, li, div, p'
        }

        var options = $.extend(defaults, options);

        var indexes = Array();
        //
        $(collectionHolder).children().filter(options.filter).each(function (index, element) {
            var id = $(this).attr('id');
            if (typeof(id) != 'undefined') {
                var child_index = Number(id.substring(id.lastIndexOf('_') + 1));
                if (!isNaN(child_index)) {
                    indexes.push(child_index);
                }
            }


        });

        var maxplus = Math.max.apply(null, indexes) + 1;

        var array = Array();

        for (var i = 0; i <= maxplus; i++) {
            array.push(i);
        }

        var diff = Array();

        $.grep(array, function (element) {
            if ($.inArray(element, indexes) == -1) {
                diff.push(element);
            }
        });

        var number = Math.min.apply(null, diff);

        return isFinite(number) ? number : 0;

    }

    /**
     * @param incoming_options
     * @returns {*|HTMLElement}
     */
    $.fn.collection = function (incoming_options) {
        var this_global = $(this);

        $(this).each(function () {

            var collectionHolder = $(this);

            var defaults =
            {
                debug: false,
                prototype_class: '',
                prototype_name: '__name__',
                prototype: collectionHolder.data('prototype'),
                label: 'Add',
                button: true,
                button_template: '<button type="button" class="btn btn-primary"></button>',
                button_attributes: {},
                insert: 'prepend',
                insertButton: 'append',
                insertButtonSelector: '',
                maxChildren: 0,
                childrenFilter: 'span, li, div, p, tr, td',
                maxEffect: {},
                iterateAll: null,
                afterCreate: function (e) {
                },
                beforeCreate: function (e) {
                    e.detail.collectionHolder.find('button:last').before(e.detail.element);
                },
                beforeInsertButton: function (e) {
                },
                afterInsertButton: function (e) {
                },
                onClick: function(e){
                    if(typeof e != 'undefined'){
                        e.preventDefault();
                    }

                    var maxChildren = collectionHolder.data('maxChildren');

                    if (maxChildren > 0) {
                        var childs = collectionHolder.getCollectionChildren({filter: collectionHolder.data('childrenFilter')});

                        if (childs >= maxChildren) {
                            $(this).effect(collectionHolder.data('maxEffect'));
                            return this_global;
                        }
                    }

                    // Cogemos el index del data
                    var prototype = collectionHolder.getPrototype({
                        prototype_name: collectionHolder.data('prototype_name'),
                        prototype_class: collectionHolder.data('prototype_class')
                    });

                    // Prototipo(del formulario)

                    var event = new CustomEvent("beforeCreate", {
                        "detail": {
                            'collectionHolder': collectionHolder,
                            'element': prototype
                        }
                    });
                    collectionHolder.get(0).dispatchEvent(event);
                    collectionHolder[options.insert](prototype);

                    collectionHolder.incrementIndex();

                    var event = new CustomEvent("afterCreate", {"detail": {'element': prototype, 'button' : $(this)}});
                    collectionHolder.get(0).dispatchEvent(event);
                }
            };

            var options = $.extend(defaults, incoming_options);
            collectionHolder.data('collection_options', options)

            // Actualizamos el index asignado a este elemento
            collectionHolder.asignIndex({filter: options.childrenFilter});

            collectionHolder.data('prototype_class', options.prototype_class);
            collectionHolder.data('prototype_name', options.prototype_name);
            collectionHolder.data('prototype', options.prototype);

            if (options.maxChildren > 0) {
                collectionHolder.data('maxChildren', options.maxChildren);
                collectionHolder.data('maxEffect', options.maxEffect);
                collectionHolder.data('childrenFilter', options.childrenFilter);
            }

            if (options.button === false) {
                return this_global;
            }

            // Event listeners
            if (typeof($(this)) == 'object') {
                collectionHolder.get(0).addEventListener("beforeCreate", options.beforeCreate, false);
                collectionHolder.get(0).addEventListener("afterCreate", options.afterCreate, false);
                collectionHolder.get(0).addEventListener("beforeInsertButton", options.beforeInsertButton, false);
                collectionHolder.get(0).addEventListener("afterInsertButton", options.afterInsertButton, false);
            }

            var addLink = $(options.button_template);

            var button;

            // Search the button
            if (addLink.is('button')) {
                button = addLink;
            } else {
                button = addLink.find('button');
            }

            // Creamos el boton añadir para colecciones

            button.attr(options.button_attributes);
            button.attr('href', 'javascript:void(0)');

            if(options.label) {
                button.html(options.label);
            }

            button.on('click', options.onClick);

            button.addClass(options.button_class);

            var event = new CustomEvent("beforeInsertButton", {
                "detail": {
                    'buttonHolder': addLink,
                    'button': button,
                    'options': options
                }
            });
            collectionHolder.get(0).dispatchEvent(event);

            // Añadimos el boton al contenedor de colecciones

            var button_container = (options.insertButtonSelector == '') ? collectionHolder : $(options.insertButtonSelector);
            $(button_container)[options.insertButton](addLink);

            var event = new CustomEvent("afterInsertButton", {
                "detail": {
                    'buttonHolder': addLink,
                    'button': button,
                    'options': options
                }
            });
            collectionHolder.get(0).dispatchEvent(event);

            // Iteracion por cada elemento de la coleccion (Ya existente)
            if(options.iterateAll) {
                $.each(collectionHolder.getCollection({filter: options.childrenFilter}), function (index, element) {
                    options.iterateAll(index, element);
                });
            }

        });

        return this_global;
    }

    /**
     * @param options
     * @returns {*|HTMLElement}
     */
    $.fn.setMD5 = function (options) {
        var defaults = {
            filter: 'input[value]'
        }

        var options = $.extend(defaults, options);

        $(this).each(function (index, element) {
            $(element).data('md5', $(element).getMD5(options.filter));
        });

        return $(this);
    }

    /**
     * @param options
     * @returns {*}
     */
    $.fn.getMD5 = function (options) {
        var defaults = {
            filter: 'input'
        }

        var options = $.extend(defaults, options);

        var md5_form = '';
        $(this).find(options.filter).each(function (index, element) {

            md5_form += $.md5($(element).val());
        });

        return $.md5(md5_form);
    }

})(jQuery);
