// +-----------------------------------------------------------+
// | SPP - library                                               								|
// +-----------------------------------------------------------+
// | Author: Stefano Picozzi <s.picozzi@gmail.com>                        		|
// +-----------------------------------------------------------+
// | file	  		: SPP/SPP/js/main.js							    				|
// | created  	: 2006/11/11  by Stefano Picozzi						           |
// | modified 	: 2009/11/11  by Stefano Picozzi						           |
// +-----------------------------------------------------------+
/**
 * Main JavaScript library
 * @package		SPP
 * @version			1.3
 * @author			Stefano Picozzi <s.picozzi@gmail.com>
 * @filesource
*/

/**
 * Get element
 * @return 	object
 * @param		string	e
 * @param		string	f
*/
function spp_GetElement(e,f){
	return $(e);
	/* Modified since mootools
	if(document.layers){
			f=(f)?f:self;
			if(f.document.layers[e]) {
					return f.document.layers[e];
			}
			for(W=0;i<f.document.layers.length;W++) {
					return(spp_GetElement(e,fdocument.layers[W]));
			}
	}
	if(document.all) {
			return document.all[e];
	}
	return document.getElementById(e);
	*/
}

/**
 * Get element in the specified window
 * @return 	object
 * @param		object	win		Window object
 * @param		string	e		Element name
 * @param		string	f		Layer
*/
function spp_GetElementInWindow(win,e,f){
	if(win.document.layers){
			f=(f)?f:self;
			if(win.f.document.layers[e]) {
					return win.f.document.layers[e];
			}
			for(W=0;i<win.f.document.layers.length;W++) {
					return(spp_GetElementInWindow(win,e,fdocument.layers[W]));
			}
	}
	if(document.all) {
			return win.document.all[e];
	}
	return win.document.getElementById(e);
}


/**
 * Javascript event function to create a Jump menu
 *
 * The function redirects the frame <i>targ</i> w.r.t. the selected element of <i>selObj</i>.
 * If <i>restore</i> = TRUE and <i>selObj</i> is present in the target page, then
 * the selected option is preserved.
 * @return 	void
 * @param		object		selObj		The select object name
 * @param		bool		restore		Wether we reset the select object
*/
function spp_JumpMenu(selObj,restore){
	eval("self.location='"+selObj.options[selObj.selectedIndex].value+"'");
	if (restore) selObj.selectedIndex=0;
}


/**
 * Javascript event function to create a Jump menu
 *
 * The function redirects the frame <i>targ</i> w.r.t. the selected element of <i>selObj</i>.
 * If <i>restore</i> = TRUE and <i>selObj</i> is present in the target page, then
 * the selected option is preserved.
 * @return 	void
 * @param		object		selObj		The select object name
 * @param		object		f			The form object
 * @param		bool		restore		Wether we reset the select object
*/
function spp_JumpSubmit(selObj,f,restore){
	if (!$chk(selObj))	selObj	= "this";
	f.action=selObj.options[selObj.selectedIndex].value;
	if (restore) selObj.selectedIndex=0;
	f.submit();
}


/**
 * Javascript function to manage a Div Replacement Menu
 *
 * The function redirects the frame <i>targ</i> w.r.t. the selected element of <i>selObj</i>.
 *
 * @return 	void
 * @param		object		selObj		The select object name
*/
function spp_DivSwitchMenu(divset, selObj, reset){
	if (!$chk(reset)) reset = false;
	// Get the divset (base) id
	var id = new spp_Id(divset);
	// Get selected index
	var selindex = selObj.selectedIndex;
	// Hide the non selected divs (and store the selected index)
	var selected = null;
	for (var i=0; i<selObj.options.length; i++) {
		var sid = new spp_Id(divset);
		sid.elname += '_' + i;
		if (i != selindex) {
			spp_HideElement(spp_GetElement(sid.getString()));
			//if (1) spp_GetElement(sid.getString()).reset();
		} else spp_ShowElement(spp_GetElement(sid.getString()));

	}
}


/**#@+
 * Known issues:
 * o Opera 5+ for Linux,
 * o Konqueror 2+, 3
 */

/**
 * Shows/Hides/Toggles the element given as argument by setting their <i>style.display</i> to 'none'
 *
 * @param	string	action	The action to be performed, in {'show','hide','toggle'}
 * @param	mixed	el		The concerned element
 * @param	string	effect	The effect to be applied, in {'fade'}
 * @return 	void
*/
function spp_HSelement(action,el,effect){
	if ($type(el) == 'string') var el = spp_GetElement(el);
	if ($chk(el)) {
		if (!$chk(effect)) {
			if (action == 'hide') el.setStyle('display','none');
			else if (action == 'show' || el.getStyle('display') == 'none') {el.setStyle('display','block');}
			else el.setStyle('display','none');
		} else {
			switch (effect) {
				case 'fade':
					if (action == 'hide') var transition = 'Fx.Transitions.Expo.easeOut';
					else if (action == 'show' || el.getStyle('display') == 'none') var transition = 'Fx.Transitions.Expo.easeIn';
					else var transition = 'Fx.Transitions.Expo.easeOut';
					el.set('morph', {
						duration: 1000,
						transition: transition,
						link: 'chain'
						});
					el.morph({
						'opacity': [0.97,0]
					});
				break;
				default:
					el.setStyle('width',0);
					el.setStyle('height',0);
					el.setStyle('top',3000);
					el.setStyle('left',3000);
				break;
			}
		}
	}
}

/**
 * Shows the element given as argument by setting their <i>style.display</i> to 'none'
 *
 * @param	mixed	el		The concerned element
 * @param	string	effect	The effect to be applied, in {'fade'}
 * @return 	void
*/
function spp_ShowElement(el,effect) {
	spp_HSelement('show',el,effect);
}
/**
 * Hides the element given as argument by setting their <i>style.display</i> to 'none'
 *
 * @param	mixed	el		The concerned element
 * @param	string	effect	The effect to be applied, in {'fade'}
 * @return 	void
*/
function spp_HideElement(el,effect) {
	spp_HSelement('hide',el,effect);
}
/**
 * Hides the element given as argument by setting their <i>style.display</i> to 'none'
 *
 * @param	mixed	el		The concerned element
 * @param	string	effect	The effect to be applied, in {'fade'}
 * @return 	void
*/
function spp_ToggleElement(el,effect) {
	spp_HSelement('hide',el,effect);
}


/**
 * Shows the element selected in the <i>Select</i> form object <i>selObj</i> given as argument
 * @return 	string 	The value of the selected otion
 * @param		string	el,...
*/
function spp_ShowSelectedOption(selObj,pref,suf){
	var val = selObj.options[selObj.selectedIndex].value;
	if ($chk(pref)) val = pref + val;
	if ($chk(suf)) val = val + suf;
	var el	= spp_GetElement(val);
	if ($chk(el.style)) {
		el.style.display = 'block';
		return val;
	} else return 0;

}

/**#@-*/



/**
 * Set the selected index a select element
 *
 * @param string 	selObj	The select object
 * @param string 	idx		The selected index
 */
function spp_SetSelectIndex(selObj,idx){
	selObj.selectedIndex = idx;
}


/**
 * Set the text of the idx^th option of a select element
 *
 * @param string 	sel		The id of the element
 * @param string 	idx		Index of the option to modify
 * @param string 	text	The text to assign
 */
function spp_SetOptionText(sel,idx,text){
	var selObj = spp_GetElement(sel);
	selObj.options[idx].text = text;
}



/**
 * Returns the first parent row containing the provided element
 * @param el	The element
*/
function spp_getElementRow(el) {
	if ($type(el) == "string") el = spp_GetElement(el);
	if (!$chk(el)) return null;
	if (el.get('tag') == 'tr' || el.get('tag') == 'TR') return el;
	// Get enclosing table
	var out = el.getParent('tr');

	return out;
}

/**
 * Checks/unchecks row i and changes its CSS
 *
 *
 * @param   string	Form name
 * @param   string	Basename of the element
 * @param   int   	Row index of element
 * @param   string CSS - Non-checked row
 * @param   string CSS - Checked row
 *
 * @return  boolean  The (new) checked status
 */
function spp_setFormCb(basename, elname, rownum, css_uch, css_ch){
	var id = new spp_Id(basename,elname,rownum);
	var cb = spp_GetElement(id.getString());

	var tblname = spp_getID(basename,"sppFTable");

	if ($chk(cb)) {
		if (cb.checked) {
			cb.checked = false;
			if ($chk(css_uch) && $chk(css_ch)) spp_setRowCss(tblname, rownum+1, css_uch);
		} else {
			cb.checked = true;
			if ($chk(css_uch) && $chk(css_ch)) spp_setRowCss(tblname, rownum+1, css_ch);
		}
		return cb.checked
	}
	return null;

}

/**
 * Checks/unchecks row i and changes its CSS
 *
 * Same as spp_setFormCb, but for the case when the PrimCheckbox itself is clicked (actions are reversed)
 *
 * @param   string	Form name
 * @param   string	Basename of the element
 * @param   int   	Row index of element
 * @param   string CSS - Non-checked row
 * @param   string CSS - Checked row
 *
 * @return  boolean  The (new) checked status
 */
function spp_setFormCb_primcb(basename, elname, rownum, css_uch, css_ch){
	var id = new spp_Id(basename,elname,rownum);
	var cb = spp_GetElement(id.getString());

	var tblname = spp_getID(basename,"sppFTable");
	if ($chk(cb)) {
		if (!cb.checked) {
			cb.checked = false;
			spp_setRowCss(tblname, rownum+1, css_uch);
		} else {
			cb.checked = true;
			spp_setRowCss(tblname, rownum+1, css_ch);
		}
		return cb.checked
	}
	return null;

}

/**
 * Highlights the current row
 *
 * @param   string   the form name
 * @param   string   basename of the element
 *
 * @return  boolean  true if works, false otherwise
 */
function spp_setFormCbRowCss(basename, rownum, css, freezeSelected){

	var tblname = spp_getID(basename,"sppFTable");

	if ($chk(tblname)) {
		if ($chk(css)) spp_setRowCss(tblname, rownum, css, freezeSelected);
    }
}

/**
 * Highlights the current row
 *
 * @param   string   the form name
 * @param   string   basename of the element
 *
 * @return  boolean  true if works, false otherwise
 */
function spp_setRowCss(table, i, css, freezeSelected){
	if (!$chk(css)) return false;
	if ($type(table) !== 'object') table = spp_GetElement(table);
	if (!$chk(freezeSelected)) var freezeSelected = false;

	if ($chk(table.rows[i].cells)) {
		var rcells = table.rows[i].cells;
		var j = 0;
		while ($chk(rcells[j])  && rcells[j] && (!freezeSelected || (rcells[j].className !== "selectedRow" && rcells[j].className !== "selectedEvenRow") && rcells[j].className !== "selectedOddRow")) {
			rcells[j].className = css;
			j++;
		}
	}
}

