(function($) {

	$.geoEdit = {
		 FCKeditorInstance : [],								
		 toggle : function (button) {       
			var aOwner = getOwnerHandler(button);

			var FCKeditorInstanceIndex = -1;
			// Cerca se era gia' stato cambiato il nome interno
			for(var i=0; i < $.geoEdit.FCKeditorInstance.length; i++) {
				if ($.geoEdit.FCKeditorInstance[i].button == button) {
					FCKeditorInstanceIndex = i} 
			}
			if (FCKeditorInstanceIndex == -1) {alert ('Not found FCKeditor wrapper')}
			var wrapper = $.geoEdit.FCKeditorInstance[FCKeditorInstanceIndex];	


			// Try to get the FCKeditor instance, if available.
			var oEditor ;
			if ( typeof( FCKeditorAPI ) != 'undefined' )
				oEditor = FCKeditorAPI.GetInstance( wrapper.dataFCKeditor.id) ;

			// If the _Textarea DIV is visible, switch to FCKeditor.
			if ( wrapper.dataTextarea.style.display != 'none' ) {
				// If it is the first time, create the editor.
				if ( !oEditor ) {

					jQuery.geoEdit.createEditor(wrapper) ;
				}
				

				// Switch the DIVs display.
				wrapper.dataTextarea.style.display = 'none' ;
				wrapper.divFCKeditor.style.display = '' ;

				// This is a hack for Gecko 1.0.x ... it stops editing when the editor is hidden.
				if ( oEditor && !document.all ) {
					if ( oEditor.EditMode == FCK_EDITMODE_WYSIWYG )
						oEditor.MakeEditable() ;
				}
			}
			else {

				// Set the textarea value to the editor value.
				wrapper.dataTextarea.value = oEditor.GetXHTML() ;
				// Switch the DIVs display.
				wrapper.dataTextarea.style.display = '' ;
				wrapper.divFCKeditor.style.display = 'none' ;

				if (!aOwner.owner._modified) {aOwner.owner._modified = new Object()}
				var aElementName = aOwner.owner.nameFromThisInputElement(wrapper.dataTextarea);
				aOwner.owner._modified[aElementName] = wrapper.dataTextarea.value;

			}
				
		},	
		
		 createEditor : function (wrapper) {


			// Copy the value of the current textarea, to the textarea that will be used by the editor.
			wrapper.dataFCKeditor.value = wrapper.dataTextarea.value ;

			// Automatically calculates the editor base path based on the _samples directory.
			// This is usefull only for these samples. A real application should use something like this:
			// oFCKeditor.BasePath = '/fckeditor/' ;	// '/fckeditor/' is the default value.


			var sBasePath = '/components/fckeditor/2.6/' ;		
			

			// Create an instance of FCKeditor (using the target textarea as the name).
			var oFCKeditor = new FCKeditor( wrapper.dataFCKeditor.id ) ;

			oFCKeditor.BasePath = sBasePath ;
			oFCKeditor.Width = '95%' ;
			oFCKeditor.Height = '700' ;
								
			oFCKeditor.ReplaceTextarea() ; 			
		}

	};
})(jQuery);


jQuery.fn.GeoEditorCreateWrapper = function(obj) {
		var newWrapper = new Object();
		newWrapper.dataTextarea = obj;		
		newWrapper.button = jQuery(obj).prev().get(0);				
		newWrapper.divFCKeditor = jQuery(obj).next().get(0);			
		newWrapper.dataFCKeditor = jQuery(obj).next().children(0).get(0);					
		$.geoEdit.FCKeditorInstance.push(newWrapper);
		var FCKeditorInstanceIndex = $.geoEdit.FCKeditorInstance.length-1;
		newWrapper.myPosition = FCKeditorInstanceIndex;
		newWrapper.dataFCKeditor.id = newWrapper.dataFCKeditor.id+FCKeditorInstanceIndex;
		newWrapper.id = obj.id;
		return obj;

};


jQuery.fn.GeoEditor = function(a) {
	for ( var i = 0, ol = this.length; i < ol; i++ )
	{	var obj = this[i];
	
		jQuery(obj)
		.before(jQuery('<button type="button" class="enableEditor"/>')
		.bind('click', function(){
			jQuery.geoEdit.toggle(this);
			}));
		jQuery(obj)
		.after(jQuery('	<div id="_FCKeditor" style="display: none"><textarea id="_DataFCKeditor" cols="80" rows="20"></textarea></div>'))
		.GeoEditorCreateWrapper(obj);	
	}
	return this;
};


