// TODO PAULM: refactor to use nl.caiw.cool namespace

/*
 * This script will convert your html form elements (input, textarea, select) to Ext JS form fields.
 * Usage: 
 * 1. put class 'caiw' on your html form elements 
 * 2. include this script.
 * 3. instantiate per form you want to convert:
 * 			var form = new ExtJSForm({
 *				formElementId: 'formElementId
 *				fieldConfig: {formElement: {attribute: value}}
 *			});
 *
 * Field config is optional.   
 *
 * @author Paul Middelkoop
 */
var ExtJSForm = Class.create({
	comboBoxEmptyText: 'Kies een waarde...',

	initialize: function(config) {
		Ext.apply(this, config);
		
		this.form = new Ext.form.BasicForm(this.formElementId, {});
		this.fieldConfig = config.fieldConfig;
	
		this.addDateFields();
		this.addDateTimeFields();
		this.addTimeFields();
		this.addDoubleFields();
		this.addIntegerFields();
		this.addTextFields();
		this.addTextAreaFields();
		this.addComboBoxFields();
		this.addHiddenFields();
		this.addPasswordFields();
		
		this.form.on('actioncomplete', function(form, action) {
            this.alreadySubmitted = false;
		}.bind(this));
		
		this.form.on('actionfailed', function(form, action) {
            this.alreadySubmitted = false;
		}.bind(this));

		FormManager.register(this);	
	},	

	getForm: function() {
		return $(this.formElementId);
	},
	
	positionErrorIcons: function() {
		if (this.dirty) {
			// isValid() will call validate() of each field. validate() will reposition the error icon
			form.isValid();
		}
	},

    ajaxSubmit: function(options, force) {    
        if ((!this.alreadySubmitted || force) && this.isValid()) {
            this.alreadySubmitted = true;
            
            options['headers'] = {
				'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
			} 

        	this.form.doAction('submit', options);    
        }
    },
    
    setValidator: function(validator) {
    	this.validator = validator;
    },
    
	requireField: function(fieldName, dataFieldNames) {
		var field = form.form.findField(fieldName);
		var hasData = false;
		
		for (var i = 0; i < dataFieldNames.length; i++) {
			if ($(dataFieldNames[i]).value.length > 0) {
				hasData = true;
				break;
			}
		}
		
		field.allowBlank = !(hasData && (field.getValue().blank()));
		
		return field.isValid();				
	},    
    
    isValid: function() {
		if (typeof this.validator == "function") {
            this.validator();
        }	

		this.dirty = true;
		
		var pageIsValid = this.form.isValid();
		
		this.toggleErrorOnPage(pageIsValid);
		
		return pageIsValid;    
    },
    
    toggleErrorOnPage: function(pageIsValid) {
    	var pageHeaders = $$('h2.pageheader');
    	if (pageHeaders.length > 0) {
	    	if (pageIsValid == true) {
				pageHeaders.each(function(element) {
					element.removeClassName('error_on_page');	
				});
			} else {
				pageHeaders.each(function(element) {
					if (!element.hasClassName('error_on_page')) {
						element.addClassName('error_on_page');		
					}
				});
			}
		}
    },
    
    submit: function(action, force) {
        if ((!this.alreadySubmitted || force) && this.isValid()) {
            this.alreadySubmitted = true;
            
            if (action) {
	            this.getForm().action = "?action=" + action;
            }
            
      		this.getForm().submit();
		}    	
    },
	
	addDateFields : function() {
		var format = new String(Ext.form.DateField.prototype.format);
		Ext.apply(Ext.form.DateField.prototype, {format: format.replace(/y/, 'Y')});
		
		this.each('input[type=text].date.caiw', function (element) {
			var dateField = new Ext.form.DateField(this.getMainFieldOptions(element));
			this.addFieldToForm(dateField);
		}.bind(this));
	},	
	
	addDateTimeFields: function() {
		this.each('input[type=text].datetime.caiw', function (element) {
			element.hide();
			var options = this.getMainFieldOptions(element);
			options['otherToNow'] = false;
			options['id'] = element.id + '-datetime';
			options['name'] = element.id;
			// We don't use an error icon for the date field, since it will be rendered over the time field.
			// This can probably be fixed by manually render the icon in the onValid() and onInvalid()  
			options['dateConfig'] = {allowBlank: !element.hasClassName('required'), cls: 'caiw'};
			
			var timeOptions = this.getFieldOptions(element);
			timeOptions['cls'] = 'caiw';
			options['timeConfig'] = timeOptions;
			
			var dateTimeField = new Ext.ux.form.DateTime(options);
			this.addFieldToForm(dateTimeField);
		}.bind(this));

		this.each('.ux-datetime-date', function(element) {
			this.setStyle(element);
		}.bind(this));

		this.each('.ux-datetime-time', function(element) {
			this.setStyle(element);
		}.bind(this));
	},
	
	addTimeFields : function() {
		
		this.each('input[type=text].time.caiw', function (element) {
			var options = this.getMainFieldOptions(element);		
			options['format'] = 'H:i';
			var timeField = new Ext.form.TimeField(options);
			this.addFieldToForm(timeField);
		}.bind(this));
	},	
	
	addDoubleFields: function() {
		// TODO PAULM: implement maxValue / decimalPrecision / decimalPrecision 
		this.each('input[type=text].double.caiw', function (element) {
			var options = this.getMainFieldOptions(element);
			options['allowDecimals'] = true;
			options['maxValue'] = 99999999.99;
			options['decimalPrecision'] = 2;
			options['decimalSeparator'] = '.';
			
			var numberField = new Ext.form.NumberField(options);
			this.addFieldToForm(numberField);
		}.bind(this));
	},
	
	addIntegerFields: function() {
		this.each('input[type=text].integer.caiw', function (element) {
			var options = this.getMainFieldOptions(element);
			options['allowDecimals'] = false;
			options['maxValue'] = 99999999.99;
			
			var numberField = new Ext.form.NumberField(options);
			this.addFieldToForm(numberField);
		}.bind(this));
	},
	
	addTextFields: function() {
		this.each('input[type=text].string.caiw', function(element) {
			var textField = new Ext.form.TextField(this.getMainFieldOptions(element));
			this.addFieldToForm(textField);
		}.bind(this));
	},
	
	addPasswordFields: function() {
		this.each('input[type=password].caiw', function(element) {
			var options = this.getMainFieldOptions(element);
			options['inputType'] = 'password';

			if (element.id == 'checkpassword') {
				options['vtype'] = 'password';
				options['initialPassField'] = 'password';
			}			
			var passwordField = new Ext.form.TextField(options);
			this.addFieldToForm(passwordField);
		}.bind(this));
	},

	addTextAreaFields: function() {
		this.each('textarea.caiw', function (element) {
			var textArea = new Ext.form.TextArea(this.getMainFieldOptions(element));
			this.addFieldToForm(textArea);
		}.bind(this));
	},
	
	addComboBoxFields: function() {
		this.each('select.caiw', function (element) { 
			var options = this.getMainFieldOptions(element);
			options['triggerAction'] = 'all';
			options['typeAhead'] = true;
			options['applyTo'] = null;
			options['transform'] = element.id;
			options['forceSelection'] = true;
			options['emptyText'] = this.comboBoxEmptyText;
			
			var defaultAutoCreate = {tag: 'input', type: 'text', autocomplete: 'off'};
			defaultAutoCreate['class'] =  element.className;
			options['defaultAutoCreate'] = defaultAutoCreate;
			options['hiddenId'] = element.id;
			options['disabled'] = element.disabled;
					
			var comboBoxId = element.id;
			if (element.hasClassName("remote")) {
				options['valueField'] = 'id';
				options['displayField'] = 'text';
				options['queryParam'] = 'search';
				options['minChars'] = '0';
				options['lazyInit'] = false;
				
				var store = new Ext.data.JsonStore({
				    url: eval(element.name + "ControllerUrl"),
				    baseParams: {action: eval(element.name + "ControllerAction"), maxResults: eval(element.name + "MaxResults"), 
						filterValue: eval(element.name + "FilterValue")},
				    root: 'entities',
				    fields: ['id', 'text'],			    
					id: 'id'
				});
				
				options['store'] = store;
			}
			
            var empty = element.hasClassName('empty');            
					
			var comboBoxField = new Ext.form.ComboBox(options);
			this.addFieldToForm(comboBoxField);
			var	maxWidth = null;
			
			try {
				maxWidth = eval(comboBoxId.replace(/\./g,'_') + "ComboBoxMaxWidth");
			} catch(e) {
				// the variable doe not exist, this will happen when the select tag 
				// we are extjs-ing was not created useing the form:select tag.
			}
			
			comboBoxField.setWidth(this.calculateComboboxWidth(comboBoxField, maxWidth));
			comboBoxField.syncSize();

			if (empty) {			    
				comboBoxField.clearValue();
				comboBoxField.originalValue = '';
			}
		
			if (element.hasClassName('remote')) {
				var width = eval(comboBoxId.replace('.','_') + "ComboBoxWidth");
				if (maxWidth != null) {
					width = Math.min(width, maxWidth);
				}
				comboBoxField.setWidth(width);
				comboBoxField.syncSize();
		
				if (typeof(eval(comboBoxId + "DefaultId")) != 'undefined' && eval(comboBoxId + "DefaultId") != -1) {
					comboBoxField.setValue(eval(comboBoxId + "DefaultId"));
				}
				if (typeof(eval(comboBoxId + "DefaultValue")) != 'undefined' && eval(comboBoxId + "DefaultValue") != -1) {
					Ext.form.ComboBox.superclass.setValue.call(comboBoxField, eval(comboBoxId + "DefaultValue"));
				}
			}
	
			
		}.bind(this));
	},
	
	calculateComboboxWidth: function(comboBoxField, maxWidth) {
		var textMetrics = Ext.util.TextMetrics.createInstance(comboBoxField.getEl());
		var size = textMetrics.getWidth(this.comboBoxEmptyText);
		
		comboBoxField.store.each(function(record) {
			size = Math.max(size, textMetrics.getWidth(record.get('text')));
		});
		
		size = size + 60;
		if (maxWidth != null) {
			return Math.min(maxWidth, size);
		} else {
			return size;
		}
		
	},

	addHiddenFields: function() {
		this.each('input[type=hidden].caiw', function (element) {
			var hiddenField = new Ext.form.Hidden(this.getMainFieldOptions(element));
			this.addFieldToForm(hiddenField);
		}.bind(this));
	},

	addFieldToForm: function(field) {
		this.addQtipToField(field);
		this.form.add(field);
	},
	
	addQtipToField: function(field) {
		if (field.msgTarget == 'side') {	
			field.on('invalid', function(field, msg) {
		       	field.el.dom.qtip = msg;
				field.el.dom.qclass = 'x-form-invalid-tip';
			});
			field.on('valid', function(field, msg) {
		       	field.el.dom.qtip = '';
				field.el.dom.qclass = '';
			}.bind(this));
		}
	},

	each: function(selector, fieldFunction) {	
		$$(selector).each(function (element) {
			var elements = this.getForm().getElements();
			for (var i = 0; i < elements.length; i++) {
				if (elements[i].name == element.name) {
					fieldFunction(element);
				}
			}
		}.bind(this));
	},
	
	getMainFieldOptions: function(element) {
		var options = this.getFieldOptions(element);
		options['applyTo'] = element.id;
		options['allowBlank'] = !element.hasClassName('required');
		options['id'] = element.id;
		
		if (this.fieldConfig && this.fieldConfig[element.id]) {
			options = Ext.apply(options, this.fieldConfig[element.id]);
		}
		
		if (!options['msgTarget']) {
			options['msgTarget'] = 'side';
		}
		
		if (options['msgTarget'] == 'side') {
			$($(element.id).parentNode).addClassName('x-form-element');
		}
		
		return options;
	},
	
	getFieldOptions: function(element) {
		var options = {
			allowBlank: !element.hasClassName('required'),
			msgTarget: element.hasClassName('errorIconAsQtip') ? 'qtip' : 'side' 
		}
		return options;
	},

	setStyle: function(element) {
		element.addClassName('caiw');
		element.setStyle({'paddingLeft': '0px'});
	},
	
	findField: function(element) {
		return this.form.findField(element);
	}
});