/**
 * Checks/unchecks all rows in a range
 *
 * @param   string   	Form name
 * @param   string   	Basename of the element (the full name is , where min <= i <= max)
 * @param	  bool		Wether we check or uncheck
 * @param   integer  	min element count
 * @param   integer  	max element count
 *
 * @return  boolean  true if works, false otherwise
 */
function spp_setCheckboxesRange(tableBasename, cbName, doCheck, min, max, even_css_ch, odd_css_ch, even_css, odd_css){
	var tblid = new spp_Id(tableBasename,"sppFTable");
	for (var i = min; i < max; i++) {
		var cb = spp_GetElement(spp_getID(tblid.basename, cbName, i));
		// FORM-PART of cbName IS NOT the same NAME FORMNAME
		if ($chk(cb)) {
			cb.checked = doCheck;
		}
	}
	var table = spp_GetElement(tblid.getString());
	var even = (Math.ceil(min/2) == min/2);
	for (var i = min; i < max; i++) {
		even = (even) ? false : true;
		if (!doCheck) {
			if (even) spp_setRowCss(table, i+1, even_css);
			else spp_setRowCss(table, i+1, odd_css);
		} else {
			if (even) spp_setRowCss(table, i+1, even_css_ch);
			else spp_setRowCss(table, i+1, odd_css_ch);
		}
	}
} // end of the 'setCheckboxesRange()' function


/**
 * Checks/unchecks all rows in a range
 *
 * @param   string   	the form name
 * @param   string   	basename of the element
 * @param	  string		The name of the Checkbox
 * @param   integer  	min element count
 * @param   integer  	max element count
 *
 * @return  The number of checked rows
 */
function spp_countCheckedRows(tableBasename, cbName, min, max){
	var tblid = new spp_Id(tableBasename,"sppFTable");
	var table = spp_GetElement(tblid.getString());
	if ($chk(table)) {
		var cb;
		var count=0;
		for (var i = min; i < max; i++) {
			var cb = spp_GetElement(spp_getID(tblid.basename, cbName, i));
			if ($chk(cb) && cb.checked) count++;
		}
		return count;

	}
	return NULL;

} // end of the 'spp_countCheckedRows



/**
 * Popups a Html (edition) window. A simplified version of spp_popupWIndow
 * @return 	void
 * @param string	href	The href to load in he new window
 * @param string	name	The name of the window to be opened
 * @param int		width	The width of the windo to be opened
 * @param int		height	The height of the windo to be opened
 * @param string	align	The horizontal alignement of the window ('left', 'center' or 'right')
 * @param string	valign	The vertical alignement of the window ('top', 'middle' or 'bottom')
 */
function spp_popupEditWindow(href, name, width, height, align, valign) {
	if (href.indexOf('?') == -1) href += '?';
	// Mask the opener (with iframe)
	/*
	spp_disableWindow(window,'sppIframe_mask');
	*/
	// Popuup
	href += '&wt=edt';
	var out = spp_popupWindow(href,name,width,height,align,valign,0);
	out.enableWindow = function (){
		spp_enableWindow(out,'sppIframe_mask');
	}
	if (!$chk(window.sppChilds)) window.sppChilds = new Array();
	window.sppChilds.push(out);
	return out;
}
// Extend current window
window.enableWindow = function (){
	spp_enableWindow(window,'sppIframe_mask');
}

/**
 * Activates full-screen IFRAME with transition
 */
function spp_disableWindow(win,maskname){
	if (!$chk(win)) 			var win 		= window;
	if (!$chk(maskname)) 	var maskname	= 'sppIframe_mask';
	var mask = spp_GetElement('sppIframe_mask');
	mask.set('class','mask');
	mask.setStyle('background-color','#000');
	mask.set('morph', {
		duration: 700,
		transition: Fx.Transitions.Cubic.easeOut,
		link: 'chain'
		});
	mask.morph({
		opacity: [0,0.6]
	});
	win.sppEnabled = 0;
}

/**
 * Activates full-screen IFRAME with transition
 */
function spp_enableWindow(win,maskname){
	if (!$chk(win)) 			var win 		= window;
	if (!$chk(maskname)) 	var maskname	= 'sppIframe_mask';
	var mask = spp_GetElement(maskname);
	mask.set('class','hiddenAbs');
	win.sppEnabled = 1;
}

/**
 * Reloads the window with same url
 */
function spp_wreload(win){
	if (!$chk(win)) var win = self;
	win.location.href=win.location.href;
}

/**
 * Reloads the window with same url
 */
function spp_wredirect(url,win){
	if (!$chk(win)) var win = self;
	win.location.href=url;
}

/**
 * Reloads the window with same url
 */
function spp_silentRefuse(home,win){
	if (!$chk(win)) var win = self;
	if ($chk(win.opener)) win.close();
	else win.location.href=home;
}

/**
 * Popups a (edition) window. A simplified version of spp_popupWIndow
 * @return 	void
 * @param string	href	The href to load in he new window
 * @param string	name	The name of the window to be opened
 * @param int		width	The width of the windo to be opened
 * @param int		height	The height of the windo to be opened
 * @param string	align	The horizontal alignement of the window ('left', 'center' or 'right')
 * @param string	valign	The vertical alignement of the window ('top', 'middle' or 'bottom')
 */
function spp_popup_IFRAME_EditWindow(href, name, width, height, align, valign) {
	if (href.indexOf('?') == -1) href += '?';
	href += '&wt=edt';
	return spp_popupWindow(href,name,width,height,align,valign,0);
}

/**
 * Popups a  window.
 * @return 	void
 * @param string	href	The href to load in the new window
 * @param string	name	The name of the window to be opened
 * @param int		width	The width of the window to be opened
 * @param int		height	The height of the window to be opened
 * @param string	align	The horizontal alignement of the window ('left', 'center' or 'right')
 * @param string	valign	The vertical alignement of the window ('top', 'middle' or 'bottom')
*/
function spp_popup_IFRAME_Window(href, name, width, height, align, valign, toolbar) {
	var xpos, ypos;
	if (!$chk(width) || width === "full") {
		width = window.innerWidth;
		xpos = Math.round((window.innerWidth-width)/2);
	}
	if (!$chk(height) || height === "full") {
		height = (1-0.02)*window.innerHeight;
		ypos = Math.round((window.innerHeight-height)/2);
	}
	if (!$chk(toolbar)) toolbar = 1;
	if (!$chk(xpos)) {
		if ($chk(align)) {
			if (align == 'center') 		xpos = Math.round((window.innerWidth-width)/2);
			else if (align == 'left') 		xpos = 0;
			else if (align == 'right') 	xpos = Math.round((1-0.02)*window.innerWidth - width);
			else 						xpos = 0;
		} else xpos = Math.round((1-0.02)*window.innerWidth - width);
	}
	if (!$chk(ypos)) {
		if ($chk(valign)) {
			if (valign == 'middle') 		ypos = Math.round((window.innerHeight-height)/2);
			else if (valign == 'top') 	ypos = 0;
			else if (valign == 'bottom')ypos = window.innerHeight - width;
			else ypos = 0;
		} else ypos = 0;
	}
	return spp_popupWindow0(href,name,width,height,xpos,ypos,toolbar,1,1,0);
}


/**
 * Popups a Html window.
 * @return 	void
 * @param string	href	The href to load in the new window
 * @param string	name	The name of the window to be opened
 * @param int		width	The width of the window to be opened
 * @param int		height	The height of the window to be opened
 * @param string	align	The horizontal alignement of the window ('left', 'center' or 'right')
 * @param string	valign	The vertical alignement of the window ('top', 'middle' or 'bottom')
*/
function spp_popupWindow(href, name, width, height, align, valign, toolbar, no_output) {
	var xpos, ypos;
	if (!$chk(width) || width === "full") 	width = screen.availWidth;
	if (!$chk(height) || height === "full") 	height = screen.availHeight;
	if (!$chk(toolbar)) toolbar = 1;

	if ($chk(align)) {
		if (align == 'center') 		xpos = Math.round((screen.availWidth-width)/2);
		else if (align == 'left') 		xpos = 0;
		else if (align == 'right') 	xpos = Math.round((1-0.05)*screen.availWidth - width);
		else 						xpos = 0;
	} else xpos = Math.round((1-0.05)*screen.availWidth - width);
	if ($chk(valign) ) {
		if (valign == 'middle') 		ypos = Math.round((screen.availHeight-height)/2);
		else if (valign == 'top') 	ypos = 0;
		else if (valign == 'bottom')ypos = screen.availHeight - width;
		else ypos = 0;
	} else ypos = 0;
	if (no_output) spp_popupWindow0(href,name,width,height,xpos,ypos,toolbar,1,1,0);
	else return spp_popupWindow0(href,name,width,height,xpos,ypos,toolbar,1,1,0);
}

sppIFM = new Object(); // IFrame Manager
sppIFM.current = -1;

/**
 * Popups up a window
 * @return 	void
 * @param string		href		The href to load in the new window
 * @param string		name		The name of the window to be opened
 * @param string		width		The width of the window to be opened
 * @param string		height		The height of the window to be opened
 * @param string		xpos		The horizontal position of the window in px
 * @param string		ypos		The vertical position of the window in px
 * @param boolean	toolbar		Wether the toolbar has to be displayed
 * @param boolean	resizable	Wether the window is resizable
 * @param boolean	scrollbars	Wether scrollbars have to be displayed
 * @param boolean	status		Wether the status of the window has to be displayed
*/
function spp_popup_IFRAME_Window0(href, name,  width, height, xpos, ypos, toolbar, resizable, scrollbars, status){

	// Get Free IFrame  (we have prepares some of them on each page)
	// N.B. Should be created "On The Fly" but does not work with Drag Package Below
	// Each IFrame is identified as sppIframe_N, with N=0,1,2,..,M
	sppIFM.current++;
	var iframeName = "sppIframe_" + sppIFM.current;
	var iframe = spp_GetElement(iframeName);
	iframe.set('src',href);
	iframe.setStyle('width',width);
	iframe.setStyle('height',0);
	iframe.setStyle('top',ypos);
	iframe.setStyle('left',xpos);
	iframe.setStyle('opacity',0.5);
	iframe.setStyle('background-color','#fff');

	iframe.set('morph', {
		duration: 700,
		transition: Fx.Transitions.Expo.easeOut,
		link: 'chain'
		});
	iframe.morph({
		'width':width,
		'height':height,
		'top': ypos,
		'left': xpos,
		'opacity': [0.7,0.97]
		});
	return popup;
}