jQuery.fn.GeoSetButton = function(a) {
	for ( var i = 0, ol = this.length; i < ol; i++ ) {
		var aButton = this[i];
		switch (aButton.className) 	{
				case 'modifica':
				jQuery(aButton).bind("handlingEdit", function(event) {
		    		toggleStandardButton(this);});
				break;
	
				case 'cancella':
				jQuery(aButton).bind("handlingEdit", function(event) {
		    		toggleStandardButton(this);});

				break;
	
				case 'salva':
				jQuery(aButton).bind("handlingEdit", function(event) {
		    		toggleStandardButton(this);});
				break;
	
				case 'annulla':
				jQuery(aButton).bind("handlingEdit", function(event) {
		    		toggleStandardButton(this);});
				break;

				case 'enableEditor':
				jQuery(aButton).bind("handlingEdit", function(event) {
		    		toggleEditor(this);});
				break;
				case 'spedisci':
				jQuery(aButton).bind("handlingEdit", function(event) {
		    		return this});
				break;

				default : 
				jQuery(aButton).bind("handlingEdit", function(event) {
				toggleDisablig(this);});
		    		break;
		}
	}
	return this;
};






/* Queste sono tutte le funzioni utilizzate dal sistema di Editing Client Side di Geode 
*/



// Returns the serialized XML string for the specified DOM node.
function xml2Objects(node, aStack) {
  if (node == null) {alert("xml2Objects: node is null"); return;}
  if (typeof(node.nodeType) == "undefined") {alert("xml2Objects: node is not a DOM node"); return;} 
  
  switch (node.nodeType) {
    case 1: // Element
      var aParent = aStack[aStack.length - 1];   
      var newElement =  aParent.getObjElement (node.tagName );
      
      if (newElement != null ) { 
      	aStack.push(newElement.addChild()) 
      }  
    
      var xml = "<" + node.tagName;
      var content = "";
      
      for (var i = 0; i < node.attributes.length; ++i) {
        var attribute = node.attributes[i];
        
        // Opera can have null attributes.
        if (attribute == null) {
          continue;
        }
        
        if (attribute.specified) {
          xml += xml2Objects(attribute, aStack);
        }
      }
      
      if (node.hasChildNodes()) {
        xml += ">";
      
        for (var child = node.firstChild; child != null; child = child.nextSibling) {
          content = xml2Objects(child, aStack);
          xml += content;          
        }
        
        xml += "</" + node.tagName + ">";
      }
      else {
        xml += "/>";
      }
      
      if (newElement != null ) { 
		newElement.setValue(content, xml );      
		aStack.pop()
	}
	
      
      return xml;
      
    case 2: // Attribute
      // Namespace node.
      if (node.name.match(/^xmlns(:|$)/) ) {
        return "";
      }
      
      var name  = node.name;
      var value = node.value.replace(/&/g, "&amp;")
                            .replace(/"/g, "&quot;")
                            .replace(/</g, "&lt;")
                            .replace(/>/g, "&gt;");

        
      return " " + name + '="' + value + '"';
      
    case 3: // Text
        return node.data.replace(/&/g, "&amp;")
                        .replace(/"/g, "&quot;")        
                        .replace(/</g, "&lt;")
                        .replace(/>/g, "&gt;");

      
    case 4: // CDATA section
      return "<![CDATA[" + node.data.replace(/]]>/g, "]]]]><![CDATA[>") + "]]>";
      
    case 7: // Processing instruction
      return "<?" + node.target + " " + node.data + "?>";
      
    case 8: // Comment
      return "<!--" + node.data + "-->";  
      
    case 9: // Document
      var xml = "";
      for (var child = node.firstChild; child != null; child = child.nextSibling) {
        xml += xml2Objects(child, aStack) + "\n";
      }
      
      return xml;
      
    case 10: // Document type
      var xml = "<!DOCTYPE " + node.name + ' PUBLIC "' + node.publicId + '" "' + node.systemId + '" [\n';
      
      xml += "]>";
      
      return xml;
      
    case 11: // Document fragment
      var xml = "";
    
      for (var child = node.firstChild; child != null; child = child.nextSibling) {
        xml += xml2Objects(child, aStack);
      }
      
      return xml;
      
    default:
      alert("xml2Objects - Unsupported node: " + node.nodeName + " (" + node.nodeType + ")"); 
      
  }
}



function getOwnerHandler(obj) {
	if ((obj != null) && (obj.nodeType == 1)) {
		if ((obj.id.indexOf('GeoRow')==0) || (obj.id.indexOf('GeoHeader')==0) || (obj.id.indexOf('GeoGroup')==0)) {
			return obj;
		}
	        var ret = getOwnerHandler(obj.parentNode);
		if (ret != null) {return ret;}
	}
	return null;

}

function setOwnerInstance(obj, owner) {
	if (obj.id.indexOf('GeoGroup')== -1) {Alert('Set Proxy non su GeoGroup')}
	var proxy = new dataTypeProxy(obj, owner, obj);
	obj.owner = proxy;
	return proxy;
}


function stringOfChar(chr, cnt) {
	var tmp = '';
	for (var i=0; i<cnt; i++) {
		tmp += chr; }
	return tmp;
}

