/*
* XForms2 client-side
---------------------
* @version: 2.0B
* @build: 44, 2007-02-22 20:27:33
* @author: Filatov Dmitry <alpha@design.ru>
*/

function Value(mValue) {
	
	this.mValue = null;

	this.reset();
	
	if(mValue) {
		this.set(mValue);
	}

}

Value.prototype = {

	reset : function() {
	
		this.set('');
	
	},

	get : function() {
	
		return this.mValue;
	
	},

	set : function(mValue) {
	
		this.mValue = mValue;
	
	},
	
	match : function(sPattern) {
	
		return this.get().match(sPattern)? true : false;
	
	},
	
	clone : function() {
	
		var oClonedValue = new Value();
		
		oClonedValue.set(this.get());
		
		return oClonedValue;
	
	},
	
	isEqual : function(oValue) {
	
		return oValue instanceof Value &&
			this.mValue == oValue.mValue;
	
	},
	
	isEmpty : function(oValue) {
	
		return this.mValue == '';
	
	},
	
	toString : function() {
		
		return this.get();
		
	}
	
};

function ValueMultiple(mValue) {

	ValueMultiple.baseConstructor.call(this, mValue);

};

ValueMultiple.inheritFrom(Value);

ValueMultiple.prototype.reset = function() {

	this.set([]);

};

ValueMultiple.prototype.match = function(sPattern) {	

	for(var i = 0; i < this.mValue.length; i++) {
		if(this.mValue[i].match(sPattern)) {
			return true;
		}
	}
	
	return false;
	
};

ValueMultiple.prototype.clone = function() {
	
	var oClonedValue = new ValueMultiple();
		
	oClonedValue.set(this.get());
		
	return oClonedValue;
	
};
	
ValueMultiple.prototype.isEqual = function(oValue) {
	
	if(!(oValue instanceof ValueMultiple) ||
		this.mValue.length != oValue.mValue.length
		) {
		return false;
	}
	
	for(var i = 0; i < this.mValue.length; i++) {
		if(this.mValue[i] != oValue.mValue[i]) {
			return false;
		}
	}
	
	return true;
	
};
	
ValueMultiple.prototype.isEmpty = function(oValue) {
	
	return this.mValue.length == 0;
	
};

ValueMultiple.prototype.add = function(mAddValue) {

	this.mValue.push(mAddValue);

};

function ValueDate(mValue) {
		
	ValueDate.baseConstructor.call(this, mValue);		

};

ValueDate.inheritFrom(Value);

ValueDate.prototype.reset = function() {

	this.mValue = [];
	this.mValue['year'] = '';
	this.mValue['month'] = 1;
	this.mValue['day'] = '';
	
};

ValueDate.prototype.get = function() {

	if(this.mValue['year'] == '' || this.mValue['day'] == '') {
		return '';		
	}
	
	return this.getYear() + '-' + this.getMonth() + '-' + this.getDay();
	
};

ValueDate.prototype.set = function(mValue) {
	
	var aMatched = mValue.match(/^(-?\d{0,4})-(\d{0,2})-(-?\d{0,2})/);
	
	if(aMatched) {
		
		var oDate = new Date(
			parseInt(aMatched[1]),
			parseInt(aMatched[2]) - 1,
			parseInt(aMatched[3])
			);	
		
		this.mValue['year'] = oDate.getFullYear();
		this.mValue['month'] = oDate.getMonth() + 1;
		this.mValue['day'] = oDate.getDate();		
		
	}			
	
};

ValueDate.prototype.clone = function() {
	
	var oClonedValue = new ValueDate();
		
	oClonedValue.set(this.get());
		
	return oClonedValue;
	
};
	
ValueDate.prototype.isEqual = function(oValue) {
	
	if(!(oValue instanceof ValueDate) ||
		this.get() != oValue.get()
		) {
		return false;
	}		
	
	return true;
	
};
	
ValueDate.prototype.isEmpty = function(oValue) {
	
	return false;
	
};

ValueDate.prototype.getYear = function() {
	
	return this.mValue['year'];
	
};

ValueDate.prototype.getMonth = function() {
	
	return this.mValue['month'];
	
};

ValueDate.prototype.getDay = function() {
	
	return this.mValue['day'];
	
};

/*
FormWidget
@author Filatov Dmitry
@date   28.12.2006
*/

function FormWidget(
	oElement,
	oClassElement,
	bTemplate
	) {
			
	this.oElement = oElement;
	this.oClassElement = oClassElement || oElement;
			
	this.sId = Common.Dom.getAttribute(oElement, 'id');
	this.oDependenceProcessor = new DependenceProcessor(this);	
	this.aObservers = [];	
	this.oParent = null;
	this.oForm = null;
	this.bEnabled = true;
	this.bRequired = false;
	this.bValid = true;
	this.oValue = this.createValue();
	this.oLastProcessedValue = null;	
	this.oMultiplier = null;
	this.bTemplate = bTemplate || false;
	
	this.setValueFromElement();
	this.addHandlers();
	
}

FormWidget.ROLE_ELEMENT       = 'element';
FormWidget.ROLE_CLASS_ELEMENT = 'class-element';

FormWidget.CLASS_NAME_REQUIRED     = 'required';
FormWidget.CLASS_NAME_REQUIRED_OK  = 'required-ok';
FormWidget.CLASS_NAME_INVALID      = 'invalid';
FormWidget.CLASS_NAME_DISABLED     = 'disabled';
FormWidget.CLASS_NAME_INVISIBLE    = 'invisible';
FormWidget.CLASS_NAME_SELECTED     = 'selected';
FormWidget.CLASS_NAME_HIDDEN       = 'hidden';
FormWidget.CLASS_NAME_SUBMITTED    = 'submitted';

FormWidget.prototype = {

	createValue : function() {
	
		return new Value();
	
	},

	addHandlers : function() {
		
		if(this.isTemplate()) {
			return;
		}
	
		var
			oThis = this,
			aEvents = []
			;

		function process(oEvent) {					
		
			var oEvent = Common.Event.normalize(oEvent);
			
			oEvent.cancelBubble = true;
	
			oThis.processEvents(true);
	
		}
		
		aEvents = this.getEventList();
		
		for(var i = 0; i < aEvents.length; i++) {		
			Common.Event.add(
				this.oElement,
				aEvents[i],
				process
				);		
		}
	
	},
	
	getEventList : function() {
	
		return [];
	
	},
	
	processEvents : function(
		bUpdateSubmit,
		bStateChanged,
		bByParent
		) {
		
		this.setValueFromElement();

		if(!(bStateChanged || this.isChanged())) {
			return;
		}
		else {
			this.updateLastProcessedValue();			
		}
		
		this.notifyObservers();			
			
		if(bUpdateSubmit && this.oForm) {
			this.oForm.updateSubmit();
		}
		
		if(!bByParent && this.oParent) {				
			this.oParent.processEvents(bUpdateSubmit);
		}
	
	},
	
	isChanged : function() {
	
		return !this.oValue.isEqual(this.oLastProcessedValue);
	
	},
	
	updateLastProcessedValue : function() {
		
		this.oLastProcessedValue = this.oValue.clone();
	
	},
	
	init : function() {
		
		if(this.isTemplate()) {
			return;
		}
			
		this.processEvents(false);		
	
	},

	getValue : function() {
	
		return this.oValue;
	
	},	

	setValue : function(oValue) {
		
		this.oValue = oValue;
		
		this.processEvents(true);
		
	},
	
	getId : function() {
	
		return this.sId;
	
	},
	
	setId : function(sId) {
		
		this.sId = sId;
		
	},
	
	isTemplate : function() {
		
		return this.bTemplate;
		
	},
	
	addClass : function(sClassName) {
		
		Common.Class.add(this.oClassElement, sClassName);
		
	},
	
	removeClass : function(sClassName) {
		
		Common.Class.remove(this.oClassElement, sClassName);
		
	},
	
	disable : function(bByParent) {			
	
		if(!this.isEnabled()) {
			return false;
		}
		
		this.bEnabled = false;	
		this.oElement.disabled = true;
		
		this.addClass(FormWidget.CLASS_NAME_DISABLED);
		
		if(bByParent) {
			this.processEvents(true, true, true);
		}	
		
		if(this.oMultiplier) {
			this.oMultiplier.disableByOuter();
		}
	
	},
	
	enable : function(bByParent) {

		if(this.oParent && !this.oParent.isEnabled()) {
			return false;
		}
		
		this.bEnabled = true;
		this.oElement.disabled = false;
		
		this.removeClass(FormWidget.CLASS_NAME_DISABLED);
		
		if(bByParent) {
			this.processEvents(true, true, true);
		}	

		if(this.oMultiplier) {
			this.oMultiplier.enableByOuter();
		}
		
		return true;
		
	},
	
	isEnabled : function() {			
	
		return this.bEnabled;
	
	},		
	
	setRequired : function() {							
	
		this.bRequired = true;
	
		Common.Class.replace(this.oClassElement, FormWidget.CLASS_NAME_REQUIRED_OK, FormWidget.CLASS_NAME_REQUIRED);

	},
	
	unsetRequired : function() {				
		
		this.bRequired = false;
		
		Common.Class.replace(this.oClassElement, FormWidget.CLASS_NAME_REQUIRED, FormWidget.CLASS_NAME_REQUIRED_OK);
	
	},
	
	isRequired : function() {		
		
		return this.bRequired;
	
	},
	
	setValid : function() {
	
		this.bValid = true;
		
		this.removeClass(FormWidget.CLASS_NAME_INVALID);
	
	},
	
	setInvalid : function() {
	
		this.bValid = false;
		
		this.addClass(FormWidget.CLASS_NAME_INVALID);
	
	},
	
	isValid : function() {
	
		return this.bValid;
	
	},
	
	setParent : function(oParent) {
	
		this.oParent = oParent;		
	
	},
	
	setForm : function(oForm) {		
		
		this.oForm = oForm;		
		
		oForm.addWidget(this);
	
	},
	
	hide : function() {
		
		this.addClass(FormWidget.CLASS_NAME_INVISIBLE);		
		
	},
	
	show : function() {
		
		this.removeClass(FormWidget.CLASS_NAME_INVISIBLE);
		
	},
	
	focus : function() {
	
		var oAncestor = this.oParent;
	
		do {
			
			if(oAncestor instanceof Sheet) {
				oAncestor.setAsCurrent();
			}
			
			oAncestor = oAncestor.oParent;
			
		}	
		while(oAncestor);		
		
		this.oElement.focus();
	
	},
		
	attachObserver : function(oObserver) {
	
		this.aObservers.push(oObserver);
	
	},
	
	detachObserver : function(oObserver) {
	
		this.aObservers.remove(oObserver);
	
	},
	
	detachObservers : function() {
		
		var
			aDependencies,
			oObserver
			;
		
		for(var i = 0; i < this.aObservers.length;) {
			
			if(this.aObservers[i] == this) {
				
				i++;
				continue;
				
			}
			
			oObserver = this.aObservers[i];
			
			aDependencies = this.aObservers[i].getDependencies();
			
			for(var j = 0; j < aDependencies.length; j++) {
				if(aDependencies[j].getFrom() == this) {					
					this.aObservers[i].removeDependence(aDependencies[j]);
				}
			}
			
			this.detachObserver(oObserver);
			
			oObserver.updateByObservable();
			
		}
		
	},
	
	notifyObservers : function() {
	
		for(var i = 0; i < this.aObservers.length; i++) {			
			this.aObservers[i].updateByObservable();
		}
		
	},
	
	updateByObservable : function(bByParent) {		
		
		this.oDependenceProcessor.process();
		
		if(!bByParent && this.oParent) {
			this.oParent.oDependenceProcessor.process();
		}
	
	},
	
	addDependence : function(oDependence) {		
		
		oDependence.getFrom().attachObserver(this);
		
		this.oDependenceProcessor.addDependence(oDependence);
	
	},
	
	removeDependence : function(oDependence) {			
		
		this.oDependenceProcessor.removeDependence(oDependence);
		
	},
	
	getDependencies : function() {
		
		return this.oDependenceProcessor.getDependencies();
		
	},
	
	getMultiplier : function() {
		
		return this.oMultiplier;
		
	},
	
	setMultiplier : function(oMultiplier) {
		
		this.oMultiplier = oMultiplier;
		
	},
	
	updateElements : function(iIndex) {
		
		this.oElement = document.getElementById(iIndex > 0?
			this.oElement.id.match(Multiplicator.REG_EXP_REPLACE)[1] + '_' + iIndex :
			this.oElement.id
			);
		
		this.oClassElement = document.getElementById(iIndex > 0?
			this.oClassElement.id.match(Multiplicator.REG_EXP_REPLACE)[1] + '_' + iIndex :
			this.oClassElement.id
			);
			
		this.updateId(this.oElement.id);
		
	},		
	
	updateId : function(sId) {
		
		this.oForm.removeWidget(this);
		
		this.setId(sId);
		
		this.oForm.addWidget(this);						
		
	},

	addChild : function(oChild) {
	
		return oChild;
	
	},	
	
	removeChild : function(oChild) {},
	
	removeChildren : function(oChild) {},
	
	setValueFromElement : function() {},		
	
	enableChildrenByValue : function(aPatterns) {},
	
	clone : function(oElement, oClassElement) {}

};

