ark.namespace('util.AsyncForm');

(function() {
    var Dom = YAHOO.util.Dom,
        Connect = YAHOO.util.Connect,
        Event = YAHOO.util.Event,
        CustomEvent = YAHOO.util.CustomEvent;
        
ark.util.AsyncForm = function(sFormIdOrName) {
    this._formName = sFormIdOrName;
    this._formId = null;
    this._bFound = false;
    this._bForcedReset = false;
    this.cfg = {
        async: true,
        disable_on_submit: true,
        error_is_invalid: true,
        reset_on_submit: true
    };


    this._verbose = false;
    this._log = function(msg) {
        if( "console" in window ) {
            if( this._verbose ) {
                console.log('[AsyncForm] '+msg);
            }
        }
    }

    this._asyncSubmit = function(obj) {
        if( !this._formId ) return;
        this._log(this._formName+' submitting asynchronously');
        var oForm = Dom.get(this._formId);
        // Is this a file uploader?
        var elements = oForm.elements;
        var n = elements.length;
        var bFile = false;
        for(var i = 0; i < n; i++ ) {
            if( elements[i].type == 'file' ) {
                bFile = true;
                break;
            }
        }
        this._log(this._formName+' file mode = '+bFile);

        var sMethod = oForm.getAttribute('METHOD');
        if( !sMethod ) {
            sMethod = 'POST';
        }

        var sURL = oForm.getAttribute('ACTION');
        if( sURL.indexOf('?') != -1 ) {
            var parts = sURL.split('?');
            sURL = parts[0];
            var parameters = parts[1];
        } else {
            var parameters = null;
        }
    
        var callback = {
            success: this._submitSuccess,
            upload: this._submitSuccess,
            failure: this._submitFailed,
            argument: this
        };

        // SUBMIT FORM ASYNCHRONOUSLY
        Connect.setForm(oForm,bFile);
        Connect.asyncRequest(sMethod,sURL,callback,parameters);
        this.submittingEvent.fire(this._formName);

        if( this.cfg['disable_on_submit'] ) {
            var n = elements.length;
            for(var i = 0; i < n; i++ ) {
                elements[i].setAttribute('disabled',true);
            }
        }
    }

    this._submitSuccess = function(oResponse) {
        var obj = oResponse.argument;
        obj._log(obj._formName+' submitSuccess');
        var oForm = Dom.get(obj._formId);
        try {
            var oR = eval("("+oResponse.responseText+")");
        } catch( e ) {
            var oR = { };
            oR._error = 'Invalid response';
        }
        if(oR._error && obj.cfg['error_is_invalid']) {
            obj.invalidEvent.fire(obj._formName,oR);
        } else {
            if( obj.cfg['reset_on_submit'] ) {
                // we shall reset the form 
                obj._bForcedReset = true;
                oForm.reset();
            }
            obj.submittedEvent.fire(obj._formName,oR);
        }

        if( obj.cfg['disable_on_submit'] ) {
            var elements = oForm.elements;
            var n = elements.length;
            for(var i = 0; i < n; i++ ) {
                elements[i].removeAttribute('disabled');
            }
        }

		// redirecting page if needed
		if(oR._redirect){ 
			oR._redirect = oR._redirect.replace(/&amp;/,"&");
			self.location = oR._redirect;	
		}
    }

    this._submitFailed = function(oResponse) {
        var obj = oResponse.argument;
        obj._log(obj._formName+' submitFailed');
        obj.failedEvent.fire(obj._formName);
        if( obj.cfg['disable_on_submit'] ) {
            var oForm = Dom.get(obj._formId);
            var elements = oForm.elements;
            var n = elements.length;
            for(var i = 0; i < n; i++ ) {
                elements[i].removeAttribute('disabled');
            }
        }
    }

    this.submit = function(e,obj) {
        obj._log('submit "event" triggered '+e+' '+obj);
        if( obj.cfg['async'] ) {
            if( e ) {
                Event.stopEvent(e);
            }
            obj._asyncSubmit(this);
        }
    }

    this.reset = function(e,obj) {
        if( !this._bForcedReset ) {
            obj._log('reset "event" triggered '+e+' '+obj);
            obj.resetEvent.fire(this._formId);
        } else {
            this._bForcedReset = false;
        }
    }
    
    this.submit_clicked = function(e,obj) {
        obj._log('submit_clicked "event" triggered '+e+' '+obj);
        if (obj && typeof obj.submit  == 'function') {
            Event.stopEvent(e);
            obj.submit(e,obj);
        }
    }
    
    this._initForm = function(obj,form) {
        obj._bFound = true;
        obj._formId = form.id;
        obj._log(obj._formName+' initializing');
        obj._log(' * id = '+obj._formId);

        // cannot only rely on this, need to do the onclick on submit button too
        Event.on(obj._formName,'submit',obj.submit,obj);
        Event.on(obj._formName,'reset',obj.reset,obj);
        // walk down the form to find submit buttons
        var elements = form.elements;
        var n = elements.length;
        for( var i = 0; i < n; i++ ) {
            if( elements[i].type == 'submit' ) {
                Event.on(elements[i],'click',obj.submit_clicked,obj);
            }
        }
    }

    this.initForm = function(obj) {
        obj._initForm(obj,this);
    }

    this._walkDomCb = function(node) {
        var aNodes = [];
        if( node.tagName == 'FORM' ) {
            aNodes[aNodes.length] = node;
        } else {
            var n = node.childNodes.length;
            for( var i = 0; i < n; i++ ) {
                var child = node.childNodes[i];
                if( child.tagName == 'FORM' ) {
                    aNodes[aNodes.length] = child;
                } else {
                    var aChildren = this._walkDomCb(child);
                    // merge
                    var m = aChildren.length;
                    for( var j = 0; j < m; j++ ) {
                        aNodes[aNodes.length] = aChildren[j];
                    }
                }
            }
        }
        return aNodes;
    }

    this._walkDom = function() {
        this._log('looking for '+this._formName);
        var aChildren = this._walkDomCb(document.body);
        this._log('found '+aChildren.length+' form(s) in document');
        for(var i = 0; i < aChildren.length; i++ ) {
            var node = aChildren[i];
            if( node.getAttribute('name') == this._formName ) {
                this._log('found '+this._formName);
                return node;
            }
        }
        return null;
    }
    
    this._checkPresence = function() {
        if( !this._bFound ) {
            var oNode = this._walkDom();
            if( oNode ) {
                // give it an ID!
                this._formId = Dom.generateId(oNode,'af_');
                this._log('generated id '+this._formId);
                this._bFound = true;
                this._initForm(this,oNode);
            }
        }
    }

    var oForm = Dom.get(this._formName);
    if( oForm ) {
        this._initForm(this,oForm);
    } else {
        Event.onAvailable(this._formName,this.initForm,this);
        Event.on(window,'load',this._checkPresence,this,true);
    }

    this.submittingEvent = new YAHOO.util.CustomEvent('submittingEvent');
    this.submittedEvent  = new YAHOO.util.CustomEvent('submittedEvent');
    this.failedEvent     = new YAHOO.util.CustomEvent('failedEvent');
    this.invalidEvent    = new YAHOO.util.CustomEvent('invalidEvent');
    this.resetEvent      = new YAHOO.util.CustomEvent('resetEvent');
}

})();