// datetime parsing and formatting routimes. modify them if you wish other datetime format
function str2dt (str_datetime) {
	var re_date = /(\d+)\-(\d+)\-(\d+)\T(\d+)\:(\d+)\:(\d+)\.(\d+)/;
	if (!re_date.exec(str_datetime))
		return alert("Invalid Datetime format: "+ str_datetime);
	return (new Date (RegExp.$1, RegExp.$2-1, RegExp.$3, RegExp.$4, RegExp.$5, RegExp.$6));
}

function spanDigits(asrc) {
	var src = new String(asrc);
	if (src.length == 1) return "0" + src;
	else return src;
}


function time2xml (aDateTime) {
	return (new String (
			spanDigits(aDateTime.getHours())+":"+spanDigits(aDateTime.getMinutes())+":"+spanDigits(aDateTime.getSeconds())+".000"));
}

function dateTime2xml(aDateTime) {
	return (new String (
			aDateTime.getFullYear()+"-"+spanDigits(aDateTime.getMonth()+1)+"-"+spanDigits(aDateTime.getDate())+"T"+time2xml ()));
}

function date2xml(aDateTime) {
	return (new String (
			aDateTime.getFullYear()+"-"+spanDigits(aDateTime.getMonth()+1)+"-"+spanDigits(aDateTime.getDate())+"T00:00:00.000"));
}



function date2string(aDateTime) {
	return (new String (spanDigits(aDateTime.getDate())+ "/" + spanDigits(aDateTime.getMonth()+1) + "/" + aDateTime.getFullYear()));
}

function string2date(aDate) {
  	    var dt = new Date();
	    var TimeArray = aDate.split("/");
	    dt.setUTCFullYear(TimeArray[2],TimeArray[1]-1,TimeArray[0]);
	    return dt;
}

function xml2date(xmlDate) {
  	    var dt = new Date();
            var dtS = xmlDate.slice(xmlDate.indexOf('T')+1, xmlDate.indexOf('.'))
	    var TimeArray = dtS.split(":");
	    dt.setUTCHours(TimeArray[0],TimeArray[1],TimeArray[2]);
	    dtS = xmlDate.slice(0, xmlDate.indexOf('T'))
	    TimeArray = dtS.split("-");
	    dt.setUTCFullYear(TimeArray[0],TimeArray[1]-1,TimeArray[2]);
	    return dt;
}

function _element() {return this._element;}
function _string2xml(level)  {
                 var ret = stringOfChar('\t',level) + '<' + this._element + '>';    
                 ret += this._obj;
                 ret += '</' + this._element + '>\n';
                 return   ret; 
}


function _string2encodedXml(level)  {
                 var ret = stringOfChar('\t',level) + '<' + this._element + '>';    
                 ret += $.geoKarma.string2xml(this._obj);
                 ret += '</' + this._element + '>\n';
                 return   ret; 
}

function _string2value() {return this._obj;}				
function _value2string(str, xml) 
	{this._obj = new String(str)}
	
function _encodedValue2String(str, xml) 
	{this._obj = new String($.geoKarma.xml2string( str))}
	
function _array2xml(level)  {
		var ret = '';
		if (this._obj.length > 0) {
			ret = stringOfChar('\t',level) + '<' + this._element + '>';    
			for (var i=0; i<this._obj.length; i++) {
				ret += this._obj[i].toXML(level+1);
			}
                 	ret += '</' + this._element + '>\n';			
		}	
		return ret;
}

function _complex2value() {return null;}				
function _value2complex(str, xml) {}
function _returnSelf() {return this;}
function _removeChild(aChild) {
	for (var i = 0; i <this._obj.length; i++) {
	    if (this._obj[i] == aChild) {
	        this._obj.splice(i,1);
	    } 
	}
}

function _complexGetObjElement(aName) {
        var ret = this[aName];
        return ret;
}


function _arrayGetObjElement(aName) {
        /* Sarebbe meglio controllare se quello richiesto sia quello che sto creando */
	if (this.createChild == null) {alert('Non definito il costruttore del figlio')}
	var ret = this.createChild();
	this._obj.push(ret);
	return ret;
}

function _xmlrawGetObjElement(aName) {
        /* Passa se stesso in quanto deve accumulare i valori che gli passano */
	return this;
}

function _xmlrawRemoveChild(aChild) {
}

function _value2xmlraw(str, xml) {
	if ((!xml) || (xml=='')) {this._obj = new String(str)} else {this._obj = new String(xml)} 
}