function FieldContainer(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	this.aChildren = [];
	
	FieldContainer.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);			
	
}

FieldContainer.inheritFrom(FormWidget);

FieldContainer.prototype.addChild = function(
	oChild,
	iIndex
	) {		
		
	if(iIndex > -1 && iIndex < this.aChildren.length) {		
		this.aChildren.splice(iIndex, 0, oChild);		
	}
	else {
		this.aChildren.push(oChild);
	}
		
	oChild.setParent(this);		
	
	if(this.oForm) {
		oChild.setForm(this.oForm);
	}
	
	return oChild;
	
};

FieldContainer.prototype.removeChild = function(oChild) {
	
	oChild.detachObservers();	
	oChild.removeChildren();
	
	this.aChildren.remove(oChild);
	
	if(this.oForm) {
		this.oForm.removeWidget(oChild);
	}
	
	oChild = null;
	
};

FieldContainer.prototype.removeChildren = function() {
	
	for(var i = 0; i < this.aChildren.length;) {
		this.removeChild(this.aChildren[i]);
	}
	
};

FieldContainer.prototype.setForm = function(oForm) {

	FieldContainer.superClass.setForm.call(this, oForm);

	for(var i = 0; i < this.aChildren.length; i++) {
		this.aChildren[i].setForm(oForm);
	}
	
};

FieldContainer.prototype.disable = function(bByParent) {

	FieldContainer.superClass.disable.call(this, bByParent);
	
	for(var i = 0; i < this.aChildren.length; i++) {
		this.aChildren[i].disable(true);
	}		

};

FieldContainer.prototype.enable = function(bByParent) {

	FieldContainer.superClass.enable.call(this, bByParent);
	
	for(var i = 0; i < this.aChildren.length; i++) {
	
		this.aChildren[i].enable(true);
		this.aChildren[i].updateByObservable(true);
		
	}
		
};

FieldContainer.prototype.isValid = function() {

	for(var i = 0; i < this.aChildren.length; i++) {
		if(!this.aChildren[i].isValid() && this.aChildren[i].isEnabled()) {
			return false;
		}
	}
	
	return true;
	
};
	
FieldContainer.prototype.isRequired = function() {

	if(FieldContainer.superClass.isRequired.call(this)) {
		return true;
	}
	
	for(var i = 0; i < this.aChildren.length; i++) {
		if(this.aChildren[i].isRequired() && this.aChildren[i].isEnabled()) {
			return true;
		}
	}
	
	return false;
	
};

FieldContainer.prototype.init = function() {

	FieldContainer.superClass.init.call(this);
	
	for(var i = 0; i < this.aChildren.length; i++) {
		this.aChildren[i].init();
	}
	
};

FieldContainer.prototype.isChanged = function() {

	return true;

};

FieldContainer.prototype.focus = function() {
		
	if(this.aChildren.length > 0) {
		this.aChildren[0].focus();
	}
	
};

FieldContainer.prototype.getCountChildrenByPattern = function(sPattern) {

	var iResult = 0;

	for(var i = 0; i < this.aChildren.length; i++) {
	
		if(!this.aChildren[i].isEnabled()) {
			continue;
		}
	
		if(this.aChildren[i] instanceof FieldContainer) {
			if(this.aChildren[i].getCountChildrenByPattern(sPattern) > 0) {
				iResult++;
			}
		}
		else if(this.aChildren[i].getValue().match(sPattern)) {
			iResult++;
		}
		
	}
	
	return iResult;

};

FieldContainer.prototype.updateElements = function(iIndex) {
	
	FieldContainer.superClass.updateElements.call(this, iIndex);
	
	for(var i = 0; i < this.aChildren.length; i++) {		
		this.aChildren[i].updateElements(iIndex);
	}
	
};

FieldContainer.prototype.clone = function(
	oElement,
	oClassElement,
	iIndex
	) {

	var oClone = new FieldContainer(
		oElement,
		oClassElement
		);
		
	this.cloneChildren(oClone, iIndex);
		
	return oClone;

};

FieldContainer.prototype.cloneChildren = function(oParent, iIndex) {
	
	for(var i = 0; i < this.aChildren.length; i++) {		
		oParent.addChild(
			this.aChildren[i].clone(
				document.getElementById(this.aChildren[i].oElement.id.match(Multiplicator.REG_EXP_REPLACE)[1] + '_' + iIndex),
				document.getElementById(this.aChildren[i].oClassElement.id.match(Multiplicator.REG_EXP_REPLACE)[1] + '_' + iIndex),
				iIndex
				)
			);
	}
	
};

function Sheet(
	oElement,
	oClassElement,
	bTemplate,	
	bSelected
	) {
	
	SheetContainer.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
	this.oLegendButton = null;
	this.oPrevButton = null;
	this.oNextButton = null;
	this.bSelected = bSelected;			
	
}

Sheet.inheritFrom(FieldContainer);

Sheet.prototype.addLegendButton = function(oButton) {
	
	this.oLegendButton = oButton;
	
	this.addChild(oButton);
	
	var oThis = this;
	
	oButton.setHandler(
		function() {
	
			oThis.oParent.select(oThis);
			
			return false;
	
		}
	);
	
};

Sheet.prototype.addPrevButton = function(oButton) {
	
	this.oPrevButton = oButton;
	
	this.addChild(oButton);
	
	var oThis = this;
	
	oButton.setHandler(
		function() {
	
			oThis.oParent.prev(oThis);
			
			return false;
	
		}
	);
	
};

Sheet.prototype.addNextButton = function(oButton) {
	
	this.oNextButton = oButton;
	
	this.addChild(oButton);
	
	var oThis = this;
	
	oButton.setHandler(
		function() {
	
			oThis.oParent.next(oThis);
			
			return false;
	
		}
	);
	
};

Sheet.prototype.setParent = function(oParent) {
	
	Sheet.superClass.setParent.call(this, oParent);
	
	if(this.isSelected()) {
		this.oParent.select(this);		
	}
	
};

Sheet.prototype.isSelected = function() {

	return this.bSelected;

};

Sheet.prototype.select = function() {

	this.bSelected = true;
	
	this.addClass(FormWidget.CLASS_NAME_SELECTED);
	
	if(this.oLegendButton) {		
		this.oLegendButton.addClass(FormWidget.CLASS_NAME_SELECTED);
	}

};

Sheet.prototype.unselect = function() {

	this.bSelected = false;
	
	this.removeClass(FormWidget.CLASS_NAME_SELECTED);	
	
	if(this.oLegendButton) {
		this.oLegendButton.removeClass(FormWidget.CLASS_NAME_SELECTED);
	}

};

function SheetContainer(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	SheetContainer.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
		
	this.iCurrentSheetIndex = 0;		
	
}

SheetContainer.inheritFrom(FieldContainer);

SheetContainer.POSTFIX_ID = '_sheet_container';

SheetContainer.prototype.getId = function() {

	return this.sId + SheetContainer.POSTFIX_ID;

};

SheetContainer.prototype.findSheetIndex = function(oSheet) {

	for(var i = 0; i < this.aChildren.length; i++) {
		if(this.aChildren[i] == oSheet) {
			return i;
		}
	}

};

SheetContainer.prototype.select = function(oSheet) {
	
	this.selectByIndex(this.findSheetIndex(oSheet));

};

SheetContainer.prototype.prev = function(oSheet) {

	this.selectByIndex(this.findSheetIndex(oSheet) - 1);

};

SheetContainer.prototype.next = function(oSheet) {

	this.selectByIndex(this.findSheetIndex(oSheet) + 1);

};

SheetContainer.prototype.selectByIndex = function(iIndex) {
	
	if(!this.aChildren[iIndex]) {
		return;
	}
	
	this.aChildren[this.iCurrentSheetIndex].unselect();
	this.aChildren[iIndex].select();
	
	this.iCurrentSheetIndex = iIndex;
		
};



function InputGroup(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	InputGroup.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
}

InputGroup.inheritFrom(FieldContainer);

function CheckBoxGroup(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	CheckBoxGroup.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);			
	
}

CheckBoxGroup.inheritFrom(InputGroup);

CheckBoxGroup.prototype.createValue = function() {

	return new ValueMultiple();

};

CheckBoxGroup.prototype.setValueFromElement = function() {

	this.oValue.reset();
	
	for(var i = 0; i < this.aChildren.length; i++) {		
		if(this.aChildren[i].isChecked() && this.aChildren[i].isEnabled()) {
			this.oValue.add(this.aChildren[i].getValue());
		}
	}

};

CheckBoxGroup.prototype.addChild = function(oChild) {

	if(!(oChild instanceof CheckBox)) {
		return;		
	}
	
	CheckBoxGroup.superClass.addChild.call(this, oChild);
	
	if(oChild.isChecked()) {
		this.oValue.add(oChild.getValue());
	}
	
	return oChild;
	
};

CheckBoxGroup.prototype.enableChildrenByValue = function(aPatterns) {

	var
		bMatched = false,		
		oChild		
		;
	
	for(var i = 0; i < this.aChildren.length; i++) {
	
		oChild = this.aChildren[i];
	
		bMatched = false;
	
		for(var j = 0; j < aPatterns.length && !bMatched; j++) {
			
			bMatched = oChild.getValue().match(aPatterns[j])? true : false;
			
			if(bMatched) {
				oChild.enable();				
			}
			
		}
		
		if(!bMatched) {		
			oChild.disable();												
		}				
					
	}
	
	this.processEvents(true);

};

CheckBoxGroup.prototype.clone = function(
	oElement,
	oClassElement,
	iIndex
	) {
	
	var oClone = new CheckBoxGroup(
		oElement,
		oClassElement,
		false
		);
		
	this.cloneChildren(oClone, iIndex);
		
	return oClone;
	
};

function RadioButtonGroup(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	RadioButtonGroup.baseConstructor.call(
		this,
		oElement,
		oClassElement, 
		bTemplate		
		);
	
}

RadioButtonGroup.inheritFrom(InputGroup);

RadioButtonGroup.prototype.setValueFromElement = function() {

	this.oValue.reset();
	
	for(var i = 0; i < this.aChildren.length; i++) {		
		if(this.aChildren[i].isChecked() && this.aChildren[i].isEnabled()) {		
		
			this.oValue.set(this.aChildren[i].getValue());
			return;
			
		}
	}

};

RadioButtonGroup.prototype.addChild = function(oChild) {

	if(!(oChild instanceof RadioButton)) {
		return;		
	}
	
	RadioButtonGroup.superClass.addChild.call(this, oChild);
	
	if(oChild.isChecked()) {
		this.oValue.set(oChild.getValue());
	}
	
	return oChild;
	
};

RadioButtonGroup.prototype.enableChildrenByValue = function(aPatterns) {

	var
		bMatched = false,		
		oChild,
		bRecheckChildren = false,
		iFirstEnabledChildIndex = -1
		;
	
	for(var i = 0; i < this.aChildren.length; i++) {
	
		oChild = this.aChildren[i];
	
		bMatched = false;
	
		for(var j = 0; j < aPatterns.length && !bMatched; j++) {
			
			bMatched = oChild.getValue().match(aPatterns[j])? true : false;
			
			if(bMatched) {
					
				if(iFirstEnabledChildIndex < 0) {
					iFirstEnabledChildIndex = i;
				}
							
				if(this.isEnabled()) {
					oChild.enable();
				}
				
			}
			
			if(!bMatched && oChild.isChecked()) {
				bRecheckChildren = true;
			}
			
		}
		
		if(!bMatched) {		
			oChild.disable();												
		}				
					
	}		
	
	if(bRecheckChildren && iFirstEnabledChildIndex > -1) {
		
		this.oValue.set(this.aChildren[iFirstEnabledChildIndex].getValue());
		
		this.aChildren[iFirstEnabledChildIndex].check();			
			
	}
	
	this.processEvents(true);

};

