$.fn.fld_die = function(options){
    return this.each(function() {
        var self = $(this);
        self.attr('disabled', 'disabled');
		if (undefined != options && undefined != options['not_empty'] && options['not_empty']) {
			return;
		}
		self.empty();
    });
};

$.fn.fld_revive = function(options){
    return this.each(function() {
        var self = $(this);
        self.removeAttr('disabled');
    });
};

$.fn.fld_seed = function(options){
    options = $.extend({
        'method': 'ajax'
    }, options);

    function ajax(obj) {
        $.ajax({
            url: options.url,
            type: 'POST',
            cache: false,
            dataType: 'json',
            data: options.data,
            success: function(data, textStatus) {
                if (data && '200' == data.status) {
                    var options = '<option value=""></option>';
                    for (var i in data.options) {
                        options += '<option value="' + data.options[i].id + '">' + data.options[i].title + '</option>';
                    }
                    obj.removeAttr('disabled').html(options);
                };
            }
        });
    };
    
    function populate(dst) {
        if (options.slice && undefined != options.slice) {
            var src = $('option', options.src);
            dst.empty().append((eval(options.slice)).clone());
        }
        else {
            dst.empty().append(options.src.html());
        }
        
        if (undefined != dst.attr('fe_def')) {
            dst.find('option[value=' + dst.attr('fe_def') + ']').attr('selected', 'selected')
        }
    };

    return this.each(function() {
        var self = $(this);
        switch (options.method) {
            case 'ajax':
                ajax(self);
                break;
            
            case 'populate':
                populate(self);
                break;
        }
    });
};

/**
 * Устанавливает обработчики глобальных элементов управления (например кнопка "Добавить", по нажатии которой
 * необходимо добавлять новые наборы полей). 
 * 
 * @param	string	act 		Название акции. На данный момент реализована одна, 'add' - добавить новый набор полей.
 * @param 	hash	options 	Набор дополнительных параметров, передаваемых в редактор.
 * 								Для акции 'add' необходимо задать:
 * 									jQuery	object	Объект, который будет клонироваться для создания нового набора полей.
 * 									jQuery	place	Объект, перед которым будут вставляться новые наборы полей.
**/
$.soc_formeditor = function(act, options) {
	options = $.extend({
        'hook_after_clone': function(obj) { return obj }
    }, options);
	
    switch (act) {
        case 'add':
            var new_form = options['object'].clone(true);
            new_form.insertBefore(options['place']).removeClass('item-for-add').addClass('new-field');
			options.hook_after_clone(new_form);
            var id_holder = undefined == new_form.attr('fe_id') ? $('[fe_id=]', new_form) : new_form;
            id_holder.attr('fe_id', '-' + (new Date()).getTime());
            new_form.soc_formeditor(options);
            $('a.i-20', new_form).click();
            return false;
    }
};

/**
 * Редактор форм. Предоставляет функционал по редактированию/AJAX созданию/сохранению/удалению сущностей.
 * Понятия:
 *    - Сущность - коллекция информации о некотором объекте. Имеет два представления: view - режим просмотра, 
 * 		edit - режим редактирования. Например сущность - адрес проживания. Содержит данные по стране/региону/городу/улице/...
 *    - Набор полей - часть информации об объекте, которая обрабатывается как единое целое. Например сущность - Мессенджеры состоит из
 *     	набора полей - предоставляющих онформацию по отдельным мессенджерам. Смысл введения набора полей - возможность 
 *     	добавлять/удалять/редактировать логические блоки информации внутри сущности. 
 * 
 * @param	hash	options		Набор опций, допустимы следующие значения:
 * 									bool	online		
 * 									bool	autosave	
 * 									func	before_save	Функция, вызывается перед AJAX отправкой данных на сервер.
 * 														Принимает в качестве входного аргумента hash с сохраняемыми параметрами. 
 *                                                                      func    after_edit      Функция, вызывается сразу после выхода из режима редактирования.
 *  								func	before_edit	Функция, вызывается после переключения в режим редактирования.
 *  													Принимает в качестве входного параметра редактируемый объект.
 */
