/* ============================================================
 * mopabootstrap-collection.js v3.0.0
 * http://bootstrap.mohrenweiserpartner.de/mopa/bootstrap/forms/collections
 * ============================================================
 * Copyright 2012 Mohrenweiser & Partner
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============================================================ */

!function ($) {
    "use strict";

    /* Collection PUBLIC CLASS DEFINITION
     * ============================== */

    var Collection = function (element, options) {
        this.$element = $(element);
        this.options = $.extend({}, $.fn.collection.defaults, options);

        // This must work with "collections" inside "collections", and should
        // select its children, and not the "collection" inside children.
        var $collection = $(this.options.collection_id);

        // Indexes must be different for every Collection
        if (typeof this.options.index === 'undefined') {
            this.options.index = {};
        }
        if (!this.options.initial_size) {
            this.options.initial_size = $collection.children().size();
        }

        this.options.index[this.options.collection_id] = this.options.initial_size - 1;
    };
    Collection.prototype = {
        constructor: Collection,
        add: function () {
            if (typeof this.options.max == 'number' && this.getItems().length >= this.options.max) {
                return;
            }
            // this leads to overriding items
            this.options.index[this.options.collection_id] = this.options.index[this.options.collection_id] + 1;
            var index = this.options.index[this.options.collection_id];
            if ($.isFunction(this.options.addcheckfunc) && ! this.options.addcheckfunc()) {
                if ($.isFunction(this.options.addfailedfunc)) {
                    this.options.addfailedfunc();
                }
                return;
            }
            this.addPrototype(index);
        },
        addPrototype: function (index) {
            var $collection = $(this.options.collection_id);
            var prototype_name = $collection.data('prototype-name');
            var prototype_label = $collection.data('prototype-label');

            // Just in case it doesn't get it
            if (typeof prototype_name === 'undefined') {
                prototype_name = '__name__';
            }

            if (typeof prototype_label === 'undefined') {
                prototype_label = '__name__label__';
            }

            var name_replace_pattern = new RegExp("((\"|&quot;|&amp;quot;|'|&#039;|&amp;#039;)((?!(\"|&quot;|&amp;quot;|'|&#039;|&amp;#039;|" + prototype_name + ")).)+?)(" + prototype_name + ")", 'ig');
            var label_replace_pattern = new RegExp("((\"|&quot;|&amp;quot;|'|&#039;|&amp;#039;)((?!(\"|&quot;|&amp;quot;|'|&#039;|&amp;#039;|" + prototype_label + ")).)+?)(" + prototype_label + ")", 'ig');
            var rowContent = $collection.attr('data-prototype')
                    .replace(/\n/g, '')
                    .replace(label_replace_pattern, "$1" + index)
                    .replace(name_replace_pattern, "$1" + index);
            var $row = $(rowContent);

            if (false !== $(window).triggerHandler('before-add.mopa-collection-item', [$collection, $row, index])) {
                $collection.append($row);
                $(window).triggerHandler('add.mopa-collection-item', [$collection, $row, index])
            }
        },
        remove: function (row) {
            var $collection = $(this.options.collection_id);

            if (typeof row == 'undefined') {
                row = this.$element.closest('.collection-item');
            }

            if (typeof row != 'undefined') {
                if (row instanceof jQuery) {
                    row = row.get(0);
                }

                var oldIndex = this.getIndex(row);

                if (oldIndex == - 1) {
                    throw new Error('row not contained in collection');
                }

                if (false !== $(window).triggerHandler('before-remove.mopa-collection-item', [$collection, row, oldIndex])) {
                    row.parentNode.removeChild(row);
                    $(window).triggerHandler('remove.mopa-collection-item', [$collection, row, oldIndex]);
                }
            }
        },
        /**
         * Get the index of the current row zero based
         * return -1 if not found
         */
        getIndex: function (row) {
            if (row instanceof jQuery) {
                row = row.get(0);
            }

            var $collection = $(this.options.collection_id);
            var items = $collection.children();

            for (var i = 0; i < items.size(); i ++) {
                if (row == items[i]) {
                    return i;
                }
            }
            return - 1;
        },
        getItem: function (index) {
            var items = this.getItems();

            return items[index];
        },
        getItems: function () {
            var $collection = $(this.options.collection_id);
            return $collection.children();
        }
    };

    /* COLLECTION PLUGIN DEFINITION
     * ======================== */

    $.fn.collection = function (option) {
        var coll_args = arguments;

        return this.each(function () {
            var $this = $(this),
                collection_id = $this.data('collection-add-btn'),
                data = $this.data('collection'),
                options = typeof option == 'object' ? option : {};

            if (collection_id) {
                options.collection_id = collection_id;
            }
            else if ($this.closest(".collection-items").attr('id')) {
                options.collection_id = '#' + $this.closest(".collection-items").attr('id');
            } else {
                options.collection_id = this.id.length === 0 ? false : '#' + this.id;
                if (!options.collection_id) {
                    throw new Error('Could not load collection id');
                }
            }
            if (!data) {
                $this.data('collection', (data = new Collection(this, options)));
            }
            if (coll_args.length > 1) {
                var arg1 = coll_args[1];
                var returnval;
            }
            if (option == 'add') {
                data.add();
            }
            if (option == 'remove') {
                data.remove(arg1);
            }
            if (option == 'getIndex') {
                returnval = data.getIndex(arg1);
            }
            if (option == 'getItem') {
                returnval = data.getItem(arg1);
            }
            if (option == 'getItems') {
                returnval = data.getItems();
            }
            if (coll_args.length > 1 && typeof coll_args[2] == 'function') {
                coll_args[2].call(this, returnval);
            }
        });
    };

    $.fn.collection.defaults = {
        collection_id: null,
        initial_size: 0,
        addcheckfunc: false,
        addfailedfunc: false,
        max: false
    };

    $.fn.collection.Constructor = Collection;

    /* COLLECTION DATA-API
     * =============== */

    $(function () {
        $('body').on('click.collection.data-api', '[data-collection-add-btn]', function (e) {
            var $btn = $(e.target);

            if (! $btn.hasClass('btn')) {
                $btn = $btn.closest('.btn');
            }
            $btn.collection('add');
            e.preventDefault();
        })
        .on('click.collection.data-api', '[data-collection-remove-btn]', function (e) {
            var $btn = $(e.target);

            if (! $btn.hasClass('btn')) {
                $btn = $btn.closest('.btn');
            }
            $btn.collection('remove');
            e.preventDefault();
        });
    });

}(window.jQuery);