function spp_popupWindow0(href, name,  width, height, xpos, ypos, toolbar, resizable, scrollbars, status){
	var features = 'toolbar=0';
	if ($chk(xpos) && xpos != null) features = (features) ?  features + ',left=' + xpos		: features + 'left=' + xpos;
	if ($chk(ypos) && ypos != null) features = (features) ?  features + ',top=' + ypos	 	: features + 'top=' + ypos;
	if ($chk(width) && width > 0)  features = (features) ?  features + ',width=' + width 	: features + 'width=';
	if ($chk(width) && height > 0) features = (features) ?  features + ',height=' + height	: features + 'height=' + height;
	if ($chk(toolbar)  && toolbar != null) features = (features) ?  features + ',toolbar=' + toolbar	: features + 'toolbar=' + toolbar;
	if ($chk(resizable)  && resizable != null) features = (features) ?  features + ',resizable=' + resizable	: features + 'resizable=' + resizable;
	if ($chk(scrollbars)  && scrollbars != null) features = (features) ?  features + ',scrollbars=' + scrollbars	: features + 'scrollbars=' + scrollbars;

	if ($chk(status) && status != null) features = (features) ?  features + ',status=' + status	: features + 'status=' + status;
	popup = window.open(href,name,features);
	popup.focus();

	var w = ($chk(width)) ? width : popup.outerWidth;
	var h = ($chk(height)) ? height : popup.outerHeight;
	popup.resizeTo(100,100);
	var steps	= 10;

	var dw 		= Math.floor((w-50)/steps);
	var dh 		= Math.floor((h-50)/steps);

	for (var i=0; i<steps; i++) {
		popup.resizeBy(dw,dh);
	}
	return popup;
}

/**
 * Javascript event function to create a Jump menu opening a popup window
 *
 * The function pops up a new window named <i>name</i> w.r.t. the selected element of <i>selObj</i>.
 * If <i>restore</i> = TRUE and <i>selObj</i> is present in the target page, then
 * the selected option is preserved.
 * @return 	void
 * @param object	selObj	The <select> object
 * @param	bool	restore	Wether we reset the select object
 * @param string	name	The name of the window to be opened
 * @param string	width	The width of the window to be opened
 * @param string	height	The height of the window to be opened
 * @param string	align	The horizontal alignement of the window ('left', 'center' or 'right')
 * @param string	valign	The vertical alignement of the window ('top', 'middle' or 'bottom')
*/
function spp_jumpMenu4popup(selObj, restore, name, width, height, align, valign){
	var href = selObj.options[selObj.selectedIndex].value;
	spp_popupEditWindow(href, name, width, height, align, valign);
	if (restore) selObj.selectedIndex=0;
}

/**
 * Popups a window which name is the provided ID
 *
 * This function should be used to make clear that the name of the window refers to an element ID
 *
 * @param string	href	The href to load in the new window
 * @param string	id		The id of the element opening the window
 * @param string	width	The width of the window to be opened
 * @param string	height	The height of the window to be opened
 * @param string	align	The horizontal alignement of the window ('left', 'center' or 'right')
 * @param string	valign	The vertical alignement of the window ('top', 'middle' or 'bottom')
*/
function spp_popupIDwindow(href, id, width, height, align, valign){
	return spp_popupEditWindow(href, id, width, height, align, valign);
}

/**
 * Sets the background color of the element "e" to the given color "c", where<br />
 * o "e": Is given by the name of the current window,
 * o "c": Is an hexadecimal color (including #)
 * @param string c
*/
function spp_setOpenerElBgColorFromIDwindow(c){
	var elname = window.name+'_bgcolor';
	var col		= '#'+c
	if(document.all) {
		window.opener.document.all[elname].bgColor=col;
	} else window.opener.document.getElementById(elname).bgColor=col;
}

/**
 * Sets the value of the element "e" to the given value "v", where "e": Is given by the name of the current window
 * @param mixed v
*/
function spp_setOpenerElValueFromIDwindow(v,html,pos){
	var elname = window.name;

	if(document.all) {
		if ($chk(window.opener.document.all[elname])) var el = window.opener.document.all[elname];
	} else var el = window.opener.document.getElementById(elname);
	switch (el.get('tag')) {
		case 'select':
			var selected = null;
			for (var i=0; i<el.options.length; i++) {
				if (el.options[i].value == v) {
					el.selectedIndex = i;
					return true;
				}
			}
			var opt = new Element('option',{'value': v});
			opt.set('html',html);
			if (!$chk(pos)) {
				var pos = el.options.length;
				el.options[pos] = opt;
				el.selectedIndex = pos;
			} else  {
				var ppos = (pos>0) ? pos : el.options.length+pos;
				for (var i=el.options.length; i>=ppos; i--) {
					if (i>=ppos) {
						el.options[i] = el.options[i-1].clone();
					}
					if (i==ppos) el.options[i] = opt;
				}
				el.selectedIndex = ppos;
			}

		break;
		default:
			el.value = v;
	}
}

function spp_addSelectOption(sel,text,value,pos) {
	if ($type(sel) == 'string') var sel = spp_GetElement(sel);
	if ($chk(sel)) {
		var opt = new Element('option',{'value': value, 'text': text});

		if (!$chk(pos)) {
			var pos = el.options.length;
			sel.options[pos] = opt;
			sel.selectedIndex = pos;
		} else  {
			if (pos === 'end') pos = sel.options.length + 0;
			var ppos = (pos>0) ? pos : sel.options.length + pos;
			for (var i=sel.options.length; i>=ppos; i--) {
				if (i>=ppos) {
					sel.options[i] = sel.options[i-1].clone();
				}
				if (i==ppos) sel.options[i] = opt;
			}
			sel.selectedIndex = ppos;
		}
	}
}


/**
 * Gets a value stored in the window name: Substring after "=", if character "=" is found, and false otherwise
*/
function spp_getValFromWindowName(){
	if ((n=window.name.indexOf('_sppeq_'))>-1) {
		return window.name.substr(n+1);
	} else {
		return false;
	}
}

/**
 * Gets attribute from the window name: Substring precedding "="  if character "=" is found, and false
*/
function spp_getAttibuteFromWindowName(){
	if ((n=window.name.indexOf('_sppeq_'))>-1) {
		return window.name.substr(0,n);
	} else {
		return false;
	}
}

/**
 * Closes the current window
 */
function spp_close(targ){
	if (!$chk(targ) ) targ = self;
	if (!$chk(targ.opener)) targ.opener = self;
	targ.close();
}