RadioButtonGroup.prototype.clone = function(
	oElement,
	oClassElement,
	iIndex
	) {
	
	var oClone = new RadioButtonGroup(
		oElement,
		oClassElement,
		false
		);
		
	this.cloneChildren(oClone, iIndex);
		
	return oClone;
	
};

function TextInput(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	TextInput.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
}

TextInput.inheritFrom(FormWidget);

TextInput.prototype.setValue = function(oValue) {
		
	this.oElement.value = oValue.get();
	
	TextInput.superClass.setValue.call(this, oValue);
		
};

TextInput.prototype.getEventList = function() {
	
	return ['keyup', 'blur'];
	
};

TextInput.prototype.setValueFromElement = function() {

	this.oValue.set(this.oElement.value);

};

TextInput.prototype.clone = function(
	oElement,
	oClassElement
	) {

	return new TextInput(
		oElement,
		oClassElement
		);

};

function NumberInput(
	oElement,
	oClassElement,
	bTemplate
	) {		

	NumberInput.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
		
	this.addPreProcessHandlers();

}

NumberInput.inheritFrom(TextInput);

NumberInput.prototype.addPreProcessHandlers = function() {

	if(this.isTemplate()) {
		return;
	}
	
	function preProcess(oEvent) {
	
		var oEvent = Common.Event.normalize(oEvent);					
		
		if(oEvent.ctrlKey) {
			return true;
		}		

		if(oEvent.iKeyCode != 8 && (oEvent.iKeyCode < 45 || oEvent.iKeyCode > 57 || oEvent.iKeyCode == 47)) {			
			
			if(!oEvent.which) {
				oEvent.returnValue = false;				
			}
			else {
				return false;
			}
			
		}
	
	}
		
	this.oElement.onkeypress = preProcess.closure(this.oElement);

};

NumberInput.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new NumberInput(
		oElement,	
		oClassElement,
		false
		);
		
};

function DateInput(
	oElement,
	oClassElement,
	bTemplate
	) {			
	
	if(!bTemplate) {

		this.oDayInput = this.createNumberInput('day-' + oElement.id, 2);
		this.oMonthInput = this.createMonthInput('month-' + oElement.id);	
		this.oYearInput = this.createNumberInput('year-' + oElement.id, 4);
		
	}
		
	DateInput.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
		
	if(this.isTemplate()) {
		return;
	}
	
	this.replaceElement();			
	
	this.addChild(this.oDayInput);
	this.addChild(this.oMonthInput);
	this.addChild(this.oYearInput);
	
	this.addExtendedHandlers();
	
	this.initValue();
	
}

DateInput.inheritFrom(FieldContainer);

DateInput.prototype.createValue = function() {
	
	return new ValueDate();
	
};

DateInput.prototype.addChild = function(oChild) {
			
	this.oElement.parentNode.appendChild(oChild.oElement);	
	
	return DateInput.superClass.addChild.call(this, oChild);
	
};

DateInput.prototype.setValue = function(oValue) {
		
	var
		oYear = new Value(),
		oMonth = new Value(),
		oDay = new Value()
		;
	
	oYear.set(oValue.getYear());
	oMonth.set(oValue.getMonth());
	oDay.set(oValue.getDay());
		
	this.oYearInput.setValue(oYear);
	this.oMonthInput.setValue(oMonth);
	this.oDayInput.setValue(oDay);
	
	this.oElement.value = oValue.toString();	
	
	DateInput.superClass.setValue.call(this, oValue);		
		
};

DateInput.prototype.isRequired = function() {		
		
	return FieldContainer.superClass.isRequired.call(this);
	
};

DateInput.prototype.isValid = function() {		
		
	return FieldContainer.superClass.isValid.call(this);
	
};

DateInput.prototype.replaceElement = function() {

	var oNewElement = document.createElement('input');
	
	oNewElement.setAttribute('type', 'hidden');
	oNewElement.setAttribute('id', this.oElement.getAttribute('id'));	
	oNewElement.setAttribute('name', this.oElement.getAttribute('name'));			
	oNewElement.value = this.oElement.value;
	
	this.oElement.parentNode.replaceChild(oNewElement, this.oElement);
	
	this.oElement = oNewElement;
	
};

DateInput.prototype.addExtendedHandlers = function() {

	if(this.isTemplate()) {		
		return;
	}
	
	var oThis = this;
	
	function process() {
	
		oThis.processDate();
	
	}		
		
	Common.Event.add(
		this.oDayInput.oElement,
		'blur',
		process
		);
		
	Common.Event.add(
		this.oMonthInput.oElement,
		'blur',
		process
		);
		
	Common.Event.add(
		this.oYearInput.oElement,
		'blur',
		process
		);

};

DateInput.prototype.processDate = function() {		
	
	if(this.oYearInput.getValue().isEmpty() ||
		this.oDayInput.getValue().isEmpty()
		) {							
		return;		
	}
	
	this.setValue(new ValueDate(this.oYearInput.getValue().get() + '-' + this.oMonthInput.getValue().get() + '-' + this.oDayInput.getValue().toString()));

};

DateInput.prototype.createNumberInput = function(sId, iSize) {	
	
	var oElement = document.createElement('input');
	
	oElement.id = sId;
	oElement.size = iSize;
	oElement.maxLength = iSize;	
	
	return new NumberInput(oElement);

};

DateInput.prototype.createMonthInput = function(sId) {

	var
		oElement = document.createElement('select'),
		aMonths = Resources.getMonthsByType('genitive')
		;		
	
	oElement.id = sId;
	
	// IE hack
	document.body.appendChild(oElement);	
	
	oElement.options.length = 0;
	
	for(var i = 0, a; i < aMonths.length; i++) {				
		oElement.options[oElement.options.length] = new Option(aMonths[i], i + 1);		
	}		
	
	return new SelectInput(document.body.removeChild(oElement));

};

DateInput.prototype.setValueFromElement = function() {
	
	if(this.isTemplate()) {		
		return;
	}
	
	this.oValue.set(this.oYearInput.getValue() + '-' + this.oMonthInput.getValue() + '-' + this.oDayInput.getValue());
	
};

DateInput.prototype.initValue = function() {
	
	var oValue = new ValueDate();
	
	oValue.set(this.oElement.value);
	
	this.setValue(oValue);
	
	this.processDate();
	
};

DateInput.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new DateInput(
		oElement,
		oClassElement,
		false	
		);
	
};

function StateInput(
	oElement,
	oClassElement,
	bTemplate
	) {		
	
	StateInput.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
}

StateInput.inheritFrom(TextInput);

StateInput.prototype.check = function() {
			
	this.oElement.checked = true;	
	
};
	
StateInput.prototype.uncheck = function() {
	
	this.oElement.checked = false;	
	
};

StateInput.prototype.isChecked = function() {
	
	return this.oElement.checked;
	
};

StateInput.prototype.processEvents = function(bUpdateSubmit) {

	StateInput.superClass.processEvents.call(this, bUpdateSubmit);
	
	if(this.oParent instanceof InputGroup) {		
		this.oParent.processEvents(bUpdateSubmit);
	}

};
	
StateInput.prototype.getEventList = function() {
	
	return ['click'];
	
};

function RadioButton(
	oElement,
	oClassElement,
	bTemplate
	) {		
	
	RadioButton.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
}

RadioButton.inheritFrom(StateInput);

RadioButton.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new RadioButton(
		oElement,
		oClassElement,
		false
		);
	
};

function CheckBox(
	oElement,
	oClassElement,
	bTemplate
	) {		
	
	CheckBox.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
}

CheckBox.inheritFrom(StateInput);

CheckBox.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new CheckBox(
		oElement,
		oClassElement,
		false
		);
	
};

function SelectInput(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	SelectInput.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
	this.aOptions = [];

	for(var i = 0; i < this.oElement.options.length; i++) {
		this.aOptions[i] = {
			sLabel : this.oElement.options[i].innerHTML,
			sValue : this.oElement.options[i].value
			};
	}
	
}

SelectInput.inheritFrom(FormWidget);

SelectInput.prototype.setValue = function(oValue) {
	
	for(var i = 0; i < this.aOptions.length; i++) {
	
		if(this.aOptions[i].sValue == oValue.toString()) {
	
			this.oElement.selectedIndex = i;
			break;
			
		}
	}		
	
	TextInput.superClass.setValue.call(this, oValue);
		
};

SelectInput.prototype.getEventList = function() {
	
	return ['change'];
	
};

SelectInput.prototype.setValueFromElement = function() {
		
	this.oValue.set(this.oElement.selectedIndex >= 0? this.oElement.options[this.oElement.selectedIndex].value : '');

};

SelectInput.prototype.enableChildrenByValue = function(aPatterns) {

	var
		bMatched = false,
		oOption		
		;			
	
	this.oElement.options.length = 0;					
	
	for(var i = 0; i < this.aOptions.length; i++) {
	
		oOption = this.aOptions[i];
	
		bMatched = false;
	
		for(var j = 0; j < aPatterns.length && !bMatched; j++) {
			
			bMatched = oOption.sValue.match(aPatterns[j])? true : false;
			
			if(bMatched) {								
				this.oElement.options[this.oElement.options.length] = new Option(oOption.sLabel, oOption.sValue);				
			}
			
		}
		
	}
	
	this.processEvents(true);

};

SelectInput.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new SelectInput(
		oElement,
		oClassElement,
		false	
		);
	
};

function SliderInput(
	oElement,	
	oClassElement,
	bTemplate,
	oOptions
	) {

	this.dStep = oOptions.dStep || 1;		
	this.dMin = oOptions.dMin || 0;
	this.dMax = oOptions.dMax || 100;
		
	SliderInput.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
	if(this.isTemplate()) {
		return;
	}
		
	var oSliderElements = this.createElements(oElement);
	
	this.oContainer = oSliderElements.oContainer;
	this.oControlElement = oSliderElements.oControlElement;	
	this.oLabelMin = oSliderElements.oLabelMin;
	this.oLabelMax = oSliderElements.oLabelMax;	
	
	this.bEnabled = true;
	
	var dInitValue = isNaN(parseFloat(this.oElement.value))? '' : parseFloat(this.oElement.value);				
	
	this.iLastControlPosition = 0;
	
	this.setStep(this.dStep);	
	this.setMin(this.dMin);
	this.setMax(this.dMax);		
	
	this.oContainerOffset = null;
	
	this.fClickHandler = null;
	this.fDragStartHandler = null;
	this.fDragHandler = null;
	this.fDragEndHandler = null;	
	this.fNullHandler = null;
	this.fSyncHandler = null;		
	
	this.initValue(dInitValue);
	this.addExtendedHandlers();
	
	this.iIndex = SliderInput.add(this);

}

SliderInput.inheritFrom(NumberInput);

SliderInput.CLASS_NAME_SLIDER_CONTAINER  = 'slider';
SliderInput.CLASS_NAME_SLIDER_HORIZONTAL = 'slider-horizontal';
SliderInput.CLASS_NAME_SLIDER_VERTICAL   = 'slider-vertical';
SliderInput.CLASS_NAME_CONTROL_ELEMENT   = 'control';
SliderInput.CLASS_NAME_LABEL_MIN         = 'label-min';
SliderInput.CLASS_NAME_LABEL_MAX         = 'label-max';
SliderInput.CLASS_NAME_INITED            = 'slider-inited';

SliderInput.KEY_CODE_ARROW_RIGHT = 39;
SliderInput.KEY_CODE_ARROW_LEFT  = 37;

SliderInput.createHorizontalSlider = function(oElement, oClassElement, bTemplate, oOptions) {

	return new SliderInput(oElement, oClassElement, bTemplate, oOptions);

};

SliderInput.createVerticalSlider = function(oElement, oClassElement, bTemplate, oOptions) {

	return new SliderVerticalInput(oElement, oClassElement, bTemplate, oOptions);

};

SliderInput.aAll = [];
SliderInput.iActiveIndex = 0;

SliderInput.add = function(oSliderInput) {

	if(!(oSliderInput instanceof SliderInput)) {
		return;
	}
	
	if(SliderInput.aAll.length == 0) {
		Common.Event.add(
			document,
			'keyup',
			SliderInput.processKeyPress
			);
	}

	SliderInput.aAll[SliderInput.aAll.length] = oSliderInput;
	
	return SliderInput.aAll.length - 1;	

};

SliderInput.setActiveIndex = function(iIndex) {
	
	SliderInput.iActiveIndex = iIndex;
	
};