function dataTypeInitialize () {
	new dataTypeString(null, null);
	dataTypeString.prototype.toXML = _string2encodedXml;
	dataTypeString.prototype.getValue = _string2value;				
	dataTypeString.prototype.setValue = _encodedValue2String;
        dataTypeString.prototype.addChild = _returnSelf;			


	new dataTypeNumber(null, null);
	dataTypeNumber.prototype.toXML = _string2xml;
	dataTypeNumber.prototype.getValue = _string2value;				
	dataTypeNumber.prototype.setValue = _value2string;
        dataTypeNumber.prototype.addChild = _returnSelf;			


	new dataTypeDecimal(null, null);
	dataTypeDecimal.prototype.toXML = _string2xml;
	dataTypeDecimal.prototype.getValue = _string2value;				
	dataTypeDecimal.prototype.setValue = _value2string;
        dataTypeDecimal.prototype.addChild = _returnSelf;			


	new dataTypeDateTime(null, null);
	dataTypeDateTime.prototype.toXML = _string2xml;
	dataTypeDateTime.prototype.getValue = _string2value;				
	dataTypeDateTime.prototype.setValue = _value2string;
        dataTypeDateTime.prototype.addChild = _returnSelf;			


	new dataTypeDate(null, null);
	dataTypeDate.prototype.toXML = _string2xml;
	dataTypeDate.prototype.getValue = _string2value;				
	dataTypeDate.prototype.setValue = _value2string;
        dataTypeDate.prototype.addChild = _returnSelf;			


	new dateTypeInteger(null, null);
	dateTypeInteger.prototype.toXML = _string2xml;
	dateTypeInteger.prototype.getValue = _string2value;				
	dateTypeInteger.prototype.setValue = _value2string;
        dateTypeInteger.prototype.addChild = _returnSelf;			

	
	new dateTypeBoolean(null, null);
	dateTypeBoolean.prototype.toXML = _string2xml;
	dateTypeBoolean.prototype.getValue = _string2value;				
	dateTypeBoolean.prototype.setValue = _value2string;
        dateTypeBoolean.prototype.addChild = _returnSelf;		

        
	new dateTypeComplex(null, null);
	dateTypeComplex.prototype.toXML = _array2xml;
	dateTypeComplex.prototype.getValue = _complex2value;
	dateTypeComplex.prototype.setValue = _value2complex;
        dateTypeComplex.prototype.addChild = _returnSelf;
        dateTypeComplex.prototype.removeChild = _removeChild;			
        dateTypeComplex.prototype.getObjElement = _arrayGetObjElement;

        
	new dateTypeXMLRAW(null, null);
	dateTypeXMLRAW.prototype.toXML = _string2xml;
	dateTypeXMLRAW.prototype.getValue = _string2value;
	dateTypeXMLRAW.prototype.setValue = _value2xmlraw;
        dateTypeXMLRAW.prototype.addChild = _returnSelf;
        dateTypeXMLRAW.prototype.removeChild = _xmlrawRemoveChild;			
        dateTypeXMLRAW.prototype.getObjElement = _xmlrawGetObjElement;


        
	new dataTypeProxy(null, null, null);        
    dataTypeProxy.prototype.obj = function(){return this._obj;}
	dataTypeProxy.prototype.gui = function(){return this._gui;}

	dataTypeProxy.prototype.normalizeRawObject = function(aElementName) {
		/* Toglie l'elementName dai campi di tipo rawXml che vengono caricati erroneamente con il proprio outer */	
		var ret = null;
		if (this._obj != null) {
			ret = this._obj[aElementName];
			if ((ret) && (ret._obj)) {
				var replacingTag = '<' + aElementName + '>';
				ret._obj = ret._obj.replace(replacingTag, '');
				replacingTag = '</' + aElementName + '>';
				ret._obj = ret._obj.replace(replacingTag, '');
			}
			
		}
		return ret;
	}

	dataTypeProxy.prototype.elements2GUI = function() {
		var myDocType = this._avatarRow;
		var myData = groups.definitions[myDocType];
		for (var aElement in myData.rules) {
			var myElement = myData.rules[aElement];	 //name
			var aType = myElement["type"];
			var aRef = myElement["ref"];		
			var aName = myElement["name"];	
			
			switch (aType) {
				case 'input' : {
						xml2input(this, aName);				
						break;						
					 	
				}	
				case 'select' : {
					xml2select(this, aName);				
					break;
				}	
				case 'text' : {
					xml2text(this, aName);				
					break;
				}	
				
				case 'textarea' : {
					this.normalizeRawObject(aName);
					xml2textarea(this, aName);				
					break;
				}					
				case 'datePicker' : {
					xml2datePicker(this, aName);				
					break;
				}	
				
				default : {
					alert('Unknown GUI type element(' + aType +') of ' + aName + ' in ' + myDocType)
					break;															
				}	
			}					
		}
	}	
	
	dataTypeProxy.prototype.nameForThisRow = function(aElementName) {
		var ret = aElementName;
		if (this._gui != null) {
		    var suffix = this._gui.id;
		    suffix = suffix.substring(suffix.length - 4, suffix.length);
		    ret = aElementName + suffix;
		}
		return ret;
	}
	
	dataTypeProxy.prototype.nameFromThisInputElement = function(input) {
		var ret = input.id;
		if (ret) {		    
		    ret = ret.substring(0, ret.length - 4);
		}
		return ret;
	}
	
	
	dataTypeProxy.prototype.changeButtons = function() {
		$("button", this._gui).trigger("handlingEdit");
	}
	
	dataTypeProxy.prototype.handleClick = function (aButton) {
	   switch (aButton.className) 			   
		{
			case 'modifica':
			this.changeButtons();						
			this.handleEditing ('editable');			
			break;

			case 'cancella':
			this.deleteRecord();
			break;

			case 'salva':
			if (this.postRecord()) {
				this.changeButtons();
				this.handleEditing ('readonly');
			}	
			break;

			case 'annulla':
			this.elements2GUI();
			this.changeButtons();			
			this.handleEditing ('readonly');			
			break;

			default:
			//
		}			   
	
	}
	
	dataTypeProxy.prototype.handleEditing = function (aClassName) {
		if (this._gui != null) {
			$(this._gui).removeClass('readonly editable').addClass(aClassName);

			var aSelector = '';
			aClassName == 'readonly' ? aSelector = '.editable' : aSelector = '.readonly';		
			var inputs = $(aSelector, this._gui);
			for (var i = 0; i < inputs.length; i++) {
			   var aInput = inputs[i];

		           if (aInput.className != aClassName) {
				aClassName == 'readonly' ? aInput.className = 'readonly' : aInput.className = 'editable';
				aClassName == 'readonly' ? aInput.readOnly = true : aInput.readOnly = false;			      		
				aClassName == 'readonly' ? aInput.disabled = true : aInput.disabled = false;						
		           }
			}
			$('a.date-picker', this._gui).toggle();			

		}
	}	

	
	dataTypeProxy.prototype.postRecord = function() {
		if (!this._modified) {return true}
		var valid = this.validator.form();
		if (!valid) {return false}
		if (confirm('Vuoi salvare i dati della riga?')) {
			if (this._obj == null )  {
				if (this._constructor == null) {
				   alert('Need constructor object');
				   return false;
				}	
			    /* La root si suppone sempre esistente e quindi est sempre da array  */
			   this._obj = this._constructor.getObjElement('ElementFittizio');
			}
			if (this._obj != null) {
				for (var aElement in this._modified) {
				    this._obj[aElement]._obj = this._modified[aElement];}
			}		    
			documentModified = true;
			this._modified = null;
			return true;
		}
		return false;
	} 
	dataTypeProxy.prototype.resetRecord = function () {
		alert('Vuoi perdere le modifiche ' + this._obj._elementName);
	}
	dataTypeProxy.prototype.deleteRecord = function () {
	        if (this._obj == null) {
	        	this._gui.parentNode.removeChild(this._gui);
	        	return null;
	        }
	        if (confirm('Vuoi cancellare ' + this._obj._element + '?')) {
				if ((this._obj != null) && (this._obj._parent != null)) {
					this._obj._parent.removeChild(this._obj);
					this._obj = null;
					documentModified = true;					
				}
				this._gui.parentNode.removeChild(this._gui);
		}	
	}
	/* L'insertRecord e' chiamata sul proxy attivo su questa GUI. 
	   Da questo Proxy prende la definizione dell'html vero e proprio, lo crea, gli attacca un nuovo proxy e lo popola con i dati dell'oggetto. 
	   E' l'altra faccia della createGUIProxy */
	dataTypeProxy.prototype.insertRecord = function (aObj) {
		var proxy =  null;
		if ((this._avatarRow != null) && (this._table != null)) {
			
			var myData = groups.definitions[this._avatarRow];	
			var aInternalCount = ++geoIdentification + 9000;
			var aInternalId = aInternalCount.toString();
			var aHtml = myData.html.replace(/9000/g, aInternalId);
			aInternalId = 'GeoRow' + aInternalId;
			aHtml = aHtml.replace(myData.rowId, aInternalId);		
			var aSelector = '#' + this._table;
			$(aSelector).append(aHtml);
			aSelector = '#' + aInternalId;
			var guiObj = $(aSelector);			
			proxy = new dataTypeProxy(guiObj[0], aObj, this._table);
			proxy._avatarRow = this._avatarRow;			
			proxy._constructor = this._constructor;						
			guiObj[0].owner = proxy;
			aInternalId = aInternalCount.toString();
			var myJson = createJson(aInternalId, this);
			proxy.validator = guiObj.validate(myJson);
			
				
		}
		if (proxy == null) {proxy =  this}
		if (aObj != null)  {
		   proxy._obj = aObj;
		   proxy.elements2GUI();
		}
		$('button', proxy._gui).GeoSetButton().trigger("handlingEdit");		
		return proxy;		
		
	}	
        
}


