/*
	JRapid.prototype.openListing = function(me, entity, canvas, listing, subset, replace, handler, openWindow, url, serverPath) {
	JRapid.prototype.loadListing = function(container, entity, subset, openWindow, canvas, handler, serverPath) {
 * 
 * 
 */

/**************************** JRAPID CONFIG **********************************/

JRapid_Source.cache = false; 
JRapid_Input.dontDispatchChangeEvent = true;

function JRapid(obj) {
    this.timeoutSeconds = 10;
    this.dateRegExp = '\\d\\d/\\d\\d/\\d\\d\\d\\d';
    this.dateTimeRegExp = '\\d\\d/\\d\\d/\\d\\d\\d\\d \\d\\d:\\d\\d';    
    this.timeRegExp = '\\d\\d:\\d\\d';    
   ///this.timeQuantityRegExp = '[\\d+d]?[\\s]*[\\d+h]?[\\s]*[\\d+m]?[\\s]*';     
    this.timeQuantityRegExp = '^([\\d]+d){0,1}[ ]{0,1}([\\d]+h){0,1}[ ]{0,1}([\\d]+m){0,1}[ ]{0,1}$';
   // this.timeQuantityRegExp ='\\d\\d:\\d\\d - \\d\\d:\\d\\d';
    	this.timeRangeRegExp = '\\d\\d:\\d\\d - \\d\\d:\\d\\d';            
}

JRapid.FILE_EXTENSION = '.html';

/**************************** ERROR HANDLING **********************************/

/******************************* UTILS ***************************************/

JRapid.prototype.wrap = function(obj) {
	return application.wrapNode(obj);	
};

JRapid.prototype.get = function(id) {
	return application.getElementById(id);	
};

JRapid.prototype.getServerPath = function(container, def) {
	if (def) {
		container.node.setAttribute('serverPath', def);
	}
	//var path = container.node.getAttribute('serverPath');
	//return path ? path : JRapid.SERVER_PATH;
	return JRapid.SERVER_PATH;
};

