﻿/*** Form.js begin ***/
var Abstract = {};

Object.extend(window, {
    PREFIX: "__",
    $: function() {
        var elements = [];
        for (var i = 0; i < arguments.length; i++) {
            var e = arguments[i];
            if (typeof e == 'string') {
                e = document.getElementById(e);
            }
            if (arguments.length == 1) {
                return e;
            }
            elements.push(e);
        }
        return elements;
    },
    $I: function(cid) {
        var str = PREFIX + cid;
        var obj;
        eval("obj=" + str);
        return obj;
    },
    Class: {
        create: function() {
            return function() {
                if (typeof this.initialize == "function") {
                    this.initialize.apply(this, arguments);
                }
            };
        }
    }
}, false);

var Field = {
    clear: function() {
        for (var i = 0; i < arguments.length; i++)
            $(arguments[i]).value = '';
    },

    focus: function(element) {
        $(element).focus();
    },

    present: function() {
        for (var i = 0; i < arguments.length; i++)
            if ($(arguments[i]).value == '') return false;
        return true;
    },

    select: function(element) {
        $(element).select();
    },

    activate: function(element) {
        element = $(element);
        element.focus();
        if (element.select)
            element.select();
    }
}

/*--------------------------------------------------------------------------*/

var Form = {
    serialize: function(form) {
        var elements = Form.getElements($(form));
        var queryComponents = new Array();

        for (var i = 0; i < elements.length; i++) {
            var queryComponent = Form.Element.serialize(elements[i]);
            if (queryComponent)
                queryComponents.push(queryComponent);
        }

        return queryComponents.join('&');
    },

    getElements: function(form) {
        form = $(form);
        var elements = new Array();

        for (tagName in Form.Element.Serializers) {
            var tagElements = form.getElementsByTagName(tagName);
            for (var j = 0; j < tagElements.length; j++)
                elements.push(tagElements[j]);
        }
        return elements;
    },

    getInputs: function(form, typeName, name) {
        form = $(form);
        var inputs = form.getElementsByTagName('input');

        if (!typeName && !name)
            return inputs;

        var matchingInputs = new Array();
        for (var i = 0; i < inputs.length; i++) {
            var input = inputs[i];
            if ((typeName && input.type != typeName) ||
          (name && input.name != name))
                continue;
            matchingInputs.push(input);
        }

        return matchingInputs;
    },

    disable: function(form) {
        var elements = Form.getElements(form);
        for (var i = 0; i < elements.length; i++) {
            var element = elements[i];
            element.blur();
            element.disabled = 'true';
        }
    },

    enable: function(form) {
        var elements = Form.getElements(form);
        for (var i = 0; i < elements.length; i++) {
            var element = elements[i];
            element.disabled = '';
        }
    },

    findFirstElement: function(form) {
        return Form.getElements(form).find(function(element) {
            return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
        });
    },

    focusFirstElement: function(form) {
        Field.activate(Form.findFirstElement(form));
    },

    reset: function(form) {
        $(form).reset();
    }
}

Form.Element = {
    serialize: function(eleName) {
        element = $(eleName);
        if (null == element) alert(eleName + " is null!");
        var method = element.tagName.toLowerCase();
        var parameter = Form.Element.Serializers[method](element);

        if (parameter) {
            var key = encodeURIComponent(parameter[0]);
            if (key.length == 0) return;

            if (parameter[1].constructor != Array)
                parameter[1] = [parameter[1]];

            return parameter[1].map(function(value) {
                return key + '=' + encodeURIComponent(value);
            }).join('&');
        }
    },

    getValue: function(node) {
        element = $(node);
        if (null == element) alert(node + " is null!");
        var method = element.tagName.toLowerCase();
        var parameter = Form.Element.Serializers[method](element);

        if (parameter)
            return parameter[1];
    }
}

Form.Element.Serializers = {
    input: function(element) {
        switch (element.type.toLowerCase()) {
            case 'submit':
            case 'hidden':
            case 'password':
            case 'text':
                return Form.Element.Serializers.textarea(element);
            case 'checkbox':
            case 'radio':
                return Form.Element.Serializers.inputSelector(element);
        }
        return false;
    },

    inputSelector: function(element) {
        if (element.checked)
            return [element.name, element.value];
    },

    textarea: function(element) {
        return [element.name, element.value];
    },

    select: function(element) {
        return Form.Element.Serializers[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
    },

    selectOne: function(element) {
        var value = '', opt, index = element.selectedIndex;
        if (index >= 0) {
            opt = element.options[index];
            value = opt.value;
            if (!value && !('value' in opt))
                value = opt.text;
        }
        return [element.name, value];
    },

    selectMany: function(element) {
        var value = new Array();
        for (var i = 0; i < element.length; i++) {
            var opt = element.options[i];
            if (opt.selected) {
                var optValue = opt.value;
                if (!optValue && !('value' in opt))
                    optValue = opt.text;
                value.push(optValue);
            }
        }
        return [element.name, value];
    }
}

/*--------------------------------------------------------------------------*/

var $F = Form.Element.getValue;

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = function() { }
Abstract.TimedObserver.prototype = {
    initialize: function(element, frequency, callback) {
        this.frequency = frequency;
        this.element = $(element);
        this.callback = callback;

        this.lastValue = this.getValue();
        this.registerCallback();
    },

    registerCallback: function() {
        setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
    },

    onTimerEvent: function() {
        var value = this.getValue();
        if (this.lastValue != value) {
            this.callback(this.element, value);
            this.lastValue = value;
        }
    }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
    getValue: function() {
        return Form.Element.getValue(this.element);
    }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
    getValue: function() {
        return Form.serialize(this.element);
    }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = function() { }
Abstract.EventObserver.prototype = {
    initialize: function(element, callback) {
        this.element = $(element);
        this.callback = callback;

        this.lastValue = this.getValue();
        if (this.element.tagName.toLowerCase() == 'form')
            this.registerFormCallbacks();
        else
            this.registerCallback(this.element);
    },

    onElementEvent: function() {
        var value = this.getValue();
        if (this.lastValue != value) {
            this.callback(this.element, value);
            this.lastValue = value;
        }
    },

    registerFormCallbacks: function() {
        var elements = Form.getElements(this.element);
        for (var i = 0; i < elements.length; i++)
            this.registerCallback(elements[i]);
    },

    registerCallback: function(element) {
        if (element.type) {
            switch (element.type.toLowerCase()) {
                case 'checkbox':
                case 'radio':
                    Event.observe(element, 'click', this.onElementEvent.bind(this));
                    break;
                case 'password':
                case 'text':
                case 'textarea':
                case 'select-one':
                case 'select-multiple':
                    Event.observe(element, 'change', this.onElementEvent.bind(this));
                    break;
            }
        }
    }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
    getValue: function() {
        return Form.Element.getValue(this.element);
    }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
    getValue: function() {
        return Form.serialize(this.element);
    }
});
/*** Form.js end ***/
