/**
 * parent doesn't actually have to be a form
 * this will send multipart/form-data 
 */

var DaxForm = new Class({
    Implements: [Events, Options],
    options: {selectors: new Array()
             },
    fieldNames: new Hash(),

    initialize: function(parent, options){
        this.setOptions(options);
        this.form = parent;
    },

    getFields: function(){
        var selectors = "input, textarea, select";
        
        this.options.selectors.each(function(selector){
            selectors += ',' + selector;
        });
        
        return this.form.getElements(selectors);
    },

    getFieldsHash: function(){
        var fields = this.getFields();
        var fieldsHash = new Hash();

        fields.each(function(field){
            if (fieldsHash.has(field.name)){
                var existing = fieldsHash.get(field.name);
                if (!(existing instanceof Array)){
                    existing = new Array(existing);
                }
                existing.push(field);
                fieldsHash.set(field.name, existing);
            }
            else {
                fieldsHash.set(field.name, field);
            }
        });

        return fieldsHash;
    },

    setFieldNames: function(names){
        var self = this;
        $each(names, function(name, fieldName){
            self.fieldNames.set(fieldName, name);
        });
    },
    
    getFieldName: function(fieldName){
        if (this.fieldNames.has(fieldName)){
            return this.fieldNames.get(fieldName);
        }
        return fieldName;
    },

    validate: function(rules){
        var self = this;
        var fields = this.getFieldsHash();
        var errors = new Array();
        $each(rules, function(ruleArr, fieldName){
            if (fields.has(fieldName)){
                var field = fields.get(fieldName);
                ruleArr.each(function(rule){
                    switch(rule){
                    case 'notempty':
                        if (field.value == ''){
                            errors.push("Please provide a value for " + self.getFieldName(fieldName));
                        }
                        break;
                    case 'checked': // at least one checked
                        if (field instanceof Array){
                            var checked = false;
                            field.each(function(subfield){
                                if (subfield.checked) {
                                    checked = true;
                                }
                            });
                            if (!checked){
                                errors.push("Please provide a value for " + self.getFieldName(fieldName));
                            }
                        }
                        break;
                    case 'money':
                        if (field.value == '' || !field.value.match(/^[0-9]*(\.[0-9]+){0,1}$/)){
                            errors.push("Please enter a valid monetary value for " + self.getFieldName(fieldName));
                        }
                        break;
                    case 'email': 
                        if (!field.value.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i)){
                            errors.push("Please enter a valid formatted " + self.getFieldName(fieldName));
                        }
                    }
                });
            }
            else if (ruleArr.contains('strict')){
                errors.push("Please provide a value for " + self.getFieldName(fieldName));
            }

        });
        return errors;
    },

    displayErrors: function(errors){
        var text = '';
        errors.each(function(error){
            text += error + "\n";
        });
        alert(text);
    },
    
    
    fillFormReq: function(url, postString, onComplete){
        var self = this;
        var req = new Request.JSON({url: url,
                                    onComplete: function(message){
                                        if (message){
                                            if (message.status == 'success'){
                                                self.getFields().each(function(field){
                                                    var val = message.data[field.name];
						    //                                                                                                   alert(field.name + " : " + val);


                                                    // need some more complex logic for radio/check
                                                    if (field.type == 'checkbox'){
                                                        if (field.name.substring(field.name.length - 2) == '[]'){
                                                            var rootName = field.name.substring(0, field.name.length - 2);
                                                        }
                                                        else {
                                                            var rootName = field.name;
                                                            
                                                        }

                                                        val = message.data[rootName];
                                                        if (((val instanceof Array)
                                                             && val.contains(field.value))
                                                            || field.value == val){
                                                            field.checked = true;
                                                        }
                                                    }
                                                    else if (field.type == 'radio'){
                                                        if (field.value == val) {
                                                            field.checked = true;
                                                        }
                                                    }
                                                    else if (field.type == 'file'){

                                                    }
                                                    else {
                                                        // avoid add null to fields
                                                        if (!$defined(message.data[field.name])) return;

                                                        if (field.nodeName.strtolower == 'select'){
                                                            setSelectValue(field, val);
                                                        }
                                                        else {
                                                            field.value = val;
                                                        }
                                                    }
                                                });
                                                if (onComplete){
                                                    onComplete(message.data);
                                                }
                                            }
                                            else {
                                                alert(message.reason);
                                            }
                                        }
                                        else {
                                            alert("There was an error retrieving the form data.");
                                        }
                                    }
                                   });
        req.send(postString);
    },

    /**
     * force is an array of fields to force clear, usually hiddens
     */
    clearForm: function(force){
        var self = this;
        self.getFields().each(function(field){
            if ((field.type == 'button'
                 || field.type == 'hidden')
                && !((force instanceof Array)
                     && force.contains(field.name))){
                return;
            }
            else if (field.type == 'checkbox'
                     || field.type == 'radio'){
                field.checked = false;
            }
            else if (field.nodeName.toLowerCase() == 'select'){
                field.selectedIndex = 0;
            }
            else {
                field.value = '';
            }
        });
    },


    /**
     * use built in FormData object
     **/
/*    getPostData: function(boundary){
        var CRLF = "\r\n";
        var dataEls = this.getFields();

        // holds the pieces the multipart request
        var data = new Array();

        //console.log(dataEls);

        dataEls.each(function(el){
            var postData = '';
            var type = 'text';
            var val = el.value;


            if (el.nodeName.toLowerCase() == 'input'){
                if (el.name == '') {
                    return;
                }

                switch(el.type){
                    // skip buttons
                case 'button':
                    return; 
                case 'checkbox':
                case 'radio':
                    if (!el.checked) return;
                    break;
                case 'file':
                    type = 'file';
                    // if no files don't include
                    if (el.files.length == 0) {
                        return;
                    }
                }
            }

            postData += 'Content-Disposition: form-data; '
                +  'name="' + el.get('name') + '"; ';
            
            if (type == 'file'){           
                $A(el.files).each(function(file){
                    postData += 'filename="' + file.fileName + '"' + CRLF
                        + 'Content-Type: application/octet-stream'
                        + CRLF + CRLF // end of headers                                                  
                        + file.getAsBinary() 
			+ CRLF;
                });
            }
            if (el.nodeName.toLowerCase() == 'div'){ // this is for RTE
                postData +=  CRLF + CRLF
                    + el.get('html') + CRLF;
            }
            else {
                // this converts unicode to utf-8
                // otherwise non-ascii may cause an illegal character exception in FF
                var encoded = '';
                for(var i = 0; i < el.value.length; i++){
                    var code = el.value.charCodeAt(i);

                    if (code >= 0x0800){
                        encoded += String.fromCharCode(0xE0 | ((code & 0xF000) >> 12),
                                                       0x80 + ((code & 0x0FC0) >> 6),
                                                       0x80 + (code & 0x003F)
                                                      );
                    }
                    else if (code >= 0x0080){ // not verified
                        encoded += String.fromCharCode(0x60 + ((code & 0x07C0) >> 6),
                                                       0x80 + (code & 0x003F)
                                                      );
                    }
                    else {
                        encoded += el.value.substring(i, i+1);
                    }
                }

                postData += CRLF + CRLF
                    + encoded + CRLF;
                
            }

            data.push(postData);
        });

        var reqContent = "--" + boundary + CRLF
            + data.join("--" + boundary + CRLF)
            + "--" + boundary + "--" + CRLF;
        return reqContent;
        
    },
*/
    send: function(url, rules, simplePost){
        if (rules){
            var errors = this.validate(rules);
            if (errors.length > 0){
                this.displayErrors(errors);
                return false;
            }
        }

        var boundary = "FORMDATA-----------" + (new Date()).getTime();
        var contentType = "multipart/form-data; boundary=" + boundary; 
        
        var self = this;
        var req = new Request.JSON({url: url,
				    onComplete: function(message, text){
					self.fireEvent('success', [message, text]);
				    }
				   });

	if (simplePost){
            req.post(this.form);
        }
        else {
	    try {
		formData = new FormData(this.form);
	    }
            catch (err){
		//console.log(this.form);
		//console.log(err);
		alert("Your browser doesn't support FormData.  Cannot continue.");
                return false;                                     
	    }
	    

            //req.setHeader("Content-Type", contentType);                                 
            req.xhr.upload.addEventListener('progress', function(e){
                if (e.lengthComputable) {
                    var percentage = Math.round((e.loaded * 100) / e.total);  
                    self.fireEvent('progress', percentage);
                }
                
            },
                                            false);

	    req.xhr.onreadystatechange = function (aEvt) {
		if (req.xhr.readyState == 4) {
		    if (req.xhr.status == 200){
			text = req.xhr.responseText;
			message = JSON.decode(text);
			
                        self.fireEvent('success', [message, text]);
		    }
		    else {
                        alert("Failed to upload form data.");
			self.fireEvent('fail', [text]);
		    }
		}
	    };


	    req.xhr.open("POST", url);
	    req.xhr.send(formData);
//            req.send(this.getPostData(boundary));
        }
    }                    
    
});