SliderInput.processKeyPress = function(oEvent) {
	
	var
		oEvent = Common.Event.normalize(oEvent),		
		oSliderInput = SliderInput.aAll[SliderInput.iActiveIndex]
		;	
		
	if(!oSliderInput) {
		return;
	}
		
	switch(oEvent.iKeyCode) {
		
		case SliderInput.KEY_CODE_ARROW_RIGHT:		
			oSliderInput.next();
		break;
											
		case SliderInput.KEY_CODE_ARROW_LEFT:		
			oSliderInput.prev();
		break;	
			
		default:
		break;				
		
	}
	
};

SliderInput.prototype.createElements = function(oElement) {
		
	var		
		oResult = {
			oContainer      : document.createElement('div'),
			oControlElement : document.createElement('div'),
			oLabelMin       : document.createElement('div'),
			oLabelMax       : document.createElement('div')
			}
		;
				
	oResult.oContainer.id = 'container-' + this.oElement.id;
	oResult.oControlElement.id = 'control-' + this.oElement.id;
	oResult.oLabelMin.id = 'label-min-' + this.oElement.id;
	oResult.oLabelMax.id = 'label-max-' + this.oElement.id;
				
	Common.Class.add(oResult.oContainer, SliderInput.CLASS_NAME_SLIDER_CONTAINER);
	Common.Class.add(oResult.oContainer, this.getContainerClassName());
	Common.Class.add(oResult.oControlElement, SliderInput.CLASS_NAME_CONTROL_ELEMENT);		
	Common.Class.add(oResult.oLabelMin, SliderInput.CLASS_NAME_LABEL_MIN);		
	Common.Class.add(oResult.oLabelMax, SliderInput.CLASS_NAME_LABEL_MAX);
		
	oResult.oContainer.appendChild(oResult.oControlElement);
	oResult.oContainer.appendChild(oResult.oLabelMin);
	oResult.oContainer.appendChild(oResult.oLabelMax);
		
	oElement.parentNode.insertBefore(oResult.oContainer, oElement);
		
	return oResult;
		
};
	
SliderInput.prototype.getContainerClassName = function() {
	
	return SliderInput.CLASS_NAME_SLIDER_HORIZONTAL;
	
};
	
SliderInput.prototype.initValue = function(dInitValue) {
		
	if(dInitValue === '') {
		this.setValue(new Value(this.getMin()));
	}
	else {			
		this.setValue(new Value(dInitValue));
	}
	
	this.addClass(SliderInput.CLASS_NAME_INITED);
		
};
	
SliderInput.prototype.addExtendedHandlers = function() {
	
	var oThis = this;
	
	this.fClickHandler = function(oEvent) {
		
		SliderInput.setActiveIndex(oThis.iIndex);
		
		oThis.drag(Common.Event.normalize(oEvent));
		
	};
	
	this.fDragStartHandler = function() {
	 
		oThis.dragStart();
		
	};
	
	this.fDragHandler = function(oEvent) {
	
		oThis.drag(Common.Event.normalize(oEvent));
	
	};
	
	this.fDragEndHandler = function(oEvent) {
	
		oThis.dragEnd(Common.Event.normalize(oEvent));
	
	};
	
	this.fNullHandler = function() {
	
		return false;
	
	};
	
	this.fSyncHandler = function() {
	
		oThis.setValue(new Value(parseFloat(this.value)? parseFloat(this.value) : 0));
	
	};

	Common.Event.add(
		this.oContainer,
		'click',
		this.fClickHandler
		);
		
	Common.Event.add(
		this.oControlElement,
		'mousedown',
		this.fDragStartHandler
		);	
	
	Common.Event.add(
		this.oElement,
		'blur',
		this.fSyncHandler
		);
	
};

SliderInput.prototype.getStep = function() {
	
	return this.dStep;
	
};
	
SliderInput.prototype.setStep = function(dStep) {
	
	this.dStep = dStep > 0? dStep : 1;		
		
	this.setValue(this.getValue());		
		
};
	
SliderInput.prototype.getMin = function() {
	
	return this.dMin;
	
};
	
SliderInput.prototype.setMin = function(dMin) {
		
	if(dMin >= this.getMax()) {
		this.dMin = this.getMax() - this.getStep();
	}
	else {
		this.dMin = dMin;
	}				
				
	this.oLabelMin.innerHTML = this.dMin;
				
	this.setValue(this.getValue().get() < this.dMin? new Value(this.dMin) : this.getValue());
		
};
	
SliderInput.prototype.getMax = function() {
	
	return this.dMax;
	
};
	
SliderInput.prototype.setMax = function(dMax) {
		
	if(dMax <= this.getMin()) {
		this.dMax = this.getMin() + this.getStep();
	}
	else {
		this.dMax = dMax;
	}
		
	this.oLabelMax.innerHTML = this.dMax;
		
	this.setValue(this.getValue().get() > this.dMax? new Value(this.dMax) : this.getValue());
		
};
	
SliderInput.prototype.dragStart = function() {
	
	if(!this.isEnabled()) {
		return false;
	}
		
	this.updateContainerOffset();				
		
	Common.Event.add(
		document,
		'selectstart',
		this.fNullHandler
		);
	
	Common.Event.add(
		document,
		'mousemove',
		this.fDragHandler
		);
		
	Common.Event.add(
		document,
		'mouseup',
		this.fDragEndHandler
		);
		
};
	
SliderInput.prototype.drag = function(oEvent) {
	
	if(!this.isEnabled()) {
		return false;
	}
	
	this.updateContainerOffset();		
		
	this.setValue(this.calculateValueByOffset(this.calculateOffset(oEvent)));
	
};
		
SliderInput.prototype.dragEnd = function() {
			
	Common.Event.remove(
		document,
		'mousemove',
		this.fDragHandler
		);
		
	Common.Event.remove(
		document,
		'mouseup',
		this.fDragEndHandler
		);	
		
	Common.Event.remove(
		document,
		'selectstart',
		this.fNullHandler
		);
	
};

SliderInput.prototype.setValue = function(oValue) {			
		
	var dNewValue = Math.round((oValue.get() - this.getMin()) / this.getStep()) * this.getStep() + this.getMin();
		
	if(dNewValue < this.getMin()) {
		dNewValue = this.getMin();
	}
	else if(dNewValue > this.getMax()) {
		dNewValue = this.getMax();
	}		
		
	this.oValue.set(parseFloat(dNewValue));
		
	this.syncControlElement();
	
	SliderInput.superClass.setValue.call(this, this.oValue);
	
};
	
SliderInput.prototype.syncControlElement = function() {
		
	var iPosition = this.calculatePositionByValue(this.getValue());
		
	if(iPosition == this.iLastControlPosition) {			
		return;
	}
		
	this.iLastControlPosition = iPosition;
		
	this.moveControlElement(iPosition);
	
};
	
SliderInput.prototype.moveControlElement = function(iPosition) {
		
	this.oControlElement.style.left = iPosition + '%';
	
};
	
SliderInput.prototype.next = function() {
	
	if(!this.isEnabled()) {
		return false;
	}
	
	this.setValue(new Value(parseFloat(this.getValue().get()) + this.getStep()));
	
};
	
SliderInput.prototype.prev = function() {
	
	if(!this.isEnabled()) {
		return false;
	}
	
	this.setValue(new Value(parseFloat(this.getValue().get()) - this.getStep()));
	
};
	
SliderInput.prototype.updateContainerOffset = function() {
			
	this.oContainerOffset = Common.Dom.getAbsoluteCoords(this.oContainer);
	
};
	
SliderInput.prototype.calculateOffset = function(oEvent) {
	
	return Common.Event.getAbsoluteCoords(oEvent).iLeft - this.oContainerOffset.iLeft;
	
};
	
SliderInput.prototype.calculatePositionByValue = function(oValue) {
	
	return Math.round(100 * (oValue.get() - this.getMin()) / (this.getMax() - this.getMin()));
	
};
	
SliderInput.prototype.calculateValueByOffset = function(iOffset) {
		
	return new Value((iOffset / this.oContainer.offsetWidth) * (this.getMax() - this.getMin()) + this.getMin());
	
};

SliderInput.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new SliderInput(
		oElement,	
		oClassElement,
		false,
		{
			dStep : this.dStep,
			dMin  : this.dMin,
			dMax  : this.dMax
		}
		);
	
};

function SliderVerticalInput(
	oElement,	
	oClassElement,
	bTemplate,
	oOptions
	) {

	SliderVerticalInput.baseConstructor.call(
		this,
		oElement,	
		oClassElement,
		bTemplate,
		oOptions
		);
	
}

SliderVerticalInput.inheritFrom(SliderInput);

SliderVerticalInput.prototype.getContainerClassName = function() {
	
	return SliderInput.CLASS_NAME_SLIDER_VERTICAL;
	
};

SliderVerticalInput.prototype.moveControlElement = function(iPosition) {
		
	this.oControlElement.style.top = iPosition + '%';
	
};

SliderVerticalInput.prototype.calculateOffset = function(oEvent) {

	return this.oContainerOffset.iTop - Common.Event.getAbsoluteCoords(oEvent).iTop;

};

SliderVerticalInput.prototype.calculatePositionByValue = function(oValue) {
	
	return 100 - SliderVerticalInput.superClass.calculatePositionByValue.call(this, oValue);
	
};

SliderVerticalInput.prototype.calculateValueByOffset = function(iOffset) {
		
	return new Value((iOffset / this.oContainer.offsetHeight) * (this.getMax() - this.getMin()) + this.getMax());
	
};

SliderVerticalInput.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new SliderVerticalInput(
		oElement,	
		oClassElement,
		false,
		{
			dStep : this.dStep,
			dMin  : this.dMin,
			dMax  : this.dMax
		}
		);
	
};

function Button(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	Button.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
	this.fHandler = null;
		
}

Button.inheritFrom(FormWidget);

Button.prototype.setHandler = function(fHandler) {
	
	this.fHandler = fHandler;
	
	if(this.isEnabled()) {
		this.enable();
	}
		
};

Button.prototype.enable = function(bByParent) {
	
	if(!Button.superClass.enable.call(this, bByParent)) {
		return false;
	}
	
	if(this.fHandler) {
		Common.Event.add(
			this.oElement,
			'click',
			this.fHandler
			);
	}
	
};

Button.prototype.disable = function(bByParent) {
	
	Button.superClass.disable.call(this, bByParent);
	
	if(this.fHandler) {
		Common.Event.remove(
			this.oElement,
			'click',
			this.fHandler
			);
	}
	
};

Button.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new Button(
		oElement,
		oClassElement,
		false	
		);
	
};

function SubmitButton(
	oElement,
	oClassElement,
	bTemplate
	) {
	
	SubmitButton.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		bTemplate
		);
	
}

SubmitButton.inheritFrom(FormWidget);

SubmitButton.prototype.setForm = function(oForm) {

	SubmitButton.superClass.setForm.call(this, oForm);
	
	this.oForm.addSubmit(this);	
	
};

SubmitButton.prototype.clone = function(
	oElement,
	oClassElement
	) {
	
	return new SubmitButton(
		oElement,
		oClassElement,
		false	
		);
	
};

function Form(
	oElement,
	oClassElement,
	bUpdatableSubmit,
	bCheckForValid
	) {
	
	Form.baseConstructor.call(
		this,
		oElement,
		oClassElement,
		false
		);
	
	this.aWidgets = [];
	this.aWidgets[this.getId()] = this;
	this.aSubmits = [];	
	this.bUpdatableSubmit = bUpdatableSubmit || false;
	this.bCheckForValid = bCheckForValid || false;	
	this.addSubmitHandler();
	
}

Form.inheritFrom(FieldContainer);

Form.prototype.addSubmitHandler = function() {

	var oThis = this;

	function process() {
		
		return oThis.checkForSubmit();
	
	}
	
	this.oElement.onsubmit = process.closure(this.oElement);

};

Form.prototype.checkForSubmit = function() {		
	
	if(this.isReadyForSubmit()) {		
		return true;		
	}
	
	this.getFirstErrorElement().focus();
	
	this.addClass(FormWidget.CLASS_NAME_SUBMITTED);	
	
	return false;

};

Form.prototype.init = function() {
	
	Form.superClass.init.call(this);
	
	this.updateSubmit();
	
};

Form.prototype.setForm = function(oForm) {};
	
Form.prototype.addChild = function(oChild) {		
	
	Form.superClass.addChild.call(this, oChild);		
	
	oChild.setForm(this);
	
};

Form.prototype.addSubmit = function(oSubmit) {
	
	if(!(oSubmit instanceof SubmitButton)) {
		return;
	}

	this.aSubmits.push(oSubmit);	

};