JRapid.prototype.getElementsById = function(id, node) {
    if (document.all) {
        var ret = document.all[id];
        return ret == null ? [] : (ret.length == null || ret.length == 0 
            || (ret.tagName && ret.tagName.toLowerCase() == 'select') ? [ret] : ret); 
    } else if(document.evaluate) {
        var ret = new Array();    
        var result = document.evaluate("//*[@id='" + id + "']", node ? node : document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
        var el;
        while (el = result.iterateNext()) {
        	ret[ret.length] = el;
        }
        return ret;
    }
};

JRapid.prototype.getParam = function(param, def) {
	var url = window.location.search.toString().substring(1);
    var params = url.split('&');
    for (var i=0; i < params.length; i++) {
        var parameter = params[i].split("=");        
        if (parameter[0] == param) {
            return parameter[1];        
        }
    }
    
	var hash = window.location.hash;
	if (hash && hash.length > 0) {
		var params = hash.substring(1).split('&');
	    for (var i=0; i < params.length; i++) {
	        var parameter = params[i].split("=");	        
	        if (parameter[0] == param) {
	        	return parameter[1];        
	        }
	    }
	}
	
    return def;
};

JRapid.prototype.createSource = function() {
	var source = document.createElement('div');
	source.setAttribute('jclass', 'JRapid_Source');
	source.setAttribute('class', 'JRapid_Source');	
	source.className = 'container__';
	return jrapid.wrap(source);
}

JRapid.prototype.replaceAll = function(string, pattern, replacement) {
    while (string.match(pattern)) {
        string = string.replace(pattern, replacement);
    }
    return string;
};

JRapid.prototype.escapeParam = function(param) {
    if (param == null) {
        return param;
    }
    var parts = param.split('/');
    var ret = '';
    for (var i=0; i < parts.length; i++) {
        ret += (i>0?'|/':'') + parts[i];
    }
    return ret;
};

JRapid.prototype.getRowFor = function(me) {
    var row = me.outerNode;
    while (row && row.getAttribute) {
        if (row.getAttribute('row') == 'row') {
            return row;            
        }
        row = row.parentNode;
    }    
};

/********************************* NEXT ***************************************/

JRapid.prototype.nextreport = function(key, me) {
	window.open('../report/' + me.getAttribute('report') + '?' + key 
		+ (me.getAttribute('pdf') ? '&pdf=pdf' : ''), '_blank', 'width=700,height=600,resizable=yes');
};

JRapid.prototype.nextfunction = function(key, me) {
	eval(me.getAttribute('function') + '(key, me)');
};

JRapid.prototype.nextpanel = function(key, me) {
	window.location = me.getAttribute('panel') + JRapid.FILE_EXTENSION;
};

JRapid.prototype.nextform = function(key, me) {
	jrapid.openForm(me, me.getAttribute('entity'), 'formcanvas', key, me.getAttribute('defaultset'), null, true);    
};

/********************************* CRUD ***************************************/

JRapid.prototype.cancel = function(obj) {
    var container = jrapid.wrap(obj).getContainer();
    container.node.parentNode.removeChild(container.node);
}

JRapid.prototype.apply = function(me, handler, confirmed, prompted, doNotClose) {

    var container = me.getContainer();
    var xml = container.getElementById('xml');
    me.setDisabled(true);
    jrapid.hasErrors = '';
    
    // rich texts
    var xmlOuter = xml.outerNode;
    if (xmlOuter && xmlOuter.triggers && xmlOuter.triggers['__onapply']) {
        for (var i=0; i < xmlOuter.triggers['__onapply'].length; i++) {
            xmlOuter.triggers['__onapply'][i].execute(null, me);
        }
    }
    
    // validate
    if (jrapid.hasErrors.length || !this.validate(container.getElementById('form').outerNode)) {
        if (jrapid.hasErrors.length) {
            alert(jrapid.hasErrors);
        }
        me.setDisabled(false);
        return false;
    }

    
    // confirmation handling
    this.setConfirmedAndPrompted(xml, confirmed, prompted);
    
    // set timeout
    var t;
    if (jrapid.timeoutSeconds) {
        var timeout = function() {
                //jrapid.endTransaction(transactionId);
        	if (t && !confirm(jrapid.timeoutSeconds + ' seconds have passed. \n\nPlease verify your Internet connection.\n\nKeep waiting?')) {
                me.setDisabled(false);
                xml.abort();
            } else if (t) {
                t = setTimeout(timeout, jrapid.timeoutSeconds*1000);
            }
        };
        t = setTimeout(timeout, jrapid.timeoutSeconds*1000);
    }
    
    // init transation
    var tx = jrapid.startConsole('Applying', false, 'green');
  
    // send the post
    xml.post(function(xmlDoc, status) {
    
    	// end console
    	jrapid.endConsole(tx);    		
   	
        // clear timeout
        if (t) { clearTimeout(t); t = null; }
        
		// check network error
		if (status != 200) {
			me.setDisabled(false);
			jrapid.startConsole('Network error', true, 'red');
			return false;
		}
    
        // do the work
        if (xmlDoc == null || xmlDoc.documentElement == null || xmlDoc.documentElement.tagName == 'exception') {
            me.setDisabled(false); 
            jrapid.startConsole('Error', true, 'red');
            if (xmlDoc != null && xmlDoc.documentElement && xmlDoc.documentElement.hasChildNodes()) {
                alert(xmlDoc.documentElement.childNodes[0].nodeValue);
            } else {
                alert('Unable to store');
            }
            return false;
        } else if (xmlDoc.documentElement.tagName == 'confirmation') {
            jrapid.startConsole('Confirm', true, 'yellow');
            if (confirm(xmlDoc.documentElement.childNodes[0].nodeValue)) {
                return jrapid.apply(me, handler, (confirmed ? (confirmed+',') : '') + xmlDoc.documentElement.getAttribute('code'));
            } else {
                me.setDisabled(false);
                return;
            }
        } else if (xmlDoc.documentElement.tagName == 'prompt') {
            jrapid.startConsole('Prompt', true, 'yellow');
            var value;
            if (value = prompt(xmlDoc.documentElement.childNodes[0].nodeValue, '')) {
                return jrapid.apply(me, handler, confirmed, (prompted ? (prompted+',') : '') + xmlDoc.documentElement.getAttribute('code') + '=' + value);
            } else {
                me.setDisabled(false);
                return;
            }
        } 
        
        jrapid.startConsole('Saved', true, 'green');
        if (container.node && container.node.listingContainer) {
        	var xsl = jrapid.listingGetXsl(container.node.listingContainer);
        	if (xsl && xsl.refresh) {
        		xsl.refresh();
        	}
        }
        
		if (doNotClose) {
			var id =  xmlDoc.documentElement.childNodes[0].nodeValue;
			var oldDoc = xml.getXmlDocument();
			oldDoc.selectSingleNode('/*').setAttribute('id', id);
			xml.setXml(oldDoc.xml);
			me.setDisabled(false);
		}

        if (handler) {
            handler(xmlDoc.documentElement && xmlDoc.documentElement.hasChildNodes() ? xmlDoc.documentElement.childNodes[0].nodeValue : null);
        }
        
        try { 
        	if (!doNotClose && !xml.getAttribute('repeat')) {
        		container.close();        		
			}
		} catch (e) {
	    }
		me.setDisabled(false);
        
    });
    
};

JRapid.prototype.setConfirmedAndPrompted = function(xml, confirmed, prompted) {
    var url = xml.getUrl();
    if (url.indexOf('?') >= 0) {
        url = url.split('?')[0];
    }
    url += '?';
    if (confirmed) {
        url += 'confirmed=' + confirmed;
    }
    if (prompted) {
        var prompts = prompted.split(',');
        var promptParam = '';
        for (var i=0; i < prompts.length; i++) {
            promptParam += (i > 0 ? ',' : '') + prompts[i].split('=')[0];
            url += '&' + prompts[i];
        }            
        url += '&prompted=' + promptParam;
    }
    xml.setUrl(url);
};

JRapid.prototype.store = function(me, handler, isAsync, entity) {
    this.apply(me, function(key) {
    	if (handler) {
	        handler(key, me);
		}
		if (isAsync) {
			jrapid.startAsyncConsole(me.getContainer(), key, entity);
		}
		if (me.getContainer().getElementById('xml').getAttribute('repeat')) {
	        jrapid.loadForm(me.getContainer(), entity, '0', null, false, null, null, null, true);
        }
    });
};

JRapid.prototype.openListing = function(me, entity, canvas, listing, subset, replace, handler, openWindow, url, serverPath) {
	
    var container = me.getContainer();
    if (replace && canvas) {
        canvas.innerHTML = '';
    }
    
    // clone source
    var id = 'listing' + Math.random();
    var source = jrapid.createSource(true);
    source.setId(id);
    source.setInnerHTML('');    
    
    // append source to canvas
    if (canvas) {
    	canvas.appendChild(source.outerNode);
    } else {
    	document.body.appendChild(source.outerNode);
    }
    var w;
    if (openWindow) {
    	w = application.openWindow(entity, source.outerNode);
    	w.setAttribute('onresizewindow', 'jrapid.onResizeListWindow(this, "' + id + '");');
		w.helpButton.setAttribute("onhelpclick", "jrapid.openHelp(jrapid.wrap(this),'" + entity + "',false)");
    }
    
    // console
    var txOpenListing = jrapid.startConsole('Opening listing', false, 'green');
   
    // load source
    source.setUrl(url ? url : (entity + (listing && listing.length > 0 ? '_' : '') + listing + '_list' + JRapid.FILE_EXTENSION));
    source.open(function() {
   		
    	if (!source.isOpened()) {
		   	jrapid.endConsole(txOpenListing);
	   		jrapid.startConsole('Network error', true, 'red');
	   		return;
    	}
    	
        var childContainer = source.getChildContainer();
        var xsl = jrapid.listingGetXsl(childContainer);
        xsl.getStyle().display = '';
        var baseurl = jrapid.getServerPath(childContainer, serverPath) + entity + (subset && subset.length > 0 ? ('/' + subset) : '');
        xsl.setUrl(baseurl + ',page1');
        xsl.setAttribute('baseurl', baseurl);
        xsl.setAttribute('entity', entity);
        
        xsl.refresh(function(foo, xmlDoc, status) {
    		// end console
        	jrapid.endConsole(txOpenListing);
        	
        	// check network error
        	if (status != 200) {
        		jrapid.startConsole('Network error', true, 'green');  
        		return;
        	}
        	
        	// check service error
        	if (xmlDoc == null || xmlDoc.documentElement == null || xmlDoc.documentElement.tagName == 'exception') {
        		jrapid.startConsole('Network error', true, 'red'); 
				if (xmlDoc != null && xmlDoc.documentElement && xmlDoc.documentElement.hasChildNodes()) {
					alert(xmlDoc.documentElement.childNodes[0].nodeValue);
				} else {
					alert('Unable to read');
				}
        		return; 
        	}
        	
        	// call handler
        	if (handler) {
                handler(xsl.getContainer());                
            }
            
            // resize window
        	if (w) {
        		var maindiv = xsl.getContainer().getElementById('maindiv');
        		// TODO window width is hard coded
        		jrapid.wrap(w).resizeTo(700 + 'px', maindiv.getHeight() + 'px', true);
        	}
            
        });
    });
};

JRapid.prototype.loadListing = function(container, entity, subset, openWindow, canvas, handler, serverPath) {
	// this method is only used from body.onload in *list

    var xsl = container.getElementById('xsl_1_1');
    var baseurl = jrapid.getServerPath(container, serverPath) + entity + (subset && subset.length > 0 ? ('/' + subset) : '');
    xsl.setUrl(baseurl + ',page1');
    xsl.setAttribute('baseurl', baseurl);
    xsl.setAttribute('entity', entity);
    
    xsl.getStyle().display = '';

    if (openWindow) {
        canvas = container.getElementById('window');
        application.openWindow(entity, container.getElementById('maindiv').outerNode);
    }

    if (canvas) {
		if (container.node) {
            container.node.canvas = canvas;
        } else {
            application.canvas = canvas;
        }
    }
    
    // console
    var tx = jrapid.startConsole('Loading listing', false, 'green');

    xsl.refresh(function() {
    	// TODO if (network or service error) return error
    
    	jrapid.endConsole(tx);
    	jrapid.startConsole('Listing ok', true, 'green');
    	
        if (openWindow) {
            var win = container.getElementById('window');
            win.open();
        }
        
        if (handler) {
        	handler();
        }        
        
    }, true);
}

JRapid.prototype.resizeTable = function(xsl, win) {
	var container = xsl.getContainer();
	var canvas;
	if (win) {
		canvas = win;
	} else {
		canvas = (container.node && container.node.canvas) ? container.node.canvas : (application.canvas ? application.canvas : null);
	}	
	
	if (canvas) {
		var table = jrapid.listingGetTable(container);
		if (!table) {
			return;
		} 
		if (table.outerNode.tagName.toLowerCase() == 'table') {
			table = table.getParentNode();
		} 
		var filters = container.getElementById('filterfieldset');
		if (filters) {
			filters.getStyle().display = 'none';
		}
		xsl.getStyle().display = 'none';
		var canvasHeight = canvas.getHeight() - (win ? JRapid.WINDOW_HEIGHT : 0);
		xsl.getStyle().display = '';
		var diff = canvasHeight - container.getElementById('maindiv').getHeight();
		var h = table.getHeight() + diff;
		if (h > 0) table.getStyle().height = h+'px';
		table.getStyle().overflowY = 'scroll';
		if (filters) {
			filters.getStyle().display = '';
		}
	}
};

JRapid.prototype.onResizeListWindow = function(me, id) {
    /* at the moment of calling this function the window is not visible, just the 
        dotted box shown at resizing time, so timeout is needed */
	setTimeout(function() { jrapid.resizeTable(jrapid.listingGetXsl(new Container(document.getElementById(id))), me); }, 10);
};

JRapid.prototype.openForm = function(me, entity, canvas, id, defaultset, module, openWindow) {
    var container = me.getContainer();
    var sourcePrototype = jrapid.createSource();
    sourcePrototype.outerNode.id = 'source' + new Date().getTime();
    document.body.appendChild(sourcePrototype.outerNode);
   
    skipWindow = true;
    //sourcePrototype.setUrl((module ? ('../forms.' + module + '/') : '') + entity + (skipWindow ? '_baseform.htmli' : '_form.htmli'));
    sourcePrototype.setUrl((module ? ('../forms.' + module + '/') : '') + entity + (skipWindow ? '_form.html' : '_form.htmli'));
    
    // start console
    var txOpenForm = jrapid.startConsole('Opening form', false, 'green');
    
    sourcePrototype.open(function() {
    	// end console
    	jrapid.endConsole(txOpenForm);
    
    	if (!sourcePrototype.isOpened()) {
		    var tx = jrapid.startConsole('Network error', true, 'red');    		
		    return;
    	}
    
        var childContainer = sourcePrototype.getChildContainer();
        //openWindow(entity, sourcePrototype.outerNode);
        jrapid.loadForm(childContainer, entity, id, defaultset, openWindow);
    });
    sourcePrototype.getChildContainer().node.listingContainer = container;  
};

JRapid.prototype.loadForm = function(container, entity, id, defaultset, openWindow, handler, confirmed, prompted, repeat, serverPath) {
	serverPath = jrapid.getServerPath(container, serverPath);
	
    var children = container.getElementById('xmlmultiple').getChildren();
    for (var i=0; i < children.getLength(); i++) {
        if (children.item(i).getAttribute('baseurl')) {
            children.item(i).setUrl(serverPath + children.item(i).getAttribute('baseurl'));
        }
    }
    
    // decorate form with a window
    if (openWindow) {    	
    	var w = application.openWindow(entity, container.getElementById('windowcontainer').outerNode);
		w.helpButton.setAttribute("onhelpclick", "jrapid.openHelp(jrapid.wrap(this),'" + entity + "',true)");
	}

    var xsl = container.getElementById('xsl');
    var xml = container.getElementById('xml');
    
    xml.setUrl(serverPath + entity + '/' + (defaultset ? (defaultset + '/') : '') + id);
	xml.setAttribute('repeat', repeat ? 'repeat' : '');
	xml.setAttribute('baseurl', serverPath + entity + '/' + (defaultset ? (defaultset + '/') : '') );			
	xml.setAttribute('entity', entity);
	
	// confirmation handling
    this.setConfirmedAndPrompted(xml, confirmed, prompted);
    
    // console
	var tx = jrapid.startConsole('Loading', false, 'green');
	
	xml.setUrl(xml.getUrl() + '&' + new Date().getTime());    
    xsl.refresh(function(foo, xmlDoc, status) {
    	// end console
    	jrapid.endConsole(tx);

    	if (status != 200) {
    		alert('network error');
    		jrapid.startConsole('Network error', true, 'red');
    		return;
    	}
    	
    	var xmlDoc = xml.getXmlDocument();  
    	if (!JRapid.ignoreErrors) {  
    		if (xmlDoc == null || xmlDoc.documentElement == null || xmlDoc.documentElement.tagName == 'exception') {
	            jrapid.startConsole('Error', true, 'red');
	            if (xmlDoc != null && xmlDoc.documentElement && xmlDoc.documentElement.hasChildNodes()) {
	                alert(xmlDoc.documentElement.childNodes[0].nodeValue);
	            } else {
	                alert('Unable to read');
	            }
	            return false;
	        } else if (xmlDoc.documentElement.tagName == 'confirmation') {
	            jrapid.startConsole('Confirm', true, 'yellow');
	            if (confirm(xmlDoc.documentElement.childNodes[0].nodeValue)) {
	                return jrapid.loadForm(container, entity, id, defaultset, false, handler, (confirmed ? (confirmed+',') : '') + xmlDoc.documentElement.getAttribute('code'));
	            } else {
	                return;
	            }
	        } else if (xmlDoc.documentElement.tagName == 'prompt') {
	            jrapid.startConsole('Prompt', true, 'yellow');
	            var value;
	            if (value = prompt(xmlDoc.documentElement.childNodes[0].nodeValue, '')) {
	                return jrapid.loadForm(container, entity, id, defaultset, false, handler, confirmed, xmlDoc.documentElement.getAttribute('code') + '=' + value);
	            } else {
	                return;
	            }
	        } 
	    	jrapid.startConsole('Opened ok', true, 'green');
		}   
    	 	
    	var windowContainer = container.getElementById('windowcontainer');
    	var win = windowContainer.getParentNode();
		

    	 var xslDiv = container.getElementById('xsl');
         if (document.all) {
         	xslDiv.getStyle().display = 'inline';
         } else {
         	xslDiv.getStyle().position = 'absolute';
         	p = xslDiv;
         	while (p != null && p.getWidth) {
         		//alert(p.getWidth() + " " + p.getId());
         		p = p.getParentNode();
         	}
         }

         var height = windowContainer.getHeight();
         var width = xslDiv.getWidth();  
         
		  
         xslDiv.getStyle().position = '';
         if (win && win.resizeTo) {
        	 win.resizeTo((width + 60)+'px', (height + 52)+'px', true, null, true);
         }
    		
        if (handler) {
            handler();
        }
    }, true);
};

JRapid.prototype.openFormFromListing = function(me, entity, canvas, defaultsetparams, defaultset, module) {

	var id = jrapid.evaluateIfNotNull(defaultsetparams, me, '0');
	if (defaultsetparams && (id == '0' || id == '')) {
		if (confirm('It is necessary to save before continuing. Save now?')) {
			var submit = me.getContainer().getParent().getElementById('submit');
			jrapid.apply(submit, function(newId) {
				jrapid.openForm(me, entity, canvas, newId, defaultset, module, true);
				var xml = submit.getContainer().getElementById('xml');
				if (xml.getAttribute('baseurl')) {
					xml.setUrl(xml.getAttribute('baseurl') + '/' + newId);				
					var path = xml.getAttribute('entity');
					path = path == null || path.length == 0 ? path : path.substring(0,1).toLowerCase() + path.substring(1);
					path = '/' + path + '/@id';
    				if (xml.outerNode.triggers && xml.outerNode.triggers[path]) {
						for (var i=0; i < xml.outerNode.triggers[path].length; i++) {
							xml.outerNode.triggers[path][i].execute(null, submit);
				        }
				    } 
				}
			}, null, null, true);
        }
	} else {
		jrapid.openForm(me, entity, canvas, id, defaultset, module, true);
	}
	return false;
};

var c; //????

/******************************** VALIDATION **********************************/

JRapid.validations = [];
JRapid.validations['required'] = function(obj) { return obj.value && (obj.tagName.toLowerCase() != 'select' || obj.value != '0') ? null : (obj.title + ' is required'); };
JRapid.validations['date'] = function(obj) { return obj.value == '' || obj.value.match(jrapid.dateRegExp) ? null : (obj.title + ' is a date'); };
JRapid.validations['datetime'] = function(obj) { return obj.value == '' || obj.value.match(jrapid.dateTimeRegExp) ? null : (obj.title + ' is datetime'); };
JRapid.validations['time'] = function(obj) { return obj.value == '' || obj.value.match(jrapid.timeRegExp) ? null : (obj.title + ' is time'); };
JRapid.validations['timequantity'] = function(obj) { return obj.value == '' || obj.value.match(jrapid.timeQuantityRegExp) ? null : (obj.title + ' is timequantity'); };
JRapid.validations['timerange'] = function(obj) { return obj.value == '' || obj.value.match(jrapid.timeRangeRegExp) ? null : (obj.title + ' is timerange'); };
JRapid.validations['email'] = function(obj) { return obj.value == '' || obj.value.match(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/) ? null : (obj.title + ' is email');};
JRapid.validations['short'] = function(obj) { return obj.value == '' || obj.value.match(/^\-?[0-9]+$/) ? null : (obj.title + ' is short'); };
JRapid.validations['integer'] = function(obj) { return obj.value == '' || obj.value.match(/^\-?[0-9]+$/) ? null : (obj.title + ' is integer'); };
JRapid.validations['long'] = function(obj) { return obj.value == '' || obj.value.match(/^\-?[0-9]+$/) ? null : (obj.title + ' is long'); };
JRapid.validations['float'] = function(obj) { return obj.value == '' || obj.value.match(/^\-?[0-9]+(\.[0-9]+)?$/) ? null : (obj.title + ' is float'); };
JRapid.validations['double'] = function(obj) { return obj.value == '' || obj.value.match(/^\-?[0-9]+(\.[0-9]+)?$/) ? null : (obj.title + ' is double'); };

JRapid.prototype.validateElement = function(element) {
    var validation = element.getAttribute('validate');
    var msg = '';
    var hasErrors = false;
    if (validation) {    
        var validations = validation.split(',');
        for (var j = 0; j < validations.length; j++) {
			if (element.value) {
				if (JRapid.validations[validations[j]]) {
					var errorMessage = JRapid.validations[validations[j]](element);
					if (errorMessage) {
						msg += errorMessage + ' - ';
						hasErrors = true;
					}
				}
			}            
        }
        element.style.color = hasErrors ? 'red' : '';
        window.status = msg;
    }    
};

JRapid.prototype.validate = function(form) {

    var elements = form.elements;
    var n = elements.length;
    var msg = '';
    var first = null;
	
    for (var i=0; i < n; i++) {
    	var e = elements[i];
        var p = e.parentNode;
        var validation = e.getAttribute('validate');
        var currentStyle = p.currentStyle ? p.currentStyle : window.getComputedStyle(p, null);
        if (validation && currentStyle.color != 'green' && currentStyle.color != 'rgb(0, 128, 0)') {    
            var validations = validation.split(',');
            var hasErrors = false;
            for (var j=0; j < validations.length; j++) {
                if (JRapid.validations[validations[j]]) {
                	var errorMessage = JRapid.validations[validations[j]](e);
                    if (errorMessage) {
                        msg += errorMessage + '\n';
                        first = elements[i];
                        hasErrors = true;
                        e.style.color = 'red';
                    }    
                }            
            }
            e.style.color = hasErrors ? 'red' : '';
        }    
    }
    if (msg.length) {
        alert(msg);
        try { first.focus(); } catch (e) {}
        return false;
    }  
	
    return true;
};


var jrapid = new JRapid();
var prd = new JRapid();

/*************************** EXPR EVALUATION **********************************/

function evaluated(path, row) {
try {
	var n=-1;
    var newPath = '';
  	for (var i=0; i < path.length; i++) {
		var c = path.charAt(i);
		if (c == '(' || c == ')' || c == ',' || c == ' ') {
			newPath += evaluatedPart(path.substring(n+1, i), row) + path.charAt(i);
			n = i;
		}
	}
	if (n != path.length-1) {
		newPath += evaluatedPart(path.substring(n), row);
	}
			
			
			} catch (e) {throw e; alert(e.message); }
/*
	// TODO check all separators
    var parts = path.split(new RegExp('(\\(|\\)|\\s+|,)'));
    //var parts = /(\\(|\\)|\\s+|,)/i.exec(path);
    var newPath = '';
    for (var i=0; i < parts.length; i++) {
       newPath = newPath + evaluatedPart(parts[i], row);	
	}	
	alert(newPath);*/
	return newPath;
}

function evaluatedPart(path, row) {
	
    if (row.outerNode) {
        row = row.outerNode;
    }
    //Cross-browser fix
	var partsBracket = path.split(new RegExp('(\\[|\\])'));
	var parts = [];
	for (var i=0, j=0; i < partsBracket.length; i++) {
		if (partsBracket[i]!='[' && partsBracket[i]!=']') {
			parts[j++] = partsBracket[i]
		}
	}
		
    var newPath = '';
    var k = 0;
    
    for (var i=0; i < parts.length; i++) {
        if ((i%2)==0) {
            newPath = newPath + parts[i];
        } else {
            // TODO trim
            if (parts[i] == '*') {
                newPath = newPath + '[(\\d+)]';
            } else {
                var expr = parts[i].replace('ROWNUM', rownum(row, k++));
                newPath = newPath + '[' + eval(expr) + ']';
            }
        }
    }
    return newPath;
}


function rownum(row, k) {
    var ks = [];
    
    while (row && row.getAttribute) {
        if (row.getAttribute('row') == 'row') {
            ks[ks.length] = row.rowIndex;
        }
        row = row.parentNode;
    }
    return ks[ks.length-k-1];
}

function evaluateBoolean(xpath, obj) {
    var xsl = '<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xmlns:xslt2="http://www.htmli.com/1999/XSL/Transform"  exclude-result-prefixes="xslt xslt2">';
    xsl += '<xslt:namespace-alias stylesheet-prefix="xslt2" result-prefix="xslt"/>';
    xsl += '<xslt:output method="xml" omit-xml-declaration="yes" /><xslt:template match="/"><out>';
    xsl += '<xslt:choose><xslt:when test="' + xpath + '">1</xslt:when><xslt:otherwise>0</xslt:otherwise></xslt:choose>';
    xsl += '</out></xslt:template></xslt:stylesheet>';
    var xslDocument = XmlDocument.create();
    xslDocument.async = false;
    xslDocument.loadXML(xsl);
    var container = application.wrapNode(obj).getContainer();
    var xmlDoc = container.getElementById('xml').getXmlDocument();

   	var str = xmlDoc.transformNode(xslDocument).substring(5);
    return str.substring(0,str.length-6) == '1';
}
 

JRapid.prototype.evaluateXpath = function(xpath, obj) {

    var xslCollection = '<xslt:for-each select="' + xpath + '"><xslt:value-of select="." /><xslt:if test="position()!=last()">,</xslt:if></xslt:for-each>';
    var xslSingle = '<xslt:value-of select="' + xpath + '" />';

    var buildXsl = function(m) {
        var xsl = '<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xmlns:xslt2="http://www.htmli.com/1999/XSL/Transform" exclude-result-prefixes="xslt xslt2">';
        xsl += '<xslt:namespace-alias stylesheet-prefix="xslt2" result-prefix="xslt"/>';
        xsl += '<xslt:output method="xml" omit-xml-declaration="yes" /><xslt:template match="/"><out>';
        xsl += m;
        xsl += '</out></xslt:template></xslt:stylesheet>';
        return xsl;
    }
    
    var parseResult = function(str) {
    	str = str.substring(5);
    	str = str.substring(0, str.length-6);
    	return str == 'NaN' ? '' : str;
    };
    
    var xslDocument = XmlDocument.create();
    xslDocument.async = false;
    xslDocument.loadXML(buildXsl(xslCollection));
    var container = application.wrapNode(obj).getContainer();
    var xmlDoc = container.getElementById('xml').getXmlDocument();
    try {
    	return parseResult(xmlDoc.transformNode(xslDocument));
    } catch (e) {
        xslDocument.async = false;
      	xslDocument.loadXML(buildXsl(xslSingle));
	return parseResult(xmlDoc.transformNode(xslDocument));
    }
};

JRapid.prototype.evaluateIfNotNull = function(expr, obj, def) {
	if (expr == null || expr == '0' || !expr) {
		return def;
	}
	var node = application.wrapNode(obj.getContainer().node.parentNode);
	return jrapid.evaluateXpath(expr, node);
};

/******************************** CONSOLE **********************************/

JRapid.prototype.startConsole = function(label, timeout, color) {
	var console = document.getElementById('jrapid_console');
	if (console == null) {
		console = document.createElement('div');
		console.className = 'jrapid_console';
		console.id = 'jrapid_console';
		document.body.appendChild(console);
	}
	
	var div = document.createElement('div');
	div.id = new Date().getTime();
	div.innerHTML = label;
	div.className = 'jrapid_console_message';	
	div.style.backgroundColor = color;
	console.appendChild(div);
	
	if (timeout) {
		setTimeout(function() { div.parentNode.removeChild(div); }, 1000);
	}	
	return div.id;
};


JRapid.prototype.endConsole = function(id) {
	if (!id) {
		return;
	} 
	var console = document.getElementById('jrapid_console');
	if (console == null) {
		return;
	}
	
	for (var i=0; i < console.childNodes.length; i++) {
		if (console.childNodes[i].id == id) {
			console.removeChild(console.childNodes[i]);	
			return;	
		}
	}	
};

/******************************** TRIGGERS **********************************/

JRapid.prototype.initialTriggers = function(me) {
	setTimeout(function() {
	    var xml = me.getContainer().getElementById('xml');
        if (xml.outerNode.triggers && xml.outerNode.triggers['main'] != null) {
	        var c = xml.outerNode.triggers['main'];
		    for (var i=0; i < c.length; i++) {
	            c[i].execute(null, xml);
    	    }
	    }
	}, 1);
};

JRapid.prototype.trigger = function(fpath, me) {
    setTimeout(function() {
        jrapid.triggerWrapped(fpath, me);
    }, 1);
};

JRapid.prototype.triggerWrapped = function(fpath, me) {
	
    c = new Date().getTime();
    me.sync();
    var spath = fpath;
    while (spath.indexOf('[') != -1) {
        spath = spath.replace(new RegExp('\\[[^\\]]*\\]'), '');
    }
    var evaluatedPath = evaluated(fpath, me.outerNode);
    var xml = me.getContainer().getElementById('xml').outerNode;
    if (xml.triggers && xml.triggers[spath]) {
        for (var i=0; i < xml.triggers[spath].length; i++) {
			
            xml.triggers[spath][i].execute(evaluatedPath, me);
        }
    }                                
};

JRapid.prototype.registerAbstract = function(container, triggers, handler) {
	var xml = container.getElementById('xml').outerNode;
    if (xml.triggers == null) {
        xml.triggers = new Array();
    }
    var triggerArray = triggers.split(';');
    for (var i=0; i < triggerArray.length; i++) {
        var k = jrapid.replaceAll(triggerArray[i], new RegExp('\\[[^\\]]*\\]'), '');
        if (xml.triggers[k] == null) {
            xml.triggers[k] = new Array();
        }
        handler(xml.triggers[k], xml.triggers[k].length, triggerArray[i]);
    }    
};

JRapid.prototype.registerInitialTrigger = function(container, trigger) {
    var xml = container.getElementById('xml').outerNode;
    if (xml.triggers == null) {
        xml.triggers = new Array();
    }
    if (xml.triggers['main'] == null) {
        xml.triggers['main'] = new Array();
    }
    xml.triggers['main'][xml.triggers['main'].length] = trigger;    
};

JRapid.prototype.registerCalculatedProperty = function(container, slaveFpath, slaveId, calculus, triggers, triggerMode) {
	if (triggerMode != 'onload') {
	    jrapid.registerAbstract(container, triggers, function(array, index, trigger) {
	        array[index] = new JRapid_Registration_CalculatedProperty(slaveFpath, slaveId, calculus, trigger, triggerMode);
	    });    
	}
    if (!triggerMode || triggerMode == 'onload') {
	    jrapid.registerInitialTrigger(container, new JRapid_Registration_CalculatedProperty(slaveFpath, slaveId, calculus, null, triggerMode));
	}
};

JRapid.prototype.registerSubsetParams = function(container, slaveFpath, slaveId, params, subset, triggers, whenNotInSubset) {
    jrapid.registerAbstract(container, triggers, function(array, index, trigger) {
        array[index] = new JRapid_Registration_SubsetParams(slaveFpath, slaveId, params, trigger, subset, whenNotInSubset);
    });
    jrapid.registerInitialTrigger(container, new JRapid_Registration_SubsetParams(slaveFpath, slaveId, params, null, subset, whenNotInSubset));
    var xml = container.getElementById('xml').outerNode;
    if (!xml.subsetParams) {
        xml.subsetParams = [];
    }
    xml.subsetParams[slaveId] = params;
};

JRapid.prototype.registerIf = function(container, slaveFpath, slaveId, condition, triggers, func, applyToCanvas, triggerOnApply) {
	jrapid.registerAbstract(container, triggers, function(array, index, trigger) {
        array[index] = new JRapid_Registration_If(slaveFpath, slaveId, condition, trigger, func, applyToCanvas);
    });
    if (func != jrapid.checkIf) {
        jrapid.registerInitialTrigger(container, new JRapid_Registration_If(slaveFpath, slaveId, condition, null, func, applyToCanvas));
    }
    if (triggerOnApply) {
        jrapid.registerAbstract(container, '__onapply', function(array, index, trigger) {
            array[index] = new JRapid_Registration_If(slaveFpath, slaveId, condition, null, func, applyToCanvas);
        });
    }
};

JRapid.prototype.registerCondition = function(container, slaveFpath, slaveId, params, triggers, func, rpcService, applyToCanvas) {
    jrapid.registerAbstract(container, triggers, function(array, index, trigger) {
        array[index] = new JRapid_Registration_Condition(slaveFpath, slaveId, params, trigger, func, rpcService, applyToCanvas);
    });
    jrapid.registerInitialTrigger(container, new JRapid_Registration_Condition(slaveFpath, slaveId, params, null, func, rpcService, applyToCanvas));
    /* async problems, apply() can be called before this, causing unwanted behaviour 
    if (func == jrapid.checkUnique) {
        jrapid.registerAbstract(prefix, '__onapply', function(array, index, trigger) {
            array[index] = new JRapid_Registration_Condition(slaveFpath, slaveId, params, null, func, rpcService);
        });
    }*/
};

JRapid.prototype.registerDynamicValue = function(container, slaveFpath, slaveId, params, triggers, rpcService, triggerMode) {
	if (triggerMode != 'onload') {
	    jrapid.registerAbstract(container, triggers, function(array, index, trigger) {
	        array[index] = new JRapid_Registration_DynamicValue(slaveFpath, slaveId, params, trigger, rpcService, triggerMode);
	    });
	}
    if (!triggerMode || triggerMode == 'onload') {
	    jrapid.registerInitialTrigger(container, new JRapid_Registration_DynamicValue(slaveFpath, slaveId, params, null, rpcService, triggerMode));
	}
};

JRapid.prototype.registerDynamicForEach = function(prefix, slaveFpath, slaveId, params, triggers, service, fullXpath, triggerMode) {
	// TODO implement other trigger modes
    jrapid.registerAbstract(prefix, triggers, function(array, index, trigger) {
        array[index] = new JRapid_Registration_DynamicForEach(slaveFpath, slaveId, params, trigger, service, fullXpath, triggerMode);
    });
    if (!triggerMode || triggerMode == 'onload') {
		jrapid.registerInitialTrigger(prefix, new JRapid_Registration_DynamicForEach(slaveFpath, slaveId, params, null, service, fullXpath));
	}
};

JRapid.prototype.registerEmbeddedListing = function(container, slaveId, entity, params, triggers, subset, listing, name, containerEntity, module, defaultset, defaultsetparams) {
    jrapid.registerAbstract(container, triggers, function(array, index, trigger) {
        array[index] = new JRapid_Registration_EmbeddedListing(slaveId, params, trigger, entity, subset, listing, name, containerEntity, module, defaultset, defaultsetparams);
    });
    jrapid.registerInitialTrigger(container, new JRapid_Registration_EmbeddedListing(slaveId, params, null, entity, subset, listing, name, containerEntity, module, defaultset, defaultsetparams));
};

JRapid.prototype.registerjQuery = function(container, id, plugin) {
    /*jrapid.registerAbstract(prefix, '__onapply', function(array, index, trigger) {
        array[index] = new JRapid_Registration_RichText(id, 'save');
    });*/
    jrapid.registerInitialTrigger(container, new JRapid_Registration_jQuery(id, plugin));
};

JRapid.prototype.registerRememberLast = function(container, id) {
	jrapid.registerInitialTrigger(container, new JRapid_Registration_RememberLast(id));
};
        
function JRapid_Registration_CalculatedProperty(slaveFpath, slaveId, calculus, trigger, triggerMode) {
    this.slaveFpath = slaveFpath;
    this.slaveId = slaveId;    
    this.calculus = calculus;
    this.trigger = trigger;
    this.triggerMode = triggerMode;
};

function JRapid_Registration_SubsetParams(slaveFpath, slaveId, params, trigger, subset, whenNotInSubset) {
    this.slaveFpath = slaveFpath;
    this.slaveId = slaveId;    
    this.params = params.length ? params.split(';') : [];
    this.trigger = trigger;
    this.subset = subset;
    this.whenNotInSubset = whenNotInSubset;
};

function JRapid_Registration_If(slaveFpath, slaveId, condition, trigger, func, applyToCanvas) {
    this.slaveFpath = slaveFpath;
    this.slaveId = slaveId;    
    this.condition = condition;
    this.trigger = trigger;
    this.func = func;
    this.applyToCanvas = applyToCanvas;
};

function JRapid_Registration_Condition(slaveFpath, slaveId, params, trigger, func, rpcService, applyToCanvas) {
    this.slaveFpath = slaveFpath;
    this.slaveId = slaveId;    
    this.params = params.length ? params.split(';') : [];
    this.trigger = trigger;
    this.func = func;
    this.rpcService = rpcService;
    this.applyToCanvas = applyToCanvas;
};

function JRapid_Registration_DynamicValue(slaveFpath, slaveId, params, trigger, rpcService, triggerMode) {
    this.slaveFpath = slaveFpath;
    this.slaveId = slaveId;    
    this.params = params.length ? params.split(';') : [];
    this.trigger = trigger;
    this.rpcService = rpcService;
    this.triggerMode = triggerMode;
};

function JRapid_Registration_DynamicForEach(slaveFpath, slaveId, params, trigger, service, fullXpath) {
    this.slaveFpath = slaveFpath;
    this.slaveId = slaveId;    
    this.params = params.length ? params.split(';') : [];
    this.trigger = trigger;
    this.service = service;
    this.fullXpath = fullXpath;
};

function JRapid_Registration_EmbeddedListing(slaveId, params, trigger, entity, subset, listing, name, containerEntity, module, defaultset, defaultsetparams) {
    this.slaveId = slaveId;
    this.params = params.length ? params.split(';') : [];
    this.trigger = trigger;
    this.entity = entity;
    this.subset = subset;
    this.listing = listing;    
    this.name = name;
    this.containerEntity = containerEntity;
    this.module = module;
    this.defaultset = defaultset;
    this.defaultsetparams = defaultsetparams;
};

function JRapid_Registration_jQuery(id, plugin) {
    this.id = id;
    this.plugin = plugin;
};

function JRapid_Registration_RememberLast(id) {
    this.id = id;
};

JRapid_Registration_SubsetParams.prototype.execute = function(evaluatedPath, me) {
    try {
        
        var container = me.getContainer();
        var xsl = container.getElementById('window_subset_' + this.slaveId);
        var xmlmultiple = xsl.getPreviousElementSibling();
        var xml = xmlmultiple.getFirstElementChild();
        xmlmultiple.getLastElementChild().setXml(container.getElementById('xml').getXmlDocument().xml);
        var ud = this.slaveId;
        var canvas = jrapid.getElementsById('div_subset_' + this.slaveId, container.node);
        for (var i=0; i < canvas.length; i++) {
            var child = evaluatedPath == null ? null : evaluated(jrapid.replaceAll(this.trigger, '_', '.'), canvas[i]);
            if (child == evaluatedPath) {
                var url = jrapid.getServerPath(container) + this.subset;
                for (var j=0; j < this.params.length; j++) {
                    url += '/' + jrapid.escapeParam(jrapid.evaluateXpath(evaluated(this.params[j], canvas[i]), canvas[i]));
                }
                var whenNotInSubset = this.whenNotInSubset;
				xml.setUrl(url);
                xml.get(function(c) { 
                	xsl.refresh();
                    var disabled;
                    var option;
                    var value;
                    
                    if (c.children.length) {
                    	var obj = c.children[0];
	                    disabled = obj.disabled;
	                    // TODO get options when using selectmultiple?
    	                option = obj.options && obj.selectedIndex >= 0 ? obj.options[obj.selectedIndex] : null;
        	            value = obj.value;
					}
                    c.innerHTML = xsl.getInnerHTML(); 
                    if (c.children.length) {
	                    c.children[0].disabled = disabled;
	                    c.children[0].value = value;
	                    if (option && value != c.children[0].value && whenNotInSubset != 'donotshow') {
	                        if (whenNotInSubset == 'shownotvalid') {
	                            option.style.color = 'red';
	                        }
	                        c.children[0].options[c.children[0].options.length] = option;
	                        option.selected = true;
	                    }
	                }
                    //this.setValue();
                }, canvas[i]);            
            }
        }
    } catch (e) {
       throw e;
    }
};

JRapid.prototype.getSubsetParams = function(me, slaveId) {
    var xml = document.getElementById(me.getContainer().getPrefix() + 'xml');
    if (xml.subsetParams && xml.subsetParams[slaveId]) {
        return xml.subsetParams[slaveId];
    }       
    return '';
};

JRapid_Registration_CalculatedProperty.prototype.execute = function(evaluatedPath, me) {
    try {
        var container = me.getContainer();
        var canvas = jrapid.getElementsById(this.slaveId, container.node);
        for (var i=0; i < canvas.length; i++) {
			if (this.triggerMode == 'onchangenew' && canvas[i].value) {
				continue;
			}
            var child = evaluatedPath == null ? null : evaluated(jrapid.replaceAll(this.trigger, '_', '.'), canvas[i]);
            var currentStyle = canvas[i].parentNode.currentStyle ? canvas[i].parentNode.currentStyle : window.getComputedStyle(canvas[i].parentNode,null);            
                
            if (currentStyle.color != 'green' && (child == evaluatedPath || evaluatedPath.match(child.replace(/\[/g, '\\[').replace(/\]/g, '\\]')))) {
               	if (!jrapid.isNewOrHidden(canvas[i])) {
                    var value = jrapid.evaluateXpath(evaluated(this.calculus, canvas[i]), canvas[i]);
   	                canvas[i].value = value;                 
					application.dispatch('change', canvas[i], 'HTMLEvents');
				}
			}
        }
        
    } catch (e) {
    	throw e;
    }    
}

JRapid_Registration_If.prototype.execute = function(evaluatedPath, me) {
    var container = me.getContainer();
    var canvas = jrapid.getElementsById((this.applyToCanvas ? 'td_': '') + this.slaveId, container.node);
    for (var i=0; i < canvas.length; i++) {
        var child = evaluatedPath == null ? null : evaluated(jrapid.replaceAll(this.trigger, '_', '.'), canvas[i]);
        if (evaluatedPath == child || evaluatedPath.match(child.replace(/\[/g, '\\[').replace(/\]/g, '\\]'))) {
            var value = evaluateBoolean(evaluated(this.condition, canvas[i]), canvas[i]);
            if (this.applyToCanvas && canvas[i].parentNode.getAttribute('labelposition') == 'top') {
                this.func(canvas[i].parentNode, value);
                this.func(canvas[i].parentNode.previousSibling, value);                
            } else if (this.applyToCanvas && !canvas[i].parentNode.getAttribute('row')) {
                this.func(canvas[i].parentNode, value);
            } else {
                this.func(canvas[i], value);
            }                    
        }
    }
}

JRapid.prototype.displayTabIf = function(obj, bool) {
    var tab = application.wrapNode(obj);
    var i = 0; 
    while (tab.getPreviousSibling()) {
        i++;
        tab = tab.getPreviousSibling();
    }
    if (bool) {
        tab.getParentNode().showChild(i);
    } else {
        tab.getParentNode().hideChild(i);
    }
};

JRapid.prototype.displayIf = function(obj, bool) { obj.style.display = (bool ? '' : 'none'); };
JRapid.prototype.visibleIf = function(obj, bool) { obj.style.visibility = (bool ? '' : 'hidden'); };
JRapid.prototype.readonlyIf = function(obj, bool) { obj.readOnly = bool; };
JRapid.prototype.disabledIf = function(obj, bool) {  obj.disabled = bool; };

JRapid.prototype.checkIf = function(obj, bool, msg) {
    if (!bool) {
        jrapid.hasErrors += (msg?msg:'Invalid value') + '\n';
    }
    obj.style.backgroundColor = bool ? '': 'red';
};

JRapid.prototype.checkUnique = function(obj, isUnique) {
    if (isUnique != null && !isUnique) {
        alert('This field is not unique. ');
        jrapid.hasErrors += 'This field is not unique. ';
    }
    obj.style.backgroundColor = isUnique == null || isUnique ? '': 'red';
};


JRapid_Registration_Condition.prototype.execute = function(evaluatedPath, me) {

    var container = me.getContainer();
    var canvas = jrapid.getElementsById((this.applyToCanvas ? 'td_': '') + this.slaveId, container.node);
    var params = [];
	var x = [];

    for (var i=0; i < canvas.length; i++) {
        var child = evaluatedPath == null ? null : evaluated(jrapid.replaceAll(this.trigger, '_', '.'), canvas[i]);
        if (child == evaluatedPath) {
            var paramsString = '';
            params[i] = [];
            for (var j=0; j < this.params.length; j++) {
                params[i][params[i].length] = jrapid.evaluateXpath(evaluated(this.params[j], canvas[i]), canvas[i]);
                paramsString += ',params[' + i + '][' + j + ']';
            }
            if (this.applyToCanvas && canvas[i].parentNode.getAttribute('labelposition') == 'top') {
                x[i] = canvas[i].parentNode;
                //this.func(canvas[i].parentNode.previousSibling, value);                
            } else if (this.applyToCanvas && !canvas[i].parentNode.getAttribute('row')) {
                x[i] = canvas[i].parentNode;
            } else {
				x[i] = canvas[i];
            }  
            // TODO param path
            var xmlrpcserver = new JRapid_XmlRpcServer(JRapid.XMLRPC_PATH);
            var func = this.func;
            eval('xmlrpcserver.executeAsync(this.rpcService, function(r) { func(x[' + i + '], r); }' + paramsString + ')');    
        }
    }    
};

JRapid_Registration_DynamicValue.prototype.execute = function(evaluatedPath, me) {

    try {
	    var container = me.getContainer();
	    var canvas = jrapid.getElementsById((this.applyToCanvas ? 'td_': '') + this.slaveId, container.node);
	    for (var i=0; i < canvas.length; i++) {
            var child = evaluatedPath == null ? null : evaluated(jrapid.replaceAll(this.trigger, '_', '.'), canvas[i]);
            if (this.triggerMode == 'onchangenew' && canvas[i].value) {
        		continue;
        	}
            var currentStyle = canvas[i].parentNode.currentStyle ? canvas[i].parentNode.currentStyle : window.getComputedStyle(canvas[i].parentNode,null);
            
        	if (currentStyle.color != 'green' && (child == evaluatedPath || evaluatedPath.match(child.replace(/\[/g, '\\[').replace(/\]/g, '\\]')))) {
                var params = new Array();
                var p = '';
                for (var j=0; j < this.params.length; j++) {
                	params[params.length] = jrapid.evaluateXpath(evaluated(this.params[j], canvas[i]), canvas[i]);
                    p += ',params[' + j + ']';
                }
                var x = canvas[i];
                // TODO param path
                var xmlrpcserver = new JRapid_XmlRpcServer(JRapid.XMLRPC_PATH);
                var setDynamicValue = this.setDynamicValue;
                eval('xmlrpcserver.executeAsync(this.rpcService, function(r, e) {  if (e) { } else { setDynamicValue(canvas[' + i + '], r);}} ' + p + ')');
            }
        }
    } catch (e) {
        throw e;
    }
    
};

JRapid_Registration_DynamicValue.prototype.setDynamicValue = function(x, r) {
    /* if null value show empty string */
	r = r == null ? '' : r;
	if (x.type == 'checkbox') {
        x.checked = r || r == 'true';
    } else {
        x.value = r; 
    }
    
    // sync and cascade
	//var myEvent = application.createEvent('HTMLEvents');
	//myEvent.initEvent('change');
	//application.wrapNode(x).dispatchEvent(myEvent);
	application.dispatch('change', application.wrapNode(x), 'HTMLEvents');
};

JRapid_Registration_DynamicForEach.prototype.execute = function(evaluatedPath, me) {

    try {
        var container = me.getContainer();
	    var prefix = container.getPrefix();
        var canvas = jrapid.getElementsById(prefix + 'div_' + this.slaveId);
	    var xslt = container.getElementById('xsl');
	    
	    var xsl = '<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xmlns:xslt2="http://www.htmli.com/1999/XSL/Transform">';
	    xsl += '<xslt:namespace-alias stylesheet-prefix="xslt2" result-prefix="xslt"/>';
	    xsl += '<xslt:output method="html" omit-xml-declaration="yes" /><xslt:template match="/">';
	    xsl += xslt.getXslt().selectSingleNode('//*[@id = "' + prefix + 'div_' + this.slaveId + '"]').xml;
	    xsl += '</xslt:template></xslt:stylesheet>';
	    var xslDocument = XmlDocument.create();
	    xslDocument.async = false;
	    xslDocument.loadXML(xsl);
    
	    var multipleXml = container.getElementById('xmlmultiple').getXmlDocument();
	    
	    // TODO this should be set according to ROWNUM when used in inline environments
	    var fullXpath = this.fullXpath;
	    var xpath = fullXpath.substring(0, fullXpath.lastIndexOf('/'));

	    
        for (var i=0; i < canvas.length; i++) {
            var child = evaluatedPath == null ? null : evaluated(jrapid.replaceAll(this.trigger, '_', '.'), canvas[i]);

            if (child == evaluatedPath || evaluatedPath.match(child.replace(/\[/g, '\\[').replace(/\]/g, '\\]'))) {
                var params = new Array();
                var p = '';
                for (var j=0; j < this.params.length; j++) {
                    params[params.length] = jrapid.evaluateXpath(evaluated(this.params[j], canvas[i]), canvas[i]);
                    p += '/' + params[j];
                }
                var x = canvas[i];
                
				var xml = XmlDocument.create();
				xml.onreadystatechange = function() {
					if (xml.readyState == 4) {
						if (xml.parseError.errorCode != 0) {
							alert(xml.parseError.reason);
							return;
						}
						
						// append new lines to xml
						var parentNode = multipleXml.selectSingleNode(xpath);
						var childNodes = multipleXml.selectNodes(fullXpath);
						for (var k=childNodes.length-1; k>=0; k--) {
							childNodes[k].parentNode.removeChild(childNodes[k]);
						}
						var newNodes = xml.documentElement.childNodes;
                        var n = newNodes.length;
                        var elementName = fullXpath.substring(fullXpath.lastIndexOf('/')+1);
                        for (var k=0; k < n; k++) {
                            if (!newNodes[k].attributes) {
                                continue;
                            }
                       
                            // TODO importnode for ff3
                            var e = xml.createElement(elementName);
                            for (var l=0; l < newNodes[k].attributes.length; l++) {
                                var name = newNodes[k].attributes[l].name;
                                var value = newNodes[k].attributes[l].value;
                                e.setAttribute(name, value);
                            }
                            while (newNodes[k].hasChildNodes()) {
                                e.appendChild(newNodes[k].childNodes[0]);
                            }
                            parentNode.appendChild(e);
                        }
                       
                        // refresh html
                        container.getElementById('xml').setXml(multipleXml.selectSingleNode(xpath).xml);
                        x.innerHTML = multipleXml.transformNode(xslDocument);					
					}
				};
				xml.load(jrapid.getServerPath(container) + this.service + p);
            }
        }
    } catch (e) {
        throw e;
    }
    
};

JRapid_Registration_EmbeddedListing.prototype.execute = function(evaluatedPath, me) {
    var container = me.getContainer();
    var sources = jrapid.getElementsById(this.slaveId, container.node);
    for (var i=0; i < sources.length; i++) {
        var child = evaluatedPath == null ? null : evaluated(jrapid.replaceAll(this.trigger, '_', '.'), sources[i]);
        if (child == evaluatedPath) {
            var params = '';
            
            for (var j=0; j < this.params.length; j++) {
                
                if (this.params[j] && this.params[j].length) {
                    params += '/' + jrapid.escapeParam(jrapid.evaluateXpath(evaluated(this.params[j], sources[i]), sources[i]));
                }
            }
            // TODO check when there are more than one defaultsetparam
			var defaultsetparams = this.defaultsetparams ? this.defaultsetparams.split(';')[0] : null;
            var defaultset = this.defaultset;
            if (sources[i].innerHTML == '') {
            	jrapid.openListing(me, this.entity, sources[i], this.listing, this.subset + params, true, function(c) {
            		var add = c.getElementById('add');
            		if (add) {
            			add.setAttribute('defaultset', defaultset);
            			add.setAttribute('defaultsetparams', defaultsetparams);
            		}
    	       // }, true, '../forms.' + this.module + '/' + this.containerEntity + '_' + this.name + '_embeddedlist.htmli');
            	 }, false, '../forms.' + this.module + '/' + this.entity + (this.listing?('_' + this.listing):'') + '_list.html');
			} else {
				jrapid.loadListing(new Container(sources[i].children[0]), this.entity, this.subset + params, false);				
			}
        }
    }
};

JRapid_Registration_jQuery.prototype.execute = function(evaluatedPath, me) {
	var container = me.getContainer();
	var elements = jrapid.getElementsById(this.id);
	for (var i=0; i<elements.length; i++) {
		var a = elements[i];
		eval('$(a).' + this.plugin + '();');
	};	
};

JRapid_Registration_RememberLast.prototype.execute = function(evaluatedPath, me) {
	var container = me.getContainer();
	if (window.rememberLast && window.rememberLast[this.id]) {
		var objs = jrapid.getElementsById(this.id, container.node);
		var value = window.rememberLast[this.id];
		for (var i=0, n=objs.length; i < n; i++) {
			if (!objs[i].value || objs[i].value == '0') {
				objs[i].value = value;
				jrapid.wrap(objs[i]).sync();
			}
		}
	}
};

JRapid.prototype.rememberLast = function(obj) {
	if (!window.rememberLast) {
		window.rememberLast = [];
	}
	window.rememberLast[obj.id] = obj.value;	
};		



/********************************* SUGGEST *********************************/

JRapid.prototype.suggestKeyDown = function(me, entity, property, ev) {
    if (ev.keyCode == 13) {
        application.stopPropagation(ev);
        application.preventDefault(ev);
    }  /*else if (ev.keyCode == 9) {
        var container = me.getContainer();
        var xsl = container.getElementById('suggests');
        var input = xsl.outerNode.input;
        if (input) {
            application.wrapNode(input).sync();
        }
    } */      
};

JRapid.prototype.suggestDblClick = function(me, entity, property) {
    this.suggest(me, entity, property);
};

JRapid.prototype.suggestBlur = function(me, entity, property) {
    var container = me.getContainer();
    var xsl = container.getElementById('suggests');
    setTimeout(function() {
        xsl.getStyle().display = 'none';
    }, 250);
    xsl.outerNode.suggestSelectedIndex == null
};

JRapid.prototype.suggestKeyUp = function(me, entity, property, ev) {

    var container = me.getContainer();
    var xsl = container.getElementById('suggests');        
    
    if (ev.keyCode == 9 || ev.keyCode == 27 || ev.keyCode == 13 || (me.getValue().length < 1 && ev.keyCode != 40 && ev.keyCode != 38)) {
        xsl.outerNode.suggestSelectedIndex == null
        xsl.getStyle().display = 'none';
        return;
    }

    
    if (ev.keyCode == 40 && xsl.getStyle().display != 'none') {
    
        if (xsl.outerNode.suggestSelectedIndex == null) {
            xsl.outerNode.suggestSelectedIndex = -1;
        }
        
        if (xsl.outerNode.suggestSelectedIndex >= xsl.getChildren().getLength()-1) {
            return;
        }
        if (xsl.outerNode.suggestSelectedIndex >= 0) {
            var oldItem = xsl.getChildren().item(xsl.outerNode.suggestSelectedIndex);
            oldItem.getStyle().backgroundColor = '';
            oldItem.getStyle().color = '';
        }
        
        xsl.outerNode.suggestSelectedIndex++;
        var item = xsl.getChildren().item(xsl.outerNode.suggestSelectedIndex);
        item.getStyle().backgroundColor = '#000099';
        item.getStyle().color = '#ffffff';        
        me.setValue(item.outerNode.title);
		
		/*        
		 	if (me.dispatchChangeEvent) {
            me.dispatchChangeEvent();
        }*/	
		application.dispatch('change', me, 'HTMLEvents');
                
    } else if (ev.keyCode == 38 && xsl.getStyle().display != 'none') {
        if (xsl.outerNode.suggestSelectedIndex == null) {
            xsl.outerNode.suggestSelectedIndex = -1;
        }
        
        if (xsl.outerNode.suggestSelectedIndex <= 0) {
            return;
        }
        
        if (xsl.outerNode.suggestSelectedIndex >= 0) {
            var oldItem = xsl.getChildren().item(xsl.outerNode.suggestSelectedIndex);
            oldItem.getStyle().backgroundColor = '';
            oldItem.getStyle().color = '';
        }
        
        xsl.outerNode.suggestSelectedIndex--;
        var item =    xsl.getChildren().item(xsl.outerNode.suggestSelectedIndex);
        item.getStyle().backgroundColor = '#000099';
        item.getStyle().color = '#ffffff';        
        me.setValue(item.outerNode.title);
		
		/*
        if (me.dispatchChangeEvent) {
            me.dispatchChangeEvent();
        }
        */
		application.dispatch('change', me, 'HTMLEvents');
		
        //me.sync();
        
    } else if (ev.keyCode != 16) {
        if (me.getValue().length || ev.keyCode == 40) {
            this.suggest(me, entity, property);
        }
        
    }
        
};

JRapid.prototype.suggest = function(me, entity, property) {
    var container = me.getContainer();
    var xsl = container.getElementById('suggests');
    xsl.outerNode.suggestSelectedIndex = null;
    xsl.setUrl(jrapid.getServerPath(container) + entity + '/suggest' + property + '/' + me.getValue());
    xsl.outerNode.input = me.outerNode;
    xsl.refresh(function() {
        var style = xsl.getStyle();
        style.top = (me.getY() - xsl.getContainingBlock().getY() + me.getHeight()-2) + "px";
        style.left = (me.getRelativeX()-4) + "px";    
        style.display = xsl.hasChildren() ? '' : 'none';        
    });
};

/********************************* MULTILINE *********************************/

JRapid.prototype.multilineRemove = function(obj, fpath) {
	
	var me = jrapid.wrap(obj);
    var container = me.getContainer();
    var row = jrapid.getRowFor(me);
    var xpath = evaluated(fpath, row);
    var xml = container.getElementById('xml');
    xml.remove(xpath);
    row.parentNode.removeChild(row);
    return;    
};

JRapid.prototype.multilineInsert = function(obj, xpath, property) {
	var me = jrapid.wrap(obj);
    return jrapid.multilineAdd(obj, xpath, property, jrapid.getRowFor(me).rowIndex);
};

JRapid.prototype.multilineUp = function(obj, xpath) {
	
	var me = jrapid.wrap(obj);
    var row = jrapid.getRowFor(me);    
    if (row.rowIndex > 1) {
        var container = me.getContainer();    
        var xml = container.getElementById('xml');
        var xmlDoc = xml.getXmlDocument();    
        var node = xmlDoc.selectSingleNode(evaluated(xpath, row));
        node.parentNode.insertBefore(node, node.previousSibling);
        xml.setXml(xmlDoc.xml);    
    
        row.parentNode.insertBefore(row, row.previousSibling);
    }
    
};

JRapid.prototype.insertAfterNode = function(node, newNode, refNode) {
		var refNodeWrapped = jrapid.wrap(refNode);
		if (refNodeWrapped.getNextElementSibling()) {
			return node.insertBefore(newNode, refNodeWrapped.getNextElementSibling().outerNode);
		} else {
			return node.appendChild(newNode);
		}
};

JRapid.prototype.multilineDown = function(obj, xpath) {
	
	var me = jrapid.wrap(obj);
    var row = jrapid.getRowFor(me);    
    if (row.rowIndex < row.parentNode.children.length-3) {
        var container = me.getContainer();    
        var xml = container.getElementById('xml');
        var xmlDoc = xml.getXmlDocument();    
        var node = xmlDoc.selectSingleNode(evaluated(xpath, row));
		
		var nodeWrapped = jrapid.wrap(node);
		var rowWrapped = jrapid.wrap(row);  
		if( nodeWrapped.getNextElementSibling() ) {
			jrapid.insertAfterNode(node.parentNode,node,nodeWrapped.getNextElementSibling().outerNode);			
	        xml.setXml(xmlDoc.xml);
			jrapid.insertAfterNode(row.parentNode,row,rowWrapped.getNextElementSibling().outerNode);				
		}
		
    }    
};

JRapid.prototype.multilineAdd = function(obj, fpath, property, rowNum){

	var me = jrapid.wrap(obj);
	var tr = jrapid.getRowFor(me);
	
	var tbody = tr.parentNode;
	
	var container = me.getContainer();
	var xml = container.getElementById('xml');
	var xmlDoc = xml.getXmlDocument();
	if (rowNum) {
		var node = xmlDoc.selectSingleNode(evaluated(fpath + '/' + property + '[ROWNUM]', tr));
		if (node.nextSibling) {
			node.parentNode.insertBefore(xmlDoc.createElement(property), node.nextSibling);
		}
		else {
			node.parentNode.appendChild(xmlDoc.createElement(property));
		}
	} else {
		var node = xmlDoc.selectSingleNode(evaluated(fpath, tbody));
		node.appendChild(xmlDoc.createElement(property));
	}
	xml.setXml(xmlDoc.xml);
	var newTr = tbody.children[tbody.children.length - 2].cloneNode(true);
	tr.style.color = '';
	newTr.style.display = '';
	tr.parentNode.insertBefore(newTr, rowNum ? tbody.children[rowNum] : tbody.children[tbody.children.length - 2]);
	newTr.children[0].style.display = '';
	
	if (rowNum){ 
		for (var i = 0; i < newTr.children.length; i++) {
			newTr.children[i].style.display = '';
		}
	}
    return true;
};

JRapid.prototype.multilineInsertEntity = function(obj, xpath, entity) {
    return jrapid.multilineAddEntity(obj, xpath.substring(0, xpath.lastIndexOf('/')), xpath.substring(xpath.lastIndexOf('/')+1, xpath.lastIndexOf('[')), entity, jrapid.getRowFor(me).rowIndex);
};

JRapid.prototype.multilineAddEntity = function(obj,fpath, property, entity, rowNum, async) {
	var me = jrapid.wrap(obj);
    var tr = jrapid.getRowFor(me);
    
    var tbody = tr.parentNode;    
    var container = me.getContainer();    
    var xml = container.getElementById('xml');
    var xmlDoc = xml.getXmlDocument();
    
    // console
    var tx = jrapid.startConsole('Adding', false, 'green');
    
    var httpRequest = HttpRequest.create();
    
	// TODO this should be async but also allow sync to be called later
	httpRequest.open("GET", jrapid.getServerPath(container) + entity + '/0' /*?' + new Date().getTime()*/, false);
    var command = function() {                    
        if (httpRequest.readyState == 4) {
        
        	// end console
        	jrapid.endConsole(tx);
        	
			// check network error
			if (httpRequest.status != 200) {
				jrapid.startConsole('Network error', true, 'red');
				window.status = 'Network error';
				return false;
			}      
			  
            var newNode = xmlDoc.createElement(property);
            var childDoc = httpRequest.responseXML;
            var children = childDoc.documentElement.childNodes;
            for (var i=0; i < children.length; i++) {
                var n = children[i].cloneNode(true);
                /*if (n.tagName != path.substring(1)) {*/
                    newNode.appendChild(n);
                /*}*/
            }
            newNode.setAttribute('id', 0);
            
            var actualNodesLength = xmlDoc.selectNodes(evaluated(fpath, tbody) + '/' + property).length;
            if (rowNum && rowNum <= actualNodesLength) {
                var n = xmlDoc.selectSingleNode(evaluated(fpath, tbody) + '/' + property + '[' + rowNum + ']');
              	n.parentNode.insertBefore(newNode, n); 
            } else {
                xmlDoc.selectSingleNode(evaluated(fpath, tbody)).appendChild(newNode);
            }
            xml.setXml(xmlDoc.xml);
            
            //create the new TR of the table
			var newTr = tbody.children[tbody.children.length-2].cloneNode(true);            
            tr.style.color = '';                       
            newTr.style.display = '';
            newTr.onkeydown = function() {};        

            tr.parentNode.insertBefore(newTr, rowNum ? tbody.children[rowNum] : tbody.children[tbody.children.length-1].previousSibling);
            
            //display the images if the row is between the last and the first row
            if(rowNum != null){
            	var length = newTr.children.length;
            	for(var i = length - 1; i > 2 ; i--){
					newTr.children[i].style.display = ''; //TD containing the image
            	}
            }
            //jrapid.multilineCalculateIndexes(tbody);
            
            return true;
        }
    };
    try {
	    httpRequest.send("");  
	    return command(); 
	} catch (e) {
		jrapid.startConsole('Network error', true, 'red');
		window.status = 'Network error';				
	}
	return false;
};

JRapid.prototype.multilineCalculateIndexes = function(tbody) {
    for (var i=0; i < tbody.children.length; i++) {
        tbody.children[i].children[0].children[0].value = i;
    }
};

JRapid.prototype.checkIfIsNew = function(me) {

    var node = me.outerNode;
    var success = false;

    while (node && node.parentNode && node.parentNode.getAttribute) {
        node = node.parentNode;
        
        if (node.getAttribute("row")) { 
            if (node.parentNode.getAttribute('extendable') == 'extendable') {           
                var current = node.rowIndex;
                var total = node.parentNode.children.length;
                if (current == (total-2)) {
                    
                    if (node.getAttribute('entity')) {
                        // TODO this is async!
                        success = jrapid.multilineAddEntity(me, node.getAttribute('selectexpr').substring(0, 
                            node.getAttribute('selectexpr').lastIndexOf('/')), node.getAttribute('property'), node.getAttribute('entity'), null, true);
                    } else {
                        success = jrapid.multilineAdd(me, node.getAttribute('selectexpr'), node.getAttribute('property'));
                    }    
                    
                    if (success) {
	                    for (var i=0; i < node.children.length; i++) {
    	                    node.children[i].style.display = '';
        	            }
					}                    
                }
            }
            break;
        }
    }
    
    return success;

};

JRapid.prototype.isNewOrHidden = function(me) {

    var node = me;

    while (node && node.parentNode && node.parentNode.getAttribute) {
        node = node.parentNode;
        if (node.getAttribute("row")) {
            if (node.parentNode.getAttribute('extendable') == 'extendable') {
                var current = node.rowIndex;
                var total = node.parentNode.children.length;
                return current == (total-3) || current == (total-2);
            }
            break;
        }
    }
    return false;

};


JRapid.prototype.multilineChangedNew = function(me, fpath, property, entity, rowNum) {
//    me.outerNode.onkeydown = function() {};
//    jrapid.multilineAddEntity(me, fpath, property, entity, rowNum);
};

 
JRapid.prototype.multilineDetailAdd = function(obj, selectexpr, name, id, entity) {
	var me = jrapid.wrap(obj);
    var tbody = me.outerNode.previousSibling.previousSibling.lastChild;
    
    // TODO make this method work as with suggest one embedded entity
    
    var newTR = tbody.insertRow(tbody.children.length-1);
    newTR.setAttribute('row', 'row');
    var newCell = newTR.insertCell();
    var div = document.createElement('div');
    div.id = 'row_' + id;
    newCell.appendChild(div);
    
/*    tbody.lastChild.cloneNode(true);
    tbody.appendChild(newTR);
    tbody.childNodes[tbody.childNodes.length-2].style.display = '';
    */
    
    jrapid.suggestEmbeddedEntity(me, application.wrapNode(div), selectexpr, entity, name, null, true);

};


/********************************* EMBEDDED *********************************/

JRapid.prototype.showHideEmbeddedEntity = function(obj, xpath, entity, property, value, handler) {
	var me = jrapid.wrap(obj);
    var container = me.getContainer();
    var xml = container.getElementById('xml');
    var xmlDoc = xml.getXmlDocument();
    var checked = typeof(value)!='undefined' ? value : me.getChecked();
    var div = me.getParentNode().getNextElementSibling();
    
    var xpath = evaluated(xpath, me);
    var node = xmlDoc.selectSingleNode(xpath + '/' + property);
    if (node) {
        node.setAttribute('id', checked ? 1 : -1);
        xml.setXml(xmlDoc.xml);
        if(handler) {
            handler();
        }
    } else if (checked) {
        jrapid.suggestEmbeddedEntity(me, div, xpath, entity, property, handler);
    }
    var style = div.getStyle();
    style.visibility = checked ? 'visible' : 'hidden';
    style.color = checked ? '' : 'green';
}

JRapid.prototype.suggestEmbeddedEntity = function(me, div, xpath, entity, property, handler, isMultiLine) {
    
    var container = me.getContainer();
    var prefix = container.getPrefix();
    
    var xslt = container.getElementById('xsl');
    var lcFirstEntity = entity.substring(0,1).toLowerCase() + entity.substring(1);
    
    var xsl = '<xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xmlns:xslt2="http://www.htmli.com/1999/XSL/Transform">';
    xsl += '<xslt:namespace-alias stylesheet-prefix="xslt2" result-prefix="xslt"/>';
    xsl += '<xslt:output method="html" omit-xml-declaration="yes" /><xslt:template match="/">';
    xsl += xslt.getXslt().selectSingleNode('//*[@id = "' + prefix + div.getId() + '"]').xml;
    xsl += '</xslt:template></xslt:stylesheet>';
    var xslDocument = XmlDocument.create();
    xslDocument.async = false;
    xslDocument.loadXML(xsl);
    
    var multipleXml = container.getElementById('xmlmultiple').getXmlDocument();
    var oldNode = multipleXml.selectSingleNode('/*/' + xpath + '/' + property);
        
    var ajax = new XMLHttpRequest();
    ajax.open('GET', jrapid.getServerPath(container) + entity + '/0', true);
    // console
    var tx = jrapid.startConsole('Embedding', false, 'green');
    
    ajax.onreadystatechange = function() {
        if (ajax.readyState == 4) {
        	
        	// end console
        	jrapid.endConsole(tx);
        	
        	// TODO if (network or service error) return error           
        	var xml = ajax.responseXML;
       
            if (!oldNode || isMultiLine) {
                oldNode = multipleXml.createElement(property);
                var parentNode = multipleXml.selectSingleNode('/*' + xpath);
                parentNode.appendChild(oldNode);
            }
            var n = oldNode.childNodes.length;
            for (var i=0; i < n; i++) {
                oldNode.removeChild(oldNode.childNodes[0]);
            }
            
            var children = xml.documentElement.childNodes;
            for (var i=0; i < children.length; i++) {
                oldNode.appendChild(children[i].cloneNode(true));
            }
           
            oldNode.setAttribute('id', isMultiLine ? 0 : 1);
            container.getElementById('xml').setXml(multipleXml.selectSingleNode('/root' + xpath).xml);
            div.setInnerHTML(multipleXml.transformNode(xslDocument));
            if (handler) {
                handler();
            }
        }
    };        
    // TODO add subset or defaultset
    ajax.send('');
};

/********************************* COLLECTION *********************************/

JRapid.prototype.textareaCollectionSync = function(obj, expr, name) {
	
	var me = jrapid.wrap(obj);
    var values = me.getValue().split('\n');
    
    var container = me.getContainer();
    var xml = container.getElementById('xml');
    var xmlDoc = xml.getXmlDocument();
    var selectexpr = evaluated(expr + '/' + name, me);
    
    var nodes = xmlDoc.selectNodes(selectexpr);
    for (var i=nodes.length-1; i >= 0; i--) {
        nodes[i].parentNode.removeChild(nodes[i]);
    }
    
    var parentNode = xmlDoc.selectSingleNode(evaluated(expr, me));
    for (var i=0; i < values.length; i++) {
        if (values[i] && values[i].replace(/^\s+|\s+$/g,'').length) {
            var newNode = xmlDoc.createElement(name);
            newNode.appendChild(xmlDoc.createTextNode(values[i].replace(/^\s+|\s+$/g,'')));
            parentNode.appendChild(newNode);
        }
    }
    
    xml.setXml(xmlDoc.xml);    
};

JRapid.prototype.collectionKeyDown = function(select, event, xpath, property) {
    var xml = jrapid.wrap(select).getContainer().getElementById('xml');
    var i = select.selectedIndex;
   
    if (event.keyCode == 38 && event.ctrlKey && i > 0) {
        jrapid.collectionSwap(select, -1, 0, xml.getXmlDocument(), xml, i, xpath, property);
    } else if (event.keyCode == 40 && event.ctrlKey && i < (select.options.length-1)) {
       jrapid.collectionSwap(select, 1, 1, xml.getXmlDocument(), xml, i, xpath, property);
    }      
};

JRapid.prototype.collectionSwap = function(select, n, j, xmlDoc, xml, i, xpath, property) {
    var aux = select.options[i+n];
    var option = select.options[i];
    select.options[i+n] = new Option(option.text, option.value);
    select.options[i] = aux;
    select.options[i].selected = true;
    var path = evaluated(xpath, select) + '/' + property;        
    var node1 = xmlDoc.selectSingleNode(path + '[' + (i+j) + ']');    
    var node2 = xmlDoc.selectSingleNode(path + '[' + (i+1+j) + ']');    
    node1.parentNode.insertBefore(node2, node1);
    xml.setXml(xmlDoc.xml); 	
};

JRapid.prototype.collectionRemoveEntity = function(me, xpath, property) {
    var select = me.outerNode;
    if (select.selectedIndex >= 0) {

        // sync
        var container = me.getContainer();
        var xml = container.getElementById('xml');
        var xmlDoc = xml.getXmlDocument();
    
        var node = xmlDoc.selectSingleNode(evaluated(xpath, me) + '/' + property + '[' + (select.selectedIndex+1) + ']');
        node.parentNode.removeChild(node);
        xml.setXml(xmlDoc.xml);
        
        // display
        select.remove(select.selectedIndex);
    }
};

JRapid.prototype.collectionAddEntity = function(me, id, entity, subset, subsetparams, minrows, maxrows, displayCanvas, unique, firstPage) {

	var select = me.getParentNode().getParentNode().getFirstElementChild();

    if (maxrows && select.outerNode.options.length >= maxrows) {
        alert('Max rows: ' + maxrows);
        return false;
    }

    var container = me.getContainer();
    var selectxsl = container.getElementById('window_select_xsl' + id);

    if (subset && subset != '') {
        var url = jrapid.getServerPath(container) + entity + '/' + subset;
        if (subsetparams && subsetparams.length) {
	        var params = subsetparams.split(';');
	        for (var j=0; j < params.length; j++) {
	            url += '/' + jrapid.escapeParam(jrapid.evaluateXpath(evaluated(params[j], me), me));
	        }
	    }
        selectxsl.setUrl(url + (firstPage ? ',page1' : ''));        
    } else {
        selectxsl.setUrl(jrapid.getServerPath(container) + entity + (firstPage ? ',page1' : ''));
    }
    
    selectxsl.setAttribute('baseurl', selectxsl.getUrl());
    
    // console
    var tx = jrapid.startConsole('Add', false, 'green');
    
    selectxsl.refresh(function() {
    	// console
    	jrapid.endConsole(tx);
    	
    	// TODO if (network or service error) return error
        if (unique) {
        	var windowSelect = selectxsl.getLastElementChild().outerNode;
        	var currentSelect = select.outerNode;
            for (var i=windowSelect.options.length-1; i >= 0; i--) {
                for (var j=0, n=currentSelect.options.length; j < n; j++) {
                    if (windowSelect.options[i].value == currentSelect.options[j].value) {
                        windowSelect.remove(i);
                        break;
                    }
                }
            }    
        }        
    });
    
    selectxsl.getPreviousElementSibling().getStyle().display = firstPage ? '' : 'none';
    selectxsl.outerNode.parentNode.style.display = '';
    
    var win = container.getElementById(selectxsl.outerNode.id + '_window');
    if (win) {
    	win.open();
    } else {
    	var win = application.openWindow('Choose', selectxsl.outerNode.parentNode, null, true, true, true);
    	win.id = selectxsl.outerNode.id + '_window';
    	jrapid.wrap(win).resizeTo('360px', '260px', true);
    }
    selectxsl.outerNode.slaveSelect = select;
    selectxsl.outerNode.displayCanvas = displayCanvas;
    selectxsl.outerNode.unique = unique;
};

JRapid.prototype.collectionSelectFilter = function(input, value, comboproperty) {
    var xsl = input.getNextElementSibling();
    xsl.setUrl(xsl.getAttribute('baseurl') + (value ? ('!' + comboproperty + '=' + value) : ''));
    xsl.refresh(
    	// TODO if (network or service error) return error
    );
};

JRapid.prototype.collectionSelectWindowDblClick = function(me) {
    if (me.getSelectedIndex() == -1) {
        return;
    }
    
    var xsl = me.getParentNode().getParentNode().outerNode;
    var select = xsl.slaveSelect.outerNode;
    var maxrows = select.getAttribute('maxrows');
    
    if (maxrows && select.options.length >= parseInt(maxrows)) {
        alert('Max rows: ' + maxrows);
        return false;
    }
    
    var container = me.getContainer();
    
    var text = me.outerNode.options[me.outerNode.selectedIndex].text;
    var value = me.outerNode.options[me.outerNode.selectedIndex].value;
    
    select.options[select.options.length] = new Option(text, value);
    
    if (xsl.unique) {
        me.remove(me.getSelectedIndex());
    }
    
    var node = select.getAttribute('property');
    var selectexpr = evaluated(select.getAttribute('selectexpr'), select);
                        
    var xmlDoc = XmlDocument.create();
    xmlDoc.loadXML('<' + node + ' id=\'' + value + '\' />');

    var target = container.getElementById('xml');
    var targetDoc = target.getXmlDocument();
    targetDoc.selectSingleNode(selectexpr).appendChild(xmlDoc.documentElement);
    target.setXml(targetDoc.xml);
    
    var canvas = xsl.displayCanvas;
    if (canvas) {
        var txt = '';
        for (var i=0; i < select.options.length; i++) {
            txt += (i == 0 ? '' : ', ') + select.options[i].text;
        }
        canvas.innerHTML = txt;
        canvas.title = txt;
    }
};

/********************************* COMBO *********************************/

JRapid.prototype.comboKeyDown = function(me, entity, event) {
    if (event.keyCode == 13) {
		jrapid.comboOpened = false;
		application.stopPropagation(event);
		application.preventDefault(event);
    } else if (event.keyCode == 9) {
        jrapid.comboOpened = false;
        var container = me.getContainer();
        var xsl = container.getElementById('window_combo_xsl' + me.getId());
        xsl.getStyle().display = 'none';
        if (me.getNextElementSibling().getValue() == -1) {
            me.getStyle().color = 'red';
        }
        return;
    }
    return false;
};

JRapid.prototype.comboBlur = function(obj) {
	var me = jrapid.wrap(obj);
	obj.style.color = me.getNextSibling().getValue() == '' ? 'red' : ''; 
	jrapid.tooltipOff(me.outerNode);
};

JRapid.prototype.comboKeyUp = function(me, entity, ev, subset, subsetparams, comboproperty) {
    var container = me.getContainer();
    var xsl = container.getElementById('window_combo_xsl' + me.getId());        
    me.getStyle().color = '';
    
    if (ev.keyCode == 9 || ev.keyCode == 27 || ev.keyCode == 13 || 
            (me.getValue().length < 1 && ev.keyCode != 40 && ev.keyCode != 38)) {
        xsl.getStyle().display = 'none';
        return;
    }

    if (ev.keyCode == 40 && xsl.getStyle().display != 'none') {
        var tbody = xsl.outerNode.children[0].children[0].children[0];
        this.comboMove(xsl, tbody, 1);
        jrapid.comboSetValue(me, tbody.children[xsl.outerNode.comboSelectedIndex].title, 
                tbody.children[xsl.outerNode.comboSelectedIndex].getAttribute('rowid'));        
        
    } else if (ev.keyCode == 38 && xsl.getStyle().display != 'none') {
    	var tbody = xsl.outerNode.children[0].children[0].children[0];
        this.comboMove(xsl, tbody, -1);
        jrapid.comboSetValue(me, tbody.children[xsl.outerNode.comboSelectedIndex].title, 
                tbody.children[xsl.outerNode.comboSelectedIndex].getAttribute('rowid'));    
   
    } else if (ev.keyCode != 16) {
        jrapid.comboShow(me, xsl, entity, ev, subset, subsetparams, comboproperty, true);
    }
};

JRapid.prototype.comboMove = function(xsl, tbody, diff) {
    if (xsl.outerNode.comboSelectedIndex == null) {
        xsl.outerNode.comboSelectedIndex = -1;
    }

    if ((diff > 0 && xsl.outerNode.comboSelectedIndex >= tbody.children.length-1) ||
        diff < 0 && xsl.outerNode.comboSelectedIndex <= 0) {
        return;
    }
    
    if (xsl.outerNode.comboSelectedIndex >= 0) {
        var style = tbody.children[xsl.outerNode.comboSelectedIndex].style;
        style.backgroundColor = '';
        style.color = '';
    }
    
    xsl.outerNode.comboSelectedIndex+=diff;
    var style = tbody.children[xsl.outerNode.comboSelectedIndex].style;
    style.backgroundColor = '#000099';
    style.color = '#ffffff';
};

JRapid.prototype.comboSetValue = function(keyInput, key, id) {
    if (key != null) {
        keyInput.setValue(key);
    } 
    var input = keyInput.getNextSibling();
    id = id == null ? '' : id;
    if (id != input.getValue()) {
	    input.setValue(id);
	    //var newEvent = application.createEvent('HTMLEvents');
	    //newEvent.initEvent('change');
	    //input.dispatchEvent(newEvent);
		application.dispatch('change', input.outerNode, 'HTMLEvents');	
	}
    
    keyInput.outerNode.style.backgroundColor = '';
    keyInput.outerNode.style.color = '';  
};

JRapid.prototype.suggestClicked = function(obj) {
	
    var input = application.wrapNode(obj.getContainer().getElementById('suggests').outerNode.input);
   
    input.setValue(obj.getTitle());
    
    //var newEvent = application.createEvent('UIEvents');
    //newEvent.initUIEvent('change');
    //input.dispatchEvent(newEvent);
	application.dispatch('change', input, 'HTMLEvents');
	
	//obj.getParentNode().getStyle().display = 'none';
}

JRapid.prototype.comboShow = function(me, xsl, entity, ev, subset, subsetparams, comboproperty, setFirst) {
    var url;
    var container = me.getContainer();
    if (subset) {
        url = jrapid.getServerPath(container) + entity + '/' + subset;
        if (subsetparams) {
	        var params = subsetparams.split(';');
    	    for (var j=0; j < params.length; j++) {
        	    url += '/' + jrapid.evaluateXpath(evaluated(params[j], me), me);
	        }
	    }
        url += ',page1';
        url += (me.getValue()? ('!' + comboproperty + '=' + me.getValue()) : '');
    } else {
        url = jrapid.getServerPath(container) + entity + ',page1' + (me.getValue()? ('!' + comboproperty + '=' + me.getValue()) : '');
    }

    xsl.setUrl(encodeURI(url));
    xsl.outerNode.comboSelectedIndex = -1;
    xsl.outerNode.comboSelected = me;
	var comboTime = new Date().getTime();
	
	jrapid.comboOpened = true;
	xsl.refresh(function() {
    	/* check to see if this is the last call */    	
    	if (!jrapid.comboOpened || (jrapid.lastComboTime && jrapid.lastComboTime > comboTime)) {
    		return;
    	}
		jrapid.lastComboTime = comboTime;
    
    	// TODO if (network or service error) return error
    	xsl.getStyle().top = (me.getY() - xsl.getContainingBlock().getY() + me.getHeight()-2) + "px";
        xsl.getStyle().left = (me.getRelativeX()-4) + "px";    
        if (xsl.getLastElementChild() && xsl.getLastElementChild().getFirstElementChild().getFirstElementChild().hasChildren()) {
            xsl.getStyle().display = '';
            if (setFirst && me.getValue().toLowerCase() == xsl.getLastElementChild().getFirstElementChild().getFirstElementChild().getFirstElementChild().getTitle().toLowerCase()) {
                jrapid.comboSetValue(me, xsl.getLastElementChild().getFirstElementChild().getFirstElementChild().getFirstElementChild().getTitle(), 
                    xsl.getLastElementChild().getFirstElementChild().getFirstElementChild().getFirstElementChild().getAttribute('rowid'));
           }
        } else {
            xsl.getStyle().display = 'none';                
        }
    });    
    jrapid.comboSetValue(me, null, null);    
}
    
JRapid.prototype.comboDblClick = function(obj, entity, eventObj, subset, subsetparams, comboproperty) {
	
	var me = jrapid.wrap(obj);
	var ev = jrapid.wrap(eventObj)
    var container = me.getContainer();
    var xsl = container.getElementById('window_combo_xsl' + me.getId());        
    jrapid.comboShow(me, xsl, entity, ev, subset, subsetparams, comboproperty, false);    
};

JRapid.prototype.comboClicked = function(obj, id, key, rowid) {
	var me = jrapid.wrap(obj);
    var container = me.getContainer();
    var xsl = container.getElementById('window_combo_xsl' + id);        
    xsl.getStyle().display = 'none';    
    jrapid.comboSetValue(xsl.outerNode.comboSelected, key, rowid);    
};

/********************************* CHECKBOX *********************************/

JRapid.prototype.checkboxClicked = function(obj, selectexpr, name, value, isEntity, refreshCanvas) {
	
	var me = jrapid.wrap(obj);
	var id = me.getValue();    
    selectexpr = evaluated(selectexpr, me);
    var target = me.getContainer().getElementById('xml');
    var targetDoc = target.getXmlDocument();
        
    if (me.outerNode.checked) {
        var xmlDoc = XmlDocument.create();
        if (isEntity) {
            xmlDoc.loadXML('<' + name + ' id="' + id + '" />');
        } else {
            xmlDoc.loadXML('<' + name + '>' + value + '</' + name + '>');
        }
                                            
        targetDoc.selectSingleNode(selectexpr).appendChild(xmlDoc.documentElement);
        target.setXml(targetDoc.xml);                
    } else {
        var expr = isEntity ? (selectexpr + '/' + name + '[@id="' + id + '"]') : (selectexpr + '/' + name + '[. = "' + value + '"]');
        var node = targetDoc.selectSingleNode(expr);
        node.parentNode.removeChild(node);
        target.setXml(targetDoc.xml);
    }    
    
    if (refreshCanvas) {
        var values = targetDoc.selectNodes(selectexpr + '/' + name);
        var txt = '';
        for (var i=0; i < values.length; i++) {
            txt += (i == 0 ? '' : ', ') + values[i].firstChild.nodeValue;
        }
        refreshCanvas.innerHTML = txt;
    }
};

JRapid.prototype.radioClicked = function(me, selectexpr, name, value, isEntity, refreshCanvas) {
	var id = me.getValue();
    selectexpr = evaluated(selectexpr, me);
    var target = me.getContainer().getElementById('xml');
    var targetDoc = target.getXmlDocument();
        
    if (me.outerNode.checked) {
        var xmlDoc = XmlDocument.create();
        if (isEntity) {
            xmlDoc.loadXML('<' + name + ' id="' + id + '" />');
        } else {
            xmlDoc.loadXML('<' + name + '>' + value + '</' + name + '>');
        }
                                            
        targetDoc.selectSingleNode(selectexpr).appendChild(xmlDoc.documentElement);
        target.setXml(targetDoc.xml);                
    } else {
        var expr = isEntity ? (selectexpr + '/' + name + '[@id=' + id + ']') : (selectexpr + '/' + name + '[. = "' + value + '"]');
        var node = targetDoc.selectSingleNode(expr);
        node.parentNode.removeChild(node);
        target.setXml(targetDoc.xml);
    }    
    
    if (refreshCanvas) {
        var values = targetDoc.selectNodes(selectexpr + '/' + name);
        var txt = '';
        for (var i=0; i < values.length; i++) {
            txt += (i == 0 ? '' : ', ') + values[i].firstChild.nodeValue;
        }
        refreshCanvas.innerHTML = txt;
    }
};

/***************************** FILE UPLOAD *********************************/

JRapid.prototype.openHelp = function(me, entity, form, width, height) {	
	var type;
	if( form )
		type = 'form';
	else
		type = 'list';
			
	var div = document.createElement('div');
	div.style.overflow = 'scroll';
	div.innerHTML = "<iframe scrolling='no' frameborder='no' style='width: 400px; height: 500px' name='iframe'" + entity + "'>";
	width = width ? width : '';
	height = height ? height : '';
	div.children[0].src = '../help.Main/' + entity + '_' + type +'.htm';
	document.body.appendChild(div);
	
	var win = application.openWindow(entity + ' Help', div);
    jrapid.uploadinput = me.getPreviousElementSibling().getPreviousElementSibling();
    jrapid.uploaddiv = win;
	jrapid.wrap(win).resizeTo('407px','80px',true);
};

JRapid.prototype.fileChange = function(me, entity, width, height) {	
	var div = document.createElement('div');
	div.innerHTML = "<iframe scrolling='no' frameborder='no' style='width: 400px; height: 80px' name='iframe'" + entity + "'>";
	width = width ? width : '';
	height = height ? height : '';
	div.children[0].src = '../jrapid-runtime/upload.jsp?entity=' + entity + '&width=' + width + '&height=' + height;
	document.body.appendChild(div);
	
	var win = application.openWindow('Upload file', div);
    jrapid.uploadinput = me.getPreviousElementSibling().getPreviousElementSibling();
    jrapid.uploaddiv = win;
	jrapid.wrap(win).resizeTo('407px','80px',true);
};

function onupload(file) {
    var input = jrapid.uploadinput;
    input.setValue(file);
        
    if (input.getNextElementSibling().outerNode.tagName.toLowerCase() == 'img') {
    	input.getNextElementSibling().outerNode.src = ('../upload/' + file);
    } else {
    	input.getNextElementSibling().outerNode.href = '../upload/' + file;
        input.getNextElementSibling().outerNode.innerHTML = file.substring(file.indexOf('!')+1);
    }
    
    //input.dispatchChangeEvent();
    application.dispatch('change', input.outerNode, 'HTMLEvents');
    jrapid.uploaddiv.parentNode.removeChild(jrapid.uploaddiv);
};

/********************************* FILTERS *********************************/

jrapid.filters = [];

JRapid.prototype.setFilter = function(key, property, value, op) {    
    if (!jrapid.filters[key]) {
        jrapid.filters[key] = new Array();
    }
    if (value == '') {
        jrapid.filters[key][property] = null;
        return;
    }
    if (!op) {
        jrapid.filters[key][property] = [value];
    } else if (op < 0) {
        for (var i=jrapid.filters[key][property].length; i >=0 ; i--) {
            if (jrapid.filters[key][property][i] == value) {
                jrapid.filters[key][property].splice(i,1);                
            }
        }
    } else {
        if (!jrapid.filters[key][property]) {
            jrapid.filters[key][property] = [value];
        } else {
            jrapid.filters[key][property].push(value);
        }
    }
};

JRapid.prototype.getFilters = function(key) {
    var url = '';
    for (var property in this.filters[key]) {    
    	// TODO escape filters
        if (property != 'toXMLRPC' && this.filters[key][property] && this.filters[key][property] != "0" && this.filters[key][property].length) {
                url += (property + '=' + this.getFiltersAsString(this.filters[key][property]) + ':');
        }
    }
    return url == '' ? '' : url.substring(0, url.length-1);
};

JRapid.prototype.getFiltersAsString = function(array) {
    var string = '';
    for (var i=0; i < array.length; i++) {
        string += (i > 0 ? ',' : '') + array[i];
    }
    return string;
}

JRapid.prototype.filter = function(property, value, me, op) {    
    var container = me.getContainer();
    this.setFilter(container.getPrefix(), property, value, op);
    this.refreshFilter(container);
};

JRapid.prototype.refreshFilter = function(container) {
	var xsl = jrapid.listingGetXsl(container);
	var filters = this.getFilters(container.getPrefix());
    if (xsl.getAttribute('useparams')) {
        xsl.setUrl(xsl.getAttribute('baseurl') + '/' + container.node.subsetParams + ',page1' + (filters.length ? ('!' + filters) : ''));
    } else {
	    xsl.setUrl(xsl.getAttribute('baseurl') + ',page1' + (filters.length ? ('!' + filters) : ''));
	}
    
    // start console
    var tx = jrapid.startConsole('Filtering', false, 'green');
    
    xsl.refresh(function() {
		// end console
		jrapid.endConsole(tx);
		
		// TODO if (network or service error) return error
    });
};

JRapid.prototype.showHideFilters = function(obj) {    
    var me = jrapid.wrap(obj);
	var next = me.getNextElementSibling();
	
	next.outerNode.style.display = (next.outerNode.style.display == 'none' ? '' : 'none');
};

/*application.addEventListener('keydown', function(ev) {
    var target = ev.getTarget().getParentNode();

    if (ev.keyCode == 37) {
        target.getParentNode().getChildNodes().item(target.getCellIndex()-1).getFirstChild().focus();        
    } else if (ev.keyCode == 39) {
        target.getParentNode().getChildNodes().item(target.getCellIndex()+1).getFirstChild().focus();        
    } else if (ev.keyCode == 38) {
        target.getParentNode().getParentNode().getChildNodes().item(target.getParentNode().getRowIndex()-1).getChildNodes().item(target.getCellIndex()).getFirstChild().focus();        
    } else if (ev.keyCode == 40) {
        target.getParentNode().getParentNode().getChildNodes().item(target.getParentNode().getRowIndex()+1).getChildNodes().item(target.getCellIndex()).getFirstChild().focus();        
    }
    
});*/


/********************************* LISTING TABS **************************/

JRapid.prototype.listingTabClick = function(obj, entity) {
	var me = application.wrapNode(obj);
    var container = me.getContainer();
    var index=0;
	obj = obj.parentNode;
	while (obj.previousSibling) {
		if (obj.previousSibling.nodeType == 1) {
			index++;
		}
		obj = obj.previousSibling;
	}
	var pane = obj.parentNode.nextSibling; // TODO ff
	var j = 0;
	var tab;
	while (pane && (pane.nodeType != 1 || pane.className.indexOf('jrapid_tab') >= 0)) {
		if (pane.nodeType == 1) {
			if (j++ == index) {
				tab = application.wrapNode(pane);
				break;
			}
		}
		pane = pane.nextSibling;
	}
    
    if (tab.getAttribute('restriction')) {
        this.setFilter(container.getPrefix(), '_saved', tab.getAttribute('restriction'));
    } else  {
        this.setFilter(container.getPrefix(), '_saved', '');
    }
    
    
    if (tab.getAttribute('view')) {
        container.getElementById('selectview').setSelectedIndex(tab.getAttribute('view'));
    } else {
        container.getElementById('selectview').setSelectedIndex(0);
    }

    //Get all filters
    var filters = this.getFilters(container.getPrefix());            
    /*if (tab.getAttribute('restriction')) {
        filters = (filters.length ? ( filters + ':') : '') + '_saved=' + tab.getAttribute('restriction');
    }*/
    
    var children = tab.getChildren();
    for (var i=0; i < children.getLength(); i++) {
        var child = children.item(i);

/*        window.status = child.getAttribute('baseurl') + (filters.length ? ( '!' + filters) : '');
 */    
       child.setUrl(child.getAttribute('baseurl') + (filters.length ? ( '!' + filters) : ''));
       
       if (container.getElementById('selectview').getSelectedIndex() == i) {
            /*child.refresh();*/
        	this.refreshFilter(container);
            child.getStyle().display = '';
        } else {
            child.getStyle().display = 'none';                
        }
    }
};


/**************************** SAVED FILTERS *****************************/

JRapid.prototype.appendSavedFilter = function(me, title, restriction) {
    var container = me.getContainer();
    var tabpane = container.getElementById('tabpane');
    if (!tabpane || me.getInnerHTML() == '') {
        return;
    }
    var node = tabpane.getFirstElementChild();
    tabpane.appendTab(node, title);
    tabpane.getLastElementChild().setAttribute('restriction',restriction); 
    var tabs = tabpane.getChildren();
    var id = 'xsl_1_' + tabs.getLength();
    var views = tabpane.getLastElementChild().getChildren();
    for (var i=0; i<views.getLength(); i++) {
        views.item(i).setId('xsl_' + (i+1) + '_' + tabs.getLength());
    }
};

JRapid.prototype.removeSavedFilters = function(me) {
    var container = me.getContainer();
    var tabpane = container.getElementById('tabpane');
    if (!tabpane || me.getInnerHTML() == '') {
        return;
    }
    var nodes = tabpane.getChildren();
    for (var i=nodes.getLength()-1; i>=0; i--) {
        if (nodes.item(i).getAttribute('restriction')) {
            tabpane.removeTab(i);
        }
    }
};

JRapid.prototype.listingSavedFilterRefresh = function(me) {
    var t = me.getInnerHTML().split(';');
    var tabpane = me.getContainer().getElementById('tabpane');
    if (!tabpane) {
        return; 
    }
    var tabs = tabpane.getChildren();
    var j = 0;
    //Get saved filters tabs position
    for (;j<tabs.getLength();j++) {
        if (tabs.item(j).getAttribute('restriction')) {
            break;
        }
    }
    //Compare with existing tabs. If not present, it appends it
    for (var i=0; i < t.length; i++) {
        tabs = tabpane.getChildren();    
        if (!tabs.item(j+i) || !tabs.item(j+i).getAttribute('restriction')) {
            this.appendSavedFilter(me, t[i].split(',')[0], t[i].split(',')[1]);
        }
    }
    if (me.getAttribute('focusLast') == 'true') {
        tabpane.focusChild(j+i-1);    
    }
};

JRapid.prototype.showSaveFilter = function(me) {
    var container = me.getContainer();    
    container.getElementById('saveFilterPanel').getStyle().display='';
    container.getElementById('saveFilterLink').getStyle().display='none';        
    container.getElementById('saveFilterInput').focus();
};

JRapid.prototype.saveFilter = function(me) {
    var container = me.getContainer();
    container.getElementById('saveFilterPanel').getStyle().display='none';    
    container.getElementById('saveFilterLink').getStyle().display='';
    
    var xsl = jrapid.listingGetXsl(container);
    var name = me.getPreviousSibling().getValue();
    var filters = this.getFilters(container.getPrefix());
    
    /*this.setFilter(container.getPrefix(), '_saved', '');        */
    xsl.setUrl(xsl.getAttribute('baseurl') + ',saveas=' + name + (filters.length ? ('!' + filters) : ''));
    xsl.refresh(function() {
    	// TODO if (network or service error) return error
    
        container.getElementById('othertabs').setAttribute('focusLast','true');
        container.getElementById('othertabs').refresh(
        	// TODO if (network or service error) return error
        );
    });    
};

/*************************** VIEWS ********************/

JRapid.prototype.listingChangeView = function(obj) {
	var me = jrapid.wrap(obj);
    var container = me.getContainer();
    var tabpane = container.getElementById('tabpane');
    var index;
    for (index=1, c=tabpane.outerNode.children, n=c.length; index <=n ; index++) {
		if (c[index-1].className == 'active') {
			break;
		}
	}
    // TODO doesn't work properly with tab panes
    if (tabpane) {
    //    tabpane.getChildren().item(tabpane.getSelectedIndex()).setAttribute('view',me.getSelectedIndex());    
    }
    var i = tabpane ? (index) : 1;
    for (var j=0; j < me.outerNode.options.length; j++) {
        var xsl = container.getElementById('xsl_' + (j+1) + '_' + i);
        xsl.getStyle().display = (j == me.getSelectedIndex()) ? '' : 'none';
        if (j == me.getSelectedIndex()) {
            this.refreshFilter(container);
//            xsl.refresh();
        }
    }
};                

JRapid.prototype.listingGetXsl = function(container) {
    var tabpane = container.getElementById('tabpane');
    var i = 1;
    if (tabpane) {
    	for (i=1, c=tabpane.outerNode.children, n=c.length; i <=n ; i++) {
    		if (c[i-1].className == 'active') {
    			break;
    		}
    	}
    }    
    var view = container.getElementById('selectview');
    view = view == null ? 1 : (view.getSelectedIndex()+1);
    return container.getElementById('xsl_' + view + '_' + i);        
};

JRapid.prototype.listingGetTable = function(container) {
    var tabpane = container.getElementById('tabpane');
    var index = 1;
    if (tabpane) {
    	for (var i=0, c=tabpane.outerNode.children, n=c.length; i < n; i++) {
    		if (c[i].getAttribute('active')) {
    			index = i+1;
    			break;
    		}
    	}
    }
    var view = container.getElementById('selectview');
    view = view == null ? 1 : (view.outerNode.selectedIndex+1);
    return container.getElementById('table_' + view + '_' + index);        
};

/**************************** PAGES *******************************/

JRapid.prototype.page = function(obj, page, total) {
	var me = jrapid.wrap(obj);
    if (page <= total && page > 0) {
        var container = me.getContainer();
        var key = container.getPrefix();
        var xsl = jrapid.listingGetXsl(container);
        var filters = this.getFilters(key);
		var order = xsl.getAttribute('order') ? ('$' + xsl.getAttribute('order')) : '';
        xsl.setUrl(xsl.getAttribute('baseurl') + ',page' + page + (filters.length ? ('!' + filters) : '') + order); 
            
		// console
		var tx = jrapid.startConsole('Paging', false, 'green');
        xsl.refresh(function(param, xmlDoc, status) {
        	// console
        	jrapid.endConsole(tx);
			// check network error
        	if (status != 200) {
        		jrapid.startConsole('Network error', true, 'green');  
        		return;
        	}
        	
        	// check service error
        	if (xmlDoc == null || xmlDoc.documentElement == null || xmlDoc.documentElement.tagName == 'exception') {
        		jrapid.startConsole('Network error', true, 'red'); 
				if (xmlDoc != null && xmlDoc.documentElement && xmlDoc.documentElement.hasChildNodes()) {
					alert(xmlDoc.documentElement.childNodes[0].nodeValue);
				} else {
					alert('Unable to read');
				}
        		return; 
        	}
        });
    }
};

JRapid.prototype.pageList = function(obj, num, size) {
	var me = jrapid.wrap(obj);
    var pages = application.wrapNode(me);
    if (pages.getChildren().getLength() == 1) {
        for (var i=1, cell; i<=size; i++) {
            cell = document.createElement('option');
            cell.value = cell.innerHTML = i;    
            if (num == i) {
                cell.selected = "selected";
            }
            obj.appendChild(cell);
        }
        pages.removeChild(pages.getFirstElementChild());
    }
};

/******************************* ORDER ******************************/

JRapid.prototype.order = function(obj, label, index) {
	var me = jrapid.wrap(obj);
    var container = me.getContainer();
    var xsl = jrapid.listingGetXsl(container);
    var filters = this.getFilters(container.getPrefix());
    if (xsl.getAttribute('order') == index) {
    	index += 'd';
    }
    xsl.setUrl(xsl.getAttribute('baseurl') + ',page1' + (filters.length ? ('!' + filters) : '') + '$' + index);
    xsl.setAttribute('order', index);
     
    // console
    var tx = jrapid.startConsole('Ordering', false, 'green');
    
    xsl.refresh(function(i, xmlDoc, status) {
    	// end console
    	jrapid.endConsole(tx);
    	
    	// check network error
		if (status != 200) {
        	jrapid.startConsole('Network error', true, 'green');  
        	return;
       	}
        	
        // check service error
        if (xmlDoc == null || xmlDoc.documentElement == null || xmlDoc.documentElement.tagName == 'exception') {
        	jrapid.startConsole('Error', true, 'red'); 
			if (xmlDoc != null && xmlDoc.documentElement && xmlDoc.documentElement.hasChildNodes()) {
				alert(xmlDoc.documentElement.childNodes[0].nodeValue);
			} else {
				alert('Unable to read');
			}
        	return; 
        }

        jrapid.resizeTable(xsl);
        
    }, 0);
};


JRapid.prototype.getScreenX = function(obj) {
	if (obj.getBoundingClientRect) {
		return obj.getBoundingClientRect().left;
	} else {
		// TODO firefox
		return 0;
	}
};

JRapid.prototype.getScreenY = function(obj) {
	if (obj.getBoundingClientRect) {
		return obj.getBoundingClientRect().top;
	} else {
		// TODO firefox
		return 0;
	}
};

/************************* TOOLTIPS *************************************/

JRapid.prototype.tooltipOn = function(obj) {
	var me = jrapid.wrap(obj);
	var div = document.createElement('div');
	div.innerHTML = me.getAttribute('tooltip');
    div.className = 'jrapid_tooltip';
    //div.style.position = 'fixed';
    me.outerNode.tooltipElement = div;
    document.body.appendChild(div);
	
	var style = div.style;
    var top = 0;
    var left = 0;
    var screenX = jrapid.getScreenX(me.outerNode);
    var screenY = jrapid.getScreenY(me.outerNode);
    var width = me.getWidth();
    var height = me.getHeight();    
    style.display = '';
    if (screenX + width + 50 < document.body.clientWidth) {
    	top = screenY;
	    left = screenX + width + 5;
    } else if (screenY + height + 30 < document.body.clientHeight) {
    	left = screenX;
    	top = screenY + me.getHeight() + 3;
    } else {
   		left = screenX;
    	top = screenY - div.getLastElementChild().getHeight() + 10;
    }
    
    style.top = top + 'px';
    style.left = left + 'px';
};

JRapid.prototype.tooltipOff = function(obj) {
	var tooltip = obj.tooltipElement;
	if (tooltip) {
		tooltip.parentNode.removeChild(tooltip);
	}
};

/************************* ACTIONS *******************************/

JRapid.prototype.javascriptFormAction = function(obj, name) {
	var me = jrapid.wrap(obj);
    var container = me.getContainer();
    var id = container.getElementById('xml').getXmlDocument().selectSingleNode('/*').getAttribute('id');
    var ids = [id];
    eval(name + '(me, ids)');
    return false;
};

JRapid.prototype.javascriptListingAction = function(obj, name) {
	var me = jrapid.wrap(obj);
    var ids = this.getIds(me);
    eval(name + '(me, ids);');
    return false;
};

JRapid.prototype.openRelatedForm = function(obj, entity, defaultset, defaultsetparams) {
	var me = jrapid.wrap(obj);
    var id = '';
    if (defaultset) {
        var params = defaultsetparams ? defaultsetparams.split(';') : [];
        for (var j=0; j < params.length; j++) {
            id += (j > 0 ? '/' : '') + jrapid.evaluateXpath(params[j], me);
        }
    }
    return jrapid.openForm(me, entity, 'formcanvas', id, defaultset, null, true);    
};

JRapid.prototype.openRelatedListing = function(obj, entity, listing, subset, subsetparams) {
	var me = jrapid.wrap(obj);
    var id = '';
    if (subsetparams) {
        var params = subsetparams ? subsetparams.split(';') : [];
        for (var j=0; j < params.length; j++) {
            id += (j > 0 ? '/' : '') + jrapid.evaluateXpath(params[j], me);
        }
    }
    return jrapid.openListing(me, entity, null, listing, subset + (subset && id ? '/' : '') + id, null, null, true);
};

JRapid.prototype.getIdsAsString = function(me) {
	var ids = jrapid.getIds(me);
    var s = '';
    for (var i=0; i < ids.length; i++) {
        s += (i > 0 ? ',' : '') + ids[i];
    }
    return s.length ? s : '0';
}

JRapid.prototype.getIds = function(me) {
    var container = me.getContainer();

    var type = container.getElementById('selectview').getValue();
    var table = jrapid.listingGetTable(container);
    var ids = new Array();
    
    var index = 1;
    var tabpane = container.getElementById('tabpane');
    if (tabpane) {
    	for (var i=0, c=tabpane.outerNode.children, n=c.length; i < n; i++) {
    		if (c[i].getAttribute('active')) {
    			index = i+1;
    			break;
    		}
    	}
    }
    var view = container.getElementById('selectview');
    view = view == null ? 1 : (view.getSelectedIndex()+1);
    var items;
    switch(type) {
       	case 'thumbnails': 
        	items = jrapid.getElementsById('thumbnails_' + view + '_' + index, container.node); break;
       	case 'icons': 
            items = jrapid.getElementsById('icons_' + view + '_' + index, container.node); break;
       	case 'table': 
        default:
        	items = jrapid.getElementsById('tableitem_' + view + '_' + index, container.node); break;
    }

    for (var i=0; i<items.length; i++) {
        if (items[i].getAttribute('selected') || items[i].getAttribute('selected')=='true') {
            ids[ids.length] = items[i].getAttribute('rowid');
        }
    }    
    
    return ids;
};

JRapid.prototype.listingMouseOverThumbnail = function(me) {
    me.getFirstElementChild().getFirstElementChild().getFirstElementChild().getFirstElementChild().getNextSibling().getStyle().display = 'inline';
};

JRapid.prototype.listingMouseOutThumbnail = function(me) {
    me.getFirstElementChild().getFirstElementChild().getFirstElementChild().getFirstElementChild().getNextSibling().getStyle().display = 'none';
};

JRapid.prototype.listingToggleThumbnail = function(me) {
    if (me.getAttribute('selected') == 'true') {
        me.setAttribute('selected','false');
        me.setClassName('listing_thumbnails');
    } else {
        me.setAttribute('selected','true');        
        me.setClassName('listing_thumbnails listing_highlight');        
    }
};

JRapid.prototype.listingToggleIcon = function(me) {
    if (me.getAttribute('selected') == 'true') {
        me.setAttribute('selected','false');
        me.setClassName('listing_icons');
    } else {
        me.setAttribute('selected','true');        
        me.setClassName('listing_highlight');        
    }
};

JRapid.prototype.listingToggleBasic = function(me,odd) {
    if (me.getAttribute('selected') == 'true') {
        me.setAttribute('selected','false');
        me.setClassName(odd ? 'basic_odd' : 'basic_even');
    } else {
        me.setAttribute('selected','true');        
        me.setClassName('listing_highlight');        
    }    
};

JRapid.prototype.listingToggleTable = function(obj,odd) {
    if (obj.getAttribute('selected') == 'true') {
        obj.setAttribute('selected', 'false');
        obj.setAttribute("class", "");	
    } else {	
		obj.setAttribute("class", "jrapid_table_tr__selected");
        obj.setAttribute('selected', 'true');        
    }    
};

JRapid.prototype.listingClicked = function(me, id) {
	var me = jrapid.wrap(me);
	var node = me.getContainer().node;
    if (node && node.triggers && node.triggers.length) {
	   	for (var i=0, n=node.triggers.length; i < n; i++) {
	   		node.triggers[i](me, id);
	   	}
	}	
};

JRapid.prototype.listingRemove = function(obj, name) {
    if (confirm('Sure to delete these elements?')) {
    	var me = jrapid.wrap(obj);
        var ids = this.getIds(me);
                        
        // TODO param path
        var xmlrpcserver = new JRapid_XmlRpcServer(JRapid.XMLRPC_PATH);
        xmlrpcserver.executeAsync(name + '.remove', function(id, e) {
            if (e) {
                alert('Unable to delete');
            } else {
                jrapid.refreshFilter(me.getContainer());
            }
        }, ids);
        
    }
    return false;
};

JRapid.prototype.selectTimeSync = function(obj) {
	var me = jrapid.wrap(obj);
	var children = me.getParentNode().getChildren();
	var input = children.item(3);
	var s1 = children.item(0).outerNode;
	var s2 = children.item(2).outerNode;

	input.setValue(s1.options[s1.selectedIndex].text + ':' + s2.options[s2.selectedIndex].text);
	input.sync();
};

JRapid.prototype.selectDateSync = function(obj) {
	var me = jrapid.wrap(obj);
	var children = me.getParentNode().getChildren();
	var input = children.item(5);
	var s1 = children.item(0).outerNode;
	var s2 = children.item(2).outerNode;
	var s3 = children.item(4).outerNode;
	input.setValue(s1.value + '/' + s2.value + '/' + s3.value);
	input.sync();
};

JRapid.prototype.auditHistory = function(me, entity) {
	var id = me.getContainer().getElementById('xml').getXmlDocument().selectSingleNode('/*/@id').nodeValue;
	window.open('../jrapid-runtime/history.jsp?entity=' + entity + '&id=' + id, entity, 'resizable=yes,status=no,scrollbars=yes,width=500,height=300');
};

JRapid.prototype.navigate = function(me, select, dir, entity) {
	var options = select.outerNode.options;
	var newIndex = select.outerNode.selectedIndex + dir;
	if (newIndex >= 0 && newIndex < options.length) {
		options[newIndex].selected = true;
	}
	jrapid.loadForm(me.getContainer(), entity, select.outerNode.value);
};


JRapid.prototype.startAsyncConsole = function(container, key, service) {
	// TODO param refresh time and if append or replace text
	var textarea = document.createElement('textarea');
	textarea.className = 'jrapid_asyncconsole';
	document.body.appendChild(textarea);
	var win = application.openWindow('Executing', textarea);
	var message = "";
	
	var callServer = function(key) {
		// TODO param path
		var xmlrpcserver = new JRapid_XmlRpcServer(JRapid.XMLRPC_PATH);
		xmlrpcserver.executeAsync(service + '.getMessage', function(result) {
        	message = message + result;
			textarea.value = message;
			textarea.scrollTop = textarea.scrollHeight;
			if (result == null || result.indexOf('%END%') == -1) {
				setTimeout(function() {callServer(key)}, 1000);
			}
		}, parseInt(key));
       
	};
	
	callServer(key);	
};
    
/************************************ PANEL ************************************/

JRapid.prototype.accordeonOnClickResize = function() {
	var table = application.getElementById('table');
	if (table) {
		jrapid.panelResizeTable(table.outerNode, document.documentElement.clientHeight - 30);
	}
}

JRapid.prototype.registerPanelListing = function(me, entity, subset, subsetparams, defaultset) {
	var container = me.getContainer();
	
	var params = subsetparams.split(';');
	for (var i=0; i < params.length; i++) {
		var childContainer = container.getElementById(params[i]).getChildContainer();
		var node = childContainer.node;
		if (node.triggers == null) {
			node.triggers = [];
		}
		node.triggers[node.triggers.length] = function(foo, id) {
			// TODO only xsl (and just the current xsl) should be refreshed
			// TODO it must work with more than one subsetparam
			// TODO it must use the canvas passed by parameter, instead of me.getParentNode()			
			var child = me.getChildContainer();
			child.node.subsetParams = id;
			child.getElementById('add').setAttribute('defaultset', defaultset);
			child.getElementById('add').setAttribute('defaultsetparams', id);
			jrapid.loadListing(child, entity, subset + '/' + id, false, me.getParentNode());				
		};
	}	
};

JRapid.prototype.registerPanelForm = function(me, entity, defaultsetparams, defaultset) {
	var container = me.getContainer();
	var params = defaultsetparams.split(';');
	for (var i=0; i < params.length; i++) {
		var listing = container.getElementById(params[i]);
		var childContainer = listing.getChildContainer();
		var node = childContainer.node;
		if (node.triggers == null) {
			node.triggers = [];
		}
		node.triggers[node.triggers.length] = function(foo, id) {
			// TODO only xsl (and just the current xsl) should be refreshed. it must work with more than one param and with defaultset
			jrapid.loadForm(me.getChildContainer(), entity, id, defaultset, false, false, false, false, true);			
		};
	}	
};

/************************ PANEL SIZING ***************************/
 
JRapid.prototype.panelResizeTable = function (table, height) {
	for (var i=0, c = table.children[0].children, n = c.length; i < n; i++) {
		jrapid.panelResizeTr(c[i], height);
	}
};		
		
JRapid.prototype.panelResizeTr = function(tr, height) {
	var fixedHeight = 0;
	for (var i=0, c=tr.children, n=c.length; i < n; i++) {
		var h = c[i].getAttribute('panelheight');
		if (h && h.indexOf('%') == -1) {
			fixedHeight += parseInt(h);
		}
	}			
	for (var i=0, c=tr.children, n=c.length; i < n; i++) {
		jrapid.panelResizeTd(c[i], height-fixedHeight);
	}
};
		
JRapid.prototype.panelResizeTd = function(td, height) {
	if (td.getAttribute('panelheight')) {
		var tdHeight = td.getAttribute('panelheight');
		var index = tdHeight.indexOf('%');
		var actualHeight = index == -1 ? parseInt(tdHeight) : parseInt(tdHeight)*height/100;
		td.children[0].style.height = actualHeight + 'px';
		var fixedHeight = 0;
		for (var i=0, c=td.children[0].children, n=c.length; i < n; i++) {
			var h = c[i].getAttribute('panelheight');
			if (h && h.indexOf('%') == -1) {
				fixedHeight += parseInt(h);
			}
		}
		for (var i=0, c=td.children[0].children, n=c.length; i < n; i++) {
			var node = c[i];
			if (node.className == 'jrapid_accordeon') {
				jrapid.panelResizeAccordeon(node, actualHeight-fixedHeight);
			} else {
				jrapid.panelResizeItem(node, actualHeight-fixedHeight);
			}
		}
	}
};

JRapid.prototype.panelResizeItem = function(item, height) {
	var h = item.getAttribute('panelheight'); 
	if (h) {
		if (h.indexOf('%') == -1) {
			item.style.height = h;
		} else {
			item.style.height = (height*parseInt(h)/100) + 'px';
		}
		item.style.overflowY = 'auto';
	}

	if (item.getAttribute('listing')) {
		var xsl = jrapid.listingGetXsl(jrapid.wrap(item.children[0]).getChildContainer());
		if (xsl) {
			jrapid.resizeTable(xsl);
		}
	}	
};
		
JRapid.prototype.panelResizeAccordeonItem = function(item, height) {
	var fixedHeight = 0;
	var c = item.children[1].children;
	for (var i=0, n=c.length; i < n; i++) {
		var h = c[i].getAttribute('panelheight');
		if (h && h.indexOf('%') == -1) {
			fixedHeight += parseInt(h);
		}
	}
	for (var i=0, n=c.length; i < n; i++) {
		jrapid.panelResizeItem(c[i], height-fixedHeight);				
	}
};
		
JRapid.prototype.panelResizeAccordeon = function(accordeon, height) {
	for (var i=0, c=accordeon.children, n=c.length; i < n; i++) {
		jrapid.panelResizeAccordeonItem(c[i], height - n * JRapid.ACCORDEON_HEIGHT);				
	}
};
       
JRapid.ACCORDEON_HEIGHT = 21;
JRapid.SERVER_PATH = jrapid.getParam('path', '../xml/');    
JRapid.XMLRPC_PATH = jrapid.getParam('xmlrpcpath', '../xmlrpc/'); 
JRapid.WINDOW_HEIGHT = 30;

window.addEventListener('keydown', function(ev) {
	if (ev.keyCode == 75 && ev.ctrlKey) {
		if (JRapid_Source.cache) {
			JRapid_Source.cache = false;			
			alert('Cache disabled.');
		} else {
			JRapid_Source.cache = true;
			alert('Cache enabled.');
		}
	}   
}, false);