// модуль для работы с таблицей на форме
//
// 1 - 'tr' с заголовками помечается атрибутом 'header'
// 2 - 'tr' с шаблоном помечаем атрибутом 'template'
// 2.1 - для input,select где необходимо менять индекс в массиве нужно задать атрибут 'template-name="[{i}].zzz"'.
// 2.2 - для input,select где необходимо добавить классы нужно задать атрибут 'template-class="zzz xxx"'
// 3 - 'tr' с данными от сервера помечаем атрибутом 'entity-type="server"'
// 4 - 'tr' с новыми данными помечен атрибутом 'entity-type="dynamic"'

$.fn.TableForm = function (options) {
    var self = this;
    var methods = {
        addRow: function (event, that) {
            event.preventDefault();
            $(this).data('TableForm').addRow();
            return false;
        },
        removeByCurrent: function (event, that) {
            event.preventDefault();
            $(this).data('TableForm').removeByCurrent(that);
            return false;
        },
        getRows: function () {
            return $(this).data('TableForm').getRows();
        },
        getRowByIndex: function (index) {
            return $(this).data('TableForm').getRowByIndex(index);
        }
    };

    if (typeof options == 'string' && methods[options]) {
        return methods[options].apply(this, Array.prototype.slice.call(arguments,1));
    }

    new TableForm();

    function TableForm() {

        var _defaultOptions = {

            onBeforeInitRow: function ($tr, alredyInit, entityType) { },
            onInitRow: function ($tr, entityType) { },
            onAfterInitRow: function ($tr, entityType) { },

            onBeforeAddRow: function () { },
            onAddRow: function ($tr) { },
            onAfterAddRow: function ($tr) { },

            onReindex: function ($tr, index) { },
            onReindexElement: function ($tr, $element, index, oldName, newName) { },

            // indirectly - псевдо-удаление, строчка отправится на сервер
            onRemoveRow: function ($tr, indirectly) { },
            // показывать диалог подтверждения удаления
            removeConfirmDialog: true,
            removeConfirmMessage: CommonResources.Remove + '?',
            // включить псевдо-удаление
            removeIndirectlyServerEntity: true,

            rowSelector: 'tr'
        }

        var _options = $.extend({}, _defaultOptions, options);
        var _$table = $(self).data('TableForm', this);
        var _$trTemplate = _$table.find(_options.rowSelector + '[template]');
        var _trIndexes = {};

        reIndex();
        _$table.find(_options.rowSelector + '[entity-type="server"]').each(function (i, v) {
            initRow($(v));
        });

        reIndex();

        function initRow($tr) {

            var entityType = $tr.attr('entity-type');

            if ($tr.is('[alredy-init]')) {
                if (_options.onBeforeInitRow) {
                    _options.onBeforeInitRow($tr, true, entityType);
                }
                return;
            }

            if (_options.onBeforeInitRow) {
                _options.onBeforeInitRow($tr, false, entityType);
            }

            if (_options.onInitRow) {
                _options.onInitRow($tr, entityType);
            }

            $tr.attr('alredy-init', true);

            if (_options.onAfterInitRow) {
                _options.onAfterInitRow($tr, entityType);
            }
        }

        this.addRow = function () {
            if (_options.onBeforeAddRow) {
                _options.onBeforeAddRow();
            }

            var $trTemplateClone = _$trTemplate.clone();

            $trTemplateClone.removeClass('hidden').removeAttr('template');
            $trTemplateClone.attr('entity-type', 'dynamic');

            _$table.append($trTemplateClone);

            if (_options.onAddRow) {
                _options.onAddRow($trTemplateClone);
            }

            reIndex();
            initRow($trTemplateClone);
            reIndex();

            if (_options.onAfterAddRow) {
                _options.onAfterAddRow($trTemplateClone);
            }
        };

        this.removeRow = function ($tr) {
            var isRemoved = ($tr.attr('removed') || 'false').toLowerCase() === 'true';

            if (_options.removeIndirectlyServerEntity && $tr.is('[entity-type="server"]')) {

                var $inputRemove = $tr.find('input[name$=".Remove"]');
                //если уже поставили на удаление
                if (isRemoved) {
                    $tr.css($tr.data('oldCss'));

                    if ($inputRemove.length) {
                        $inputRemove.val(!isRemoved);
                    }
                }
                else {

                    if (_options.removeConfirmDialog) {
                        var c = confirm(_options.removeConfirmMessage);
                        if (!c)
                            return false;
                    }

                    $tr.data('oldCss', { 'backgroundColor': '#ffffff', 'textDecoration': 'none' });
                    $tr.css({
                        backgroundColor: '#fdc7c7',
                        textDecoration: 'line-through'
                    });

                    if ($inputRemove.length) {
                        $inputRemove.val(!isRemoved);
                    }
                }

                _options.onRemoveRow($tr, isRemoved, true);

                $tr.attr('removed', !isRemoved);
            }
            else {
                if (_options.removeConfirmDialog) {
                    var c = confirm(_options.removeConfirmMessage);
                    if (!c)
                        return false;
                }

                _options.onRemoveRow($tr, isRemoved, false);

                $tr.remove();

                reIndex();
            }
        }

        this.removeRowByIndex = function (i) {
            var $tr = _$table.find(_options.rowSelector + '[index="' + i + '"]');
            this.removeRow($tr);
        }

        this.removeRowByLink = function (link) {

            var $this = $(link);
            var $tr = $this.closest(_options.rowSelector);
            this.removeRow($tr);
        };

        this.removeByCurrent = function (that) {
            var $that = $(that);
            var $tr = $that.closest(_options.rowSelector);
            if ($tr.length) {
                this.removeRow($tr);
            }
        }

        function reIndex() {
            _trIndexes = {};
            var $trs = _$table.find(_options.rowSelector+'[entity-type="dynamic"],' + _options.rowSelector + '[entity-type="server"]'); //:not([template]):not([header])
            $trs.each(function (i, v) {
                var $tr = $(v);
                var $inputs = $tr.find('input,select,textarea');
                var toIndexData = {};
                $inputs.each(function (i2, v2) {
                    var $input = $(v2);
                    var oldName = $input.attr('name');
                    var newName = oldName;
                    if ($input.is('[template-name]')) {
                        newName = $input.attr('template-name').replace('{i}', i);
                        //фикс проблемы с сообщением об ошибке
                        var label = $('label[for="' + oldName + '"]');
                        if (label.length) {
                            label.attr('for', newName);
                        }
                        $input.attr('name', newName);
                    }

                    if ($input.is('[template-class]')) {
                        $input.addClass($input.attr('template-class'));
                    }

                    if (_options.onReindexElement) {
                        _options.onReindexElement($tr, $input, i, oldName, newName);
                    }
                });
                if (_options.onReindex) {
                    _options.onReindex($tr, i);
                }
                $tr.attr('index', i);
                _trIndexes[i] = toIndexData;
            });
        };

        this.getRows = function () {
            return _$table.find(_options.rowSelector + '[entity-type="dynamic"],' + _options.rowSelector + '[entity-type="server"]');
        }

        this.getRowByIndex = function (i) {
            return $tr = _$table.find(_options.rowSelector + '[index="' + i + '"]');
        }

        return this;
    }

    return this;
}