Form.prototype.updateSubmit = function() {
	
	if(!(this.bUpdatableSubmit && this.aSubmits.length > 0)) {
		return;
	}
	
	if(this.isReadyForSubmit()) {
		this.enableSubmit();		
	}
	else {
		this.disableSubmit();		
	}

};

Form.prototype.enableSubmit = function() {
	
	for(var i = 0; i < this.aSubmits.length; i++) {				
		this.aSubmits[i].enable();
	}
	
};

Form.prototype.disableSubmit = function() {
	
	for(var i = 0; i < this.aSubmits.length; i++) {				
		this.aSubmits[i].disable();
	}
	
};

Form.prototype.addWidget = function(oWidget) {

	this.aWidgets[oWidget.getId()] = oWidget;

};

Form.prototype.removeWidget = function(oWidget) {
	
	this.aWidgets[oWidget.getId()] = null;

};

Form.prototype.getWidgetById = function(sId) {

	return this.aWidgets[sId];

};

Form.prototype.isReadyForSubmit = function() {	

	var oWidget;		

	for(var sId in this.aWidgets) {
	
		oWidget = this.aWidgets[sId];				
		
		if(!(oWidget instanceof FormWidget)) {
			continue;
		}
	
		if(oWidget.isEnabled() &&
			(oWidget.isRequired() ||
				(this.bCheckForValid && !oWidget.isValid())
				)
			) {			
			return false;
		}
		
	}
	
	return true;

};

Form.prototype.getFirstErrorWidget = function() {

	for(var sId in this.aWidgets) {
	
		oWidget = this.aWidgets[sId];				
		
		if(!(oWidget instanceof FormWidget)) {
			continue;
		}
	
		if(oWidget.isEnabled() &&
			(oWidget.bRequired ||
				(this.bCheckForValid && !oElement.bValid)
				)
			) {			
			return oWidget;
		}
		
	}

};

function Multiplicator(
	oElement,
	oClassElement,
	oOptions	
	) {
		
	this.oTemplate = null;
	this.sButtonAddId = oOptions.sButtonAddId;
	this.sButtonRemoveId = oOptions.sButtonRemoveId;	
	this.iMin = oOptions.iMin || Multiplicator.REPEAT_MIN_DEFAULT;
	this.iMax = oOptions.iMax || Multiplicator.REPEAT_MAX_DEFAULT;	
	
	Multiplicator.baseConstructor.call(
		this,
		oElement,
		oClassElement
		);
				
}

Multiplicator.inheritFrom(FieldContainer);

Multiplicator.POSTFIX_ID = '_multiplicator';

Multiplicator.REPEAT_MIN_DEFAULT = 1;
Multiplicator.REPEAT_MAX_DEFAULT = 100;

Multiplicator.REG_EXP_REPLACE = new RegExp('^(.+)_.+$');

Multiplicator.prototype.getId = function() {

	return this.sId + Multiplicator.POSTFIX_ID;

};

Multiplicator.prototype.addChild = function(
	oChild,
	iIndex
	) {		

	var
		iPostfix = iIndex > -1? iIndex : this.aChildren.length,
		oMultiplier = new Multiplier(this, oChild)
		;		
	
	oMultiplier.addAddButton(new Button(document.getElementById(this.sButtonAddId + (iPostfix > 0? '_' + iPostfix : ''))));
	oMultiplier.addRemoveButton(new Button(document.getElementById(this.sButtonRemoveId + (iPostfix > 0? '_' + iPostfix : ''))));
		
	oChild.setMultiplier(oMultiplier);	
	
	return Multiplicator.superClass.addChild.call(
		this,
		oChild,
		iIndex
		);
	
};

Multiplicator.prototype.addTemplate = function(oTemplate) {	
	
	this.oTemplate = oTemplate;
	
	return oTemplate;		
	
};

Multiplicator.prototype.normalizeTemplateAttributes = function(oTemplate) {
	
	var aScriptNodes = oTemplate.oClassElement.getElementsByTagName('script');
	
	for(var i = 0; i < aScriptNodes.length;) {
		aScriptNodes[i].parentNode.removeChild(aScriptNodes[i]);		
	}
	
	this.replacePostfixAtElement(oTemplate.oClassElement, this.iMax + 1);
	
	oTemplate.setId(oTemplate.oElement.id);
	
};

Multiplicator.prototype.init = function() {
	
	Multiplicator.superClass.init.call(this);
	
	this.oTemplate.hide();
	this.oTemplate.disable();
	
	this.normalizeTemplateAttributes(this.oTemplate);
	
	this.updateMultipliers();
	
};

Multiplicator.prototype.updateMultipliers = function() {
	
	for(var i = 0; i < this.aChildren.length; i++) {		
		this.aChildren[i].getMultiplier().updateState(			
			this.aChildren.length < this.iMax,
			this.aChildren.length > this.iMin
			);		
	}
	
};

Multiplicator.prototype.add = function(oChild) {			
	
	var
		iChildIndex = this.getChildIndex(oChild) + 1,
		oNewElement = this.oTemplate.oClassElement.cloneNode(true)
		;
	
	this.increaseChildrenPostfix(iChildIndex);	
			
	this.removePostfixFromElement(oNewElement);	
	this.addPostfixToElement(oNewElement, iChildIndex);	
	
	if(oChild.oClassElement.nextSibling) {		
		oChild.oClassElement.parentNode.insertBefore(oNewElement, oChild.oClassElement.nextSibling);
	}
	else {
		oChild.oClassElement.parentNode.appendChild(oNewElement);
	}

	var	oNewChild = this.oTemplate.clone(
		document.getElementById(this.oTemplate.oElement.id.match(Multiplicator.REG_EXP_REPLACE)[1] + '_' + iChildIndex),
		document.getElementById(this.oTemplate.oClassElement.id.match(Multiplicator.REG_EXP_REPLACE)[1]  + '_' + iChildIndex),
		iChildIndex
		);	
	
	this.addChild(oNewChild, iChildIndex);
	
	oNewChild.enable();
	oNewChild.show();	
		
	this.updateMultipliers();
	
	this.addTemplateDependencies(this.oTemplate, oNewChild, oNewChild);
	
	oNewChild.processEvents(true, true);
	
	// ie hack
	document.body.className += '';
	
};

Multiplicator.prototype.addTemplateDependencies = function(
	oCurrentTemplate,	
	oCurrentWidget,
	oClonedWidget
	) {
	
	this.addDependenciesFrom(oCurrentTemplate, oCurrentWidget, oClonedWidget);
	this.addDependenciesTo(oCurrentTemplate, oCurrentWidget, oClonedWidget);
	
	if(oCurrentTemplate instanceof FieldContainer) {		
		for(var i = 0; i < oCurrentTemplate.aChildren.length; i++) {
			this.addTemplateDependencies(oCurrentTemplate.aChildren[i], oCurrentWidget.aChildren[i], oClonedWidget);
		}		
	}
	
};

Multiplicator.prototype.addDependenciesFrom = function(
	oCurrentTemplate,
	oCurrentWidget,
	oClonedWidget
	) {
		
	var aDependencies = oCurrentTemplate.getDependencies();
	
	for(var i = 0; i < aDependencies.length; i++) {				
		
		oFrom = this.findCorrespondingWidgetByTemplate(aDependencies[i].getFrom(), this.oTemplate, oClonedWidget) ||
			aDependencies[i].getFrom()
			;
		
		oCurrentWidget.addDependence(aDependencies[i].clone(oFrom));
		
		oFrom.processEvents(true, true);
		
	}
	
};

Multiplicator.prototype.addDependenciesTo = function(
	oCurrentTemplate,
	oCurrentWidget,
	oClonedWidget
	) {
		
	var aDependencies;
		
	for(var i = 0; i < oCurrentTemplate.aObservers.length; i++) {
		
		if(this.findCorrespondingWidgetByTemplate(oCurrentTemplate.aObservers[i], this.oTemplate, oClonedWidget)) {			
			continue;
		}
		
		aDependencies = oCurrentTemplate.aObservers[i].getDependencies();
	
		for(var j = 0; j < aDependencies.length; j++) {	
			if(aDependencies[j].getFrom() == oCurrentTemplate) {
				oCurrentTemplate.aObservers[i].addDependence(aDependencies[j].clone(oCurrentWidget));
			}
		}
		
	}

};

Multiplicator.prototype.findCorrespondingWidgetByTemplate = function(
	oTemplateForFind,
	oCurrentTemplate,
	oCurrentWidget
	) {
	
	if(oCurrentTemplate == oTemplateForFind) {		
		return oCurrentWidget;
	}
	
	if(oCurrentTemplate instanceof FieldContainer) {
		
		var oFoundedWidget;
		
		for(var i = 0; i < oCurrentTemplate.aChildren.length; i++) {
			
			oFoundedWidget = this.findCorrespondingWidgetByTemplate(oTemplateForFind, oCurrentTemplate.aChildren[i], oCurrentWidget.aChildren[i]);
			
			if(oFoundedWidget) {				
				return oFoundedWidget;
			}
					
		}
	}
	
};

Multiplicator.prototype.remove = function(oChild) {
		
	var iChildIndex = this.getChildIndex(oChild);
		
	oChild.oClassElement.parentNode.removeChild(oChild.oClassElement);
	
	this.decreaseChildrenPostfix(iChildIndex + 1);
	
	this.removeChild(oChild);
	
	this.processEvents(true);
	
	this.updateMultipliers();		
	
	// ie hack
	document.body.className += '';
	
};

Multiplicator.prototype.increaseChildrenPostfix = function(iStartIndex) {		
	
	for(var i = this.aChildren.length - 1; i >= iStartIndex; i--) {		
		
		this.replacePostfixAtElement(this.aChildren[i].oClassElement, i + 1);					
		this.aChildren[i].updateElements(i + 1);
		
	}		
	
};

Multiplicator.prototype.decreaseChildrenPostfix = function(iStartIndex) {
	
	for(var i = iStartIndex; i < this.aChildren.length; i++) {		
	
		this.replacePostfixAtElement(this.aChildren[i].oClassElement, i - 1);
		this.aChildren[i].updateElements(i - 1);
	
	}		
	
};

Multiplicator.prototype.getChildIndex = function(oChild) {		
	
	for(var i = 0; i < this.aChildren.length; i++) {		
		
		if(this.aChildren[i] == oChild) {
			return i;
		}		
	}
	
	return -1;
	
};

Multiplicator.prototype.replacePostfixAtElement = function(oElement, iPostfix) {	

	for(var i = 0; i < oElement.childNodes.length; i++) {		
		this.replacePostfixAtElement(oElement.childNodes[i], iPostfix);	
	}
	
	this.replacePostfixAtNode(oElement, iPostfix);
	
};

Multiplicator.prototype.replacePostfixAtNode = function(oNode, iPostfix) {		
	
	if(oNode.id) {
		oNode.id = oNode.id.replace(Multiplicator.REG_EXP_REPLACE, '$1' + (iPostfix > 0? '_' + iPostfix : ''));
	}
	
	if(oNode.htmlFor) {
		oNode.htmlFor = oNode.htmlFor.replace(Multiplicator.REG_EXP_REPLACE, '$1' + (iPostfix > 0? '_' + iPostfix : ''));
	}
	
	if(oNode.name) {
		
		oNode.name = oNode.name.replace(Multiplicator.REG_EXP_REPLACE, '$1' + (iPostfix > 0? '_' + iPostfix : ''));
						
		this.fixNode(oNode);
		
	}		
	
};

Multiplicator.prototype.removePostfixFromElement = function(oElement) {
	
	for(var i = 0; i < oElement.childNodes.length; i++) {		
		this.removePostfixFromElement(oElement.childNodes[i]);	
	}
	
	this.removePostfixFromNode(oElement);
	
};
	
Multiplicator.prototype.removePostfixFromNode = function(oNode) {	
	
	if(oNode.name) {
		oNode.name = oNode.name.replace(Multiplicator.REG_EXP_REPLACE, '$1');
	}
	
	if(oNode.id) {
		oNode.id = oNode.id.replace(Multiplicator.REG_EXP_REPLACE, '$1');
	}
	
	if(oNode.htmlFor) {
		oNode.htmlFor = oNode.htmlFor.replace(Multiplicator.REG_EXP_REPLACE, '$1');
	}	
	
};

Multiplicator.prototype.addPostfixToElement = function(oElement, iPostfix) {
	
	for(var i = 0; i < oElement.childNodes.length; i++) {		
		this.addPostfixToElement(oElement.childNodes[i], iPostfix);
	}	
	
	this.addPostfixToNode(oElement, iPostfix);
	
};