/*  E' il proxy tra interfaccia utente e dati */
function dataTypeProxy(gui, obj,  table) {
	this._gui = gui;
	this._obj = obj;
	this._table = table;
	this._avatarRow = null;	
	this._constructor = null;	

}

function dataTypeString(element, parent) {
     this._obj = new String();
     this._element = element; 
     this._parent = parent;
     return this;
}

function dataTypeNumber(element, parent) {
     this._obj = new Number();
     this._element = element; 
     this._parent = parent;
     return this;     
}

function dataTypeDecimal(element, parent) {
     this._obj = new Number();
     this._element = element; 
     this._parent = parent;
     return this;     
}

function dataTypeDateTime(element, parent) {
     this._obj = new Date();
     this._element = element; 
     this._parent = parent;
     return this;     
}

function dataTypeDate(element, parent) {
     this._obj = new Date();
     this._element = element; 
     this._parent = parent;
     return this;     
}

function dateTypeInteger(element, parent) {
     this._obj = new Number();
     this._element = element; 
     this._parent = parent;
     return this;     
}

function dateTypeBoolean(element, parent) {
     this._obj = new Boolean();
     this._element = element; 
     this._parent = parent;
     return this;     
}

function dateTypeComplex(element, parent) {
     this._obj = new Array();
     this._element = element; 
     this._parent = parent;
     this.createChild = null;
     return this;     
}

