//Компонент отправитель форм

//prefix - префикс, которым помечаются html-элементы, необходимые для работы с формой
//url - url на который отправляется запрос
//success_action - действие, которое должно быть произведено в случае 
//успешной клиентской и серверной валидации формы
//'replace_form' - форма исчезает и заменяется слоем
//'update_status' - выводит ответ сервера, форма остаётся
//'reload' - перезагружает страницу, нужно для логина и т.п.
//'direct' - с сервера возвращается непосредственно html-ответ,
//который не нужно обрабатывать
FormSender = function(prefix, url, success_action) {
    this.form = $(prefix+'_form');
    this.responseEl = $(prefix+'_response');
    this.replaceEl = $(prefix+'_replace');
    this.url = url;
    this.sender = $(prefix+'_sender');
    this.prefix = prefix;
    this.ready_status = true;
    if (!success_action)
       success_action = 'update_status';
    
    this.success_action = success_action;

    this.listeners = new Array();
    this.before_listeners = new Array();
	this.file_sends = false;
	
    if (this.sender)   
        this.sender.onclick = this.send.bind(this);
    
    this.form.onsubmit = this.send.bind(this);
}

//Добавление обработчика, который должен вызваться при успешной отправке формы
FormSender.prototype.addListener = function(handler) {
	this.listeners.push(handler);
}

FormSender.prototype.addBeforeListener = function(handler) {
    this.before_listeners.push(handler);
}

//Добавление обработчика, который должен вызваться в случае добавления файлов
//Вообще как-то по-дурацки - в будущем отрефакторить
FormSender.prototype.addFileListener = function(handler) {
    this.file_listeners.push(handler);
}

//Вызываем обработчики
FormSender.prototype.sayTo = function(param) {
	for (var i = 0; i < this.listeners.length; i++)
		this.listeners[i](param);
}

FormSender.prototype.sayBefore = function(param) {
    for (var i = 0; i < this.before_listeners.length; i++)
        this.before_listeners[i](param);
}

FormSender.prototype.send = function() {
    //Запрещаем многократную отправку форму
    if (!this.ready_status) return false;
    //Проверяем поля формы
    if (!Validator.validate(this.form)) {
        this.showError(Validator.error_message);
        return false;
    }
    this.ready_status = false;
    
    this.sayBefore();
    
    //Если есть файлы, то отправляем их
    if ($$('#'+this.form.id+' input[type="file"]').length > 0)
        this.sendFiles();
    else
        this.request();
    
    //Предотвращаем неправильную отправку формы по Enter    
    return false;
}

//Через скрытый фрейм отправляем файлы на сервер,
//Там они сохраняются во временной папке, их имена возвращаются
//FormSender записывает эти имена в скрытые input-ы
FormSender.prototype.sendFiles = function() {
	   var form_id = this.form.id;
        //Удаляем старые инпуты, хранящие информацию о файлах
		//TODO:: переписать это как-нибудь поумнее
        $$('#'+form_id+' input[name*="f_"]').each(
            function(item) {
				var name = item.name.substr('f_'.length);
				var els = $$('#'+form_id+' input[name="'+name+'"]');
				if (els.length > 0) els.each(function(item){item.remove()});
			}
        );

        if ($('ifr'))
            $('ifr').remove();

        this.form.target = 'ifr';
        this.form.method = 'post';
        this.form.action = base_url()+'services/files/save';
        this.form.enctype='multipart/form-data';

        var iframe = new Element('iframe', {'class':'hidden', 'id':'ifr', 'name':'ifr'});
        this.form.appendChild(iframe);

        //Кросс-браузерное добавление события iframe.onload     
        if (iframe.addEventListener) iframe.addEventListener("load", this.onFileSend.bind(this), false);
        else if (iframe.attachEvent) iframe.attachEvent("onload", this.onFileSend.bind(this)); 
        this.form.submit();
}

//Реакция на отправку файлов
FormSender.prototype.onFileSend = function() {
    var iframe = $('ifr');
	
    var response = getIFrameBody(iframe).innerHTML.evalJSON();

    if (response.status == 'ok') {
        //Добавляем скрытые поля
        for (var i = 0; i < response.data.length; i++) {
            var el = document.createElement('input');
            el.type = 'hidden';
            //el.name = 'f_'+response.data[i].key;
			el.name = response.data[i].key;
            el.value = response.data[i].value
            this.form.appendChild(el);
			this.file_sends = true;
        }
        //Отправляем основной запрос
        this.request();
    }
    else
        this.showError(response.message);
}

FormSender.prototype.request = function() {
    var form_data = this.form.serialize(true);
    
    if(this.add_params)
    {
        form_data = $H(form_data).update(this.add_params).toObject();
    }
    request(this.url, form_data, this.onSuccess.bind(this))
}

FormSender.prototype.addFormParams = function (params) {
    if(params)
        this.add_params = params;
    else
        this.add_params = {};
}

FormSender.prototype.onSuccess = function(transport) {
    //Если нужно просто отобразить html
    if (this.success_action == 'direct') {
        this.responseEl.update(transport.responseText);
        this.sayTo();
    }
    else {
        var response = transport.responseText.evalJSON();
        //Отладочная информация
        if (response.profile) 
            this.profile(response.profile);
        
        if (response.status == 'ok') {
            if (this.success_action == 'replace_form') {
                this.form.hide();
                this.replaceEl.update(response.message);
				show(this.replaceEl);
            }
            else 
                if (this.success_action == 'reload') {
                    location.reload();
                    return;
                }
                else 
                    if (this.success_action == 'update_status') {
                        this.responseEl.addClassName('ok');
                        this.responseEl.removeClassName('not_ok');
                        this.responseEl.update(response.message);
                    }
			
            var add_info = $H({file_sends:this.file_sends});
            add_info = add_info.merge(response.callback_params);
			this.sayTo(add_info);
			this.file_sends = false;
        }
        else {
            this.showError(response.message);
        }
    }
    
    this.ready_status = true;
}

FormSender.prototype.showError = function(message) {
    this.responseEl.removeClassName('ok');
    this.responseEl.addClassName('not_ok');
    this.responseEl.update(message);
}

//Профилирование предполагающее ряд соглашений верных в рамках нашего фреймворка
FormSender.prototype.profile = function(message) {
    message = '<br />Сервер сообщает:<br />' + message;
    $('developer-panel').update($('developer-panel').innerHTML + message);
}