Multiplicator.prototype.addPostfixToNode = function(oNode, iPostfix) {
	
	if(oNode.id) {
		oNode.id += '_' + iPostfix;
	}
	
	if(oNode.htmlFor) {
		oNode.htmlFor += '_' + iPostfix;
	}
	
	if(oNode.name) {
		
		oNode.name += '_' + iPostfix;
								
		this.fixNode(oNode);
		
	}		
	
};

Multiplicator.prototype.fixNode = function(oNode) {
	
	if(!window.opera && (
			oNode.type.toLowerCase() == 'text' ||
			oNode.type.toLowerCase() == 'radio' ||
			oNode.type.toLowerCase() == 'checkbox'
			)
		) {
	
		try {
		
			oNode.parentNode.insertBefore(
				document.createElement(
					'<input type="' + oNode.type + 
						'"name="' + oNode.name + 
						'"id="' + oNode.id + '"' +
						(oNode.className? 'class="' + oNode.className + '"' : '') +
						(oNode.size? 'size="' + oNode.size + '"' : '') +
						(oNode.maxLength? 'maxlength="' + oNode.maxLength + '"' : '') +
						(oNode.value? 'value="' + oNode.value + '"' : '') +
						(oNode.checked? 'checked="checked"' : '') +
					'/>'
					),
				oNode
				);
				
			oNode = oNode.parentNode.removeChild(oNode);
			
			oNode.outerHTML = '';

		}
		catch(oException) {}
		
	}
	
};

function Multiplier(
	oMultiplicator,
	oFormWidget
	) {
		
	this.oMultiplicator = oMultiplicator;
	this.oFormWidget = oFormWidget;
		
	this.bCanAdd = true;
	this.bCanRemove = true;

	this.oAddButton = null;
	this.oRemoveButton = null;	
	
	this.bDisabledByOuter = false;

}

Multiplier.prototype = {
	
	addAddButton : function(oButton) {
	
		this.oAddButton = oButton;		
	
		var oThis = this;
	
		oButton.setHandler(
			function() {
	
				oThis.oMultiplicator.add(oThis.oFormWidget);
			
				return false;
	
			}
		);
	
	},
	
	addRemoveButton : function(oButton) {
	
		this.oRemoveButton = oButton;		
	
		var oThis = this;
	
		oButton.setHandler(
			function() {
	
				oThis.oMultiplicator.remove(oThis.oFormWidget);
			
				return false;
	
			}
		);
	
	},

	enableByOuter : function() {
		
		this.bDisabledByOuter = false;	
		
		if(this.bCanAdd) {
			this.enableAdd();
		}
		
		if(this.bCanRemove) {
			this.enableRemove();
		}
		
	},
	
	disableByOuter : function() {
		
		this.bDisabledByOuter = true;
		
		if(this.oAddButton) {
			this.oAddButton.disable();
		}
		
		if(this.oRemoveButton) {
			this.oRemoveButton.disable();
		}
		
	},
	
	enableAdd : function() {
		
		this.bCanAdd = true;
		
		if(this.bDisabledByOuter) {
			return;
		}
		
		if(this.oAddButton) {
			this.oAddButton.enable();
		}
		
	},
	
	disableAdd : function() {
		
		this.bCanAdd = false;		
		
		if(this.oAddButton) {
			this.oAddButton.disable();
		}
		
	},
	
	enableRemove : function() {
		
		this.bCanRemove = true;
		
		if(this.bDisabledByOuter) {
			return;
		}
		
		if(this.oRemoveButton) {
			this.oRemoveButton.enable();
		}
		
	},
	
	disableRemove : function() {
		
		this.bCanRemove = false;
		
		if(this.oRemoveButton) {
			this.oRemoveButton.disable();
		}
		
	},
	
	updateState : function(		
		bEnableAdd,
		bEnableRemove
		) {
		
		if(bEnableAdd) {			
			this.enableAdd();
		}
		else {
			this.disableAdd();
		}
		
		if(bEnableRemove) {			
			this.enableRemove();
		}
		else {
			this.disableRemove();
		}
		
	}

};

function Dependence(	
	iType,
	oFrom,
	sPattern,
	iLogic,
	bInverse
	) {

	this.iType = iType;
	this.oFrom = oFrom;
	this.sPattern = sPattern;
	this.iLogic = iLogic || Dependence.LOGIC_OR;
	this.bInverse = bInverse || false;

}

Dependence.TYPE_REQUIRE = 1;
Dependence.TYPE_VALID   = 2;
Dependence.TYPE_ENABLE  = 3;
Dependence.TYPE_VALUE   = 4;
Dependence.TYPE_CLASS   = 5;

Dependence.LOGIC_OR  = 1;
Dependence.LOGIC_AND = 2;


/* static creation's methods */

Dependence.createEnableDependence = function(
	oFormWidget,
	sPattern,
	iLogic,
	bInverse
	) {

	return new Dependence(
		Dependence.TYPE_ENABLE,
		oFormWidget,
		sPattern,
		iLogic,
		bInverse
		);

};

Dependence.createRequireDependence = function(
	oFormWidget,
	iLogic,
	iMininum
	) {

	return new DependenceRequire(
		oFormWidget,
		/.+/,
		iLogic,
		false,
		iMininum
		);

};

Dependence.createValidDependence = function(
	oFormWidget,
	sPattern,
	iLogic,
	bInverse
	) {
	
	return new DependenceValid(
		oFormWidget,
		sPattern,
		iLogic,
		bInverse
		);

};

Dependence.createValidEmailDependence = function(oFormWidget) {

	return Dependence.createValidDependence(
		oFormWidget,
		/^[a-zA-Z0-9][a-zA-Z0-9\.\-\_\~]*\@[a-zA-Z0-9\.\-\_]+\.[a-zA-Z]{2,4}$/
		);
	
};

Dependence.createValidDateDependence = function(oFormWidget) {

	return Dependence.createValidDependence(
		oFormWidget,
		/^(\d{4})-(\d{1,2})-(\d{1,2})$/
		);
	
};

Dependence.createValueDependence = function(
	oFormWidget,
	aPatterns
	) {
		
	return new DependenceValue(
		oFormWidget,
		aPatterns
		);
	
};

Dependence.createClassDependence = function(
	oFormWidget,
	aPatternToClasses
	) {

	return new DependenceClass(
		oFormWidget,
		aPatternToClasses
		);
	
};

Dependence.createFunctionDependence = function(
	oFormWidget,
	sType,
	fFunction,
	iLogic,
	bInverse
	) {
	
	return new DependenceFunction(
		oFormWidget,
		sType,
		fFunction,
		iLogic,
		bInverse
		);
		
};

Dependence.prototype = {

	check : function() {			
	
		/*if(!this.oFrom.isEnabled()) {
			return false;
		}*/
		
		if(this.oFrom.isTemplate()) {
			return true;
		}
	
		var bMatched = false;
	
		bMatched = this.oFrom.getValue().match(this.sPattern)? true : false;		
		
		return this.isInverse()? !bMatched : bMatched;
	
	},
	
	getType : function() {
		
		return this.iType;
	
	},
	
	getFrom : function() {
	
		return this.oFrom;
	
	},
	
	getPattern : function() {
	
		return this.sPattern;
	
	},
	
	getLogic : function() {
	
		return this.iLogic;
	
	},
	
	isInverse : function() {
	
		return this.bInverse;
	
	},
	
	clone : function(oFrom) {
		
		return new Dependence(
			this.getType(),
			oFrom,
			this.getPattern(),
			this.getLogic(),
			this.isInverse()
			);
		
	},
	
	getResult : function() {}

};


function DependenceValid(	
	oFrom,
	sPattern,
	iLogic,
	bInverse
	) {
	
	DependenceValid.baseConstructor.call(
		this,
		Dependence.TYPE_VALID,
		oFrom,
		sPattern,
		iLogic,
		bInverse
		);	

}

DependenceValid.inheritFrom(Dependence);

DependenceValid.prototype.check = function() {

	if(this.oFrom.isTemplate()) {
		return true;
	}
	
	if(this.oFrom.getValue().isEmpty()) {
		return !this.bInverse;
	}
	
	return DependenceValid.superClass.check.call(this);	

};

DependenceValid.prototype.clone = function(oFrom) {
		
	return new DependenceValid(		
		oFrom,
		this.getPattern(),
		this.getLogic(),
		this.isInverse()
		);
		
};

function DependenceValue(	
	oFrom,
	aPatterns,
	iLogic,
	bInverse
	) {
	
	DependenceValue.baseConstructor.call(
		this,
		Dependence.TYPE_VALUE,
		oFrom,
		null,
		iLogic,
		bInverse
		);	
		
	this.aPatterns = aPatterns;
	this.aResult = [];

}

DependenceValue.inheritFrom(Dependence);

DependenceValue.prototype.getPatterns = function() {
	
	return this.aPatterns;
	
};

DependenceValue.prototype.check = function() {
	
	if(this.oFrom.isTemplate()) {
		return true;
	}

	this.aResult = [];

	var
		mValue = this.oFrom.getValue(),
		bMatched = false
		;	

	for(var i = 0; i < this.aPatterns.length; i++) {			
	
		bMatched = mValue.isEmpty() && this.aPatterns[i].sSource === null?
			true :
			(mValue.match(this.aPatterns[i].sSource)? true : false)
			;			
		
		if(this.bInverse? !bMatched : bMatched) {
			this.aResult.push(this.aPatterns[i].sDestination);
		}
	
	}
	
	return this.aResult.length > 0;

};

DependenceValue.prototype.getResult = function() {

	return this.aResult;

};

DependenceValue.prototype.clone = function(oFrom) {
		
	return new DependenceValue(		
		oFrom,
		this.getPatterns(),
		this.getLogic(),
		this.isInverse()
		);
		
};

function DependenceRequire(	
	oFrom,
	sPattern,
	iLogic,
	bInverse,
	iMin
	) {
	
	DependenceRequire.baseConstructor.call(
		this,
		Dependence.TYPE_REQUIRE,
		oFrom,
		sPattern,
		iLogic,
		bInverse
		);	
		
	this.iMin = iMin || 1;

}

DependenceRequire.inheritFrom(Dependence);

DependenceRequire.prototype.getMin = function() {
	
	return this.iMin;
	
};

DependenceRequire.prototype.check = function() {

	if(this.oFrom.isTemplate()) {
		return true;
	}
	
	var
		iCountMatched = 0,
		bHasRequiredChild = false,
		bResult = false
		;
		
	if(this.oFrom instanceof InputGroup) {
		for(var i = 0; i < this.oFrom.aChildren.length; i++) {
			if(this.oFrom.aChildren[i].isChecked()) {
				iCountMatched++;
			}
		}
	}
	else if(this.oFrom instanceof FieldContainer &&
		!(this.oFrom instanceof DateInput)
		) {				
		
		for(var i = 0; i < this.oFrom.aChildren.length; i++) {
		
			if(!this.oFrom.aChildren[i].isEnabled()) {
				continue;
			}
			else if(this.oFrom.aChildren[i] instanceof FieldContainer &&
				!(this.oFrom.aChildren[i] instanceof DateInput)) {
				
				if(this.oFrom.aChildren[i].isRequired()) {
					bHasRequiredChild = true;
				}
				else {
				
					var iCountUnrequiredChildren = 0;
					
					if(this.oFrom.aChildren[i] instanceof InputGroup) {

						for(var j = 0; j < this.oFrom.aChildren[i].aChildren.length; j++) {
							if(this.oFrom.aChildren[i].aChildren[j].isChecked()) {
								iCountUnrequiredChildren++;
							}
						}					
						
					}
					else {
						iCountUnrequiredChildren = this.oFrom.aChildren[i].getCountChildrenByPattern(this.sPattern);
					}
					
					if(this.oFrom.aChildren[i] instanceof Multiplicator) {
						iCountMatched += iCountUnrequiredChildren;
					}
					else if (iCountUnrequiredChildren > 0) {
						iCountMatched++;
					}
					
				}				
				
			}
			else if(this.oFrom.aChildren[i].isRequired()) {				
				bHasRequiredChild = true;
			}
			else if(this.oFrom.aChildren[i].getValue().match(this.sPattern)) {
				iCountMatched++;
			}
			
		}
		
	}
	else if(this.oFrom.getValue().match(this.sPattern)) {
		iCountMatched++;
	}		
	
	bResult = !bHasRequiredChild && iCountMatched >= this.iMin;
	
	return this.isInverse()? !bResult : bResult;

};

DependenceRequire.prototype.clone = function(oFrom) {
		
	return new DependenceRequire(		
		oFrom,
		this.getPattern(),
		this.getLogic(),
		this.isInverse(),
		this.getMin()
		);
		
};