function spp_URLEncode( s )
{
	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";

	var plaintext = s;
	var encoded = "";
	for (var i = 0; i < plaintext.length; i++ ) {
		var ch = plaintext.charAt(i);
	    if (ch == " ") {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} else if (SAFECHARS.indexOf(ch) != -1) {
		    encoded += ch;
		} else {
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) {
			    alert( "Unicode Character '"
                        + ch
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";
			} else {
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} // for
	return encoded;
};

function spp_URLDecode( s )
{
	if (!$chk(s)) return null;
   // Replace + with ' '
   // Replace %xx with equivalent character
   // Put [ERROR] in output if %xx is invalid.
   var HEXCHARS = "0123456789ABCDEFabcdef";
   var encoded = s;
   var plaintext = "";
   var i = 0;
   while (i < encoded.length) {
       var ch = encoded.charAt(i);
	   if (ch == "+") {
	       plaintext += " ";
		   i++;
	   } else if (ch == "%") {
			if (i < (encoded.length-2)
					&& HEXCHARS.indexOf(encoded.charAt(i+1)) != -1
					&& HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) {
				plaintext += unescape( encoded.substr(i,3) );
				i += 3;
			} else {
				alert( 'Bad escape combination near ...' + encoded.substr(i) );
				plaintext += "%[ERROR]";
				i++;
			}
		} else {
		   plaintext += ch;
		   i++;
		}
	} // while
   return plaintext;
};


function spp_Replace(string,search,replace,table,debug){
	if ($type(search) == 'array') {
		var out = string;
		for (var i=0; i<search.length; i++) out = spp_Replace(out,search[i],replace[i],table,debug);
	} else {
		var out = '';
		var p0 		= 0;
		var p 		= null;
		var p_old	= p;
		var start_s	= 0;
		var start_out	= 0;
		while ((p=string.indexOf(search,start_s)) > -1 ) {
			search += '';
			replace += '';
			var str = string.slice(start_s,p);
			out += str + replace;
			if ($chk(table)) table.push({'start': start_out, 'end': out.length - 1, 'search': search, 'replace': replace});
			start_s		= p + search.length;
			start_out 	= out.length + replace.length + 1;
		}
		out += string.slice(start_s,string.length);
	}
	return out;
}

// ============================
//				--- ELEMENT ---
// ============================

/**
 * Disables/Enables/Toggles the provided element
 * @param mixed	action 	The action to be performed, in {'disable','enable','toggle'}
 * @param string	which	The concerned element
 * @param mixed	opt 	The concerned option (if any)
 * @return element The modified element
 */
function spp_EDelement(action,el,opt) {
	if ($type(el) == 'string')  var el = spp_GetElement(el);
	var el = new Element(el);
	if ($type(el) == 'element') {
		if ($chk(el.disable) || ($chk(el.retrieve('class')) && $chk(el.retrieve('class').disable))) {
			if (action == 'disable') el.retrieve('class').disable();
			else if (action == 'enable') el.retrieve('class').enable();
			else el.retrieve('class').toggle();
			return el;
		}
		if (el.get('tag') == 'select' && $chk(opt)) {
			if ($type(opt) == 'element') var the_el = el.options[opt];
			else  var the_el = el.options[opt];
		} else var the_el = el;
		if (action == 'disable') the_el.set('disabled',true);
		else if (action == 'enable' || the_el.get('disabled')) the_el.set('disabled',false);
		else the_el.set('disabled',true);
	} else the_el = null;
	return the_el;
}
/**
 * Disables the provided element
 * @param string	which	The concerned element
 * @param mixed	opt 	The concerned option (if any)
 * @return element The modified element
 */
function spp_DisableElement(el,opt) {
	return spp_EDelement('disable',el,opt);
}
/**
 * Enables the provided element
 * @param string	which	The concerned element
 * @param mixed	opt 	The concerned option (if any)
 * @return element The modified element
 */
function spp_EnableElement(el,opt) {
	return spp_EDelement('enable',el,opt);
}
/**
 * Toggles the provided element
 * @param string	which	The concerned element
 * @param mixed	opt 	The concerned option (if any)
 * @return element The modified element
 */
function spp_ToggleElement(el,opt) {
	return spp_EDelement('toggle',el,opt);
}

// ============================
//				--- PAGE ---
// ============================
/**
  * Outputs a well formatted 'id' string
  * @param string basename
  * @param string elname
  * @param string rownum
*/
function spp_getID(basename,elname,rownum){
	var id = new spp_Id(basename,elname,rownum);
	return id.getString();
}
/**
  * Outputs a well formatted 'name' string
  * @param string basename
  * @param string elname
  * @param string rownum
*/
function spp_getName(){
	var name = new spp_Id(basename,elname,rownum);
	return name.getString();
}

/**
  * Create an ID object
  * @param strring	id_or_basename	In which case when elname is null, this is parsed as it was a formatted 'id' string
  * @param string 	elname
  * @param string 	rownum
*/
function spp_Id(id_or_basename,elname,rownum){

	// INIT
	this.basename = null;
	this.elname 	= null;
	this.rownum 	= null;

	if ($chk(elname)) {
		this.basename = ($chk(id_or_basename)) ? id_or_basename : null;
		this.elname 	= ($chk(elname)) ? elname : null;
		this.rownum 	= ($chk(rownum)) ? rownum : null;
	} else if ($type(id_or_basename) == 'string') {
		var row = id_or_basename.split("-");
		this.basename = ($chk(row[0])) ? row[0] : null;
		this.elname 	= ($chk(row[1])) ? row[1] : null;
		this.rownum 	= ($chk(row[2])) ? row[2] : null;
	} else {
		this.basename = id_or_basename.basename;
		this.elaname 	= id_or_basename.elname;
		this.rownum	= id_or_basename.rownum;
	}


	// ------------- METHODS -----------
	this.getString = function(basename,elname,rownum){
		if (!$chk(basename)) 	var basename = this.basename;
		if (!$chk(elname)) 		var elname = this.elname;
		if (!$chk(rownum)) 		var rownum = this.rownum;
		if ($chk(rownum)) 	return basename + "-" + elname + "-" + rownum;
		if ($chk(elname)) 	return basename + "-" + elname;
		return basename;
	}
}


function spp_Name(id_or_basename,elname,rownum){
	// INIT
	this.basename = null;
	this.elname 	= null;
	this.rownum 	= null;

	if ($chk(elname)) {
		this.basename = ($chk(id_or_basename)) ? id_or_basename : null;
		this.elname 	= ($chk(elname)) ? elname : null;
		this.rownum 	= ($chk(rownum)) ? rownum : null;
	} else if ($type(id_or_basename) == 'string') {
		var row = id_or_basename.split("-");
		this.rownum 	= ($chk(row[0])) ? row[0] : null;
		this.basename = ($chk(row[1])) ? row[1] : null;
		this.elname 	= ($chk(row[2])) ? row[2] : null;
	} else  {
		this.basename = id_or_basename.basename;
		this.elname 	= id_or_basename.elname;
		this.rownum	= id_or_basename.rownum;
	}


	// ------------- METHODS -----------
	this.getString = function(basename,elname,rownum){
		if (!$chk(basename)) 	var basename = this.basename;
		if (!$chk(elname)) 		var elname = this.elname;
		if (!$chk(rownum)) 		var rownum = this.rownum;
		if ($chk(rownum)) 	return rownum + "-" + basename + "-" + elname;
		if ($chk(elname)) 	return basename + "-" + elname;
		return basename;
	}
}



function spp_Page(doc){

	this.document = ($chk(doc)) ? doc : document;
	this.els = new Object();


	this.parseDocument = function(){
		var localdebug = false;
		var all = this.document.getElements("*");
		var debug = null;
		if ($chk(all)) {
			for (var i=0; i<all.length; i++) {
				if ('getProperty' in all[i] && $chk(all[i].getProperty('id'))) {
					var id = new spp_Id(all[i].id);
					// Els (ByBasename)
					if ($chk(id.basename) && $type(this.els[id.basename]) != "object") this.els[id.basename] = new Object();
					if ($chk(id.elname) && $type(this.els[id.basename][id.elname]) != "object") this.els[id.basename][id.elname] = new Object();

					if ($chk(id.rownum))  this.els[id.basename][id.elname][id.rownum] = all[i];
					else if ($chk(id.elname))  this.els[id.basename][id.elname] = all[i];
				}
			}
		}
		if ( localdebug) {
			this._alertElements("Parsed provided document:");
		}
	}

	this.walkElements = function(id, fn) {
		if ($type(id) != 'object') id = new spp_Id(id);

		if ($chk(id.basename) && $chk(id.elname) && $chk(id.rownum)) {
		// Delete only the corresponding element
			if ($chk(this.els[id.basename]) && $chk(this.els[id.basename][id.elname]) && $chk(this.els[id.basename][id.elname][id.rownum])) fn(this.els,id.basename, id.elname, id.rownum);
		} else if ($chk(id.basename) && $chk(id.elname)) {
		// Delete all rownums i.e. all elements in "els[id.basename][id.elname]" (Typically one element in each row of a (sub)-table)
			if ($chk(this.els[id.basename]) && $chk(this.els[id.basename][id.elname])) fn(this.els,id.basename, id.elname);
		} else if ($chk(id.basename) && $chk(id.rownum)) {
		// Delete The i^th row of a (sub)-table
			if ($chk(this.els[id.basename]) ) {
				for (elname in this.els[id.basename]) {
					if ($chk(this.els[id.basename][elname][id.rownum])) {
						fn(this.els,id.basename, elname, id.rownum);
					}
				}
			}
		} else if ($chk(id.elname) && $chk(id.rownum)) {
		// Delete all elements with  provided elname and rownum (Typically an ELEMENT in a (sub)-table)
		// + RE-INDEX elements
			for (basename in this.els) {
				if ($chk(this.els[basename][id.elname][id.rownum])) {
					fn(this.els,basename, id.elname, id.rownum);
				}
			}
		} else if ($chk(id.basename)) {
			for (elname in this.els[id.basename]) {
				if ($type(this.els[id.basename][elname]) == 'object') {
					for (rownum in this.els[id.basename][elname]) {
						if ($chk(this.els[id.basename][elname][rownum])) fn(this.els,id.basename, elname, rownum);
					}
				} else {
					if ($chk(this.els[id.basename][elname])) fn(this.els,id.basename, elname);
				}
			}
		} else if ($chk(id.elname)) {
			for (basename in this.els) {
				if ($chk(this.els[basename][id.elname])) fn(this.els,basename, id.elname);
			}
		} else if ($chk(id.rownum)) {
			for (basename in this.els) {
				for (elname in this.els[basename]) {
					if ($chk(this.els[basename][elname]) == 'object' && $chk(this.els[basename][elname][id.rownum])) {
						fn(this.els,basename, elname, id.rownum);
					}
				}
			}
		}
	}

	this.deleteElements = function(id){
		if ($type(id) != 'object') id = new spp_Id(id);
		this.walkElements(id, function(els,basename,elname,rownum) {
			if ($type(basename) == 'object') {
				var id = new spp_Id(basename);
				var basename = id.basename;
				var elname		= id.elname;
				var rownum	= id.rownum;
			}
			if ($chk(rownum)) {
				delete els[basename][elname][rownum];
			} else if ($chk(elname)) {
				delete els[basename][elname];
			} else {
				delete els[basename];
			}
			// IF removing the i^th row of a (sub)-table, then re-index elements with greater rownum

			if($chk(rownum) && !$chk(elname) && rownum > -1) {
				var ii 	= parseInt(rownum);
				var ii1 	= ii + 1;
				var is 	= ii + '';
				var is1 	= ii1 + '';
				while ($chk(this.els[basename][elname][is1])) {
					this.els[basename][elname][is] = this.els[basename][elname][is1];
					this.els[basename][elname][is].id 		= spp_getID(basename,elname,is);
					this.els[basename][elname][is].name 	= spp_getID(basename,elname,is);
					ii 	= ii1;
					ii1++;
					is 	= ii + '';
					is1 = ii1 + '';
				}
				delete this.els[basename][elname][rownum];
			}
		});
	}

	this._alertElements = function(s){
		var debug = ($chk(s)) ? s : null;
		for (basename in this.els) {
			for (elname in this.els[basename]) {
				if ($type(this.els[basename][elname]) == 'object') {
					for (rownum in this.els[basename][elname]) {
						debug += "\n\n"  + basename + "-" + elname + "-" + rownum + "\n --> \n" + this.els[basename][elname][rownum].get('id');
					}
				} else debug += "\n\n"  + basename + "-"  + elname + "\n --> \n" + this.els[basename][rownum].get('id');
			}
		}
		alert( debug);
	}

}

/**
 * @global	spp_Page	GLOBAL spp_Page object "sppPage"
 */
var sppPage = null;


function spp_getPage(){
	if ($chk(sppPage)) return sppPage;
	sppPage = new spp_Page();
	sppPage.parseDocument();
	return sppPage;
}


// ============================
//				--- TABLE ---
// ============================
/**
 * Instantiates a spp_Ftable object for the table identified by "tableID"
 *
 * @param	tableID		The ID of the target table
 * @return spp_table
 */
function spp_Ftable(basename, even_css, odd_css, even_css_ch, odd_css_ch){

	this.even_css = even_css;
	this.odd_css = odd_css;
	this.even_css_ch = even_css_ch;
	this.odd_css_ch = odd_css_ch;



	/**
	 * The main page object
	 *@var spp_Page
	 */
	this.page = spp_getPage();

	/**
	 * The table basename (typically, the form name)
	 *@var string
	 */
	this.basename = basename;

	/**
	 * The table id=spp_getID(basename,"sppFTable")
	 *@var string
	 */
	this.id		= spp_getID(basename,"sppFTable");

	/**
	 * The table object
	 *@var spp_Table
	 */
	this.table 	= $(this.id);

	if ($chk(this.table)) {
		/**
		 * The table body object
		 *@var element
		 */
		this.body 	=  this.table.tBodies[0];


		if (!$chk(rcard)) var rcard = this.table.getElements('tr').length;

		/**
		 * The row cardinality of the table
		 *@var int
		 */
		this.rcard 	= rcard;

		/**
		 * The element cardinality of the table
		 *@var int
		 */
		this.elcard 	= rcard;

		/**
		 * The associated form object
		 *@var element
		 */
		this.form 	= this.table.getParent('form');
	}



	//---------- INIT --------------
	this.init = function(refresh){
		if (refresh) this.refresh();
	}

	this.refresh = function(){
		this.refreshCbRowCss();

	}

	// ----------------- CHECK/UNCHECK METHODS -------------------


	this.clickElementCbRow = function(el,css_uch, css_ch){
		var cbname = 'primCheckbox';
		var rownum = spp_getElementRow(el).rowIndex;
		if ($chk(this.table.tHead)) rownum--;
		var c = spp_setFormCb(this.basename, cbname, rownum, css_uch, css_ch); // Checks the cb and sets row css
		var sign = (c) ? "+" : "-";
		this.add2multiSubmit(rownum,sign);
	}

	this.clickPrimCheckbox = function(el,css_uch, css_ch){
		var cbname = 'primCheckbox';
		var rownum = spp_getElementRow(el).rowIndex - 1;
		var c = spp_setFormCb_primcb(this.basename, cbname, rownum, css_uch, css_ch);
		var sign = (c) ? "+" : "-";
		this.add2multiSubmit(rownum,sign);
	}

	this.add2multiSubmit = function(rownum,sign){
		var localdebug = false;
		var msid = new spp_Id(this.basename,'sppMultiSubmit_ids');
		var msubmit = spp_GetElement(msid.getString());
		if ($chk(msubmit)) {
			if (rownum == "all") {
				msubmit.value = (sign=="+") ? "all" : "";
				if (localdebug) alert(" > sppMultiSubmit_ids set to \"" + msubmit.value + "\" ");
			} else  {
				var idid = new spp_Id(this.basename,'id',rownum);
				var idElement = spp_GetElement(idid.getString());
				if ($chk(idElement.value)) {
					msubmit.value += sign + idElement.value ;
					if (localdebug) alert(" > ID added to sppMultiSubmit_ids: \n     - ID=" + idElement.value + " \n     - sppMultiSubmit_ids: \n      \"" + msubmit.value + '"');
				} else if (localdebug) alert(" > ID FAILED to be added to sppMultiSubmit_ids - " + idElement.get('value'));
			}
		}
	}

	this.countSelectedCbRows = function(){
		var cbname = 'primCheckbox';
		return spp_countCheckedRows(this.basename, cbname, 0, this.rcard);
	}

	this.selectAllCbRows = function(invert){
		this.clickAllCbRows('select', invert);
	}

	this.unselectAllCbRows = function( invert){
		this.clickAllCbRows('unselect', invert);
	}


	this.clickAllCbRows = function(selectMode, invert){
		var cbname = 'primCheckbox';
		var even = true;
		for (var i=0; i<this.rcard; i++) {
			if (even) {
				var c = spp_setFormCb(this.basename, cbname, i, this.even_css, this.even_css_ch);
				if ((!$chk(invert) || !invert) && (selectMode == 'select' && !c || selectMode == 'unselect' && c)) {
					c = spp_setFormCb(this.basename, cbname, i, this.even_css, this.even_css_ch);
				}
			} else {
				var c = spp_setFormCb(this.basename, cbname, i, this.odd_css, this.odd_css_ch);
				if ((!$chk(invert) || !invert) && (selectMode == 'select' && !c || selectMode == 'unselect' && c)) {
					c = spp_setFormCb(this.basename, cbname, i, this.odd_css, this.odd_css_ch);
				}
			}
			even = !even;
		}
		var sign = (selectMode == 'select') ? "+" : "-";
		this.add2multiSubmit("all",sign);
	}

	/**
	 * Sets the CSS of each row according to the status of its checkbox (Lazy method)
	*/
	this.refreshCbRowCss = function(){
		if (!$chk(this.even_css) || !$chk(this.odd_css)) return false;
		var cbname = 'primCheckbox';
		var even = true;
		for (var i=0; i<this.rcard; i++) {
			if (even) {
				spp_setFormCb(this.basename, cbname, i, this.even_css, this.even_css_ch);
				spp_setFormCb(this.basename, cbname, i, this.even_css, this.even_css_ch);
			} else {
				spp_setFormCb(this.basename, cbname, i, this.odd_css, this.odd_css_ch);
				spp_setFormCb(this.basename, cbname, i, this.odd_css, this.odd_css_ch);
			}
			even = !even;
		}
	}


	//  ----------------- ROW METHODS -----------------------
	this.deleteElementCbRow = function(el, dbquery) {
		if (!$chk(dbquery)) dbquery = false;
		var index = spp_getElementRow(el).rowIndex;
		if (!dbquery) {
			// We need to copy the current row as it was an unchecked row
			// Update the page.els associated with the current row ---> set as hidden fields
			// N.B. "this.elcard" is NOT modified
			var id = new spp_Id(el.id);
			id.elname 	= null; //  Will select (and delete) all elements in the same table row than "el"
			this.page.walkElements(id, function(els,basename,elname,rownum) {
				if ($type(basename) == 'object') {
					var id = new spp_Id(basename);
					var basename = id.basename;
					var elname		= id.elname;
					var rownum	= id.rownum;
				}

				var el = els[basename][elname][rownum];
				// Uncheck PrimCheckbox
				/**
				 * @todo
				 * THE ROW IS KILLED AND WE LOOSE THE ENTRY (WORKS well for insert, but not for update when deleting row)
				*/
				if (elname == 'primCheckbox') {
					var primcheck_false = els[basename]['primCheckbox_false'][rownum];
					if (el.get('type') == 'hidden') {
						el.value = ($chk(primcheck_false)) ? primcheck_false.get('value') : 'delete';
					} else el.checked = false;
				}
				// Set form elements as hidden fields
				/* USELESS
				if ($chk(el.type) && el.type != "hidden" ) {
					el.type = "hidden";
				}
				*/
			});
		} else {
			// TO BE FINISHED
			// Remove the row from "page.els"
			var id = new spp_Id(el.id);
			id.elname 	= null; //  Will select (and delete) all elements in the same table row than "el"
			this.page.deleteElements(id);
		}
		// Delete the table-row
		this.deleteElementRow(el);
	}


	this.pushCbRow = function(data) {
		/**
		 *@todo Insert corresponding elements in the (main) page
		 */
		if ($chk(data)) {
			if ($type(data) == "string") {
				data = spp_URLDecode(data);
				var search	= new Array('sppFRowNum','sppFTableID');
				var replace	= new Array(this.elcard,this.id);
				//
				var scard = search.length;
				for (i=0; i<scard; i++) {
					var s = new RegExp(search[i],"g");
					data = data.replace(s,replace[i]);
				}
			}
			this.pushRow(data);
			// UPDATE the global this.page && this.elcard
			/**
			 * @todo UPDATE the global this.page
			 */
			this.elcard++;
		}
	}

	/**
	 * Checks/unchecks Cb-row containing 'el' and changes its CSS
	 *
 	 * @param   mixed   	Row index of element or element in the row
 	 * @param   string 	CSS - Non-checked row
 	 * @param   string 	CSS - Checked row
	 *
	 * @return  void
	*/
	this.selectElementCbRow = function(el, css_uch, css_ch) { //function spp_setFormCb(formname, basename, i, css_uch, css_ch){
		var rownum = spp_getElementRow(el).rowIndex - 1;
		spp_setFormCb(this.basename, 'primCheckbox', rownum, css_uch, css_ch);
	}

	/**
	 * Checks/unchecks Cb-row i and changes its CSS
	 *
 	 * @param   mixed   	Row index of element or element in the row
 	 * @param   string 	CSS - Non-checked row
 	 * @param   string 	CSS - Checked row
	 *
	 * @return  void
	*/
	this.selectCbRow = function(index, css_uch, css_ch) { //function spp_setFormCb(formname, basename, i, css_uch, css_ch){
		spp_setFormCb(this.form.name, this.basename, index, css_uch, css_ch);
	}



	/**
	 * Highlights the current row
	 *
	 * @param	int   	index
	 * @param	string   CSS class name
	 * @param	bool	Wether action are freased due to selection (?)
	 *
	 * @return  void
	*/
	this.setRowCss = function (index, css, freezeSelected){
		spp_setRowCss(this.table, index+1, css, freezeSelected);
	}

	/**
	 * Highlights the current row
	 *
	 * @param	int   	index
	 * @param	string   CSS class name
	 * @param	bool	Wether action are freased due to selection (?)
	 *
	 * @return  void
	*/
	this.setElementRowCss = function (el, css, freezeSelected){
		var rownum = spp_getElementRow(el).rowIndex;
		spp_setRowCss(this.id, rownum, css, freezeSelected);
	}


	this.setCheckboxesRange = function(doCheck, min, max) {
		spp_setCheckboxesRange(this.form.name, this.basename, doCheck, min, max, this.even_css_ch, this.odd_css_ch, this.even_css, this.odd_css);
	}


	//  ----------------- CORE METHODS -----------------------
	this.getID = function(elname,rownum,basename) {
		if (!$chk(basename)) var basename = this.basename;
		return spp_GetID(basename,rownum,elname);
	}

	this.pushRow = function(data) {
		if ($chk(data)) return this.insertRow(data, -1);
		return null;
	}

	this.popRow = function() {
		this.deleteRow(this, -1);
	}

	this.unshiftRow = function(data) {
		 if ($chk(data))  this.insertRow(data, 0);
	}

	this.shiftRow = function(data) {
		 if ($chk(data)) this.deleteRow(this, 0);
	}

	this.insertRow = function(data, index) {
    		if ($chk(data)) {
    			var newRow = new Element(this.body.insertRow(index));
			if ($type(data) == "string") {
				newRow.set('html',data);
			} else {
				var newCell;
				 for (var i = 0; i < data.length; i++) {
					newCell = newRow.insertCell(i);
					newCell.set('html') = data[i];
				}
			}
			this.rcard++;
    		}
    		return newRow;
	}

	this.deleteRow = function(index) {
		this.body.deleteRow(index);
		this.rcard--;
	}

	this.deleteElementRow = function(el) {
		var rowindex = spp_getElementRow(el).rowIndex;
		this.deleteRow(rowindex);
	}

}


// ------------------------------------------------ FORM ELEMENTS ---------------------------------------------------

/**
 * Class for handling the Options of Form-DynamicDivision
 *
 * Objects are automatically created on spp_FDynamicDiv instantiation
*/
var spp_FDynamicDivOption = new Class({

	/**
	 * Initializator
	 *
	 */
	initialize: function(settings){
		this._type = "spp_FDynamicDivOption";
		this.settings = ($type(settings) == "string")  ?  {'element': settings} : settings;
		this.ID = new spp_Id(this.settings.element);
		this.main = spp_GetElement(this.ID.getString());
		if ($type(this.main) == "element") {
			this.main.store("class",this);
		}
	},

	/**
	 * Resets the content of the current dynamicDivOption
	 *
	 * This methods seeks for a "reset" method in the stored class of the current element (if it has one). If found, the method is called. Otherwise, the statement is skipped
	 */
	reset: function() {
		var all = this.main.getElements("*");
		for (i=0; i<all.length; i++) {
			if ($type(all[i]) == "element" && $chk(all[i].retrieve('class')) && $chk(all[i].retrieve('class').reset)) {
				all[i].retrieve('class').reset();
			}
		}
	}
});

/**
 * Class for handling Form-DynamicDivision
 * @param object settings
*/
var spp_FDynamicDiv = new Class({
	/**
	 * Initializator
	 */
	initialize: function(settings){
		if (!$chk(settings)) var settings = new Object();
		this._type = "spp_FDynamicDiv";
		/**
		 * Input settings
		 * Expected members are:
		 * 	o element
		 * 	o controller
		 *	o varname
		 * 	o options
		 * 	o controller
		 * 	o jsadded
		 * @var object
		 */
		this.settings = settings
		/**
		 * Theprovided element's id
		 * @var spp_Id
		 */
		this.ID = ($type(this.settings.element) == 'element') ? new spp_Id(this.settings.element.id) : new spp_Id(this.settings.element);
		/**
		 * Storage for copies
		 * @var object
		 */
		this.jsAdded = { 'elements': new Array(), 'controllers': new Array(), 'xbuttons': new Array(), 'objects': new Array(), 'element': this.main, 'controller': null};
		/**
		 * Main's parent
		 * @var spp_Id
		 */
		this.varname = this.settings.varname;
		/**
		 * Main (enclosing) element: The main div
		 * @var element
		 */
		this.main = spp_GetElement(this.ID.getString());
		if ($type(this.main) == "element") this.main.store("class",this);
		/**
		 * Main's parent
		 * @var spp_Id
		 */
		this.root = this.main.getParent();;
		/**
		 * Options: The array of all spp_FDynamicDivOption objects
		 * @var element
		 */
		this.options = new Array(); // These are spp_FDynamicDivOption objects
		if ($type(this.settings.options) == 'string') this.settings.options = this.settings.options.split(',');
		else if ($type(this.settings.options) != 'array') this.settings.options = new Array();
		for (var i=0; i<this.settings.options.length; i++) {
			var id = new spp_Id(this.settings.options[i]);
			this.options[i] = new spp_FDynamicDivOption({'element': id.getString()});
		}

		/**
		 * The controller (typically a select box)
		 * @var element
		 */
		this.controller = ($chk(this.settings.controller)) ? spp_GetElement(this.settings.controller) : null;
		this.selectedOption = this.controller.selectedIndex;
		this.setControllerEvents();
		this.jsAdded.controller = this.controller;// Link controller in jsAdded

		/**
		  * X-Buttons
		  * @var element
		  */
		this.xbutton = ($chk(this.controller)) ? spp_GetElement( this.ID.getString(null,this.ID.elname + '_sppXButton')) : null;
		if ($chk(this.xbutton)) {
			this.xbutton_html = this.xbutton.get('html');
			this.xbutton.set('html',null);
		}
	},

	/**
	  * Sets "onChange" event for controller
	  * @return void
	 */
	setControllerEvents: function(){
		if ($chk(this.controller)) {
			this.controller.store('dynamicDiv',this);

			this.controller.addEvent('change',function(){
		    		var selindex = this.selectedIndex;
		    		var dynDiv	= this.retrieve('dynamicDiv');

				// Hide the non selected divs (and store the selected index)
				var selected = null;
				for (var i=0; i<dynDiv.options.length; i++) {
					if ($chk(dynDiv.options[i])) {
						if (i != selindex) {
							spp_HideElement(dynDiv.options[i].main); // main is the div
							if ($chk(dynDiv.options[i].reset)) dynDiv.options[i].reset();
						} else {
							spp_ShowElement(dynDiv.options[i].main);
						}
					}
				}
				// Disable the selected options in all controllers
				dynDiv.disableControllerOption(this.selectedIndex,'other',this);

				// Re-enable the previously selected option
				dynDiv.enableControllerOption(dynDiv.selectedOption,'all',this);

				// Update dynDiv's selectedOption with newly selected index
				dynDiv.selectedOption = this.selectedIndex;
		    	});
		}
	},

	/**
	 * Disables the requested option of one or more controller(s)
	 * @param mixed	opt 	The option to be disabled
	 * @param string	which	The concerned controller(s): {'all','current','other'}
	 * @param mixed currentController The current controller (necessary when which='other')
	 */
	disableControllerOption: function(opt,which,currentController){
		this.edControllerOption('disable',opt,which,currentController);
	},
	/**
	 * Disables the requested option of one or more controller(s)
	 * @param mixed	opt 	The option to be disabled
	 * @param string	which	The concerned controller(s): {'all','current','other'}
	 * @param mixed currentController The current controller (necessary when which='other')
	 */
	enableControllerOption: function(opt,which,currentController){
		this.edControllerOption('enable',opt,which,currentController);
	},
	/**
	 * Disables the requested option of one or more controller(s)
	 * @param mixed	opt 	The option to be disabled
	 * @param string	which	The concerned controller(s): {'all','current','other'}
	 * @param mixed currentController The current controller (necessary when which='other')
	 */
	toggleControllerOption: function(opt,which,currentController){
		this.edControllerOption('toggle',opt,which,currentController);
	},

	/**
	 * Disables/Enables/Toggles the requested option of one or more controller(s)
	 * @param mixed	action 	The action to be performed, in {'disable','enable','toggle'}
	 * @param mixed	opt 	The concerned option
	 * @param string	which	The concerned controller(s): {'all','current','other'}
	 * @param mixed currentController The current controller (necessary when which='other')
	 */
	edControllerOption: function(action,opt,which,currentController){
		if (!$chk(opt))  return null;
		if (!$chk(which)) var which = 'other'; // Can be previous, or current
		if (which == 'all' || which == 'current') {
			spp_EDelement(action,currentController,opt);
		}
		if (this.jsAdded.controllers.length) {
			if (which == 'all') {
				for (var i=0; i<this.jsAdded.controllers.length; i++) {
					if (this.jsAdded.controllers[i].selectedIndex != this.selectedIndex) spp_EDelement(action,this.jsAdded.controllers[i],opt);

				}
			} else if (which == 'other') {
				spp_EDelement(action,this.jsAdded.controller,opt);
				for (var i=0; i<this.jsAdded.controllers.length; i++) {
					if (this.jsAdded.controllers[i] != currentController) spp_EDelement(action,this.jsAdded.controllers[i],opt);

				}
			}
		}
	},

	/**
	 * Resets all options of the current dynamicDiv
	 */
	reset: function() {
		spp_ShowElement(this.options[0].main);
		for (var i=0; i<this.options.length; i++) {
			// N.B. this.options is an array of spp_FDynamicDivOption
			if (i) spp_HideElement(this.options[i].main); // main is the div
			this.options[i].reset();
		}
	},

	/**
	 * Javascript duplicator
	 * @return void
	 *
	 * @todo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Make this (or part of this - e.g. renaming -) a more global function !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	 */
	jsadd: function(data){
		var card 	= this.jsAdded.elements.length;

		var all = this.root.getElements("*");
		if ($chk(all)) {
			var search = new Array();
			var replace = new Array();

			var scripts	= new Array();
			for (var i=0; i<all.length; i++) {
				if ($chk(all[i].getProperty('id'))) {
					// Fill search and replace: IDs
					search.push(all[i].id);
					var id = new spp_Id(all[i].id);
					id.elname += '_spp' + card;
					replace.push(id.getString());

					// Fill search and replace: Names (we use the id defined above)
					if ($chk(all[i].get('name'))) {
						search.push(all[i].get('name'));
						var name = new spp_Name(id);
						replace.push(name.getString());
					}
					if ($type(all[i]) == "element") {
						var storedClass = all[i].retrieve('class');
						if ($chk(storedClass)) {
							var varname = storedClass.varname;
							if ($chk(varname)) {
								search.push(varname);
								replace.push(varname + '_spp'  + card);
							}
						}
					}
				} else if (all[i].get('tag') == 'script') {
					scripts.push(all[i].get('html'));
				}
			}

			// Get new  root
			if ($chk(data)) {
				var root2 = new Element('div').set('html',spp_URLDecode(data));
			} else var root2 = this.root.clone(true,true);


			// Perform replacements in the html content
			var s = spp_Replace(root2.get('html'),search,replace);
			root2.set('html',s);

			// Store in controller object
			this.jsAdded.elements.push(root2);

			// Add do document (inject after last block)
			var last = (card) ? this.jsAdded.elements[card-1] : this.root;
			var main = this.jsAdded.elements[card].inject(last,'after');

			// Run scripts
			for (var i=0; i<scripts.length; i++) {
				var script = spp_Replace(scripts[i],search,replace,null,1);
				eval(script);
			}

			// Store newly created object
			var newObject =  eval(this.varname + '_spp'  + card);

			// Reset/Configure new object
			newObject.xbutton = ($chk(newObject.controller)) ? spp_GetElement(this.ID.getString(null,this.ID.elname + '_sppXButton' + '_spp'  + card)) : null;
			if ($chk(newObject.xbutton)) {
				newObject.xbutton.set('html',this.xbutton_html);
				for (var i=0; i<this.jsAdded.xbuttons.length; i++) this.jsAdded.xbuttons[i].set('html',null);
				this.jsAdded.xbuttons.push(newObject.xbutton);
				newObject.xbutton_html = this.xbutton_html;
			}

			// Controller (newly created one)
			var newController = spp_GetElement(spp_Replace(this.controller.id,search,replace));
			if (!$chk(data)) newObject.selectedOption = 0;
			else newObject.selectedOption = newController.selectedIndex;
			if ($chk(newController) && $chk(newController.retrieve('class')) && $chk(newController.retrieve('class').reset)) {
				if (!$chk(data)) newController.retrieve('class').reset();
			} else {
				switch (newController.get('tag')) {
					case 'select':
						if (!$chk(data)) newController.selectedIndex = 0;
					break;
					default:
						// Others have to be done
				}
				// Disable controllers otpions
				if (this.jsAdded.controller) {
					this.disableControllerOption(this.jsAdded.controller.selectedIndex,'current',newController);
					this.disableControllerOption(newController.selectedIndex,'other',newController);
				}
			}

			// Store object
			this.jsAdded.objects.push(newObject);
			newObject.jsAdded = this.jsAdded; // Connect newly created this.jsAdded to rootObject.jsAdded (name 'that.jsAdded')
			// Store controller and update newly created object
			this.jsAdded.controllers.push(newController);

			// Options
			if (!$chk(data)) {
				var root2 = new Element('div').wraps(main);
				var all = root2.getElements("*");
				for (var i=0; i<all.length; i++) {
					if ($type(all[i]) == "element" && $chk(all[i].getProperty('id')) && $chk(all[i].retrieve('class'))) {
						if ($chk(all[i].retrieve('class').reset)) all[i].retrieve('class').reset();
					}
				}
			} else {
				spp_ShowElement(newObject.options[newObject.selectedOption].main);
			}
		}
	},

	/**
	 * Javascript remover for the last object sored in member 'jsAdded'
	 *
	 * @return void
	 *
	 * @todo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Make this (or part of this - e.g. renaming -) a more global function !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	 */
	jsremove: function(){
		var card = this.jsAdded.elements.length;
		if (card) {
			// Re-enable the selected option
			this.enableControllerOption(this.selectedOption,'other');
			// Re-enable the xbutton
			if (card>1) this.jsAdded.xbuttons[card-2].set('html',this.xbutton_html);

			// Delete controllers
			this.jsAdded.controllers[card-1].destroy();
			delete this.jsAdded.controllers[card-1];
			this.jsAdded.controllers.length--;
			// Delete elements
			this.jsAdded.elements[card-1].destroy();
			delete this.jsAdded.elements[card-1];
			this.jsAdded.elements.length--;
			// Delete xbuttons
			this.jsAdded.xbuttons[card-1].destroy();
			delete this.jsAdded.xbuttons[card-1];
			this.jsAdded.xbuttons.length--;
			// Delete objects
			delete this.jsAdded.objects[card-1];
			this.jsAdded.objects.length--;
			// Show the [x] button in the last controller
		}
	}

});

var spp_FCheckboxGroup = new Class({
	/**
	 * Initializator
	 */
	initialize: function(settings){

		this.settings = ($type(settings) == "string")  ?  {'element': settings} : settings;

		this._type = "spp_FCheckboxGroup";

		this.ID = new spp_Id(this.settings.element);

		/**
		 * The name of the var containing the object
		 * @var spp_Id
		 */
		this.varname = this.settings.varname;

		this.main = spp_GetElement(this.ID.getString()); // In this case, a table
		this.main.store('class',this);

		this.options = new Array();

		var i=0;
		var stop = false;
		var id 	= new spp_Id(this.settings.element);
		while (!stop) {


			var row = id.elname.split('_');
			var last = (row.length) ? row[row.length-1] : null;

			if ($chk(last) && last.slice(0,3) == 'spp') {
				row.pop();
				var idnew = new spp_Id(id.basename,row.join("_") + '_' + i + '_' + last, id.rownum);
			} else {
				var idnew = new spp_Id(id.basename, id.elname + '_' + i,  id.rownum);
			}
			var el = spp_GetElement(idnew.getString());
			if ($chk(el)) {
				this.options.push(el);
				i++;
			} else stop = true;
		}

	},

	reset: function() {
		for (var i=0; i<this.options.length;i++) {
			this.options[i].checked = false;
		}
	}
});


// ============================
//				--- Request ---
// ============================
function spp_Request(options) {
	var that = new Request(options);

	// Main Parts
	that.serverData	= null;
	that.control			= null;
	that.html			= null;
	that.values			= null;
	that.gmap			= null;

	//that.message	= null;
	that.log				= null;

	// Progress bar
	that.pb		= null;	// Stores the Progress Bar Object
	that.pbv	= 0;	// Stores the current value of the progress bar

	// Eding
	that.endf	= null; // Where to go at the end
	that.itf		= null; // The function to run at each step of the iterator
	that.close	= null;

	// Message box
	that.mssgBox 	= null;
	that.mssgSucc	= null;
	that.mssgFail	= null;
	that.endBttn	= null;

	// Cursor
	that.runningCursor	= null;
	that.currentCursor	= null;

	that.onRequest = function() {
	}

	that.onFailure = function(){
	}

	that.onSuccess = function(txt,xml){
		var localdebug = false;

		that.parseXml(xml);
		that.updatePb(true);
		var status =that.control.get("scriptStatus");
		if ($chk(that.itf)) that.itf();

		if (localdebug) alert("Server Data received and parsed. \n - Script status: " + status );
		if (status == "running") {
			var ns = that.control.get("nextScript");
			if ($chk(ns)) {
				that.currentCursor = document.body.style.cursor
				if ($chk(that.runningCursor)) document.body.style.cursor=that.runningCursor;
				var that2 			= new spp_Request({url: ns});
				that2.pb			= that.pb;
				that2.endf			= that.endf;
				that2.itf			= that.itf;
				that2.close			= that.close;
				that2.mssgBox		= that.mssgBox;
				that2.mssgSucc	= that.mssgSucc;
				that2.mssgFail		= that.mssgFail;
				that2.endBttn		= that.endBttn;
				that2.send();
				// Log is Incremental
				if (!$chk(that.log)) {
					that.log = xml.getElement('log'); // Log Element
				} else {
					that.log.set('tot',parseInt(that.log.get('tot')) + parseInt(that2.log.get('tot')));
					that.log.set('errs',parseInt(that.log.get('errs')) + parseInt(that2.log.get('errs')));
					that.log.set('warns',parseInt(that.log.get('warns')) + parseInt(that2.log.get('warns'))); //tot="18" errs="18" warns="0"
					if ($chk(that.log.errors.get('mail'))) that.log.errors.set('mail',parseInt(that.log.get('mail')) + parseInt(that2.log.get('mail'))) ;
					if ($chk(that.log.errors.get('syntax'))) that.log.errors.set('syntax',parseInt(that.log.get('syntax')) + parseInt(that2.log.get('syntax')));
				}
			}
		} else {
			document.body.style.cursor=that.currentCursor;
			if ($chk(that.endf)) {
				if ($chk(that.endf) === 'close') {
					self.close();
				} else {
					that.endf();
				}
			}
		}
	}

	that.parseXml = function(xml){
		var localdebug = false;
		that.serverData 	= xml.getElements('serverData'); 	// serverData Node
		that.control 		= xml.getElement('control'); 		// Log Element
		that.html			= xml.getElement('html');
		that.values			= xml.getElement('values');
		that.gmap			= xml.getElement('gmap');		// Will generate that.gmarkers, ....

		// SppxAmpf replacments
		var s = that.control.get("currentScript");
		if ($chk(s)) that.control.set('currentScript',s.replace(/sppxAmpf/g,'&'));
		var s = that.control.get("nextScript");
		if ($chk(s)) that.control.set('nextScript',s.replace(/sppxAmpf/g,'&'));
		var s = that.control.get("prevScript");
		if ($chk(s)) that.control.set('prevScript',s.replace(/sppxAmpf/g,'&'));

		// Log is INCREMENTAL
		if (!$chk(that.log)) {
			that.log = xml.getElement('log'); // Log Element
		} else {
			that.log.set('tot',parseInt(that.log.get('tot')) + parseInt(xml.getElement('log').get('tot')));
			that.log.set('errs',parseInt(that.log.get('errs')) + parseInt(xml.getElement('log').get('errs')));
			that.log.set('warns',parseInt(that.log.get('warns')) + parseInt(xml.getElement('log').get('warns'))); //tot="18" errs="18" warns="0"
		}
		if ($chk(that.log)) {
			if (!$chk(that.log.errors)) {
				that.log.errors = xml.getElement('errors'); // Log Element
			} else {
				if ($chk(that.log.errors.get('mail'))) that.log.errors.set('mail',parseInt(that.log.get('mail')) + parseInt(xml.getElement('errors').get('mail'))) ;
				if ($chk(that.log.errors.get('syntax'))) that.log.errors.set('syntax',parseInt(that.log.get('syntax')) + parseInt(xml.getElement('errors').get('syntax')));
			}
		}

		// HTML parsing
		if (that.html) {
			// Retrieve current page
			var page = spp_getPage();

			// Pushed Html
			var push = that.html.getElements('push');
			for (var i = 0; i < push.length; i++) {
				var mh 	= spp_GetElement("mainHtml");
				var mhp	= mh.getParent();
				var mh2	= mh.clone(false,true);
				mh2.id+=i;
				mh2.set('html', spp_URLDecode(push[i].get('text')).replace(/sppxAmpf/g,'&'));
				var newel = mhp.grab(mh2,'bottom');
			}
		}

		// GMAP parsing
		if ($chk(that.gmap) && $chk(google) && $chk(google.maps)) {
			that.gmarkers 	= null;
			that.gmarkers 	= that.gmap.getElements('marker');
			for (var i=0; i<that.gmarkers.length; i++) {
				if ($chk(that.gmarkers[i].get('glat')) && $chk(that.gmarkers[i].get('glng'))) {
					that.gmarkers[i].set('LatLng',new google.maps.LatLng(that.gmarkers[i].get('lat'), that.gmarkers[i].get('lng')));
				}
			}
		}
		 // >>> NB!!! Use textContent to retrieve innerCode
	}


	that.updatePb = function(removeAtEnd){
		if ($chk(that.pb)) {
			 that.pbv = that.control.get('percent');
			that.pb.set(that.pbv);
			if ($chk(removeAtEnd) && removeAtEnd && that.pbv == 100) {
				setTimeout("spp_dispose('" + that.pb.options.boxID + "')", 750);
				setTimeout("spp_dispose('" + that.pb.options.displayID + "')", 750);
				setTimeout("spp_replaceInnerHTML('" + that.mssgBox + "', '" + that.mssgSucc + "');", 750);
				setTimeout("spp_ShowElement('" + that.endBttn +  "');", 750);
				//spp_ShowElement(that.endBttn);
			}
		}
	}

	return that;
}

function spp_dispose(elid){
	if ($chk($(elid)) ) $(elid).dispose();
}


function spp_replaceInnerHTML(elid,html){
	if ($chk($(elid))) $(elid).innerHTML = html;
}

// ============================
//				--- FORM ---
// ============================
/**
 * Instantiates a spp_table object for the table identified by "tableID"
 *
 * @param	tableID		The ID of the target table
 * @return spp_table
 */
function spp_JsForm(name){

	/*
	var that = new Request();

	that.name = name;
	that.serverData = null;

	that.onRequest = function(that) {
		//alert (">>OnRequest");
	}

	that.onFailure = function(that){
		//alert("> Failure");
	}

	that.onSuccess = function(txt,xml){
		//alert(">> Success " + xml);
		var root = xml.firstChild; // serverData Node
		that.serverData = root;
		//alert("> root1=" + that.serverData.nodeValue );

		//alert("> root2=" + that.serverData);
	}

	that.send({'url': 'http://localhost/trisline/test.php'});

	this.parseXml = function(xml){

	}

	/*
	this. parseControlXml = function(xml) {

	}

	this.parseStructureXml = function(xml) {

	}

	this.parseValuesXml = function(xml) {

	}
	*/

	//return that;
}
//spp_JsForm.inherits(Request);
//spp_JsForm.prototype = new Request();

//var jsf = spp_JsForm();

/**
 * Transfers the selected elements of the source multi-select box to target multi-select box
 * @param		mixed	s	Source multi-select box
 * @param		mixed	t	Target multi-select box
 * @return 	void
*/
function spp_OrderedMultiSelect_transfer(s,t){
	if ($type(s) == 'string') s = spp_GetElement(s);
	if ($chk(s.selectedIndex)) {
		if ($type(t) == 'string') t = spp_GetElement(t);
		var selectOptions = s.getElementsByTagName('option');
		var transfered = new Array();
		for (var i = 0; i < selectOptions.length; i++) {
			var opt = selectOptions[i];
			if (opt.selected) {
				t.add(opt);
				i--;// Because an option was removed
			}
		}
	}
}

/**
 * Moves up the selected elements of a source multi-select
 * @param	mixed	selectList	Multi-select box
 * @return 	void
*/
function spp_OrderedMultiSelect_up(selectList){
	if ($type(selectList) == 'string') selectList = spp_GetElement(selectList);
	var selectOptions = selectList.getElementsByTagName('option');
	for (var i = 1; i < selectOptions.length; i++) {
		var opt = selectOptions[i];
		if (opt.selected) {
			selectList.removeChild(opt);
			selectList.insertBefore(opt, selectOptions[i - 1]);
		}
	}
}

/**
 * Moves down the selected elements of a source multi-select
 * @param	mixed	selectList	Multi-select box
 * @return 	void
*/
function spp_OrderedMultiSelect_down(selectList){
	if ($type(selectList) == 'string') selectList = spp_GetElement(selectList);
	var selectOptions = selectList.getElementsByTagName('option');
	for (var i = selectOptions.length - 2; i >= 0; i--) {
		var opt = selectOptions[i];
		if (opt.selected) {
		   var nextOpt = selectOptions[i + 1];
		   opt = selectList.removeChild(opt);
		   nextOpt = selectList.replaceChild(opt, nextOpt);
		   selectList.insertBefore(nextOpt, opt);
		}
     	}
}

// ============================
//			--- GOOGLE MAP ---
// ============================
var MapIconMaker={};
MapIconMaker.createMarkerIcon=function(a){var b=a.width||32;var c=a.height||32;var d=a.primaryColor||"#ff0000";var e=a.strokeColor||"#000000";var f=a.cornerColor||"#ffffff";var g="http://chart.apis.google.com/chart?cht=mm";var h=g+"&chs="+b+"x"+c+"&chco="+f.replace("#","")+","+d.replace("#","")+","+e.replace("#","")+"&ext=.png";var j=new GIcon(G_DEFAULT_ICON);j.image=h;j.iconSize=new GSize(b,c);j.shadowSize=new GSize(Math.floor(b*1.6),c);j.iconAnchor=new GPoint(b/2,c);j.infoWindowAnchor=new GPoint(b/2,Math.floor(c/12));j.printImage=h+"&chof=gif";j.mozPrintImage=h+"&chf=bg,s,ECECD8"+"&chof=gif";var h=g+"&chs="+b+"x"+c+"&chco="+f.replace("#","")+","+d.replace("#","")+","+e.replace("#","");j.transparent=h+"&chf=a,s,ffffff11&ext=.png";j.imageMap=[b/2,c,(7/16)*b,(5/8)*c,(5/16)*b,(7/16)*c,(7/32)*b,(5/16)*c,(5/16)*b,(1/8)*c,(1/2)*b,0,(11/16)*b,(1/8)*c,(25/32)*b,(5/16)*c,(11/16)*b,(7/16)*c,(9/16)*b,(5/8)*c];for(var i=0;i<j.imageMap.length;i++){j.imageMap[i]=parseInt(j.imageMap[i])}return j}

function spp_Gmap(targid,options) {
	// Options
	if (!$chk(options)) var options = {};
	if (!$chk(options.sppMarker)) options.sppMarker = {};
	if (!$chk(options.sppMarker.primaryColor)) 	options.sppMarker.primaryColor = "FF0000";
	if (!$chk(options.sppMarker.width))			options.sppMarker.width 	= 30;
	if (!$chk(options.sppMarker.height))			options.sppMarker.height 	= 30;

	// Map
	var map 	= new google.maps.Map2(document.getElementById(targid));
	map.sppTargid 	= targid;
	map.sppOptions 	= options;
	map.sppLegend	= null;
	map.sppMG		= {lat:0,lng:0,w:0};

	var lat 		= ($chk(options) && $chk(options.myLatitude)) 	? options.myLat 		: google.loader.ClientLocation.latitude;
	var lng 		= ($chk(options) && $chk(options.myLatitude)) 	? options.myLng 		: google.loader.ClientLocation.longitude;
	var zm 	= ($chk(options) && $chk(options.sppZoom)) 	? options.sppZoom 	: 7;
	map.setCenter(new google.maps.LatLng(lat,lng), zm);
	map.setUIToDefault();
	map.sppOptions 			= ($chk(options)) ? options : null;
	map.sppGeocoder 		= new google.maps.ClientGeocoder();
	map.sppLoader			= google.loader;
	map.sppClientLocation		= google.loader.ClientLocation;
	map.sppMyloc				= new google.maps.LatLng(lat, lng);
	map.sppBounds 			= map.getBounds();
	var panel	= ($chk(document.getElementById(targid + "Panel"))) ? document.getElementById(targid + "Panel") : null;
	map.sppDir				= new google.maps.Directions(map,panel);
	map.sppRequest			= new spp_Request();

	map.sppGotoAddress = function sppGotoAddress(address) {
		map.sppGeocoder.getLatLng(address,function(latLng) {
			if (!latLng) {
				alert(address + " not found");
			} else {
				map.setCenter(latLng, 13);
			}
		});
	}

	map.sppGetMarker = function (latLng,options) {
		if ($chk(options)) return new google.maps.Marker(latLng, options);
		return new google.maps.Marker(latLng);
	}

	map.sppShowMarker = function (marker,options){

		if ($chk(marker)) {
			// Get new Gravity Center
			/*
			map.sppMG.lat = (map.sppMG.lat*map.sppMG.w + marker.get('glat'))/(map.sppMG.w+1) ;
			map.sppMG.lng = (map.sppMG.lng*map.sppMG.w + marker.get('glng'))/(map.sppMG.w+1) ;
			map.sppMG.w++;
			*/
			if (!$chk(options)) var options = {};
			var latLng = new GLatLng(marker.get('glat'),marker.get('glng'));

			if ($chk(options.sppCenter)) {
				var zm = ($chk(options.zoom)) ? options.zoom : 13;
				map.setCenter(latLng, zm);
			} else {
				/* FIND A DEFAULT CENTER
				var gLatLng = new GLatLng(map.sppMG.lat,map.sppMG.lng);
				var zm = ($chk(options.sppZoom)) ? options.sppZoom : 13;
				map.setCenter(gLatLng, zm);
				*/
			}

			if (!$chk(options.icon)) {
				if ($chk(marker.get('color'))) options.primaryColor = marker.get('color');
				if ($chk(marker.get('width'))) options.width = marker.get('width');
				if ($chk(marker.get('height'))) options.height = marker.get('height');
				var newIcon = MapIconMaker.createMarkerIcon(options);
				options.icon = newIcon;
			}

			var gmarker = new map.sppGetMarker(latLng,options);
			map.addOverlay(gmarker);

			if ($chk(map.sppOptions.sppShowInfo) && map.sppOptions.sppShowInfo) {
				map.openInfoWindowHtml(latLng, spp_URLDecode(marker.textContent));
			}
			var label = marker.get('label');
			if ($chk(label)) {
				var divid = map.sppTargid + spp_URLEncode(label);
				if (!$chk($(divid))) {
					var labelSpan 	= new Element("span");
					labelSpan.addClass('small');
					labelSpan.innerHTML = "&nbsp;" + label;
					var colorImg	= new Element("img");
					colorImg.addClass('gmapCaticon');
					if (marker.get('color')) colorImg.setStyle('background-color',marker.get('color'));
					colorImg.set('src','http://www.trisline.ch/ECOM/Trisline/TOPASE/_lib/SPP/SPP/img/spacer.gif');
					var theDiv	= new Element("div");
					theDiv.set('id',map.sppTargid + spp_URLEncode(label));
					theDiv.set('valign','middle');
					theDiv.adopt(colorImg,labelSpan);
					var newel = map.sppLegend.grab(theDiv,'bottom');
				}
			}
			GEvent.addListener(gmarker, "click", function() {
					map.openInfoWindowHtml(latLng, spp_URLDecode(marker.textContent));
				});
		}
	}

	map.sppShowAddress = function sppShowAddress(address,options) {

		if (!$chk(address)) {
			return null;
		}
		map.sppGeocoder.getLatLng(address,function(latLng) {
			if (!latLng) {
				alert(address + " not found !!!! ");
			} else {
				var content = null;
				if ($chk(options)) {
					if ($chk(options.sppCenter)) {
						var zm = ($chk(options.zm)) ? options.zm : 13;
						map.setCenter(latLng, zm);
						var marker =  new map.sppGetMarker(latLng,options.sppContent);
						content = options.sppContent;
					}
				} else var marker = new map.sppGetMarker(latLng);
				map.addOverlay(marker);
				if ($chk(content)) {
					GEvent.addListener(marker, "mouseover", function() {
   						map.openInfoWindowHtml(point, content);
  					});
				}
			}
		});
	}

	map.sppShowAddresses = function sppShowAddresses(addresses,options) {
		if (!$chk(options)) var options = new Object();
		for (var i=0;i<addresses.length;i++) {
			map.sppShowAddress(addresses[i],options);
			if (i==0) options.noCenter = true;
		}
	}


	map.sppRequest = function sppRequest(options) {
		localdebug = false;
		if (localdebug) alert("New Gmap Request");
		var req = new spp_Request(options);
		req.endf = null;
		req.itf = function (){ // Function to be performed at each iteration
				for (var i=0; i<this.gmarkers.length; i++) {
					var marker = this.gmarkers[i];
					if (marker.get('glat') && marker.get('glng')) map.sppShowMarker(marker,options.sppMarker);
					else if (marker.get('address') && $chk(options) && $chk(options.glocate) && options.glocate) map.sppShowAddress(marker.get('address'),options.sppMarker);
				}
			};
		req.send();
		return req;
	}
	return map;
}