function dateTypeXMLRAW(element, parent) {
     this._obj = new Array();
     this._element = element; 
     this._parent = parent;
     this.createChild = null;
     return this;     
}


function dataTypeFactory(baseType, element, parent) {
        var ret;
	if (baseType == 'string') {
	        ret = new dataTypeString(element, parent);
	} else if (baseType == 'boolean') {
		ret = new dateTypeBoolean(element, parent);
	} else if (baseType == 'dateTime') {
		ret = new dataTypeDateTime(element, parent);
	} else if (baseType == 'date') {
		ret = new dataTypeDate(element, parent);
	} else if (baseType == 'decimal')  {
		ret = new dataTypeDecimal(element, parent);
	} else if (baseType == 'integer') {
		ret = new dateTypeInteger(element, parent);
	} else if (baseType == 'complex') {
		ret = new dateTypeComplex(element, parent);
	} else if (baseType == 'XMLRAW') {
		ret = new dateTypeXMLRAW(element, parent);
		
	} else alert('dataTypeFactory: inavlid baseType: ' + baseType);
	

	return ret;
}



function loadXml(url, handler) {
	// Se non non sono compilati i parametri  esci
	var axel = Math.random()+"";
	var a = 'axel=' + (axel * 10000000000000);
	if (url.indexOf('?') < 0) { a = '?' + a} else { a = '&' + a}
	url = url+a;
	var urlNormalized = url.replace(/&amp;/g,"&");
	
         $.get(urlNormalized, handler);	 	 
}

function saveXml(xmlDoc, queue) {
	// Se non non sono compilati i parametri  esci
	
	 if (self.onSaveGlobalCheck) {
	 	var GlobalCheckMessage = onSaveGlobalCheck();
	 	if (GlobalCheckMessage != '') {
	 		alert (GlobalCheckMessage);
	 		return false;
	 		}
	 }
	 
	 if (!documentModified) {
		alert('Il documento non sembra essere stato modificato \n Se avete modificato le righe salvate prima quelle');
		return false;
	 }	 
	 
	 if (docType == '') {return false;}
	 if (docId == '') {return false;}
	 var url = "/save/" + docType + "/" + docId + ".html";
	 var myData =  "xml=" + encodeURIComponent(xmlDoc);
	 if (arguments.length == 4) {myData =  myData + "&queue=" + queue}; 
	 if (sourceSite != '') {myData =  myData + "&sourceSite=" + sourceSite};
	 jQuery.ajax( {type :"POST", 
	 		url : url, 
	 		data :  myData,
	 		complete: function(msg){

	 			if (msg.responseText.indexOf('EGeoException')==-1) {	
	 				documentModified = false;
	 				alert('Data saved');
	 				url = '/'+docType+'/'+docId+'.html';
	 				if (sourceSite != '') {url =  url + "?sourceSite=" + sourceSite};	 				
	 				window.location.replace(url)}
	 			else	{
	 				alert('Error xml not wellformed');}
					
	 }});
	 return false;	 
}

function removeChildren (node){
	if(node){
		while(node.hasChildNodes()){
			removeChildren(node.firstChild);
			node.removeChild(node.firstChild); 
		}
	}	
	return null;
}