function DependenceClass(	
	oFrom,
	aPatternToClasses
	) {
	
	DependenceClass.baseConstructor.call(
		this,
		Dependence.TYPE_CLASS,
		oFrom,
		null,
		Dependence.LOGIC_OR,
		false
		);	
		
	this.aPatternToClasses = aPatternToClasses;
	this.aResult = [];

}

DependenceClass.inheritFrom(Dependence);

DependenceClass.prototype.getPatternToClasses = function() {
	
	return this.aPatternToClasses;
	
};

DependenceClass.prototype.check = function() {
	
	if(this.oFrom.isTemplate()) {
		return true;
	}

	this.aResult = [];

	var
		mValue = this.oFrom.getValue(),
		bMatched = false
		;	

	for(var i = 0; i < this.aPatternToClasses.length; i++) {			
			
		this.aResult.push({
			sClassName : this.aPatternToClasses[i].sClassName,
			bMatched   : mValue.match(this.aPatternToClasses[i].sPattern)? true : false
			});
	
	}
	
	return this.aResult.length > 0;

};

DependenceClass.prototype.clone = function(oFrom) {
		
	return new DependenceClass(		
		oFrom,
		this.getPatternToClasses()
		);
		
};

DependenceClass.prototype.getResult = function() {

	return this.aResult;

};


function DependenceFunction(	
	iType,	
	oFrom,
	fFunction,	
	iLogic,
	bInverse
	) {
	
	DependenceFunction.baseConstructor.call(
		this,
		iType,		
		oFrom,
		null,
		iLogic,
		bInverse
		);	
	
	this.fFunction = fFunction;

}

DependenceFunction.inheritFrom(Dependence);

DependenceFunction.prototype.getFunction = function() {
	
	return this.fFunction;
	
};

DependenceFunction.prototype.check = function() {

	if(this.oFrom.isTemplate()) {
		return true;
	}
	
	var bMatched = false;
	
	bMatched = this.fFunction(this.oFrom);		
		
	return this.isInverse()? !bMatched : bMatched;

};

DependenceFunction.prototype.clone = function(oFrom) {
		
	return new DependenceFunction(
		this.getType(),
		oFrom,
		this.getFunction(),
		this.getLogic(),
		this.isInverse()
		);
		
};

function DependenceGroup(iType) {

	this.iType = iType;	
	this.aDependencies = [];

}

DependenceGroup.prototype = {

	getType : function() {
	
		return this.iType;
	
	},

	addDependence : function(oDependence) {
	
		this.aDependencies.push(oDependence);
	
	},
	
	removeDependence : function(oDependence) {
		
		this.aDependencies.remove(oDependence);
	
	},
	
	getDependencies : function() {
		
		return this.aDependencies;
		
	},
	
	check : function() {
	
		var
			bSkip = false,
			bResult = this.aDependencies.length == 0,
			bDependenceCheckResult = false;
			;
		
		for(var i = 0; i < this.aDependencies.length && !bSkip; i++) {
		
			bDependenceCheckResult = this.aDependencies[i].check();
			
			if(bDependenceCheckResult &&
				this.aDependencies[i].getLogic() == Dependence.LOGIC_OR) {
				
				bResult = true;
				bSkip = true;
				
			}
			else if(!bDependenceCheckResult &&
				this.aDependencies[i].getLogic() == Dependence.LOGIC_AND) {
			
				bResult = false;
				bSkip = true;
			
			}
			else {			
				bResult = bDependenceCheckResult;				
			}
			
		}
		
		return bResult;
	
	},

	getResult : function() {
	
		var aResult = [];		
		
		for(var i = 0; i < this.aDependencies.length; i++) {			
			aResult = aResult.concat(this.aDependencies[i].getResult());			
		}
		
		if(aResult.length == 0
			&& this.getType() == Dependence.TYPE_VALUE
			) {
			return [/^.*$/];
		}
		
		return aResult;
	
	}
	
};

function DependenceProcessor(oFormWidget) {

	this.oFormWidget = oFormWidget;	
	this.aDependenceGroups = [];	
	
	this.aCheckingOrder = [
		Dependence.TYPE_ENABLE,
		Dependence.TYPE_VALID,
		Dependence.TYPE_REQUIRE,
		Dependence.TYPE_VALUE,
		Dependence.TYPE_CLASS
		];

}

DependenceProcessor.prototype = {
	
	addDependence : function(oDependence) {				
		
		if(!this.hasDependenciesByType(oDependence.getType())) {			
			this.aDependenceGroups[oDependence.getType()] = new DependenceGroup(oDependence.getType());			
		}
	
		this.aDependenceGroups[oDependence.getType()].addDependence(oDependence);
	
	},
	
	removeDependence : function(oDependence) {
		
		this.aDependenceGroups[oDependence.getType()].removeDependence(oDependence);
		
	},
	
	getDependencies : function() {
		
		var aResult = [];

		for(var i = 0; i < this.aCheckingOrder.length; i++) {
			
			if(!this.hasDependenciesByType(this.aCheckingOrder[i])) {
				continue;
			}
			
			aResult = aResult.concat(this.aDependenceGroups[this.aCheckingOrder[i]].getDependencies());
			
		}
		
		return aResult;
		
	},
	
	hasDependenciesByType : function(iType) {
		
		return this.aDependenceGroups[iType]? true : false;
		
	},
	
	process : function() {
		
		if(this.oFormWidget.isTemplate()) {
			return;
		}					
		
		for(var i = 0; i < this.aCheckingOrder.length; i++) {							
			this.dispatchProcessDependencies(this.aCheckingOrder[i]);			
		}
	
	},
	
	dispatchProcessDependencies : function(sType) {
		
		if(!this.hasDependenciesByType(sType)) {
			return;
		}
			
		switch(sType) {
			
			case Dependence.TYPE_ENABLE: 
				this.processEnableDependencies();
			break;
				
			case Dependence.TYPE_VALID:
				this.processValidDependencies();
			break;
				
			case Dependence.TYPE_REQUIRE:
				this.processRequireDependencies();
			break;
				
			case Dependence.TYPE_VALUE:
				this.processValueDependencies();
			break;
				
			case Dependence.TYPE_CLASS:
				this.processClassDependencies();
			break;

			default:
			break;
				
		}							
		
	},
	
	processEnableDependencies : function() {
		
		if(this.aDependenceGroups[Dependence.TYPE_ENABLE].check()) {
			this.oFormWidget.enable();						
		}
		else {
			this.oFormWidget.disable();
		}
		
	},
	
	processValidDependencies : function() {			
		
		if(this.aDependenceGroups[Dependence.TYPE_VALID].check()) {
			this.oFormWidget.setValid();
		}
		else {
			this.oFormWidget.setInvalid();
		}
		
	},
	
	processRequireDependencies : function() {
			
		if(this.aDependenceGroups[Dependence.TYPE_REQUIRE].check() && this.oFormWidget.isValid()) {												
			this.oFormWidget.unsetRequired();
		}
		else {						
			this.oFormWidget.setRequired();
		}
		
	},
	
	processValueDependencies : function() {
		
		var
			bCheckResult = this.aDependenceGroups[Dependence.TYPE_VALUE].check(),
			aClasses = this.aDependenceGroups[Dependence.TYPE_VALUE].getResult()
			;
		
		if(bCheckResult &&
			aClasses.length == 0
			) {
			return;
		}										
					
		this.oFormWidget.enableChildrenByValue(aClasses);
		
	},
	
	processClassDependencies : function() {
		
		var
			bCheckResult = this.aDependenceGroups[Dependence.TYPE_CLASS].check(),
			aClasses = this.aDependenceGroups[Dependence.TYPE_CLASS].getResult()
			;
		
		if(bCheckResult &&
			aClasses.length == 0
			) {
			return;
		}

		for(var i = 0; i < aClasses.length; i++) {
						
			if(aClasses[i].bMatched) {
				this.oFormWidget.addClass(aClasses[i].sClassName);
			}
			else {
				this.oFormWidget.removeClass(aClasses[i].sClassName);
			}
					
		}	
		
	}

};

var Resources = {

	sLanguage : (document.documentElement.lang? document.documentElement.getAttribute('lang') : 'ru'),

	aMonths : {		
		ru : {
			'normal'   : ['январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'],
			'genitive' : ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
		},
		en : {
			'normal'   : ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'],
			'genitive' : ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december']
		}
	},
	
	getMonthsByType : function(sType) {
	
		return this.aMonths[this.sLanguage][sType];
	
	}

};

function FormBuilder(aForm) {

	this.aElementsByName = [];	
	this.aTemplates = [];
	this.oForm = null;

	this.build(aForm);
	this.fillElements();
	this.addDependencies(aForm);
	
	this.oForm.init();
	
}

