// PCDForm class 
PCDForm = Class.create();
PCDForm.prototype = {
    initialize: function(el, submit) {
        if (!$(el) || !$(submit)) return false;
        this.elem = $(el);
        this.fElems = new Array();
        this.fSubmit = $(submit);
        this.getFormElements();
        this.validateOnBlur = false;
        if (this.elem.hasClassName('validate')) {
            this.addValidations();
        }
    },
    getFormElements: function() {
        var i1 =  $A(this.elem.getElementsByTagName('INPUT')); 
        var i2 =  $A(this.elem.getElementsByTagName('TEXTAREA')); 
        var i = i1.concat(i2);
        var th = this;
        i.each(function(elem) {
           th.fElems.push(new PCDFormElement(th, elem));
        });
    },
    addValidations: function() {
        this.validation = Object();
        new Insertion.After(this.fSubmit, "<span class='validationText'>&nbsp;</span>");
        this.validation.msgNode = this.fSubmit.next();
        this.validation.msgNodeShown = false; 
        this.validation.errors = 0;
        Event.observe(
            this.fSubmit, "click", 
            this.validate.bindAsEventListener(this), false
        );
    },
    updateErrors: function(n) {
        // n is numerical offset: +1, -1, etc
        this.validation.errors = this.validation.errors + n; 
        if (this.validation.errors < 0) this.validation.errors = 0;
    },
    validate: function(ev) {
        if (ev.preventDefault) // spare us from error in IE6
            ev.preventDefault();
        if (!this.validation) return;
        this.validation.errors = 0;
        var th = this;
        this.fElems.each(function(fe) { 
            if(!fe.validation) return;
            fe.validation.errors = 0;
            fe.validate() 
        });
        if (this.validation.errors > 0) {
            this.showValidationResults();
        } else {
            submitForm();
        };
    },
    showValidationResults: function() {
        if (this.validation.errors == 0) {
            this.validation.msgNode.innerHTML = '';
            return true;
        }
        var s = this.validation.errors > 1 ? ' errors' : ' error';
        this.validation.msgTxt = 'Please correct ' + this.validation.errors
            + s + ' before submitting the form';
        new Balloon({
            disp: 'tr', 
            point: this.fSubmit, 
            html: this.validation.msgTxt, 
            responders: [ Form.getElements(this.elem), 'focus' ]
        });

        this.validation.msgNodeShown = true;
    }
}

// PCDFormElement class 
PCDFormElement = Class.create();
PCDFormElement.prototype = {
    initialize: function(parentForm, el) {
        this.parentForm = parentForm;
        this.elem = el;
        this.type = this.elem.type;
        this.def = this.elem.alt ? this.elem.alt : ''; // default value is ALT
                                                       // attribute
        if (this.elem.tagName == 'TEXTAREA') this.def = this.elem.innerHTML; 
                                                       // TEXTAREA does not
                                                       // have an alt
                                                       // attribute
        if (this.type == 'password') {
            if (!this.pwdCover) this.makePwdCover();
            this.elem.parentNode.appendChild(this.pwdCover);
            Event.observe(
                this.pwdCover, "click", 
                this.handleFocus.bindAsEventListener(this), false
            );
            Event.observe(
                this.pwdCover, "focus", 
                this.handleFocus.bindAsEventListener(this), false
            );
        } else {
            Event.observe(
                this.elem, "click", 
                this.handleFocus.bindAsEventListener(this), true
            );
            Event.observe(
                this.elem, "focus", 
                this.handleFocus.bindAsEventListener(this), true
            );
            Event.observe(
                this.elem, "blur", 
                this.handleBlur.bindAsEventListener(this), false
            );
        }
        if (this.elem.hasClassName('validate')) {
            this.addValidations();
        }
        this.setDefaultStyle();
    },
    handleFocus: function(e) {
        Event.stop(e);
        this.setActiveStyle();
    },
    handleBlur: function(e) {
        Event.stop(e);
        if (this.parentForm.validateOnBlur && this.validation) this.validate();
        this.setDefaultStyle();
    },
    makePwdCover: function() {
        this.pwdCover = document.createElement('input');
        this.pwdCover.type = 'text';
        this.pwdCover.value = this.def;
        this.pwdCover.style.color = '#AAA';
        Event.observe(
            this.elem, "blur", 
            this.setDefaultStyle.bindAsEventListener(this), false
        );
    },
    setActiveStyle: function() {
        if (this.type == 'password') {
            this.pwdCover.style.display = 'none';
            this.elem.style.display = '';
            this.elem.focus();
        }
        this.elem.style.color = 'black';
        if (this.elem.value == this.def) this.elem.value = '';
    },
    setDefaultStyle: function() {
        if (this.elem.value && this.elem.value != this.def) return;
        if (this.type == 'password') {
            this.elem.style.display = 'none';
            this.pwdCover.style.display = '';
            this.pwdCover.style.color = '#AAA';
        }
        this.elem.style.color = '#AAA';
        this.elem.value = this.def;
    },
    addValidations: function() {
        this.validation = Object();
        new Insertion.After(this.elem, "<span class='validationText'>&nbsp;</span>");
        this.validation.msgNode = this.elem.next();
        this.validation.errors = 0;
    },
    validate: function() {
        this.validation.msgTxt = '';
        var th = this;
        var e = Number();
        this.elem.classNames().each(function(c) {
            if (c == 'validate') return;
            PCDFormElement.validations.each(function(v) { 
                if (v.name != c) return;
                if (!(eval(v.action(th)))) {
                    th.validation.msgTxt = v.message;
                    e++;
                }
            });
        });
        if (e > 0) {
            if (this.validation.errors == 0) 
                this.parentForm.updateErrors(+1);
            this.showValidationResults({pass:false}); 
        }
        if (e == 0) {
            if (this.validation.errors > 0)
                this.parentForm.updateErrors(-1);
            this.showValidationResults({pass: true}); 
        }
        this.validation.errors = e;
        return (this.validation.errors == 0 ) ? true : false;
    },
    showValidationResults: function(h) {
        if (h.pass)
            this.elem.style.backgroundColor = '';
            this.validation.msgNode.innerHTML = '&nbsp;';
        if (!h.pass) {
            this.elem.style.backgroundColor = '#FFFFD4';
            this.validation.msgNode.innerHTML = this.validation.msgTxt;
        }
        if (this.parentForm.validation.msgNodeShown)
            this.parentForm.showValidationResults(); 
    }
}
Object.extend(PCDFormElement, {
    validations: [
        { 
            name: 'required', 
            action: function(fe) { 
                var v = fe.elem.value;
                if (v == fe.def) return false;
                return  (!(v == null) && !(v.length == 0));
            },
            message: 'This field cannot be empty'
        },
        { 
            name: 'email', 
            action: function(fe) { 
                var v = fe.elem.value;
                return /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(v);
            },
            message: 'e.g. pat@example.org'
        },
        { 
            name: 'phone', 
            action: function(fe) { 
                var v = fe.elem.value;
                return /^((\+\d{1,3}(\.|-| )?\(?\d\)?(\.|-| )?\d{1,5})|(\(?\d{2,6}\)?))(\.|-| )?(\d{3,4})(\.|-| )?(\d{4})(( x| ext)(\.| )?\d{1,5}){0,1}$/.test(v);
            },
            message: 'e.g. 123-456-7890'
        }
    ]
});