/* Questa funzione analizza gli elementi di una GUI solo la prima volta prendendone la struttura, salvandola in formato html simbolico
(testo ) , cancellandola dalla pagina e creando un proxy che viene utilizzato come punto di partenza quando dovranno essere inseriti 
i record veri e propri.
L'insertRecord individua il Proxy crea l'html vero e proprio e lo popola con i dati dell'oggetto
*/
function createGUIProxy(aElementName, aContainer, constructor, aId, aClassName) {
	/* Togli l'html della riga di esempio e salvalo nel json di controllo */
	var aInternalCount = ++geoIdentification + 9000;
	var containerId = 'GeoHeader'+ aInternalCount.toString();			
	var containerSelector = $('#' + groups.definitions[aId].headerId);
	/* Html di geoRow che e' figlio di GeoHeader (tBody/tRow) */
	var aHtml = containerSelector.html();
	groups.definitions[aId].html = aHtml;
	/* Gli tolgo la riga di esempio*/
	containerSelector.empty();	
	/* Gli assegno un id univoco */	
	containerSelector.attr('id', containerId);
	/* Prendo il gruppo tramite il suo id e gli imposto il proxy per genenerare i record */
	var headerSelector = '#' + groups.definitions[aId].id;
	aInternalCount = ++geoIdentification + 9000;	
	var clonedHeader = $(headerSelector);
	clonedHeader.attr('id', 'GeoGroup'+ aInternalCount.toString());
	var proxy = setOwnerInstance(clonedHeader[0], null);
	if (proxy != null)  {	
		proxy._constructor = constructor;
		proxy._avatarRow = aId; 
		proxy._table = containerId;
	}	
	return proxy;	
}

function input2xml(input, aElementName) {
	var aProxy = getOwnerHandler(input);
	if (aProxy != null) {
	   if (!aProxy.owner._modified) {aProxy.owner._modified = new Object()}
	   aProxy.owner._modified[aElementName] = input.value;
	}
}


function datePicker2xml(input, aElementName) {
	var aProxy = getOwnerHandler(input);
	if (aProxy != null) {
	   if (!aProxy.owner._modified) {aProxy.owner._modified = new Object()}

	   aProxy.owner._modified[aElementName] = date2xml($.datepicker.getDateFor(input));
	}
}


function checkbox2xml(input, aElementName) {
	var aProxy = getOwnerHandler(input);
	if (aProxy != null) {
	   if (!aProxy.owner._modified) {aProxy.owner._modified = new Object()}	
	   aProxy.owner._modified[aElementName] = input.checked;
	}

}


function radio2xml(input, aElementName) {
	var aProxy = getOwnerHandler(input);
	if (aProxy != null) {
	   if (!aProxy.owner._modified) {aProxy.owner._modified = new Object()}	
	   if (input.checked) {
	   	aProxy.owner._modified[aElementName] = input.value;
	   }	
	}

}

function select2xml (input, aElementName) {
	var aProxy = getOwnerHandler(input);
	if (aProxy != null) {
	   if (!aProxy.owner._modified) {aProxy.owner._modified = new Object()}	
	   aProxy.owner._modified[aElementName] = input.options[input.selectedIndex].value ;
	   
	}

}

function xml2radio(aProxy, aElementName) {
	if (aProxy._obj != null) {
		var aElement = aProxy._obj[aElementName];
		if ((aProxy._gui != null) && (aElement != null)) {
			var aSelector = "input[@type=radio][@name='" + aElementName + "']";
			var inputs = $(aSelector, aProxy._gui);
			var aValue = aElement.getValue();
			for (var i = 0; i < inputs.length; i++) {
			   var aInput = inputs[i];
			   if (aInput.value == aValue) {aInput.checked = true} else {aInput.checked = false}
			   
			}	
		}	
	}
}

function xml2input(aProxy, aElementName) {
	if (aProxy._obj != null) {
		var aElement = aProxy._obj[aElementName];
		if ((aProxy._gui != null) && (aElement != null)) {
			var input = findChildById(aProxy._gui, aProxy.nameForThisRow(aElementName));
 			if (input != null) {
				input.value = aElement.getValue();
			}	
		}	
	}
}

function xml2datePicker(aProxy, aElementName) {
	if (aProxy._obj != null) {
		var aElement = aProxy._obj[aElementName];
		if ((aProxy._gui != null) && (aElement != null)) {
			var input = findChildById(aProxy._gui, aProxy.nameForThisRow(aElementName));
 			if (input != null) {
				input.value = date2string(xml2date(aElement._obj));

			}	
		}	
	}
}

function xml2numeric(aProxy, aElementName) {
	if (aProxy._obj != null) {
		var aElement = aProxy._obj[aElementName];
		if ((aProxy._gui != null) && (aElement != null)) {
			var input = findChildById(aProxy._gui, aProxy.nameForThisRow(aElementName));
 			if (input != null) {
				input.value = aElement.getValue();
			    /*	$(input).numeric(); */


			}	
		}	
	}
}


function xml2textarea(aProxy, aElementName) {
	if (aProxy._obj != null) {
		var aElement = aProxy._obj[aElementName];
		if ((aProxy._gui != null) && (aElement != null)) {
			var textarea = findChildById(aProxy._gui, aProxy.nameForThisRow(aElementName));
 			if (textarea != null) {
				textarea.value = aElement.getValue();
				$(textarea).GeoEditor();
				$('a.date-picker', textarea.parentNode).hide();					
			}	
		}	
	}
}