ark.util.AsyncForm.Submitting = new YAHOO.util.CustomEvent('Submitting');
ark.util.AsyncForm.Submitted = new YAHOO.util.CustomEvent('Submitted');
ark.util.AsyncForm.Failed = new YAHOO.util.CustomEvent('Failed');
ark.util.AsyncForm.Invalid = new YAHOO.util.CustomEvent('Invalid');

var aAsyncForms = { };

function ark_get_form(node) {
    if( node.tagName == 'FORM' ) {
        return node;
    } else if( !node.parentNode ) {
        return null;
    } else if( node.parentNode.tagName == 'FORM' ) {
        return node.parentNode;
    } else {
        return ark_get_form(node.parentNode);
    }
}

function ark_async_submit(obj) {
    var oForm = ark_get_form(obj);

    var sId   = oForm.getAttribute('id');
    var sName = oForm.getAttribute('name');
    if( !sId ) {
        sId = YAHOO.util.Dom.generateId(oForm,'af_');
    }
    if( !sName ) {
        oForm.setAttribute('name',sId);
    }

    if( !aAsyncForms[sId] ) {
        var oAForm = new ark.util.AsyncForm(sId);
        //oAForm._initForm(oAForm,oForm);
        oAForm.submittingEvent.subscribe(_ark_submitting);
        oAForm.submittedEvent.subscribe(_ark_submitted);
        oAForm.failedEvent.subscribe(_ark_failed);
        oAForm.invalidEvent.subscribe(_ark_invalid);
        aAsyncForms[sId] = oAForm;
    } else {
        var oAForm = aAsyncForms[sId];
    }

    ark.util.AsyncForm.Submitting.fire(sName);
    oAForm.submit(null,oAForm);
    return false;
}

function _ark_submitting(type,args) {
    ark.util.AsyncForm.Submitting.fire(args[0]);
}

function _ark_submitted(type,args) {
    ark.util.AsyncForm.Submitted.fire(args[0],args[1]);
}

function _ark_failed(type,args) {
    ark.util.AsyncForm.Submitted.fire(args[0]);
}

function _ark_invalid(type,args) {
    ark.util.AsyncForm.Invalid.fire(args[0],args[1]);
}


