var Qs_Form = {
    message: new Qs_Message({
        'eng': {
            'invalidInformationEntered': 'Please review the comments marked in red and make appropriate corrections.',
            'pleaseCorrectTheseFields': ''
        }
    }),
    options: {
        errorDisplayMethod: 'HTML'
    },

    formOptions: {},

    init: function (idForm, options)
    {
        var form = document.getElementById(idForm);
        if (!form) {
            alert('Form (id = ' + idForm + ') is not available');
            return false;
        }
        if (!form.tagName || form.tagName != 'FORM') {
            alert('Element (id = ' + idForm + ') is not a form - tagName = ' + form.tagName);
            return false;
        }
        if (options) {
            Qs_Form.formOptions[idForm] = options;
        }
        $(form).unbind('submit.form-plugin').bind('submit.form-plugin', Qs_Form.onSubmit);
        $(':submit,input:image', form).unbind('click.form-plugin').bind('click.form-plugin', Qs_Form.buttonOnClick);
    },

    buttonOnClick: function (e)
    {
        var form = this.form;
        form.clk = this;
        if (this.type == 'image') {
            if (e.offsetX != undefined) {
                form.clk_x = e.offsetX;
                form.clk_y = e.offsetY;
            } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
                var offset = $(this).offset();
                form.clk_x = e.pageX - offset.left;
                form.clk_y = e.pageY - offset.top;
            } else {
                form.clk_x = e.pageX - this.offsetLeft;
                form.clk_y = e.pageY - this.offsetTop;
            }
        }
        setTimeout(function() {
            form.clk = form.clk_x = form.clk_y = null;
        }, 10);
    },

    getOption: function (name)
    {
        return Qs_Form.options[name];
    },

    setErrorDisplayMethod: function (idForm, value)
    {
        Qs_Form.setFormOption(idForm, 'errorDisplayMethod', value);
    },

    getErrorDisplayMethod: function (idForm)
    {
        return Qs_Form.getFormOption(idForm, 'errorDisplayMethod');
    },

    setFormOption: function (idForm, name, value)
    {
        if (typeof Qs_Form.formOptions[idForm] == 'undefined') {
            Qs_Form.formOptions[idForm] = {};
        }
        Qs_Form.formOptions[idForm][name] = value;
    },

    getFormOption: function (idForm, name)
    {
        if (typeof Qs_Form.formOptions[idForm] == 'undefined' || typeof Qs_Form.formOptions[idForm][name] == 'undefined' ) {
            return Qs_Form.getOption(name);
        }
        return Qs_Form.formOptions[idForm][name];
    },

    callExternal: function (spec)
    {
        if (typeof spec == 'string') {
            $.globalEval(spec + '.call(this)');
        } else if (typeof spec == 'object' && spec != null) {
            var scriptHtml = '';
            for (var callback in spec) {
                var params = new Array();
                if (is_numeric(callback)) {
                    if (typeof spec[callback] == 'string') {
                        callback = spec[callback]
                    } else if (typeof spec[callback] == 'object'
                               && typeof spec[callback] != null
                    ) {
                        var key = array_key(spec[callback]);
                        params = spec[callback][key]
                        callback = key;
                    } else {
                        continue;
                    }
                } else {
                    params = spec[callback];
                }
                scriptHtml += callback;
                if (params.length) {
                    scriptHtml += '.apply(this, ' + json_encode(params) + ');\n';
                } else {
                    scriptHtml += '.call(this);\n';
                }
            }
            if (scriptHtml.length) {
                $.globalEval(scriptHtml);
            }
        }
    },

    onSubmitSuccess: function (response, form)
    {
        var id = $(form).attr('id');
        Qs_Form.setFormOption(id, 'response', response)
        if (response.isValid) {
            if (form) {
                var onSuccessCallback = Qs_Form.getFormOption($(form).attr('id'), 'onSuccessCallback');
                if (typeof onSuccessCallback == 'undefined') {
                    form.submit();
                } else {
                    Qs_Form.callExternal(onSuccessCallback);
                }
            }
        } else {
            var onErrorCallback = Qs_Form.getFormOption($(form).attr('id'), 'onErrorCallback');
            if (typeof onErrorCallback != 'undefined') {
                Qs_Form.callExternal(onErrorCallback);
                return true;
            }
            Qs_Form.displayErrors(id);
        }
        return response;
    },

    displayErrors: function (id)
    {
        var response = Qs_Form.getFormOption(id, 'response');
        var form = document.getElementById(id);
        var displayMethod = Qs_Form.getErrorDisplayMethod(id);
        switch (displayMethod) {
            case 'ALERT':
                var message = Qs_Form.message.get('invalidInformationEntered') + '\n';
                message += Qs_Form.prepareErrorsAlert(response.errors, response.elements);
                message += '\n\n' + Qs_Form.message.get('pleaseCorrectTheseFields');
                var name = array_key(response.errors);
                if (form[name] && form[name].focus) {
                    form[name].focus();
                } else if (form[name + '[input]'] && form[name + '[input]'].focus) { // встановлення фокуса для каптчі
                    form[name + '[input]'].focus();
                }
                $.scrollTo('#' + name + '-label');
                alert(message);
                break;
            case 'HTML':
                Qs_Form.displayErrorsHtml(form, response.errors);
                var name = array_key(response.errors);
                var focusKey = null;
                if (form[name] && form[name].focus) {
                    focusKey = name;
                } else if (form[name + '[input]'] && form[name + '[input]'].focus) { // встановлення фокуса для каптчі
                    focusKey = name + '[input]';
                }
                if (focusKey != null) {
                    if ($('[name="' + focusKey + '"]:visible', form).size()) {
                        form[focusKey].focus();
                    }
                }
                var formPrependId = Qs_Form.getFormOption(id, 'prependId');
                if (formPrependId) {
                    name = id + '-' + name;
                }
                $.scrollTo('#' + name + '-label');
                alert(
                    Qs_Form.message.get('invalidInformationEntered')
                    + '\n'
                    + Qs_Form.message.get('pleaseCorrectTheseFields')
                );
                break;
            default:
                alert('Qs_Form. Unknown errorDisplayMethod "' + displayMethod + '"');
        }

        if (typeof response.captcha == 'object' && response.captcha != null) {
            for (var name in response.captcha) {
                var captcha = $('#' + name + '-element');
                if ($(captcha).size() != 0) {
                    $('img:first', captcha).attr('src', response.captcha[name].src);
                    $('#' + name + '-id', captcha).attr('value', response.captcha[name].id);
                    $('#' + name + '-input', captcha).attr('value', '');
                    if (typeof response.captcha[name].href != 'undefined') {
                        $('a.captcha_refresh', captcha).attr('href', response.captcha[name].href);
                    }
                }
            }
        }
    },

    prepareErrorsAlert: function (errors, titles)
    {
        var messages = '';
        for (var element in errors) {
            var message = '';
            var isTitle = true;
            for (var errorIndex in errors[element]) {
                if (typeof errors[element][errorIndex] == 'string') {
                    message += '\n     - ' + errors[element][errorIndex];
                } else {
                    messages += Qs_Form.prepareErrorsAlert(errors[element], titles[element]);
                    isTitle = false;
                    break;
                }
            }
            if (isTitle && message != '') {
                messages += '\n' + titles[element] + ':' + message;
            }
        }
        return messages;
    },

    displayErrorsHtml: function (form, errors, belongsTo)
    {
        for (var element in errors) {
            var html = '';
            var elementName;
            if (typeof belongsTo != 'undefined') {
                elementName = belongsTo + '[' + element + ']';
            } else {
                elementName = element;
            }
            for (var errorIndex in errors[element]) {
                if (typeof errors[element][errorIndex] == 'string') {
                    html += '<li>' + errors[element][errorIndex] + '</li>';
                } else {
                    Qs_Form.displayErrorsHtml(form, errors[element], elementName);
                    break;
                }
            }
            if (html != '') {
                html = '<ul class="errors">' + html + '</ul>';
                var idForm = $(form).attr('id');
                var response = Qs_Form.getFormOption(idForm, 'response')
                var id = Qs_Array.get(response.elements, elementName + '[id]');
                if (null == id) {
                    id = elementName.replace(/\[\]$/, '').replace(/\]/g, '').replace(/\[/g, '-');
                }
                var formPrependId = Qs_Form.getFormOption(idForm, 'prependId');
                if (formPrependId) {
                    id = idForm + '-' + id;
                }
                $('#' + id + '-element').append(html);
            }
        }
    },

    onSubmitError: function (request, textStatus, errorThrown)
    {
        alert(textStatus + ' ' + errorThrown);
    },

    onSubmitComplete: function (XMLHttpRequest, textStatus, form)
    {
        var idForm = $(form).attr('id');
        Qs_Form.formOptions[idForm]['processRequest'] = false;
    },

    removeElementsErrors: function (form)
    {
        $('ul.errors', form).remove();
    },

    editorsTriggerSave: function (form)
    {
        if (typeof tinyMCE != 'undefined') {
            tinyMCE.triggerSave();
        }

        if (typeof FCKeditorAPI != 'undefined') {
            for (var i = 0; i < form.elements.length; i++) {
                if (form.elements[i].tagName == 'TEXTAREA') {
                    var fckObject = FCKeditorAPI.GetInstance(form.elements[i].name);
                    if (typeof fckObject != 'undefined') {
                        if (fckObject.IsDirty()) {
                            fckObject.UpdateLinkedField();
                        }
                    }
                }
            }
        }
    },

    onSubmit: function (spec)
    {
        var form;
        if (this.tagName == 'FORM') {
            form = this;
        } else {
            form = spec;
        }
        var idForm = $(form).attr('id');

        Qs_Form.editorsTriggerSave(form);
        Qs_Form.removeElementsErrors(form);

        if (typeof Qs_Form.formOptions[idForm]['processRequest'] == 'undefined'
            || Qs_Form.formOptions[idForm]['processRequest'] != true) {
            Qs_Form.formOptions[idForm]['processRequest'] = true;
            var options = {
                url: $(form).attr('action'),
                type: 'POST',
                dataType: 'json',
                data: Qs_Form.toObject(form),
                success: function (data)
                {
                    Qs_Form.onSubmitSuccess(data, form);
                },

                error: Qs_Form.onSubmitError,

                complete: function (XMLHttpRequest, textStatus)
                {
                    Qs_Form.onSubmitComplete(XMLHttpRequest, textStatus, form)
                }
            };
            $.ajax(options);
        }
        return false;
    },

    setValue: function(/*Object*/obj, /*String*/name, /*String*/value)
    {
        var val = obj[name];
        if(is_string(val)) {
            if (name.substr(-2) == '[]') {
                delete obj[name];
                obj[name.substr(0, name.length - 2)] = [val, value];
            } else {
                obj[name] = value;
            }
        } else if (is_array(val)) {
            val.push(value);
        } else {
            obj[name] = value;
        }
    },

    toObject: function (/*DOMNode||String*/ formNode)
    {
        var ret = {};
        var exclude = 'file|submit|image|reset|button|';
        if (is_string(formNode)) {
            formNode = document.getElementById(formNode);
        }
        for (var i = 0; i<formNode.elements.length; i++) {
            var item = formNode.elements[i];
            if (!item) {
                continue;
            }
            var _in = item.name;
            var type = (item.type||"").toLowerCase();
            if(_in && type && exclude.indexOf(type) == -1 && !item.disabled){
                if (type == "radio" || type == 'checkbox') {
                    if (item.checked) {
                        Qs_Form.setValue(ret, _in, item.value);
                    }
                } else if (item.multiple) {
                    ret[_in] = [];
                    for (var j in item.options) {
                        if (
                            item.options[j] != null
                            && typeof item.options[j].tagName == 'string'
                            && item.options[j].tagName == 'OPTION'
                            && item.options[j].selected
                        ) {
                            Qs_Form.setValue(ret, _in, item.options[j].value);
                        }
                    }
                } else {
                    Qs_Form.setValue(ret, _in, item.value);
                    if(type == 'image'){
                        ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
                    }
                }
            }
        }
        if (formNode.clk && !formNode.clk.disabled && formNode.clk.name) {
            if (formNode.clk.type == 'image') {
                ret[formNode.clk.name + '.x'] = formNode.clk_x;
                ret[formNode.clk.name + '.y'] = formNode.clk_y;
            } else {
                ret[formNode.clk.name] = formNode.clk.value;
            }
        }
        return ret; // Object
    }
}