function xml2text(aProxy, aElementName) {
	if (aProxy._obj != null) {
		var aElement = aProxy._obj[aElementName];
		if ((aProxy._gui != null) && (aElement != null)) {
			var textarea = findChildById(aProxy._gui, aProxy.nameForThisRow(aElementName));
 			if (textarea != null) {
				textarea.value = aElement.getValue();			}	
		}	
	}
}


function xml2checkbox(aProxy, aElementName) {
	if (aProxy._obj != null) {
		var aElement = aProxy._obj[aElementName];
		if ((aProxy._gui != null) && (aElement != null)) {
			var input = findChildById(aProxy._gui, aProxy.nameForThisRow(aElementName));
 			if (input != null) {
				input.checked = aElement.getValue();
			}	
		}	
	}
}



function xml2select (aProxy, aElementName) {
	if (aProxy._obj != null) {
		var aElement = aProxy._obj[aElementName];
		if ((aProxy._gui != null) && (aElement != null)) {
			var input = findChildById(aProxy._gui, aProxy.nameForThisRow(aElementName));
 			if (input != null) {
				for (var i=0; i<input.options.length; i++) {
					if(input.options[i].value==aElement.getValue()){input.options[i].selected=true;}
					else{input.options[i].selected=false;}
				
					}
				}

			}	
		}	
	}

function evaluateValue(aType, aValue) {
	if (aValue=='true') {
		return true
	}
	if ((aValue[0] > '0') && (aValue[0] < '9')) {
		return aValue + 0;
	}	
	return aValue;
}

function createJson (aSuffix, xProxy) {
	var myDocType = xProxy._avatarRow;
	var myJson = {	   
			event: "keyup",
					   debug : true,		
					    rules : {


						} ,
					    messages : {


					   }
		};

	var myData = groups.definitions[myDocType];
	var mySuffixedElement = '';
	for (var aElement in myData.rules) {
		var myElement = myData.rules[aElement];
			
		for (var aRule in myElement) {
			mySuffixedElement = aElement + aSuffix;
			switch (aRule) {
				case 'type' : {
					if (myElement[aRule]=='datePicker') {
						var xInput = $('#' + mySuffixedElement, xProxy._gui)[0];							
						$(xInput).datepicker(
						{  onSelect: function(dateText) { 

							var aInput = $.datepicker._curInst._input[0];
							var aProxy = getOwnerHandler(aInput);
							if (aProxy != null) {
							   if (!aProxy.owner._modified) {aProxy.owner._modified = new Object()}
							   var aElementName = aProxy.owner.nameFromThisInputElement (aInput); 	
							   aProxy.owner._modified[aElementName] = date2xml($.datepicker._curInst._getDate());
							}


						  } 
						});

						} 
						break;						
					 	
				}	
				case 'ref' : {
					break;
				}	
				case 'style' : {
					break;
				}	
				
				case 'class' : {
					break;
				}	
				
				case 'name' : {
					break;
				}	
				default : {
					if (!myJson.rules[mySuffixedElement]) {
						myJson.rules[mySuffixedElement] = new Object();
						} 
					 	
					var myRule = myJson.rules[mySuffixedElement];
					myRule[aRule] = evaluateValue(aRule, myElement[aRule]);
					break;															
				}	
				

			}
		}
	}
	return myJson

}

function myQueryCallBack(aValue) {
	if (arguments.length < 1) {
		return false;
	}
	var identifier = arguments[0]; 
	var bija = $.geoKarma.findBija(identifier); 
	var myElements = bija.myJson['fields'];
	var myJson = {};
	for (var i=1; i < arguments.length; i= i + 2 )
		{ 	var elementName = arguments[i];
			var elementValue = arguments[i + 1];
			myJson[elementName] = elementValue}
	for (var aElement in myJson) {
	
		for (var aReference in myElements) {
			if (myElements[aReference].ref == aElement) {
				var aSelectorName = '#' + bija.handler.nameForThisRow(myElements[aReference].id);
				var aSelector = $(aSelectorName); 
				if (aSelector.length > 0) {
					jQuery(aSelector[0]).attr('value', myJson[aElement]);
					input2xml(aSelector[0], myElements[aReference].id);
				}
			}
		}
	}	

}

function  toggleDisablig(obj) {

	obj.disabled = !obj.disabled;
	
}

function  toggleEditor(obj) {

	obj.disabled = !obj.disabled;
	
}

function toggleStandardButton(obj) {
	   switch (obj.className) {
			case 'modifica':
			obj.className = "salva";						

			break;

			case 'cancella':
			obj.className = "annulla";						
			break;

			case 'salva':
			obj.className = "modifica";									
			break;

			case 'annulla':
			obj.className = "cancella";												
			break;			
	}			   
	
}