$.fn.soc_formeditor = function(options){
    options = $.extend({
        'before_save': function(data) { return data },
        'oneline': false,
        'before_edit': function(obj) { return obj },
        'after_edit': function (obj) { return obj },
        'cancel_edit': function(obj) { return obj }}, options);

    return this.each(function() {
        var fe_url = $(this).attr("fe_url"); //URL для AJAX сохранения/удаления/обновления данных.
        var canvas = $(this); //Сущность, содержащая два представления.
        var v_toolbar = $('div.group-edit', canvas); //Toolbar представления view.
        var b_edit = $('a.i-20', v_toolbar); //Кнопка "редактировать" c v_toolbar.
        var b_del = $('a.i-18', v_toolbar); //Кнопка "удалить" с v_toolbar.
        var b_add = $('a.add-new-item', canvas); //Кнопа "добавить", используется как для добавления новой сущности, так и для добавления нового набора полей.
        var b_cancel = $('a.btn-cancel', canvas); //Кнопка "отменить", для отмены изменений в режиме редактирования и переключения в режим просмотра.
        var b_save = $('a.btn-ok', canvas); //Кнопка "сохранить", для сохранения и переключения в режим просмотра.
        var tmpl = {'new_field': $('div.item-for-add', canvas)};
        
        // Подключение обработчиков отображения всплывающей панели инструментов.
        canvas.bind('mouseover',
            function() {
                var self = $(this);
                if (!self.hasClass('editing')) {
                    v_toolbar.show();
                }
            }
        ).bind('mouseout',
            function() {
                var self = $(this);
                if (!self.hasClass('editing')) {
                    v_toolbar.hide();
                }
            }
        );
        
        is_max_count = function(canvas){
            var max_count = $('[fe_max_count]', canvas);
            if (0 < max_count.length) {
                var max_count_id = max_count.attr('fe_max_count_id');
                var list = $(':not(.item-for-add):not(.del-field)[fe_max_count_id=' + max_count_id + ']', canvas)
                if (list.length >= max_count.attr('fe_max_count')) {
                    return true;
                }
            }
            return false;
        }

        is_min_count = function(canvas, min_count_id){
            var min_count = min_count_id ? $('[fe_max_count_id='+min_count_id+'][fe_min_count]', canvas) : $('[fe_min_count]', canvas);
            if (0 < min_count.length) {
                if (!min_count_id)
                    min_count_id = min_count.attr('fe_max_count_id');
                var list = $('div:not(.item-for-add):not(.del-field)[fe_max_count_id=' + min_count_id + ']', canvas)
                if (min_count.attr('fe_min_count') >= list.length) {
                    return true;
                }
            }
            return false;
        }

		/**
		 * Переключает форму в режим редактирования.
		 * Скрывает инструменты для перехода в режим редактирования.
		 * Вызывает заданную пользователь функцию для выполнения дополнительных операций.
		 */
        b_edit.click(function() {
            canvas.addClass('editing').find('p.error-message').hide();
            if (!is_max_count(canvas))
                b_add.show();
            v_toolbar.hide();
            options.before_edit(canvas);
            return false;
        });
        
        // Подключение кнопки "Отмена редактирования формы".
        b_cancel.click(function() {
            $('div.new-field', canvas).remove();
            if ($(canvas).hasClass('new-field')) {
                $(canvas).remove();
            }
            $('div.del-field', canvas).removeClass('del-field').show();
            canvas.removeClass('editing');
            options.cancel_edit(canvas);
            return false;
        });
        
        // Подключение кнопки "Добавить".
        b_add.click(function() {
            if (is_max_count(canvas)) {
                b_add.hide();
                return false;
            }
            var new_line = tmpl['new_field'].clone(true);
            new_line.removeAttr('fe_max_count').removeAttr('fe_min_count');
            new_line.insertBefore($(this).parents('div.group').find('.item-for-add')).removeClass('item-for-add').addClass('new-field');
            if (is_min_count(canvas, new_line)) new_line.find('.del-field').remove();
            var id = undefined == new_line.attr('fe_id') ? $('[fe_id=]', new_line) : new_line;
            id.attr('fe_id', '-' + (new Date()).getTime());
            if (is_max_count(canvas)) {
                b_add.hide();
                return false;
            }
            return false;
        });
        
        // Подключение кнопок удаления полей.
        /**
         * 
         * @param {Object} field
         */
        b_del = function (ev) {
            var field = options.oneline ? canvas : $(this).parents('div.line');
            if (is_min_count(canvas, field.attr('fe_max_count_id'))) return false;

            var confirm_text = this.getAttribute('confirm');
            if (confirm_text) if (!confirm(confirm_text)) return false;

            if (field.hasClass('new-field')) {
                field.remove();
            } else {
                field.addClass('del-field').hide();
            }
            if (options.autosave) {
                b_save.click();
            }
            if (!is_max_count(canvas)) {
                b_add.show();
            }
            return false;
        };
        // Привязка удаления.
        $('a.del-field', canvas).click(b_del);
        
        // Подключение кнопки "Сохранить".
        b_save.click(function() {
            var rs = {'create': [], 'update': [], 'remove': []};
            var tmp, params, i, line;
            $('div.line:not(.item-for-add)[fe_id]', canvas).each(function() {
                line = $(this);
                tmp = {id: line.attr('fe_id')};
                params = {};
                $(':input[fe_input]', line).each(function () {
                    var self = $(this);
					if ('checkbox' == self.attr('type')) {
						tmp[self.attr('fe_input')] = self.attr('checked');
					}
					else {
						tmp[self.attr('fe_input')] = self.val();
					}
                });
                $('[fe_params]', line).each(function() {
                    var self = $(this);
                    eval('params = ' + self.attr('fe_params'));
                });
                $.extend(tmp, params);
                var base = options.oneline ? canvas : line;
                if (base.hasClass('new-field')) {
                    rs['create'].push(tmp);
                } else if (base.hasClass('del-field')) {
                    rs['remove'].push(tmp);
                } else {
                    rs['update'].push(tmp);
                }
            });
            
            $.ajax({
                url: fe_url,
                type: 'POST',
                cache: false,
                dataType: 'json',
                data: {soc_formeditor: JSON.stringify(options['before_save'](rs))},
                success: function(data, textStatus) {
                    if (data.status && undefined != data.status) {
                        switch (data.status) {
                            case 200:
                                $(canvas).removeClass('new-field');
                                $('div.new-field', canvas).removeClass('new-field');
                                //$('div.del-field', canvas).remove();
                                var i, j, field;
                                for (j in {'create': 0, 'update': 0}) {
                                    for (i in data.result[j]) {
                                        line = $("[fe_id=" + i + "]", canvas);
                                        $('[fe_remove]', line).hide();
                                        $('[fe_error]', line).hide(); //TODO: Так ли скрывать сообщения об ошибках (старые).
                                        var id = undefined == line.attr('fe_id') ? $('[fe_id]', line) : line;
                                        id.attr("fe_id", data.result[j][i].id);
                                        items = $("[fe_view]", line).each(function() {
                                            var self = $(this);
                                            var urlk = self.attr('fe_view_url');
                                            var val = data.result[j][i][self.attr('fe_view')];
                                            var url = urlk ? data.result[j][i][urlk] : '';

                                            if (url) {
                                                self.text('');
                                                self.append($('<a href="'+url+'" target="_blank">').text(val));
                                            } else {
                                                self.text(data.result[j][i][self.attr('fe_view')]);
                                            }
                                        });
                                        items = $("[fe_attr_name]", line).each(function() {
                                            var self = $(this);
                                            self.attr(self.attr('fe_attr_name'), data.result[j][i][self.attr('fe_attr_value')]);
                                        });
                                        try{
                                            items = $("[fe_input]", line).each(function() {
                                                var self = $(this);
                                                self.val(data.result[j][i][self.attr('fe_input')]);
                                            });
                                        }
                                        catch (e) {
                                            
                                        }
                                    }
                                }
                                for (i in data.result['remove']) {
                                    var line = $("[fe_id="+i+"]");
                                    if (line) line.remove();
                                }
                                canvas.removeClass('editing');
                                return;
                            
                            case 501:
                                $('[fe_error]', canvas).each(function() {
                                    $(this).hide();
                                });
                                for (j in {'create': 0, 'update': 0, 'remove': 0}) {
                                    for (i in data.result[j]) {
                                        var error_item = $('[fe_id=' + i + ']', canvas);
                                        for (k in data.result[j][i]['errors']) {
                                            $('[fe_error=' + k + ']', error_item).each(function() {
                                                var self = $(this);
                                                self.html(data.result[j][i]['errors'][k]);
                                                self.show();
                                            });
                                        }
                                    }
                                }
                                break;
                           
                            default:
                                console.log('done:default');
                                break;
                        }
                    }
                    else {
                    }
                },
                // Сюда, если совсем ошибка (не правильный url и т.п.).
                error: function(XMLHttpRequest, textStatus, errorThrown) {
                    console.log(XMLHttpRequest, textStatus, errorThrown)
                }
            });
            
            options.after_edit(canvas);
            return false;
        });
    });
};