FormBuilder.prototype = {
	
	getForm : function() {
		
		return this.oForm;
		
	},

	build : function(aForm) {			
		
		for(var i = 0; i < aForm.length; i++) {				
			
			this.createWidgetByObject(aForm[i].sID, aForm[i]);						
			
		}
	
	},
	
	createWidgetByObject : function(sId, oObject) {
		
		if(oObject.oRepeat) {			
			this.makeMultiplicator(sId, oObject);			
		}
		
		var bTemplate = oObject.sType == 'form'?
			false :
			(
				(oObject.oRepeat && oObject.oRepeat.bTemplate) ||
				this.getElementById(this.getParentId(oObject)).isTemplate()
			)
			;
		
		switch(oObject.sType) {
		
			case 'form':				
				return this.makeForm(sId, oObject);			
			break;
					
			case 'fieldset':
				
				if(oObject.oSheet) {
					return this.makeSheet(sId, oObject, bTemplate);
				}
				else {
					return this.makeFieldContainer(sId, oObject, bTemplate);
				}
			
			break;
			
			case 'text':				
			case 'textarea':
			case 'file':
			case 'email':
			case 'phone':
				return this.makeTextInput(sId, oObject, bTemplate);
			break;
				
			case 'number':
				return this.makeNumberInput(sId, oObject, bTemplate);
			break;
				
			case 'date':
				return this.makeDateInput(sId, oObject, bTemplate);			
			break;
				
			case 'select':				
				return this.makeSelectInput(sId, oObject, bTemplate);
			break;								
				
			case 'checkbox':				
				return this.makeCheckBoxGroup(sId, oObject, bTemplate);
			break;
				
			case 'radio':								
				return this.makeRadioButtonGroup(sId, oObject, bTemplate);
			break;
				
			case 'submit':				
				return this.makeSubmitButton(sId, oObject, bTemplate);
			break;				

			default:
			break;
		
		}
		
	},
	
	makeMultiplicator : function(sId, oObject) {				
		
		var oMultiplicator = this.getElementById(oObject.oRepeat.sID + Multiplicator.POSTFIX_ID);
		
		if(oMultiplicator) {			
			return oMultiplicator;
		}
		
		return this.getElementById(oObject.sParent_ID).addChild(
			new Multiplicator(
				document.getElementById(oObject.oRepeat.sID),
				document.getElementById(oObject.sParent_ID),
				{
					sButtonAddId    : oObject.oRepeat.sAppend_ID,
					sButtonRemoveId : oObject.oRepeat.sRemove_ID,
					iMin            : oObject.oRepeat.iMin,
					iMax            : oObject.oRepeat.iMax
				}
				)
			);
				
	},

	makeForm : function(sId, oObject) {
		
		this.oForm = new Form(
			document.getElementById(sId),
			document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
			oObject.oSubmit? oObject.oSubmit.bDisabled_button : true,
			oObject.oSubmit? oObject.oSubmit.bValid : false
			);
		
	},
		
	makeFieldContainer : function(sId, oObject, bTemplate) {			
		
		return this.addChild(
			new FieldContainer(
				document.getElementById(sId),
				document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
				bTemplate
				),
			sId,
			oObject
			);		
	
	},
	
	makeSheet : function(sId, oObject, bTemplate) {
		
		if(!this.getElementById(oObject.sParent_ID + SheetContainer.POSTFIX_ID)) {
			
			this.addChild(
				new SheetContainer(document.getElementById(oObject.sParent_ID)),
				sId,
				oObject
				);
		}			
		
		if(oObject.oSheet.sLegend_ID &&
			oObject.oSheet.sParent_ID) {
			this.makeTab(
				oObject.oSheet.sLegend_ID,				
				oObject.oSheet.sParent_ID
				);
		}
		
		var oSheet = new Sheet(
			document.getElementById(sId),
			document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
			bTemplate,			
			oObject.oSheet.bSelected
			);			
			
		if(oObject.oSheet.sLegend_ID) {
			oSheet.addLegendButton(new Button(document.getElementById(oObject.oSheet.sLegend_ID)));
		}
			
		if(oObject.oSheet.sPrev_ID) {
			oSheet.addPrevButton(new Button(document.getElementById(oObject.oSheet.sPrev_ID)));
		}
				
		if(oObject.oSheet.sNext_ID) {
			oSheet.addNextButton(new Button(document.getElementById(oObject.oSheet.sNext_ID)));
		}		
		
		return this.addChild(
			oSheet,
			sId,
			oObject
			);					
	
	},
	
	makeTextInput : function(sId, oObject, bTemplate) {
		
		return this.addChild(
			new TextInput(
				document.getElementById(sId),
				document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
				bTemplate
				),
			sId,
			oObject
			);		
	},
	
	makeNumberInput : function(sId, oObject, bTemplate) {
	
		if(oObject.oSlider) {
			
			if(oObject.oSlider.sType == 'vertical') {				
				return this.addChild(
					SliderInput.createVerticalSlider(
						document.getElementById(sId),
						document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
						bTemplate,
						{
								dMin : (oObject.oValid && oObject.oValid.mMin? oObject.oValid.mMin : 0),
								dMax : (oObject.oValid && oObject.oValid.mMax? oObject.oValid.mMax : 100),
								dStep : (oObject.oValid && oObject.oValid.mStep? oObject.oValid.mStep : 1)
						}
						),
					sId,
					oObject
					);
			}
			else {
				return this.addChild(
					SliderInput.createHorizontalSlider(
						document.getElementById(sId),
						document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
						bTemplate,
						{
								dMin : (oObject.oValid && oObject.oValid.mMin? oObject.oValid.mMin : 0),
								dMax : (oObject.oValid && oObject.oValid.mMax? oObject.oValid.mMax : 100),
								dStep : (oObject.oValid && oObject.oValid.mStep? oObject.oValid.mStep : 1)
						}
						),
					sId,
					oObject
					);
			}
			
		}
		else {
			return this.addChild(
				new NumberInput(
					document.getElementById(sId),
					document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
					bTemplate
					),
				sId,
				oObject
				);
		}
	
	},
	
	makeDateInput : function(sId, oObject, bTemplate) {
	
		return this.addChild(
			new DateInput(
				document.getElementById(sId),
				document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
				bTemplate
				),
			sId,
			oObject
			);
	
	},
	
	makeSelectInput : function(sId, oObject, bTemplate) {
	
		return this.addChild(
			new SelectInput(
				document.getElementById(sId),
				document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
				bTemplate
				),
			sId,
			oObject
			);
	
	},
	
	makeCheckBoxGroup : function(sId, oObject, bTemplate) {
		
		var oCheckBoxGroup = new CheckBoxGroup(
			document.getElementById(sId),
			document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
			bTemplate
			);				
		
		for(var i = 0; i < oObject.asOption_ID.length; i++) {		
			oCheckBoxGroup.addChild(new CheckBox(document.getElementById(oObject.asOption_ID[i][0]), document.getElementById(oObject.asOption_ID[i][1]), false));
		}
		
		return this.addChild(
			oCheckBoxGroup,
			sId,
			oObject
			);
	
	},
	
	makeRadioButtonGroup : function(sId, oObject, bTemplate) {
	
		var oRadioButtonGroup = new RadioButtonGroup(
			document.getElementById(sId),
			document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId),
			bTemplate
			);
		
		for(var i = 0; i < oObject.asOption_ID.length; i++) {		
			oRadioButtonGroup.addChild(new RadioButton(document.getElementById(oObject.asOption_ID[i][0]), document.getElementById(oObject.asOption_ID[i][1]), false));	
		}
		
		return this.addChild(
			oRadioButtonGroup,
			sId,
			oObject
			);
	
	},
	
	makeSubmitButton : function(sId, oObject, bTemplate) {			
	
		return this.addChild(
			new SubmitButton(
				document.getElementById(sId),
				document.getElementById(oObject.sRow_ID? oObject.sRow_ID : sId)
				),
			sId,
			oObject
			);
	
	},
	
	makeTab : function(
		sLegendId,		
		sTabsContainerId
		) {
			
		var			
			oTabsContainerNode = document.getElementById(sTabsContainerId + '_tabs'),
			oTabNode = document.getElementById(sLegendId)
			;
		
		if(!oTabsContainerNode) {									
			
			var oParentNode = document.getElementById(sTabsContainerId);
			
			oTabsContainerNode = oParentNode.insertBefore(document.createElement('div'), oParentNode.firstChild);	
			
			oTabsContainerNode.id = sTabsContainerId + '_tabs';	
			Common.Class.add(oTabsContainerNode, 'tabs');
			
		}
		
		oTabsContainerNode.appendChild(oTabNode.parentNode.removeChild(oTabNode));
		
	},
	
	addChild : function(
		oChild,
		sId,
		oObject
		) {
		
		var oParent = this.getElementById(this.getParentId(oObject));
		
		if(oObject.oRepeat &&
			oObject.oRepeat.bTemplate &&
			oParent instanceof Multiplicator
			) {
				
			this.addTemplate(oChild);			
			
			return oParent.addTemplate(oChild);			
			
		}		
		else if(oChild.isTemplate()) {
			this.addTemplate(oChild);
		}
		
		return oParent.addChild(oChild);
		
	},
	
	addTemplate : function(oTemplate) {
		
		this.aTemplates[oTemplate.getId()] = oTemplate;
		
	},
	
	getParentId : function(oObject) {
		
		if(oObject.oRepeat) {
			return oObject.oRepeat.sID + Multiplicator.POSTFIX_ID;
		}
		
		if(oObject.oSheet &&
			this.getElementById(oObject.sParent_ID + SheetContainer.POSTFIX_ID)) {
			return oObject.sParent_ID + SheetContainer.POSTFIX_ID;
		}
		
		return oObject.sParent_ID;
		
	},
	
	fillElements : function(oElement) {
	
		var oElement = oElement || this.oForm;
		
		if(oElement.oElement.name) {		
			this.aElementsByName[oElement.oElement.name] = oElement;
		}
		
		if(oElement instanceof InputGroup) {
			this.aElementsByName[oElement.aChildren[0].oElement.name] = oElement;
		}
		else if(oElement instanceof FieldContainer) {
			
			for(var i = 0; i < oElement.aChildren.length; i++) {
				this.fillElements(oElement.aChildren[i]);
			}
			
			if(oElement.oTemplate) {				
				this.fillElements(oElement.oTemplate);
			}
			
		}
	
	},
	
	getElementById : function(sId) {
		
		var oElement = this.oForm.getWidgetById(sId) ||
			this.getTemplateById(sId)
			;
		
		return oElement;
		
	},
	
	getElementByName : function(sName) {
	
		return this.aElementsByName[sName];
	
	},		
	
	getTemplateById : function(sId) {
		
		return this.aTemplates[sId];
		
	},
	
	addDependencies : function(aForm) {
	
		for(var i = 0; i < aForm.length; i++) {
			
			if(aForm[i].oValid) {			
				if(aForm[i].oValid.mData) {
					this.makeValidDependence(aForm[i].sID, aForm[i].oValid);
				}
			}
			
			if(aForm[i].sType == 'email') {			
				this.makeEmailDependence(aForm[i].sID);			
			}
			
			if(aForm[i].sType == 'date') {			
				this.makeDateDependence(aForm[i].sID);			
			}
			
			if(aForm[i].oRequired) {			
				this.makeRequireDependence(aForm[i].sID, aForm[i].oRequired);			
			}
			
			if(aForm[i].oDepended) {
			
				if(aForm[i].oDepended.bOptions) {
					this.makeValueDependence(aForm[i].sID, aForm[i].oDepended);
				}
				else {
					this.makeEnableDependence(aForm[i].sID, aForm[i].oDepended);
				}
			
			}
			
			if(aForm[i].oClass) {				
				this.makeClassDependence(aForm[i].sID, aForm[i].oClass);
			}
	
		}
	
	},
	
	makeRequireDependence : function(sId, oRequired) {			
	
		var
			oElement = this.getElementById(sId),
			iLogic = (oRequired.sLogic == 'or'? Dependence.LOGIC_OR : Dependence.LOGIC_AND)
			;
		
		oElement.addDependence(Dependence.createRequireDependence(oElement, iLogic, oRequired.iMin? oRequired.iMin : 1));
		
		if(oRequired.aFrom) {
			for(var i = 0; i < oRequired.aFrom.length; i++) {								
				oElement.addDependence(new DependenceRequire(this.getElementByName(oRequired.aFrom[i].sName), oRequired.aFrom[i].mData || /.+/, iLogic, oRequired.aFrom[i].bInverse? false : true, oRequired.iMin? oRequired.iMin : 1));
			}
		}
	
	},
	
	makeValidDependence : function(sId, oValid) {

		var oElement = this.getElementById(sId);
	
		if(oValid.mData instanceof Function) {
			oElement.addDependence(Dependence.createFunctionDependence(Dependence.TYPE_VALID, oElement, oDepended.aFrom.mData, Dependence.LOGIC_OR, oValid.bInverse? true : false));
		}
		else {
			oElement.addDependence(Dependence.createValidDependence(oElement, oValid.mData, Dependence.LOGIC_OR, oValid.bInverse? true : false));
		}
	
	},
	
	makeEmailDependence : function(sId) {

		var oElement = this.getElementById(sId);
	
		oElement.addDependence(Dependence.createValidEmailDependence(oElement));
	
	},
	
	makeDateDependence : function(sId) {

		var oElement = this.getElementById(sId);
	
		oElement.addDependence(Dependence.createValidDateDependence(oElement));
	
	},
	
	makeEnableDependence : function(sId, oDepended) {
		
		var oElement = this.getElementById(sId);
				
		for(var i = 0; i < oDepended.aFrom.length; i++) {
			
			if(oDepended.aFrom[i].mData instanceof Function) {
				oElement.addDependence(Dependence.createFunctionDependence(Dependence.TYPE_ENABLE, this.getElementByName(oDepended.aFrom[i].sName), oDepended.aFrom[i].mData, oDepended.sLogic == 'or'? Dependence.LOGIC_OR : Dependence.LOGIC_AND, oDepended.aFrom[i].bInverse? true : false));
			}
			else {
				oElement.addDependence(Dependence.createEnableDependence(this.getElementByName(oDepended.aFrom[i].sName), oDepended.aFrom[i].mData || /.+/, oDepended.sLogic == 'or'? Dependence.LOGIC_OR : Dependence.LOGIC_AND, oDepended.aFrom[i].bInverse? true : false));
			}
			
		}
	
	},
	
	makeValueDependence : function(sId, oDepended) {
	
		var
			oElement = this.getElementById(sId),
			aPatterns = []
			;

		for(var i = 0; i < oDepended.aFrom.length; i++) {		
		
			aPatterns = [];
		
			for(var j = 0; j < oDepended.aFrom[i].mData.length; j++) {
				
				aPatterns.push({
					sSource      : (oDepended.aFrom[i].mData[j][0] instanceof RegExp || oDepended.aFrom[i].mData[j][0] === null)? oDepended.aFrom[i].mData[j][0] : new RegExp('^' + oDepended.aFrom[i].mData[j][0] + '$'),
					sDestination : (oDepended.aFrom[i].mData[j][1] instanceof RegExp)? oDepended.aFrom[i].mData[j][1] : new RegExp('^' + oDepended.aFrom[i].mData[j][1] + '$')
					}
					);
			}			
			
			oElement.addDependence(Dependence.createValueDependence(this.getElementByName(oDepended.aFrom[i].sName), aPatterns));
		
		}						
	
	},
	
	makeClassDependence : function(sId, oClass) {
		
		var
			oElement = this.getElementById(sId),
			aPatternToClasses = []
			;
			
		for(var i = 0; i < oClass.aFrom.length; i++) {								
			
			aPatternToClasses = [];
			
			for(var j = 0; j < oClass.aFrom[i].mData.length; j++) {
				
				aPatternToClasses.push({
					sPattern   : (oClass.aFrom[i].mData[j][0] instanceof RegExp)? oClass.aFrom[i].mData[j][0] : new RegExp('^' + oClass.aFrom[i].mData[j][0] + '$'),
					sClassName : oClass.aFrom[i].mData[j][1]
					});
					
				oElement.addDependence(Dependence.createClassDependence(this.getElementByName(oClass.aFrom[i].sName), aPatternToClasses));
			
			}
			
		}
		
	}

};