var FormManager = function(){
    var forms = new Ext.util.MixedCollection();

    return {
        register : function(extJsForm){
            forms.add(extJsForm.formElementId, extJsForm);
        },
        
        get : function(formElementId){
            return forms.get(formElementId);
        }
    };
}();

Ext.apply(Ext.form.VTypes, {
    password : function(val, field) {
	
        if (field.initialPassField) {
            var pwd = Ext.getCmp(field.initialPassField);
            return (val == pwd.getValue());
        }
        return true;
    },

    passwordText : 'Wachtwoorden komen niet overeen' 
});

Ext.override(Ext.layout.FormLayout, {
	renderItem : function(c, position, target){
		if(c && !c.rendered && c.isFormField && c.inputType != 'hidden'){
			var args = [
				   c.id, c.fieldLabel,
				   c.labelStyle||this.labelStyle||'',
				   this.elementStyle||'',
				   typeof c.labelSeparator == 'undefined' ? this.labelSeparator : c.labelSeparator,
				   (c.itemCls||this.container.itemCls||'') + (c.hideLabel ? ' x-hide-label' : ''),
				   c.clearCls || 'x-form-clear-left' 
			];
			if(typeof position == 'number'){
				position = target.dom.childNodes[position] || null;
			}
			if(position){
				c.formItem = this.fieldTpl.insertBefore(position, args, true);
			}else{
				c.formItem = this.fieldTpl.append(target, args, true);
			}
			c.actionMode = 'formItem';
			c.render('x-form-el-'+c.id);
			c.container = c.formItem;
			c.actionMode = 'container';
		}else {
			Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments);
		}
	}
});
Ext.override(Ext.form.TriggerField, {
	actionMode: 'wrap',
	onShow: Ext.form.TriggerField.superclass.onShow,
	onHide: Ext.form.TriggerField.superclass.onHide
});	


