/**
 * form handler
 * http://www.redfrog.de
 * Copyright (c) 2009 casa united SAGL, redfrog Software Solutions
 */
(function($) {

    $.form = {
        defaults: {
            url: null,
            form: null, // n/a
            submit: null,
            action: 'default',
            params: {},

            onUploadsStart: function(form, files) {
                $.loading({message: '<span class="file">Datei</span> (Datei <span class="count">0</span>/<span class="sum">' + files.length + '</span>) wird hochgeladen.'});
            },
            onUploadsSuccess: function(form, files) {

            },
            onUploadsError: function(form, files) {

            },
            onUploadsComplete: function(form, files) {
                $.unloading();
            },

            onUploadStart: function(file) {
                console.debug('upload.onUploadStart ', $(file).val());
                // upload loading message
                $('#loading span.file').html($(file).val());
                var count = $('#loading span.count');
                count.html(parseInt(count.html()) + 1);
                $('#loading').center();
            },
            onUploadSuccess: function(data, file) {
                console.debug('upload.onUploadSuccess ', $(file).val(), data);
                //$(data).execute(file);
            },
            onUploadError: function(status, exception, response, file) {
                console.debug('upload.error ', status, exception, response, file);
                $.error('Datei konnte nicht erfolgreich hochgeladen werden.');
            },
            onUploadComplete: function(file) {
                console.debug('upload.complete ', $(file).val());
            }
        }
    };

    $.fn.form = function(options) {
        return this.plugin('form.options', options, $.form.defaults, function(options) {
            var form = $(this);

            $('button[type="submit"]:not(.nonajax)', form).livequery('click', function() {
                form.send({submit: this, action: $(this).buttonval()});
            });

            // activate submit buttons when a file selected
            $(':file', form).livequery(function() {
                var files = $(':file', form);

                files.change(function() {
                    files.each(function() {
                        var value = new String($(this).val());

                        if (value.length == 0) {
                            $(':submit', form).disable();
                        } else {
                            $(':submit', form).enable();
                            //throw {};
                            return false;
                        }
                    });
                });
            });

            form.submit(function() {
                return false;
            });
        });
    }

    $.fn.send = function(options) {
        return this.form(options).plugin('form.options', options, function(options) {
            console.debug('send form', [this, options]);

            try {
                submit(this, options);
            } catch (e) {
                console.debug(e);
            }
        });
    }

    /**
     * submit form via simple POST request for uplaoding files
     */
    function submit(form, options) {
        form = $(form);

        // url handling
        if ($.trim(options.url).length == 0) {
            options.url = $.trim(form.attr('action'));

            if (options.url.length == 0) {
                options.url = window.location.href;
            }
        }
        options.url = ($.trim(options.url).match(/^([^#]+)/)||[])[1];

        var success = [];
        var error = [];
        var files = $(':file', form).filter(function() { // filter file input fields without value
            if ($(this).val().length == 0) {
                $(this).remove();
                return false;
            }
            return true;
        });

        // dispatcher for file uploading
        function dispatcher() {
            var files = $(':file', form);

            if (files.length > 0) {
                upload(files[0], options);
            } else {
                if (error.length > 0) {
                    options.onUploadsSuccess.bind(options)(success);
                } else {
                    options.onUploadsError.bind(options)(error);
                }
                options.onUploadsComplete.bind(options)(form);
            }
        }

        // handle as upload or ajax form
        if (files.length > 0) {
            options.onUploadsStart.bind(options)(form, files);
            files.one('uploadSuccess', function() {
                     success.push(this);
                 })
                 .one('uploadError', function() {
                     error.push(this);
                 })
                 .one('uploadComplete', dispatcher);
            dispatcher();
        } else {
            ajaxSubmit(form, options);
        }
    }

    /**
     * submit form as ajax request
     */
    function ajaxSubmit(form, options) {
        var data = {};

        $($(form).formToArray()).each(function(i, kv) {
            var name = $(kv).attr('name');
            var name2 = name.replace(/\[\]$/, '');
            var value = $(kv).attr('value');
            var array = $(data).attr(name2) || [];

            if (name.length != name2.length) { // handel multiple elements like "field[]"
                array.push(value);
                $(data).attr(name2, array);
            } else {
                $(data).attr(name, value);
            }
        });

        data = $.extend({}, data, form.data('form.data') || {});

        // append date from hidden fields
        $('input[type="hidden"]', form).each(function() {
            var inputName = $(this).attr('name');
            var inputData = $(this).data('data');

            console.debug('add hidden data: ', inputName, inputData);
            
            if (inputData) {
                $(data).attr(inputName, inputData);
            }
        });

        // append multi select data
        $('div.multiselect').each(function() {
            var select = $('select:last', this);
            var selectName = $(select).attr('name');
            var selectedValues = [];

            $(select).find('option').each(function() {
               selectedValues.push($(this).attr('value'));
            });

            $(data).attr(selectName, selectedValues);
        });

        options.element = form;
        options.params  = {form: {name:   form.attr('name'),
                                  action: options.action,
                                  data:   data}};

        $.ajax(options);
    }

    /**
     * upload an file via simple POST
     */
    function upload(file, options) {
        file = $(file);

        var id    = new Date().getTime() + '_' + parseInt(Math.random()*10000);
        var frame = $('<iframe id="frame_' + id + '" name="frame_' + id + '" src="about:blank" class="nonajax" />')[0];
        var form  = $('<form id="form_' + id + '" name="form_' + id + '" method="POST" enctype="multipart/form-data" />');

        options.onUploadStart.bind(options)(file);

        $(frame).css({display: 'none', position: 'absolute', top: '-10000px', left: '-10000px'})
                .appendTo('body');

        $(form).css({display: 'none', position: 'absolute', top: '-10000px', left: '-10000px'})
               .attr('action', options.url)
               .attr('target', 'frame_' + id)
               .appendTo('body');

        $(file).appendTo(form)
               .trigger('uploadStart');

        // iframe onload event
        frame.attachEvent ? frame.attachEvent('onload', ready) : frame.addEventListener('load', ready, false);

        $(form).submit();

        console.debug('uploading to ', form.attr('action'));

        // callback on onload
        function ready() {
            // detach iframe onload event
            frame.detachEvent ? frame.detachEvent('onload', ready) : frame.removeEventListener('load', ready, false);

            var doc, body, response;

            try {
                doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
                body = doc.body.innerHTML;

                console.debug('ajax.onUploadSuccess  [body]', body);
                response = $.secureEvalJSON(body);

                console.debug('ajax.onUploadSuccess [json]', response);
                
                options.onUploadSuccess.bind(options)(response, $(file));
                $(file).trigger('uploadSuccess', options, response);
            } catch (e) {
                response = (response) ? response : body;

                options.onUploadError.bind(options)('error', e, response, $(file));
                $(file).trigger('uploadError', 'error', options, e, response);
            }

            setTimeout(function() { // clean up
                $(form).remove();
                $(frame).remove();
            }, 1000);

            options.onUploadComplete.bind(options)(file);
            $(file).trigger('uploadComplete', options);
        }
    }

})(jQuery);
