/*<[CDATA[*/var verif_msg;
var init_appli;
verif_msg = false;
init_appli = false;

document.observe('dom:loaded',function(){
	if(init_appli == false)
	{
		if(verif_msg==false)verif_message();
		refreshCoupCoeur();
		verifie_javascript();
	}
	init_appli = true;
});

var timer;
function Timer() {
   var dt=new Date()
 //  window.status=dt.getHours()+":"+dt.getMinutes()+":"+dt.getSeconds();
   timer =setTimeout("Timer()",1000);
}
   
            
//http://dean.edwards.name/packer/ afaire a la fin
	var urlwww = 'http://1001rss.com/';
	var urlwwwActualites = 'http://1001rss.com/actualites/';
	var urlwwwReagir = 'http://1001rss.com/reagir/';
	var urlwwwBlog = 'http://1001rss.com/blog/';
	var urlwwwMembres = 'http://1001rss.com/membres/';
	var urlwwwCompte = 'http://1001rss.com/compte/';
	var urlwwwSysteme = 'http://1001rss.com/systeme/';
	var urlwwwOutils = 'http://1001rss.com/outils/';
	var urlinclude = 'http://1001rss.com/include/';
	var urlimages = 'http://1001rss.com/images/';
	var msgprocess = "chargement en cours...<br>";
	
	//definition de variable javascript
	var autoClose = true;
	var autoCloseTimeOut = 2000;
	var modalAjax;	
	var modalNote;	
	var save_id_flux_user;	

/* fonction de test */
function isnum(m) {
  var m=parseFloat(m);
  if (isNaN(m)) {
    return false;
  }else {
  m=Number(m);
  if (isNaN(m)) {
    return false;
  }else {
    return true; }}
  } 

 
function redirection(url)
{
	window.location.replace(url);
}

function isEmail(champ) {

  if ( (champ !="") && (champ.indexOf("@") !="-1") && (champ.indexOf(".") !="-1")){
    return true;
  }else {
    return false;
  } 


}

function validateEmail( email )
{
  var emailRegex=/^\w+[\+\.\w-]*@([\w-]+\.)*\w+[\w-]*\.([a-z]{2,3}|\d+)$/i
  var validEmail = emailRegex.test(email)
  if( !validEmail )
  {
    return false;
  }
  else
  {
  	return true;
  }
  //return validEmail;
}

function doLogin()
{

	var username = $('connect_form_login').value;
	var password = $('connect_form_pass').value;
	var auto_connect = $('auto_connect').value;
	connect = "";
	
	var url =  urlwwwSysteme+'dologin.php';	
	googlestat(url);
	new Ajax.Request(url, {method: 'post',
	parameters: {action:'connection',username:username, password: password, auto_connect:auto_connect,refresh:1},
	onComplete: function(transport) {
	
	    var connect = transport.responseText;   
	   
	    if(connect=="")
	    {
		    refresh_connection();
	    	$('auto_promo').innerHTML = '';    		
	    	if (typeof modalAjax != 'undefined') {
				modalAjax.close();
			}
			if (typeof Modalbox != 'undefined') {
				Modalbox.hide();
			}

	    }else
	    {
			 ballon_login = new HelpBalloon({ 
			 id:'bconnect',
			 method: 'post',
			 content: connect,
			 cacheRemoteContent: false,
			 autoHideTimeout: 5000,  
			 icon: $('btn_ok')
			  }); 
			 
			 ballon_login.show();
	    }
	}});
}

function affiche_connection()
{
	var cible_Connection = $('Connection').id;

	var url =  urlwwwSysteme+'affiche_connection.php';

	

	googlestat(url);
	new Ajax.Request( url, {method:'post', parameters: {action:'refresh'},
	 onComplete:function(transport){
	 	var resultat = transport.responseText;
	 		new Effect.Fade(cible_Connection,{
	 		duration:0.2,
	 		fps:25,
			afterFinish:function(transport){
		 		$(cible_Connection).innerHTML = resultat;
				//$(cibleHeader).show();
				new Effect.BlindDown(cible_Connection,{duration:0.2,fps:25});
				 }
			});

		
		
	}});	
	
}

function verifie_javascript()
{
	var url =  urlwwwSysteme+'verif_JS.php';

	new Ajax.Request( url, {method:'post', parameters: {action:'refresh'}});	
	
}

function doDeLogin(uid, loginkey)
{
	
	var url =  urlwwwSysteme+'dologin.php';	
	googlestat(url);	
	new Ajax.Request(url, {method: 'post',
	parameters: {action:'deconnection', uid:uid, loginkey: loginkey},
	onSuccess: function(transport) {
	    var connect = transport.responseText;   
	    if(connect=="")
	    {
	    	auto_promo = '<div id="auto_promo" class="inscription"><div class="header_inscription">Devenir membre</div><div class="fond_inscription"><div class="content_inscription"><a href="'+urlwww+'incription">CrÃ©er et gÃ©rer ses propres flux, ses favoris, ses marques-pages, recevoir son actualitÃ© personnalisÃ©e tous les matins en pdf. VoilÃ  les outils auxquels un membre a accÃ¨s gratuitement.</a></div></div><div class="foot_inscription"></div></div>';
	    	refresh_connection();
	    	$('auto_promo').innerHTML = auto_promo;
	    }else
	    {
	    	alert(connect);
	    }
	}});
}

function refresh_connection()
{
	affiche_connection();
	if($('nav'))refreshMenuNav();
	if($('footer'))refreshMenuFooter();
	
	/* partie actualites */
	if($('content_navigation_actu'))refreshNav();
	if($('content_site'))refreshSite();
	if($('content_lecteurFlux'))refreshRss();
	if($('content_en_direct'))refreshDirect();
	
	if(urlwwwOutils == document.URL)
	{
		init_outils();
	}	
	if(urlwwwActualites == document.URL)
	{
		init_actualite();
	}	
	if(urlwwwReagir == document.URL)
	{
		init_reagir();
	}
}

function refreshMenuNav()
{
	cibleHeader = 'nav';
	//chargement(cibleHeader,6);
	
	//new Effect.toggle(cibleHeader,'blind');
	
	

	var url =  urlwwwSysteme+'header.php';
	googlestat(url);
	new Ajax.Request( url, {method:'post', parameters: {action:'refresh'},
	 onComplete:function(transport){
	 	var resultat = transport.responseText;
	 		new Effect.Fade(cibleHeader,{
	 		duration:0.2,
	 		fps:25,
			afterFinish:function(transport){
		 		$(cibleHeader).innerHTML = resultat;
				//$(cibleHeader).show();
				new Effect.BlindDown(cibleHeader,{duration:0.2,fps:25});
				 }
			});

		
		
	}});		
}

function refreshMenuFooter()
{
	cibleFooter = 'footer';
	chargement(cibleFooter,6);
	var url =  urlwwwSysteme+'footer.php';
	googlestat(url);
	new Ajax.Updater(cibleFooter, url, {method:'post', parameters: {action:'refresh'} });		
}

function recalcule_widget_hauteur(element, cible)
{
	
	retour = element.responseText;
	$(cible).update(retour);		
	$(cible).setStyle({height: null})
    var h = $(cible).getHeight();
    $(cible).setStyle({height: h + "px"});
}

function recalcule_cible_hauteur(cible)
{	
	$(cible).setStyle({height: null})
    var h = $(cible).getHeight();
    $(cible).setStyle({height: h + "px"});
}

function chargement(elem,idImg,width,height)
{

	if (typeof idImg == 'undefined' || idImg == '') {
		idImg = 7;
	}
	
	if (typeof width == 'undefined' || width == '') {
		dwidth = '';
	}
	else
	{
		dwidth = 'width="'+width+'"';
	}
	if (typeof height == 'undefined' || height == '') {
		dheight = '';
	}	
	else
	{
		dheight = 'height="'+height+'"';
	}
	
	if($(elem))
	{
	
	/* AJAX
	var url =  urlwwwSysteme+'chargement.php';
	new Ajax.Updater($(elem.id), url, {method:'post', parameters: {id:idImg} });
	*/
	
	/* JAVASCRIPT */
	//alert(elem);
	$(elem).update('<div align="center"><img '+dwidth+' '+dheight+' src="'+urlimages+'indicator/'+idImg+'.gif" align="absmiddle"></div>');
	}
}

function chargement_rubique(rubrique)
{
	chargement('general_main');
	var url =  urlinclude+'chargementRubrique.php';
	googlestat(url);
	new Ajax.Updater('general_main', url, {method:'get', evalScripts: true, parameters: {rubrique:rubrique}});
}

function ajouter_url()
{
	var form = 'lien_1001rss';
	var valeur = Form.serialize(form);
	var form = valeur.toQueryParams();
	

	
	
	if (form["url_nom"] ==  '') {
		return false;
	}
	
	if (form["url_lien"] ==  '') {
		return false;
	}

	if (form["url_rubrique"] ==  '') {
		return false;
	}

	cible = $(form["url_rubrique"]);
	chargement(cible);


	var urlajax =  urlwwwSysteme+'ajouterUrl.php';
	new Ajax.Updater(cible, urlajax, {method:'post', parameters: form });
}

function ajouter_url_zlio(url)
{
	if (url ==  '') {
		return false;
	}

	cible = $('zlio_url');
	chargement(cible);
	var urlajax =  urlwwwSysteme+'ajouterUrl.php';
	new Ajax.Updater(cible, urlajax, {method:'post', parameters: {url_rubrique:'zlio',url_lien:url} });
}

function select_value_zlio(value)
{
	$('value_liste_zlio').value=value;
	//$('liste_lien_zlio').each

	$('liste_lien_zlio').childElements().each(function(li) {
	  id_url = $(li.id).getAttribute('rel');
	  $('lien_select_zlio_'+id_url).className = 'zlio_lien';
	});

	$('lien_select_zlio_'+value).className = 'zlio_lien_select';
	
}
		 
function supprime_url(type,id_url)
{

	if (id_url ==  '') {
		return false;
	}
	
	if (type ==  '') {
		return false;
	}

	cible = $(type);
	chargement(cible);


	var urlajax =  urlwwwSysteme+'supprimeUrl.php';
	new Ajax.Updater(cible, urlajax, {method:'post', parameters:{type:type,id_url:id_url} });
}

function supprime_url_zlio(id_url)
{
	if (id_url ==  '') {
		return false;
	}

	cible = $('zlio_url');
	chargement(cible);


	var urlajax =  urlwwwSysteme+'supprimeUrlZlio.php';
	new Ajax.Updater(cible, urlajax, {method:'post', parameters:{id_url:id_url} });
}

function affiche_favoris(page_flux)
{
	$('save_action').value = "favoris";	
	if (typeof page == 'undefined') {
		page = 1;
	}
	if (typeof page_flux == 'undefined') {
		page_flux = 1;
		refreshSite(page,1);		
	}

	$('header_site').innerHTML= 'favoris';

	
	cible = $('content_lecteurFlux');

	
	chargement(cible);
	var url =  urlwwwActualites+'lecteurRss_simplepie.php';
	googlestat(url);
	new Ajax.Request(url, {method:'post', parameters: {ajax:1,favoris:1,page:page_flux}, onSuccess:function(e){
		recalcule_widget_hauteur(e, cible);}
	});	
}

function affiche_postit(id_flux_user,page_flux)
{
	save_id_flux_user = id_flux_user;
	$('save_action').value = "postit";			
	if (typeof page == 'undefined') {
		page = 1;
	}
	if (typeof id_flux_user == 'undefined') {
		id_flux_user = 0;	
	}
	if (typeof page_flux == 'undefined') {
		page_flux = 1;
		//refreshSite(page,1);		
	}
	//$('header_site').innerHTML= 'postit';

	
	cible = $('content_lecteurFlux');

	
	chargement(cible);

	var url =  urlwwwActualites+'lecteurRss_simplepie.php';
	googlestat(url);
	new Ajax.Request(url, {method:'post', parameters: {ajax:1,postit:1,id_flux_user:id_flux_user,page:page_flux}, onSuccess:function(e){
		recalcule_widget_hauteur(e, cible);}
	});	
}

function affiche_inscription()
{
	url_inscription = urlwwwSysteme+"verif_inscription.php";

	googlestat(url_inscription);
	Modalbox.show(url_inscription, {title: "verification inscription",  width: 500, height: 220, method:'POST', params:''});
	//Modalbox.resizeToContent();
	//Modalbox.resizeToInclude('verif_connection', {afterResize: function(){new Effect.Appear('verif_connection');}});
	return false;
}

function recuperation_passeword()
{

	var url =  urlwwwMembres+'passwordoublie.php';
	googlestat(url);
	email = $('email_recuperation').value;
	chargement($('retour_message'),3);
	valid_form_compte = $('valid_form_compte').value;
	new Ajax.Updater('retour_message', url, {
		method:'post',
		parameters: {email:email,valid_form_compte:valid_form_compte}
	});
}

function verif_login()
{
	login = $('login').value;

	retour_verif_login = $('retour_verif_login');
	chargement(retour_verif_login,1,10,10);
	var urlverif =  urlwwwMembres+'verif_login.php';
	new Ajax.Request(urlverif, {method: 'post',parameters: {ajax:1, login:login},
	  onFailure:function(e){
		log.error('Erreur verif login');
		},
	  onComplete: function(transport) {

		var valueRetourVerif = transport.responseText;
		
		if(valueRetourVerif==1)
		{
			message = '<img src="'+urlimages+'check.gif" align="absmiddle" width="14" height="14" alt"identifiant libre" title"identifiant libre">';
		}
		else 
		{
			$('login').focus();
			message = '<img src="'+urlimages+'close.png" align="absmiddle" width="14" height="14" alt"identifiant existe dÃ©jÃ " title"identifiant existe dÃ©jÃ ">';	
		}
		
		panelVerifLogin = '<input type="hidden" value="'+valueRetourVerif+'" id="valueRetourLogin">'+message;
		retour_verif_login.innerHTML = panelVerifLogin;

		}
	});
	
}

function verif_confirm_password(pass,confirm)
{
	pass = $(pass).value;
	confirm = $(confirm).value;
	retour_verif_pass = $('retour_verif_pass');
	if(pass==confirm)
	{
		valueRetourPass = 1;
		message = '<img src="'+urlimages+'check.gif" align="absmiddle" width="14" height="14" alt"identifiant libre" title"identifiant libre">';
	}
	else 
	{
		valueRetourPass = 2;
		message = '<img src="'+urlimages+'close.png" align="absmiddle" width="14" height="14" alt"identifiant existe dÃ©jÃ " title"identifiant existe dÃ©jÃ ">';	
	}
	
	panelVerifPass = '<input type="hidden" value="'+valueRetourPass+'" id="valueRetourPass">'+message;
	retour_verif_pass.innerHTML = panelVerifPass;
}

function verif_email()
{
	email = $('email').value;

	if(validateEmail(email) == true)
	{
		valueRetourMail = 1;
		message = '<img src="'+urlimages+'check.gif" align="absmiddle" width="14" height="14" alt"identifiant libre" title"identifiant libre">';
	}
	else 
	{
		valueRetourMail = 2;
		message = '<img src="'+urlimages+'close.png" align="absmiddle" width="14" height="14" alt"identifiant existe dÃ©jÃ " title"identifiant existe dÃ©jÃ ">';	
	}
	
	panelVerifMail = '<input type="hidden" value="'+valueRetourMail+'" id="valueRetourMail">'+message;
	$('retour_verif_email').innerHTML = panelVerifMail;
}

function verif_inscription()
{

	formId = 'form_inscription_1001rss';
	valeur = Form.serialize(formId);
	form = valeur.toQueryParams();

	msg = '';
	url =  urlwwwMembres+'do_inscription.php';
	
	if(form["login"].length == 0)
	{
		msg += 'Vous devez prÃ©ciser un identifiant<br>';
	}	
	if(form["login"].length <=5 && form["login"].length >0)
	{
		msg += 'Votre identifiant doit comporter au minimum 6 caractÃ¨res<br>';
	}
	if(form["password"].length == 0)
	{
		msg += 'Vous devez prÃ©ciser un mot de passe<br>';
	}
	if(form["password"] != form["verif_password"])
	{
		msg += 'Votre mot de passe est diffÃ©rent<br>';
	}
	if(form["email"].length == 0)
	{
		msg += 'Vous devez prÃ©ciser un mail<br>';
	}
	if(validateEmail(form["email"]) == false && form["email"].length != 0)
	{
		msg += 'Votre mail n\'est pas valide<br>';
	}
	
	if(typeof form["condition_general"] == 'undefined')
	{
		msg += 'Vous devez accepter les conditions gÃ©nÃ©rales<br>';
	}
	
	if(form["flash_reponse"]!= 1)
	{
		msg += 'capcha manquant<br>';
	}
	
	if(msg.length == 0)
	{
		//fonction inscription
		chargement($('retour_message'),6);

		googlestat(url);
		new Ajax.Request( url, {
			evalScripts: true,
			method:'post',
			parameters: form,
			onSuccess: function(transport) {
				retour = transport.responseText;

				switch (retour)
				{
					case '1':
					msg = 'Vous allez recevoir un mail pour confirmer votre inscription<br>';
					$('form_inscription_1001rss').hide();
					break;
					case '2':
					msg = 'L\'identifiant existe dÃ©jÃ , veuillez sÃ©lectionner un autre identifiant<br>';
					break;
					case '3':
					msg = 'L\'email existe dÃ©jÃ , veuillez sÃ©lectionner une autre adresse email<br>';
					break;
					default:
					msg = 'L\'identifiant existe dÃ©jÃ , veuillez sÃ©lectionner un autre identifiant<br>';
					break; 

				} 
				
				$('retour_message').innerHTML = msg;
							 
				

			}
		});	
		return true;
	}
	else
	{

		$('retour_message').innerHTML = msg;
					
		return false;
	}	
}

function getPageCoords (element) {
var coords = { x: 0, y: 0};
while (element) {
coords.x += element.offsetLeft;
coords.y += element.offsetTop;
element = element.offsetParent;
}
return coords;
}
function getElementObject (elementId) {
if (document.all)
return document.all[elementId];
else if (document.getElementById)
return document.getElementById(elementId);
else
return null;
}
	

//styled examples use the window factory for a shared set of behavior
//http://localhost/windows/documentation/documentation.html OU http://prototype-window.xilinus.com/documentation.html
// forum http://pwc-forum.xilinus.com/

function modal_ajax(container,options){
urlRequest = $(container).href;

modalAjax = new Window (container+'_Ajax_window',{
top:0,
left:0,
draggable:true,
resizable:true,
showEffectOptions: {duration:0.2, fps:10}
});
modalAjax.setDestroyOnClose();
//modalAjax.setCloseCallback( close );

modalAjax.setAjaxContent(urlRequest, options || {}, true, false);
modalAjax.setTitle($(container).title);


modalAjax.show();
modalAjax.setSize(800, 600);
//modalAjax.updateWidth();
//modalAjax.updateHeight();
////modalAjax.setContent('toto', true, true);

//alert(modalAjax.getSize().width);
//alert(modalAjax.getSize().height);	
//modalAjax.close();	
}

//ToolTip
/*
var tooltip = new Control.ToolTip($('btn_help_connect'),'Windows can also act as tool tips.',{
			className: 'tooltip'
});
*/	

		
document.observe('dom:loaded',function(){
	//var inscription_fav = window_factory($$('li.lien_inscription'));

	if($('btn_help_connect'))
	{
		container = $('btn_help_connect');
		//Relative Window / Dynamic Content
		var relative = new Control.Window(container,{
			position: 'relative',
			className: 'simple_window', 
			width:500,
			height:150,
			iframe:true,
			iframeshim:false,
			closeOnClick: true
		});
	}

});

function modifier_image_profil()
{

	var url =  urlwwwSysteme+'upload_img/index.php';		
	new Ajax.Request(url, {method: 'post',
	parameters: {},
	onSuccess: function(transport) {
	    var upload_img = transport.responseText;  
				parseur = new Control.Modal.open(upload_img,{
					overlayOpacity: 0.75,
					className: 'window',
					fade: true
				}); 
	}});

}

function module_image_profil(defaut_image)
{ 
	cible = $('module_image_profil');
	
	var url =  urlwwwMembres+'module_image_profil.php';		
	
	new Ajax.Updater(cible,url, {method: 'post',
	parameters: {defaut_image:defaut_image}
	});
}

function supprime_image_profil(nom_image)
{
	alert(nom_image);
}



function getPageCoords (element) {
var coords = { x: 0, y: 0};
while (element) {
coords.x += element.offsetLeft;
coords.y += element.offsetTop;
element = element.offsetParent;
}
return coords;
}
function getElementObject (elementId) {
if (document.all)
return document.all[elementId];
else if (document.getElementById)
return document.getElementById(elementId);
else
return null;
}
	
function affiche_note(container)
{
	urlRequest = $(container).href;	
	pos = getPageCoords($(container));



 note_item = new HelpBalloon({ 
 dataURL: urlRequest,
 method: 'post',
 cacheRemoteContent: false,
 autoHideTimeout: 5000,  
 icon: $(container)
  }); 
  
 note_item.show();

 			
}

function upload(){
	// hide old iframe
	var par = window.parent.document;
	var num = par.getElementsByTagName('iframe').length - 1;
	var iframe = par.getElementsByTagName('iframe')[num];
	iframe.className = 'hidden';
	
	// create new iframe
	var new_iframe = par.createElement('iframe');
	new_iframe.src = urlwwwSysteme+'upload_img/upload.php';
	new_iframe.frameBorder = '0';
	par.getElementById('iframe').appendChild(new_iframe);
	
	// add image progress
	var images = par.getElementById('images1');
	var new_div = par.createElement('div');
	var new_img = par.createElement('img');
	new_img.src = '/images/indicator.gif';
	new_img.className = 'load';
	new_div.appendChild(new_img);
	
	images.appendChild(new_div);


	var imgnum = images.getElementsByTagName('div').length - 1;
	document.iform.imgnum.value = imgnum;
	setTimeout("document.iform.submit()",5000);
}


var _oldInputFieldValue=""; // valeur prÃ©cÃ©dente du champ texte
var _currentInputFieldValue=""; // valeur actuelle du champ texte
var _resultCache=new Object(); // mÃ©canisme de cache des requÃªtes

// Ã©chappe les caractÃ¨res spÃ©ciaux
function escapeURI(La){
  if(encodeURIComponent) {
    return encodeURIComponent(La);
  }
  if(escape) {
    return escape(La)
  }
}

function refreshChanel(index,cat)
{

	if (typeof favoris == 'undefined') {
		favoris = 2;
	}
	if (typeof index == 'undefined' || index =="") {
		index=0;
	}		
	if (typeof cat == 'undefined') {
		cat ==""
	}	

	search = $('search').value;
	if(search=="Rechercher")search="";
	

	cibleChanel = $('content_1001rss_chanel');
	log.profile( 'chargement 1001rssChanel' );


	chargement(cibleChanel);
	var url =  urlwwwSysteme+'charger_channel_direct.php';
	googlestat(url);
	new Ajax.Request(url, {method:'post', evalScripts: true, parameters: {cat:cat, search:search, index:index},
	onFailure:function(e){
		log.error('Erreur chargement 1001rssChanel');
	},
	onComplete:function(transport)
	{
		var resultat = transport.responseText;
		cibleChanel.update(resultat);
		log.profile( 'chargement 1001rssChanel' );
	}});

}

function affiche_info(id_module)
{

 urlRequest = urlwwwSysteme+'info/'+id_module+'.php';
 googlestat(urlRequest);
log.info( 'info '+urlRequest );	
 note_addThis = new HelpBalloon({ 
 method: 'post',
 dataURL: urlRequest,
 cacheRemoteContent: false, 
 icon: $(id_module)
  }); 
 
 note_addThis.show();

 			
}

var nb_verifMessage =0;
function verif_message()
{
	nb_verifMessage;
	verif_msg = true;
	if($('message_user'))
	{
		
	 	urlRequest = urlwwwSysteme+'verif_message.php';	
		checkMessage = new Ajax.PeriodicalUpdater('message_user', urlRequest, {
		  method: 'get', frequency: 100, decay: 0,
			onSuccess:function(transport)
			{
				nb_verifMessage++;
				var resultat = transport.responseText;
				log.info( nb_verifMessage+ ' '+resultat );
				//checkMessage.stop();
	}
		});
	}
			
}

function affiche_password()
{
 id='btn_help_password';
 urlRequest = $(id).href+'?ajax=true';

 note_addThis = new HelpBalloon({ 
 method: 'post',
 dataURL: urlRequest,
 cacheRemoteContent: false, 
 icon: $(id)
  }); 
 
 note_addThis.show();

 			
}

function envoi_mail_contact()
{

	formId = 'form_contact_1001rss';
	valeur = Form.serialize(formId);
	form = valeur.toQueryParams();

	msg = '';
	url =  urlwwwSysteme+'envoi_mail_contact.php';
	
	if(form["sujet"].length == 0)
	{
		msg += 'Sujet manquant<br>';
	}	

	if(form["expediteur"].length == 0)
	{
		msg += 'expediteur manquant<br>';
	}
	if(validateEmail(form["expediteur"]) == false && form["expediteur"].length != 0)
	{
		msg += 'Votre mail n\'est pas valide<br>';
	}
	
	if(form["message"].length == 0)
	{
		msg += 'message manquant<br>';
	}	
	
	if(form["flash_reponse"]!= 1)
	{
		msg += 'capcha manquant<br>';
	}
	
	if(msg.length == 0)
	{
		//fonction inscription
		chargement($('retour_message'),6);
		
		//$('retour_message'),
		new Ajax.Request( url, {
			evalScripts: true,
			method:'post',
			parameters: form,
			onSuccess: function(transport) {
				retour = transport.responseText;				
				$('retour_message').innerHTML = "votre mail a bien Ã©tÃ© envoyer";
				$('form_contact_1001rss').hide();
							 
				

			}
		});	
		return true;
	}
	else
	{

		$('retour_message').innerHTML = msg;
					
		return false;
	}	
}

function refresh_generateur_flux()
{
	var form = 'form_gen_flux';
	var valeur = Form.serialize(form);
	var form = valeur.toQueryParams();
	
	cibleGenerateur = 'content_main';
	log.profile( 'chargement generateur flux' );
	chargement(cibleGenerateur);

	var url =  urlwwwOutils+'refresh_generateur_flux.php';
	

	
	form["ajax"]=1;

	googlestat(url);
	
	new Ajax.Request(url, {method: 'post',parameters: form,
	  onFailure:function(e){
		log.error('Erreur generateur flux');},
	  onComplete: function(transport) {
	  	log.profile( 'chargement generateur flux' );
	    preview = transport.responseText;
	    $(cibleGenerateur).innerHTML = preview;	    

	}});

}


function googlestat(page) {  
	 
}  

/*
function init_recherche()
{
	document.location.href = urlwww+'?search='+$('search').value;
}
*/

//prechargement des images
bulle = new Image();
bulle1 = new Image();
bulle2 = new Image();
bulle3 = new Image();
bulle4 = new Image();
bulle.src = urlimages+"helpBalloon/balloon-0.png";
bulle1.src = urlimages+"helpBalloon/balloon-1.png";
bulle2.src = urlimages+"helpBalloon/balloon-2.png";
bulle3.src = urlimages+"helpBalloon/balloon-3.png";
bulle4.src = urlimages+"helpBalloon/button.png";// 
// Copyright (c) 2008 Beau D. Scott | http://www.beauscott.com
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// 

/**
 * HelpBalloon.js
 * Prototype/Scriptaculous based help balloons / dialog balloons
 * @version 2.0.1
 * @requires prototype.js <http://www.prototypejs.org/>
 * @author Beau D. Scott <beau_scott@hotmail.com>
 * 4/10/2008
 */
var HelpBalloon = Object.extend(Class.create(), {
	/**
	 * Enumerated value for dynamic rendering position.
	 * @static
	 */
	POS_DYNAMIC: -1,
	/**
	 * Enumerated value for the top-left rendering position.
	 * @static
	 */
	POS_TOP_LEFT: 0,
	/**
	 * Enumerated value for the top-right rendering position.
	 * @static
	 */
	POS_TOP_RIGHT: 1,
	/**
	 * Enumerated value for the bottom-left rendering position.
	 * @static
	 */
	POS_BOTTOM_LEFT: 2,
	/**
	 * Enumerated value for the bottom-right rendering position.
	 * @static
	 */
	POS_BOTTOM_RIGHT: 3,
	/**
	 * CSS Classname to look for when doing auto link associations.
	 * @static
	 */
	ELEMENT_CLASS_NAME: 'HelpBalloon',
	/**
	 * Global array of all HelpBalloon instances.
	 * (Cheaper than document.getElementByClassName with a property check)
	 * @static
	 * @private
	 */
	_balloons: [],
	/**
	 * Event listener that auto-associates anchors with a dynamic HelpBalloon.
	 * Also begins mouse movement registration
	 * @static
	 */
	registerClassLinks: function(e) {
		$A(document.getElementsByClassName(HelpBalloon.ELEMENT_CLASS_NAME))
			.each(function(obj){
			// Only apply any element with an href tag
			if(obj && obj.tagName && obj.href && obj.href != '')
			{
				new HelpBalloon({
					icon:obj,
					method: 'get'
				});
			}
		});
		
		Event.observe(document, 'mousemove', HelpBalloon._trackMousePosition);
		
	},
	
	/**
	 * Private cache of the client's mouseX position
	 */
	_mouseX: 0,
	
	/**
	 * Private cache of the client's mouseY position
	 */
	_mouseY: 0,
	
	/**
	 * @param {Event} e
	 */
	_trackMousePosition: function(e) {
		if(!e) e = window.event;
		HelpBalloon._mouseX = e.clientX;
		HelpBalloon._mouseY = e.clientY;
	}
});

//
// Event for activating HelpBalloon classed links
//
Event.observe(window, 'load', HelpBalloon.registerClassLinks);

HelpBalloon.prototype = {
	
//
// Properties
// 	
	/**
	 * Configuration options
	 * @var {HelpBalloon.Options}
	 */
	options: null,

	/**
	 * Containing element of the balloon
	 * @var {Element}
	 */
	container: null,
	/**
	 * Inner content container
	 * @var {Element}
	 */
	inner: null,
	/**
	 * A reference to the anchoring element/icon
	 * @var {Element}
	 */
	icon: null,
	/**
	 * Content container
	 * @var {Element}
	 */
	content: null,
	/**
	 * Closing button element
	 * @var {Element}
	 */
	button: null,
	/**
	 * The closer object. This can be the same as button, but could 
	 * also be a div with a png loaded as the back ground, browser dependent.
	 * @var {Element}
	 */
	closer: null,
	/**
	 * Title container
	 * @var {Element}
	 */
	titleContainer: null,
	/**
	 * Background container (houses the balloon images
	 * @var {Element}
	 */
	bgContainer: null,
	/**
	 * Array of balloon image references
	 * @var {Array}
	 */
	balloons: null,
	
	/**
	 * The local store of 'title'. Will change if the balloon is making a remote call
	 * unless options.title is specified
	 * @var {String}
	 */
	_titleString: null,
	
	/**
	 * The balloons visibility state.
	 * @var {Boolean}
	 */
	visible: false,
	
	/**
	 * Rendering status
	 * @var {Boolean}
	 */
	drawn: false,

	/**
	 * Stores the balloon coordinates
	 * @var {Object}
	 */
	balloonCoords: null,
		
	/**
	 * Width,height of the balloons
	 * @var {Array}
	 */
	balloonDimensions: null,
	
	/**
	 * ID for HelpBalloon
	 * @var {String}
	 */
	id: null,
	
	/**
	 * Used at render time to measure the dimensions of the loaded balloon
	 * @private
	 */
	_lastBalloon: null,

//
// Methods
//

	/**
	 * @param {Object} options
	 * @see HelpBalloon.Options
	 * @constructor
	 */
	initialize: function(options)
	{
		
		this.options = new HelpBalloon.Options();
		Object.extend(this.options, options || {});

		this._titleString = this.options.title;
		this.balloonDimensions = [0,0];
		
		//
		// Preload the balloon and button images so they're ready
		// at render time
		//
		// 0 1
		//  X
		// 2 3
		//
		this.balloons = [];
		for(var i = 0; i < 4; i++)
		{
			var balloon = new Element('img', {
				src: this.options.balloonPrefix + i + this.options.balloonSuffix
			});
			this.balloons.push(balloon.src);
		}
		
		this._lastBalloon = balloon;
		
		this.button = new Element('img', {
			src: this.options.button
		});
		
		//
		// Create the anchoring icon, or attach the balloon to the given icon element
		// If a string is passed in, assume it's a URL, if it's an object, assume it's
		// a DOM member.
		//
		if(typeof this.options.icon == 'string')
		{
			this.icon = new Element('img', {
				src: this.options.icon,
				id: this.id + "_icon"
			});
			Element.setStyle(this.icon, this.options.iconStyle);
		}
		else
		{
			//
			// Not a string given (most likely an object. Do not append the element
			// Kind of a hack for now, but I'll fix it in the next version.
			//
			this.icon = this.options.icon;
			this.options.returnElement = true;
		}
		
		this.icon._HelpBalloon = this;
			
		//
		// Attach rendering events
		//

		for(i = 0; i < this.options.useEvent.length; i++)
			Event.observe(this.icon, this.options.useEvent[i], this.toggle.bindAsEventListener(this));
		
		this.container = new Element('div');
		this.container._HelpBalloon = this;
		
		this.id = 'HelpBalloon_' + Element.identify(this.container);
		
		HelpBalloon._balloons.push(this);

		//
		// If we are not relying on other javascript to attach the anchoring icon
		// to the DOM, we'll just do where the script is called from. Default behavior.
		//
		// If you want to use external JavaScript to attach it to the DOM, attach this.icon
		//
		if(!this.options.returnElement)
		{
			document.write('<span id="' + this.id + '"></span>');
			var te = $(this.id);
			var p = te.parentNode;
			p.insertBefore(this.icon, te);
			p.removeChild(te);
		}
	},
	
	/**
	 * Toggles the help balloon
	 * @param {Object} e Event
	 */
	toggle: function(event)
	{
		if(!event) event = window.event || {type: this.options.useEvent, target: this.icon};
		var icon = Event.element(event);
		Event.stop(event);
		if(event.type == this.options.useEvent && !this.visible && icon == this.icon)
		{
			this.show(event);
		}
		else
			this.hide();
	},

	/**
	 * Triggers the balloon to appear
	 */
	show: function(event)
	{
		if(!this.visible){
			if(!event) event = window.event;
			if(!this.drawn || !this.options.cacheRemoteContent) this._draw();
			this._reposition(event);
			this._hideOtherHelps();
			if(this.options.showEffect)
			{
				this.options.showEffect(this.container, Object.extend(this.options.showEffectOptions, {
					afterFinish: this._afterShow.bindAsEventListener(this)
				}));
			}
			else
			{
				this._afterShow();
			}
			Event.observe(window, 'resize', this._reposition.bindAsEventListener(this));
		}
	},
	
	/**
	 * Sets the container to block styling and hides the elements below the
	 * container (if in IE)
	 * @private
	 */
	_afterShow: function()
	{
		Element.setStyle(this.container, {
			'display': 'block'
		});
		this._hideLowerElements();
		this.visible = true;
		if(this.options.autoHideTimeout)
		{
			setTimeout(this._hideQueue.bind(this), this.options.autoHideTimeout);
		}
	},
	
	/**
	 * Checks the mouse position and triggers a hide after the time specified in autoHideTimeout
	 * if the mouse is not currently over the balloon, otherwise it requeue's a hide for later.
	 */
	_hideQueue: function()
	{
		if(Position.within(this.container, HelpBalloon._mouseX, HelpBalloon._mouseY))
			setTimeout(this._hideQueue.bind(this), this.options.autoHideTimeout);
		else
			this.hide();
	},
	
	/**
	 * Hides the balloon
	 */
	hide: function()
	{
		if(this.visible)
		{
			this._showLowerElements();
			if(this.options.hideEffect)
			{
				this.options.hideEffect(this.container, Object.extend(this.options.hideEffectOptions, {
					afterFinish: this._afterHide.bindAsEventListener(this)
				}));
			}
			else
			{
				this._afterHide();
			}
			Event.stopObserving(window, 'resize', this._reposition.bindAsEventListener(this));
		}
	},
	
	/**
	 * Sets the container's display to block
	 * @private
	 */
	_afterHide: function()
	{
		Element.setStyle(this.container, {
			'display': 'none'
		});
		this.visible = false;
	},
	
	/**
	 * Redraws the balloon based on the current coordinates of the icon.
	 * @private
	 */
	_reposition: function(event)
	{
		if(this.icon.tagName.toLowerCase() == 'area' || !!this.icon.isMap)
		{
			this.balloonCoords = Event.pointer(event);
		}
		else
		{
			this.balloonCoords = this._getXY(this.icon);
			//Horizontal and vertical offsets in relation to the icon's 0,0 position.
			// Default is the middle of the object
			var ho = this.icon.offsetWidth / 2;
			var vo = this.icon.offsetHeight / 2;
			
			var offsets = this.options.anchorPosition.split(/\s+/gi);
			// Only use the first two specified values
			if(offsets.length > 2)
				offsets.length = 2;
			
			for(var i = 0; i < offsets.length; i++)
			{
				switch(offsets[i].toLowerCase())
				{
					case 'left':
							ho = 0;
						break;
					case 'right':
							ho = this.icon.offsetWidth;
						break;
					case 'center':
							ho = this.icon.offsetWidth / 2;
						break;
					case 'top':
							vo = 0;
						break;
					case 'middle':
							vo = this.icon.offsetHeight / 2;
						break;
					case 'bottom':
							vo = this.icon.offsetHeight;
						break;
					default:
						var numVal = parseInt(offsets[i]); 
						if(!isNaN(numVal))
						{
							// 0 = width, 1 = height (WxH)
							if(i == 0)
							{
								if(numVal < 0)
								{
									ho = 0;
								}
								else
								{
									if(numVal > this.icon.offsetWidth)
										ho = this.icon.offsetWidth;
									else
										ho = numVal
								}
							}
							else
							{
								if(numVal < 0)
								{
									vo = 0;
								}
								else
								{
									if(numVal > this.icon.offsetHeight)
										vo = this.icon.offsetHeight;
									else
										vo = numVal
								}
							}
						}
						break;	
				}
			}
			this.balloonCoords.x += ho;
			this.balloonCoords.y += vo;
		}
		
		//
		// Figure out what position to show based on available realestate
		// unless 
		// 0 1
		//  X
		// 2 3
		// Number indicates position of corner opposite anchor
		//
		var pos = 1;
		if(this.options.fixedPosition == HelpBalloon.POS_DYNAMIC)
		{
			var offsetHeight = this.balloonCoords.y - this.balloonDimensions[1];
			if(offsetHeight < 0)
				pos += 2;
	
			var offsetWidth = this.balloonCoords.x + this.balloonDimensions[0];
			var ww = Prototype.Browser.IE ? document.body.clientWidth : window.outerWidth;
			if(offsetWidth > ww)
				pos -- ;
		}
		else
			pos = this.options.fixedPosition;

		var zx = 0;
		var zy = 0;
		
		//
		// 0 1
		//  X
		// 2 3
		//
		switch(pos)
		{
			case 0:
				zx = this.balloonCoords.x - this.balloonDimensions[0];
				zy = this.balloonCoords.y - this.balloonDimensions[1];
				break;
			
			case 1:
				zx = this.balloonCoords.x;
				zy = this.balloonCoords.y - this.balloonDimensions[1];
				break;
			
			case 2:
				zx = this.balloonCoords.x - this.balloonDimensions[0];
				zy = this.balloonCoords.y;
				break;
			
			case 3:
				zx = this.balloonCoords.x;
				zy = this.balloonCoords.y;
				break;
		}
		var containerStyle = {
			/*'backgroundRepeat': 'no-repeat',
			'backgroundColor': 'transparent',
			'backgroundPosition': 'top left',*/
			'left' 	: zx + "px",
			'top'	: zy + "px",
			'width' : this.balloonDimensions[0] + 'px',
			'height' : this.balloonDimensions[1] + 'px'
		}
		if(Prototype.Browser.IE)
		{
			//
			// Fix for IE alpha transparencies
			//
			if(this.balloons[pos].toLowerCase().indexOf('.png') > -1)
			{
				Element.setStyle(this.bgContainer, {
					'left' 		: '0px',
					'top'		: '0px',	
					'filter'	: "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.balloons[pos] + "', sizingMethod='scale')",
					'width' 	: this.balloonDimensions[0] + 'px',
					'height' 	: this.balloonDimensions[1] + 'px',
					'position'	: 'absolute'
				});
			}
			else
				containerStyle['background'] = 'transparent url(' + this.balloons[pos] + ') top left no-repeat';
		}
		else
		{
				containerStyle['background'] = 'transparent url(' + this.balloons[pos] + ') top left no-repeat';
		}
		Element.setStyle(this.container, containerStyle);
	},

	/**
	 * Renders the Balloon
	 * @private
	 */
	_draw: function()
	{
		Element.setStyle(
			this.container, 
			Object.extend(this.options.balloonStyle, {
				'position': 	'absolute',
				'display': 		'none'
			})
		);
		
		var url = this.options.dataURL;
		
		//
		// Play nicely with anchor tags being used as the icon. Use it's specified href as our
		// data URL unless one has already been used specified in this.options.dataURL. 
		// We'll also force a new request with this as it may be an image map.
		//
		if(this.icon.className == 'a')
		{
			if(!this.options.dataURL && this.icon.href != ''){
				url = this.icon.href;
				this.options.cacheRemoteContent = false;
			}
		}
		
		if(url && (!this.drawn || !this.options.cacheRemoteContent))
		{		
			var cont = new Ajax.Request(this.options.dataURL, {asynchronous: false, evalScripts: true, method: this.options.method,parameters:this.options.parameters});
			//
			// Expects the following XML format:
			// <HelpBalloon>
			// 		<title>My Title</title>
			// 		<content>My content</content>
			// </HelpBaloon>
			//
			var doHTML = false;
			if(cont.transport.responseXML)
			{
				var xml = cont.transport.responseXML.getElementsByTagName('HelpBalloon')[0];

				if(xml)
				{
					if(!this.options.title)
					{
						xmlTitle = xml.getElementsByTagName('title')[0];
						if(xmlTitle) this._titleString = xmlTitle.firstChild.nodeValue;
					}

					xmlContent = xml.getElementsByTagName('content')[0];
					if(xmlContent) this.options.content = xmlContent.firstChild.nodeValue;
				}
				else
					doHTML = true;
			}
			else
				doHTML = true;

			if(doHTML)
			{
				// Attempt to get the title from a <title/> HTML tag, unless the title option has been set. If so, use that.
				if(!this.options.title)
				{
					var htmlTitle = cont.transport.responseText.match(/\<title\>([^\<]+)\<\/title\>/gi);
					if(htmlTitle)
					{
						htmlTitle = htmlTitle.toString().replace(/\<title\>|\<\/title\>/gi, '');
						this._titleString = htmlTitle;
					}
				}
				this.options.content = cont.transport.responseText;
			}
		}
		
		this.balloonDimensions[0] = this._lastBalloon.width;
		this.balloonDimensions[1] = this._lastBalloon.height;
		
		var contentDimensions = [
			this.balloonDimensions[0] - (2 * this.options.contentMargin),
			this.balloonDimensions[1] - (2 * this.options.contentMargin)
		];
		
		var buttonDimensions = [
			this.button.width,
			this.button.height
		];
		
		//
		// Create all the elements on demand if they haven't been created yet
		//
		if(!this.drawn)
		{
			this.inner = new Element('div');
		
			this.titleContainer = new Element('div');
			this.inner.appendChild(this.titleContainer);
			
			// PNG fix for IE
			if(Prototype.Browser.IE && this.options.button.toLowerCase().indexOf('.png') > -1)
			{
				this.bgContainer = new Element('div');
				
				// Have to create yet-another-child of container to house the background for IE... when it was set in
				// the main container, it for some odd reason prevents child components from being clickable.
				this.container.appendChild(this.bgContainer);
				
				this.closer =  new Element('div');
				Element.setStyle(this.closer, {
					'filter':
						"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.options.button + "', sizingMethod='scale')"
				});
			}
			else
			{
				this.closer = this.button;
			}
			
			Event.observe(this.closer, 'click', this.toggle.bindAsEventListener(this));
			this.inner.appendChild(this.closer);
			
			this.content =  new Element('div');
			this.inner.appendChild(this.content);
			
			this.container.appendChild(this.inner);
			
			document.getElementsByTagName('body')[0].appendChild(this.container);
			
			this.drawn = true;
		}

		// Reset the title element and reappend the title value (could have changed with a new URL)
		this.titleContainer.innerHTML = '';
		this.titleContainer.appendChild(document.createTextNode(this._titleString));
		
		// Reset content value:
		this.content.update(this.options.content);

		//
		// Reapply styling to components as values might have changed
		//
		
		Element.setStyle(this.inner, {
			'position': 	'absolute',
			'top':			this.options.contentMargin + 'px',
			'left':			this.options.contentMargin + 'px',
			'width': 		contentDimensions[0] + 'px',
			'height': 		contentDimensions[1] + 'px'
		});

		Element.setStyle(this.titleContainer, {
			'width':		(contentDimensions[0] - buttonDimensions[0]) + 'px',
			'height':		buttonDimensions[1] + 'px',
			'position':		'absolute',
			'overflow':		'hidden',
			'top': 			'0px',
			'left': 		'0px'
		});
		
		Element.setStyle(this.titleContainer, this.options.titleStyle);
		
		Element.setStyle(this.closer, {
			'width': buttonDimensions[0] + 'px',
			'height': buttonDimensions[1] + 'px',
			'cursor': 	'pointer',
			'position':	'absolute',
			'top': 		'0px',
			'right': 	'0px'
		});
		
		Element.setStyle(this.content, {
			'width':		contentDimensions[0] + 'px',
			'height': 		(contentDimensions[1] - this.button.height) + 'px',
			'overflow': 	'auto',
			'position': 	'absolute',
			'top': 			buttonDimensions[1] + 'px',
			'left': 		'0px',
			'fontFamily': 	'verdana',
			'fontSize': 	'11px',
			'fontWeight': 	'normal',
			'color': 		'black'
		});
		
	},

	/**
	 * Gets the current position of the obj
	 * @param {Element} element to get position of
	 * @return Object of (x, y, x2, y2)
	 */
	_getXY: function(obj)
	{
		var pos = Position.cumulativeOffset(obj)
		var y = pos[1];
		var x = pos[0];
		var x2 = x + parseInt(obj.offsetWidth);
		var y2 = y + parseInt(obj.offsetHeight);
		return {'x':x, 'y':y, 'x2':x2, 'y2':y2};

	},

	/**
	 * Determins if the object is a child of the balloon element
	 * @param {Element} Element to check parentage
	 * @return {Boolean}
	 * @private
	 */
	_isChild: function(obj)
	{
		var i = 15;
		do{
			if(obj == this.container)
				return true;
			obj = obj.parentNode;
		}while(obj && i--);
		return false
	},

	/**
	 * Determines if the balloon is over this_obj object
	 * @param {Element} Object to look under
	 * @return {Boolean}
	 * @private
	 */
	_isOver: function(this_obj)
	{
		if(!this.visible) return false;
		if(this_obj == this.container || this._isChild(this_obj)) return false;
		var this_coords = this._getXY(this_obj);
		var that_coords = this._getXY(this.container);
		if(
			(
			 (
			  (this_coords.x >= that_coords.x && this_coords.x <= that_coords.x2)
			   ||
			  (this_coords.x2 >= that_coords.x &&  this_coords.x2 <= that_coords.x2)
			 )
			 &&
			 (
			  (this_coords.y >= that_coords.y && this_coords.y <= that_coords.y2)
			   ||
			  (this_coords.y2 >= that_coords.y && this_coords.y2 <= that_coords.y2)
			 )
			)

		  ){
			return true;
		}
		else
			return false;
	},

	/**
	 * Restores visibility of elements under the balloon
	 * (For IE)
	 * TODO: suck yourself
	 * @private
	 */
	_showLowerElements: function()
	{
		if(this.options.hideUnderElementsInIE)
		{
			var elements = this._getWeirdAPIElements();
			for(var i = 0; i < elements.length; i++)
			{
				if(this._isOver(elements[i]))
				{
					if(elements[i].style.visibility != 'visible' && elements[i].hiddenBy == this)
					{
						elements[i].style.visibility = 'visible';
						elements[i].hiddenBy = null;
					}
				}
			}
		}
	},

	/**
	 * Hides elements below the balloon
	 * (For IE)
	 * @private
	 */
	_hideLowerElements: function()
	{
		if(this.options.hideUnderElementsInIE)
		{
			var elements = this._getWeirdAPIElements();
			for(var i = 0; i < elements.length; i++)
			{
				if(this._isOver(elements[i]))
				{
					if(elements[i].style.visibility != 'hidden')
					{
						elements[i].style.visibility = 'hidden';
						elements[i].hiddenBy = this;
					}
				}
			}
		}
	},

	/**
	 * Determines which elements need to be hidden
	 * (For IE)
	 * @return {Array} array of elements
	 */
	_getWeirdAPIElements: function()
	{
		if(!Prototype.Browser.IE) return [];
		var objs = ['select', 'input', 'object'];
		var elements = [];
		for(var i = 0; i < objs.length; i++)
		{
			var e = document.getElementsByTagName(objs[i]);
			for(var j = 0; j < e.length; j++)
			{
				elements.push(e[j]);
			}
		}
		return elements;
	},

	/**
	 * Hides the other visible help balloons
	 * @param {Event} e
	 */
	_hideOtherHelps: function(e)
	{
		if(this.options.hideOtherBalloonsOnDisplay)
		{
			$A(HelpBalloon._balloons).each(function(obj){
				if(obj != this)
				{
					obj.hide();
				}
			}.bind(this));
		}
	}
};

/**
 * HelpBalloon.Options
 * Helper class for defining options for the HelpBalloon object
 * @author Beau D. Scott <beau_scott@hotmail.com>
 */
HelpBalloon.Options = Class.create();
HelpBalloon.Options.prototype = {
	
	/**
	 * @constructor
	 * @param {Object} overriding options
	 */
	initialize: function(values){
		// Apply the overriding values to this
		Object.extend(this, values || {});
	},
	
	/**
	 * Show Effect
	 * The Scriptaculous (or compatible) showing effect function
	 * @var Function
	 */
	showEffect: window.Scriptaculous ? Effect.Appear : null,
	
	/**
	 * Show Effect options
	 */
	showEffectOptions: {duration: 0.2},
	
	/**
	 * Hide Effect
	 * The Scriptaculous (or compatible) hiding effect function
	 * @var Function
	 */
	hideEffect: window.Scriptaculous ? Effect.Fade : null,
	
	/**
	 * Show Effect options
	 */
	hideEffectOptions: {duration: 0.2},
	
	/**
	 * For use with embedding this object into another. If true, the icon is not created
	 * and not appeneded to the DOM at construction.
	 * Default is false
	 * @var {Boolean}
	 */
	returnElement: false,
	
	/**
	 * URL to the anchoring icon image file to use. This can also be a direct reference 
	 * to an existing element if you're using that as your anchoring icon.
	 * @var {Object}
	 */
	icon: '../images/helpBalloon/icon.gif',
	
	/**
	 * Alt text of the help icon
	 * @var {String}
	 */
	altText: 'Click here for help with this topic.',
	
	/**
	 * URL to pull the title/content XML
	 * @var {String}
	 */
	dataURL: null,
	
	/**
	 * Static title of the balloon
	 * @var {String}
	 */
	title: null,
	
	/**
	 * Static content of the balloon
	 * @var {String}
	 */
	content: null,
	
	/**
	 * The event type to listen for on the icon to show the balloon.
	 * Default 'click'
	 * @var {String}
	 */
	useEvent: ['click'],
	
	/**
	 * Request method for dynamic content. (get, post)
	 * Default 'get'
	 * @var {String}
	 */
	method:	'get',
	
	/**
	 * Flag indicating cache the request result. If this is false, every
	 * time the balloon is shown, it will retrieve the remote url and parse it
	 * before the balloon appears, updating the content. Otherwise, it will make
	 * the call once and use the same content with each subsequent showing.
	 * Default true
	 * @var {Boolean}
	 */
	cacheRemoteContent: true,
	
	/**
	 * Vertical and horizontal margin of the content pane
	 * @var {Number}
	 */
	contentMargin: 35,
	
	/**
	 * X coordinate of the closing button
	 * @var {Number}
	 */
	buttonX: 246,
	
	/**
	 * Y coordinate of the closing button
	 * @var {Number}
	 */
	buttonY: 35,
	
	/**
	 * Closing button image path
	 * @var {String}
	 */
	button: urlimages+'helpBalloon/button.png',
	
	/**
	 * Balloon image path prefix. There are 4 button images, numerically named, starting with 0.
	 * 0 1
	 *  X
	 * 2 3
	 * X indicates the anchor corner
	 * @var {String}
	 */
	balloonPrefix: urlimages+'helpBalloon/balloon-',
	
	/**
	 * The image filename suffix, including the file extension
	 * @var {String}
	 */
	balloonSuffix: '.png',
	
	/**
	 * Position of the balloon's anchor relative to the icon element.
	 * Combine one horizontal indicator (left, center, right) and one vertical indicator (top, middle, bottom).
	 * Numeric values can also be used in an X Y order. So a value of 9 13 would place the anchor 9 pixels from
	 * the left and 13 pixels below the top. (0,0 is top left). If values are greater than the width or height
	 * the width or height of the anchor are used instead. If less than 0, 0 is used.
	 * Default is 'center middle'
	 * @var {String}
	 */
	anchorPosition: 'center middle',
	
	/**
	 * Flag indicating whether to hide the elements under the balloon in IE.
	 * Setting this to false can cause rendering issues in Internet Explorer
	 * as some elements appear on top of the balloon if they're not hidden.
	 * Default is true.
	 * @var {Boolean}
	 */
	hideUnderElementsInIE: true,
	
	/**
	 * Default Balloon styling
	 * @var {Object}
	 */	
	balloonStyle: {},
	
	/**
	 * Default Title Bar style
	 * @var {Object}
	 */
	titleStyle: {
		'color': 'black',
		'fontSize': '16px',
		'fontWeight': 'bold',
		'fontFamily': 'Verdana'
	},
	
	/**
	 * Icon custom styling
	 * @var {Object}
	 */
	iconStyle: {
		'cursor': 'pointer'
	},
	
	/**
	 * Flag indication whether to automatically hide any other visible HelpBalloon on the page before showing the current one.
	 * @var {Boolean}
	 */
	hideOtherBalloonsOnDisplay: true,
	
	/**
	 * If you want the balloon to always display in a particular location, set this 
	 */
	fixedPosition: HelpBalloon.POS_DYNAMIC,
	
	/**
	 * Number of milliseconds to hide the balloon after showing and after the mouse is not over the balloon.
	 * A value of 0 means it will not auto-hide
	 * @var {Number}
	 */
	autoHideTimeout: 0
	
};	/************************************************************************************************************
	(C) www.dhtmlgoodies.com, October 2005
	
	Version 1.2: Updated, November 12th. 2005
	
	This is a script from www.dhtmlgoodies.com. You will find this and a lot of other scripts at our website.	
	
	Terms of use:
	You are free to use this script as long as the copyright message is kept intact. However, you may not
	redistribute, sell or repost it without our permission.
	
	Thank you!
	
	www.dhtmlgoodies.com
	Alf Magne Kalleland
	
	************************************************************************************************************/		
	var panelWidth = 200;	// Width of help panel	
	var slideSpeed = 15;		// Higher = quicker slide
	var slideTimer = 10;	// Lower = quicker slide
	var slideActive = true;	// Slide active ?
	var initBodyMargin = 0;	// Left or top margin of your <body> tag (left if panel is at the left, top if panel is on the top)
	var pushMainContentOnSlide = false;	// Push your main content to the right when sliding
	var panelPosition = 0; 	// 0 = left , 1 = top
	
	/*	Don't change these values */
	var slideLeftPanelObj=false;
	var slideInProgress = false;	
	var startScrollPos = false;
	var panelVisible = false;
	function initSlideLeftPanel(expandOnly)
	{
		if(slideInProgress)return;
		if(!slideLeftPanelObj){
			if(document.getElementById('dhtmlgoodies_leftPanel')){	// Object exists in HTML code?
				slideLeftPanelObj = document.getElementById('dhtmlgoodies_leftPanel');
				if(panelPosition == 1)slideLeftPanelObj.style.width = '100%';
			}else{	// Object doesn't exist -> Create <div> dynamically
				slideLeftPanelObj = document.createElement('DIV');
				slideLeftPanelObj.id = 'dhtmlgoodies_leftPanel';
				slideLeftPanelObj.style.display='none';
				document.body.appendChild(slideLeftPanelObj);
			}
			
			if(panelPosition == 1){
				slideLeftPanelObj.style.top = "-" + panelWidth + 'px';
				slideLeftPanelObj.style.left = '0px';	
				slideLeftPanelObj.style.height = panelWidth + 'px';			
			}else{
				slideLeftPanelObj.style.left = "-" + panelWidth + 'px';
				slideLeftPanelObj.style.top = '0px';
				slideLeftPanelObj.style.width = panelWidth + 'px';
			}
			

			if(!document.all || navigator.userAgent.indexOf('Opera')>=0)slideLeftPanelObj.style.position = 'fixed';;
		}	
		
		if(panelPosition == 0){
			if(document.documentElement.clientHeight){
				slideLeftPanelObj.style.height = document.documentElement.clientHeight + 'px';
			}else if(document.body.clientHeight){
				slideLeftPanelObj.style.height = document.body.clientHeight + 'px';
			}
			var leftPos = slideLeftPanelObj.style.left.replace(/[^0-9\-]/g,'')/1;
		}else{
			if(document.documentElement.clientWidth){
				slideLeftPanelObj.style.width = document.documentElement.clientWidth + 'px';
			}else if(document.body.clientHeight){
				slideLeftPanelObj.style.width = document.body.clientWidth + 'px';
			}
			var leftPos = slideLeftPanelObj.style.top.replace(/[^0-9\-]/g,'')/1;			
			
			
		}
		slideLeftPanelObj.style.display='block';
		
		if(panelPosition==1)
			startScrollPos = Math.max(document.body.scrollTop,document.documentElement.scrollTop);
		else
			startScrollPos = Math.max(document.body.scrollLeft,document.documentElement.scrollLeft);
		if(leftPos<(0+startScrollPos)){
			if(slideActive){
				slideLeftPanel(slideSpeed);	
			
			}else{
				document.body.style.marginLeft = panelWidth + 'px';
				slideLeftPanelObj.style.left = '0px';
			}
		}else{
			if(expandOnly)return;
			if(slideActive){		
				slideLeftPanel(slideSpeed*-1);
			}else{
				if(panelPosition == 0){
					if(pushMainContentOnSlide)document.body.style.marginLeft =  initBodyMargin + 'px';
					slideLeftPanelObj.style.left = (panelWidth*-1) + 'px';	
				}else{
					if(pushMainContentOnSlide)document.body.style.marginTop =  initBodyMargin + 'px';
					slideLeftPanelObj.style.top = (panelWidth*-1) + 'px';						
				}			
			}
		}	
		
		if(navigator.userAgent.indexOf('MSIE')>=0 && navigator.userAgent.indexOf('Opera')<0){
			window.onscroll = repositionHelpDiv;
		
			repositionHelpDiv();
		}
		window.onresize = resizeLeftPanel;
		
	}
	
	function resizeLeftPanel()
	{
		if(panelPosition == 0){
			if(document.documentElement.clientHeight){
				slideLeftPanelObj.style.height = document.documentElement.clientHeight + 'px';
			}else if(document.body.clientHeight){
				slideLeftPanelObj.style.height = document.body.clientHeight + 'px';
			}		
		}else{
			if(document.documentElement.clientWidth){
				slideLeftPanelObj.style.width = document.documentElement.clientWidth + 'px';
			}else if(document.body.clientWidth){
				slideLeftPanelObj.style.width = document.body.clientWidth + 'px';
			}	
		}
	}
	
	function slideLeftPanel(slideSpeed){
		slideInProgress =true;
		var scrollValue = 0;
		if(panelPosition==1)
			var leftPos = slideLeftPanelObj.style.top.replace(/[^0-9\-]/g,'')/1;
		else
			var leftPos = slideLeftPanelObj.style.left.replace(/[^0-9\-]/g,'')/1;
			
		leftPos+=slideSpeed;
		okToSlide = true;
		if(slideSpeed<0){
			if(leftPos < ((panelWidth*-1) + startScrollPos)){
				leftPos = (panelWidth*-1) + startScrollPos;	
				okToSlide=false;
			}
		}
		if(slideSpeed>0){
			if(leftPos > (0 + startScrollPos)){
				leftPos = 0 + startScrollPos;
				okToSlide = false;
			}			
		}
		
		
		if(panelPosition==0){
			slideLeftPanelObj.style.left = leftPos + startScrollPos + 'px';
			if(pushMainContentOnSlide)document.body.style.marginLeft = leftPos - startScrollPos + panelWidth + 'px';
		}else{
			slideLeftPanelObj.style.top = leftPos + 'px';
			if(pushMainContentOnSlide)document.body.style.marginTop = leftPos - startScrollPos + panelWidth + 'px';			
			
		}
		if(okToSlide)setTimeout('slideLeftPanel(' + slideSpeed + ')',slideTimer); else {
			slideInProgress = false;
			if(slideSpeed>0)panelVisible=true; else panelVisible = false;
		}
		
	}
	
	
	function repositionHelpDiv()
	{
		if(panelPosition==0){
			var maxValue = Math.max(document.body.scrollTop,document.documentElement.scrollTop);
			slideLeftPanelObj.style.top = maxValue;
		}else{
			var maxValue = Math.max(document.body.scrollLeft,document.documentElement.scrollLeft);
			slideLeftPanelObj.style.left = maxValue;	
			var maxTop = Math.max(document.body.scrollTop,document.documentElement.scrollTop);
			if(!slideInProgress)slideLeftPanelObj.style.top = (maxTop - (panelVisible?0:panelWidth)) + 'px'; 		
		}
	}
	
	function cancelEvent()
	{
		return false;
	}
	function keyboardShowLeftPanel()
	{
			initSlideLeftPanel();
			return false;	
	
	}
	
	function leftPanelKeyboardEvent(e)
	{
		if(document.all)return;
		
		if(e.keyCode==112){
			initSlideLeftPanel();
			return false;
		}		
	}
	
	function setLeftPanelContent(text)
	{
		document.getElementById('leftPanelContent').innerHTML = text;
		initSlideLeftPanel(true);
		
	}
	if(!document.all)document.documentElement.onkeypress = leftPanelKeyboardEvent;
	document.documentElement.onhelp  = keyboardShowLeftPanel;/*
//gestion des requetes ajax
var myGlobalHandlers = {
        onCreate: function()
            {
			    Ajax.activeRequestCount++;
			    $('requete_en_cours').value = Ajax.activeRequestCount;
            },
        onComplete: function()
            {
			    Ajax.activeRequestCount--;
			    $('requete_en_cours').value = Ajax.activeRequestCount;
            },
        onFailure: function()
            {
			    $('requete_en_cours').value = 'erreur ajax';
            },
        onException: function()
            {
			    $('requete_en_cours').value = 'exception ajax';
            }
    };
Ajax.Responders.register(myGlobalHandlers);
*/

var AjaxTimeOut = 30000;
function callInProgress (xmlhttp) {
switch (xmlhttp.readyState) {
case 1: case 2: case 3:
return true;
break;
// Case 4 and 0
default:
return false;
break;
}
}
function showFailureMessage() {
log.error('temps de requete depasser');
}
// Register global responders that will occur on all AJAX requests
Ajax.Responders.register({
onCreate: function(request) {
request['timeoutId'] = window.setTimeout(
function() {
// If we have hit the timeout and the AJAX request is active, abort it and let the user know
if (callInProgress(request.transport)) {
request.transport.abort();
showFailureMessage();
// Run the onFailure method if we set one up when creating the AJAX object
if (request.options['onFailure']) {
request.options['onFailure'](request.transport, request.json);
}
}
},
AjaxTimeOut // Five seconds
);
},
onComplete: function(request) {
// Clear the timeout, the request completed ok
window.clearTimeout(request['timeoutId']);
}
});




/**
 * @contributor Matthew Foster
 * @date 		February 4th 2007
 * @purpose 	This class should be considered an "abstract" it is never intended to be a concrete class, notice there is no initialize function.
 *				This class is intended to be extended from, allowing an overwritable yet base functions for processing ajax requests.  The proposed advantage to this structure
 *				Is that during debugging all of your requests are being processed in the same area, thus allowing an easier target for reviewing ajax data.  As well as handling
 *				more of what I believe to be the monotoneous routines involved in sending ajax requests.
 */			

/*
Ajax.Application = {}

Ajax.Application.Base = Class.create(); 
Ajax.Application.Cache = Class.create();

Object.extend(Ajax.Application.Base.prototype,
						{
							method : "post",
							
							sendRequest : function(dto, cb){
								var p = this.compileDTO(dto);
										
								
								new Ajax.Request(this.url,
													{
														parameters   : p,
														method		 : this.method,
														onSuccess   : this.receiveRequest.bind(this, cb),
														onFailure    : this.ajaxFailure.bind(this),
														onException  : this.ajaxException.bind(this)
													}
												);					
							},
							
							receiveRequest : function(cb, eAja){
								
								cb(eAja);
										
							},
							ajaxFailure : function(){
								if(typeof console == "object")
									console.log("Ajax Request failed args = %o ", arguments);
								else
									alert("Ajax request has failed. Application integrity has been compromised.");
							},
							ajaxException : function(){
								
								if(typeof console == "object")
									console.log("ajax exception occured args = %o", arguments);
								
								
							},
							compileDTO : function(dto){
								
								if(typeof dto == "object")
									return $H(dto).toQueryString();
								else if(typeof dto == "string")
									return dto;
								else
									throw { message : "object sent to sendRequest was invalid type.  Type = " +typeof dto };
										
								
							}
						
						
						}
			);
			
*/

/**
 * @author Matthew Foster
 * @date   April 24th 2007
 * @purpose	This class is an extension of the base class with added functionality to allow for transparent caching.  The idea is to save the query string as a key in a hash object
 * 			and if that query string has already been sent for it will already have an ajax response and it will simply pass that immediately to the call back function
 */


/*
Object.extend(Object.extend(Ajax.Application.Cache.prototype, Ajax.Application.Base.prototype),
					{
						getCache : function(){
							
							if(!this.requestCache)
								this.requestCache = {};
							
							return this.requestCache;
						
						},
						setCache : function(obj){
						
							Object.extend(this.requestCache, obj || {});
						
						},
						sendRequest : function(dto, cb){
							
							var cache = this.getCache();
							
							var key = this.compileDTO(dto);
							
							if(!cache[key]){
								var cachedCallBack = this.registerCache.bind(this, cb, key);
								Ajax.Application.Base.prototype.sendRequest.apply(this, [key, cachedCallBack]);
							}
							else
								cb(cache[key]);
						},
						registerCache : function(cb, key, eAja){
							var cache = {};
							
							cache[key] = eAja;
							
							this.setCache(cache);
							
							cb(eAja);
							
						}				
					}
			);
*/// Copyright (c) 2006 SÃ©bastien Gruhier (http://xilinus.com, http://itseb.com)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// VERSION 2 modifiÃ© par villaumÃ© romain C2B-trunk



if(typeof Draggable == 'undefined')
  throw("portal.js requires including script.aculo.us' dragdrop.js library");

if(typeof Builder == 'undefined')
  throw("portal.js requires including script.aculo.us' builder.js library");

// Xilinus namespace
if(typeof Xilinus == 'undefined')
  Xilinus = {}
  
Builder.dump();


Xilinus.Widget = Class.create();  
Xilinus.Widget.lastId = 0;
Xilinus.Widget.remove = function(element, options) {    
  if (options && options.afterFinish)
    options.afterFinish.call();
} 


/* 
*Extension de la classe pour le portal
*
*
*/
Object.extend(Xilinus.Widget.prototype, {
  initialize: function(className, id) {
  	//creation du widjet
    className = className || "widget";  

    this._id   = id || ("widget_" + Xilinus.Widget.lastId++);
    
    this._headerDiv   = DIV({className: className + '_header', id: this._getId("header")},  ""); 
    this._titleDiv   = DIV({className: className + '_title', id: this._getId("title")},  "");    
    this._paramDiv   = DIV({className: className + '_param', id: this._getId("param")},  ""); //creation de la div param  
    this._optionDiv = DIV({className: className + '_option', id: this._getId("option")}, "");//creation de la div option   
    this._contentDiv = DIV({className: className + '_content', id: this._getId("content")},"");   
    this._footerDiv  = DIV({className: className + '_statusbar', id: this._getId("footer")}, "");
    
    var divHeader  = DIV({className: className + '_nw' }, [this._headerDiv , this._titleDiv] ); 
    var divOption = DIV({className: className + '_op'},  this._optionDiv);//creation de la div container option
    var divParam  = DIV({className: className + '_pa' }, this._paramDiv);//creation de la div container param
    var divContent = DIV({className: className + '_w' },  this._contentDiv);   
    var divFooter  = DIV({className: className + '_sw' }, this._footerDiv);  
    
    
    this._div = DIV({className: className + (className != "widget" ? " widget" : ""), id: this._getId()}, [divHeader, divParam, divContent, divOption, divFooter,]);     
    this._div.widget = this;

    return this;
  },    
  
  // detruire un module
  destroy: function() {
    this._div.remove();
  },
  
  //recuperer l'id du module
  getElement: function() {
    return $(this._getId()) || $(this._div);
  },
   
  //definir l'id du module
  setId: function(id) {
    this._id = id;
    return this;
  },
  //recupÃ©rer le titre du module
  getId: function(title) {
    return this._id;
  },
  
  //definir le titre du module
  setTitle: function(title) {
    $(this._titleDiv).update(title);
    return this;
  },
  //recupÃ©rer le titre du module
  getTitle: function(title) {
    return $(this._titleDiv)
  },
  
  setFooter: function(title) {
    $(this._footerDiv).update(title);
    return this;
  },
  //rÃ©cupÃ©rer le footer
  getFooter: function(title) {
    return $(this._footerDiv)
  },
  //rÃ©cupÃ©rer le header
  getHeader: function(title) {
    return $(this._headerDiv)
  },
  //dÃ©finir le contenu
  setContent: function(title) {
  	//if($(this._contentDiv)=="")alert(title);
    //this.chargement($(this._contentDiv));
  	this.ajaxcontent = false;
  	this.title = title;
  	$(this._contentDiv).update(title);  
    return this;
  },
  //rÃ©cupÃ©rer le contenu
   getContent: function(title) {
    return $(this._contentDiv)
  }, 
  //recalculer et dedimentionne la hauteur du module
  recalculHauteurDiv: function()
  {
    $(this._contentDiv).setStyle({height: null})
    var h = $(this._contentDiv).getHeight();
    $(this._contentDiv).setStyle({height: h + "px"});
  	
   
  	return this;
  },
     
  ajaxBoxUpdate: function ()
  {
	div =$(this._contentDiv);
  	if(typeof($(div))!='undefined')
  	{
	  	new Ajax.Request(this.page,{
	  		evalScripts: true,
	  		onComplete:function(e){
	  			retour = e.responseText;
	  			$(div).update(retour);		
	  			$(div).setStyle({height: null})
    			var h = $(div).getHeight();
    			$(div).setStyle({height: h + "px"});			
	  		}
	  		,onFailure:function(e){alert('erreur')}
	  		,asynchronous: false
	  	});

  	}

  },

  /* appeler une action d'un javascript 
  *
  *

  $A: function()
  {
  	
  }  */
  
  /* dÃ©finir le contenu du module en ajax
  * @param page page appele
  * @param delay delais avant le refraichissement du contenu du module
  */
  setAjaxContent: function(page, delay)
  {

  	this.chargement($(this._contentDiv));
  	
  	this.delay = delay;
  	this.ajaxcontent = true;
  	this.page = page;
		div =$(this._contentDiv);
  	if(this.delay >0)
  	{
  		//alert('delay');
  		new Ajax.PeriodicalUpdater($(this._contentDiv), this.page, {evalScripts: true, frequency: this.delay, decay:2, onSuccess:function(e){
  				retour = e.responseText;
	  			$(div).update(retour);		
	  			$(div).setStyle({height: null})
    			var h = $(div).getHeight();
    			$(div).setStyle({height: h + "px"});			
	  		}});			
  		//new PeriodicalExecuter(this.ajaxBoxUpdate, this.delay);
  	}
  	else
  	{
  		//alert('nodelay'+$(this._contentDiv).id); 		
  		//new Ajax.Updater($(this._contentDiv),this.page,{ afterUpdate:this.traitementRefresh(this)});
  		this.ajaxBoxUpdate();

  	}

  	return this;
  },

  //raffraichir le contenu du module
  refreshAjaxContent: function(div)
  {
  	//alert(this.page);
  	new Ajax.Updater(div, this.page,{evalScripts: true, onComplete:this.recalculHauteurDiv});  	
  	return this;
  },
  //dÃ©finir les options     
  setOption: function(title) {
  	var html = $(this._optionDiv).innerHTML;
  	//alert(html);
    $(this._optionDiv).update(html+title);  
    return this;
  },
  //rÃ©cupÃ©rer les options
  getOption: function(title) {
    return $(this._optionDiv)
  },
  
  //dÃ©finir les parametres
  setParam: function(title) {
    $(this._paramDiv).update(title.strip()); 
    return this;
  },
  //rÃ©cupÃ©rer les paramÃ¨tres 
  getParam: function(title) {
    return $(this._paramDiv)
  },   
  
  //raffraichir le contenu du module en prenant compte du delais de raffraichissement
  refreshContent: function(element)
  {
  	//alert(this.page);
  	var widget = $(element).up(".widget").widget;
  	refreshCallBack = widget.refreshCallBack;

  	if(refreshCallBack == false)
  	{
	  	if(this.ajaxcontent)
	  	{
	  		this.setAjaxContent(this.page, this.delay);
	  	}
	  	else
	  	{
	  		this.setContent(this.title);
	  	}  		
  	}
  	else
  	{
  		if('function' == typeof(eval(refreshCallBack))){
			eval(refreshCallBack)(this.delay);
		}
		else{
			alert("la fonction n'exite pas");
		}
		
  	}

  },
  //recalcule et redimentionne le module en hauteur
  updateHeight: function(orignal) { 
  	//alert(this.newHeight);
    $(this._contentDiv).setStyle({height: null})

    if(orignal >0)
    {
    	var h =  orignal;
    }
    else
    {
    	 var h = $(this._contentDiv).getHeight();
    }

    $(this._contentDiv).setStyle({height: h + "px"});
  },
  //fonction qui permet de mettre une image lors du chargement
  chargement: function(element)
  {
  	$(element).innerHTML= '<div id="chargement"><img src="images/ajax-loader.gif"></div>';
  },
  
  // PRIVATE FUNCTIONS
  _getId: function(prefix) { 
      return (prefix ? prefix + "_" : "") + this._id;
  }
});

/* 
*Extension de la classe pour les widgets
*
*
*/
Xilinus.Portal = Class.create()
Object.extend(Xilinus.Portal.prototype, {
  lastEvent: null,   
  widgets:   null,
  columns:   null, 
  
  initialize: function(columns, options) {   
    this.options = Object.extend({                  
                     url:          null,                 // Url called by Ajax.Request after a drop
                     onOverWidget: null,                 // Called when the mouse goes over a widget
                     onOutWidget:  null,                 // Called when the mouse goes out of a widget                                           
                     onChange:     null,                 // Called a widget has been move during drag and drop 
                     onUpdate:     null,                 // Called a widget has been move after drag and drop
                     removeEffect: Xilinus.Widget.remove // Remove effect (by default no effect), you can set it to Effect.SwitchOff for example
                   }, options)
    this._columns = (typeof columns == "string") ? $$(columns) : columns;
    this._widgets = new Array();    


       
    this._columns.each(function(element) {
    	//alert(element.id);
    	//classvalue = (element.className).toLowerCase();
    			//hasClassName()
    	//if(classvalue.indexOf("container") != -1)//on indique que cette div est un container
    	if(element.hasClassName("portal_container"))//on indique que cette div est un container
    	{
    		Droppables.add(element, {onHover: this.onHover.bind(this), overlap: "vertical", accept: this.options.accept})}
    	}.bind(this)
    	);  
    this._outTimer  = null;
    
    // Draggable calls makePositioned for IE fix (??), I had to remove it for all browsers fix :) to handle properly zIndex
    this._columns.invoke("undoPositioned");    
    
    this._currentOverWidget = null; 
    this._widgetMouseOver = this.widgetMouseOver.bindAsEventListener(this);
    this._widgetMouseOut  = this.widgetMouseOut.bindAsEventListener(this);
    
    Draggables.addObserver({ onEnd: this.endDrag.bind(this), onStart: this.startDrag.bind(this) }); 
  },
  
  get_colums: function(div)
	{
	
	  	var indexcolums = -1;
	  	this._columns.each(function(element) {
	  		indexcolums++;
	  		if(element.id == div)
	  		{
	  			valuecolums = indexcolums;			
	  		}	
	  	});  
	
	  	
	  	return valuecolums;
	},
  
	positionWidget: function(event)
	{
		var pos = {};
		if (typeof (event.clientX) != 'undefined')
		{
			pos.x = event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
			pos.y = event.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
		}
		else
		{
			pos.x = event.x + (document.documentElement.scrollLeft || document.body.scrollLeft);
			pos.y = event.y + (document.documentElement.scrollTop || document.body.scrollTop);
		}
		return pos
	},
	//redimentionne le widget
	resizeHover: function ( event, widget )
	{
		this.widgetResize = widget;

		var eventPosition =this.positionWidget(event);
		var popupPosition = { x : $(this.widgetResize._id).offsetLeft, y : $(this.widgetResize._id).offsetTop };
		var popupDimension = { w : $(this.widgetResize._id).offsetWidth, h : $(this.widgetResize._id).offsetHeight };
		var offsetPosition = { x : eventPosition.x - popupPosition.x, y : eventPosition.y - popupPosition.y };
		this.resize.direction = '';
		
		//hHeader = this.widgetResize.getHeader().getHeight();
		hFooter = this.widgetResize.getFooter().getHeight();

		/*
		if (offsetPosition.y <= hHeader)
		{
			this.widgetResize.getHeader().setStyle({cursor: 'n-resize', borderTop: '2px solid #5a8891'});	
			this.resize.direction += 'n';
		}
		else 
		*/
		//alert(this.estreduit);
		if ((popupDimension.h - offsetPosition.y) <= hFooter)
		{
			this.resize.direction += 's';
			this.widgetResize.getFooter().setStyle({cursor: 's-resize', borderTop: '2px solid #5a8891'});	
		}

		
		
	},
	
	resizeOut: function ( event )
	{
		if (!this.resize.resizing)
		{
			this.widgetResize.getFooter().setStyle({cursor: '', borderTop: ''});	
		}
	},
		
	resizeStart: function ( event )
	{
		//var eventPosition = EVT.position(event);
		var eventPosition = this.positionWidget(event);
		var popupPosition = { x : $(this.widgetResize._id).offsetLeft, y : $(this.widgetResize._id).offsetTop };
		this.resize.initialPosition.x = eventPosition.x - popupPosition.x;
		this.resize.initialPosition.y = eventPosition.y - popupPosition.y;
		this.resize.initialMousePosition.x = eventPosition.x;
		this.resize.initialMousePosition.y = eventPosition.y;
		this.resize.initialPopupPosition.x = popupPosition.x;
		this.resize.initialPopupPosition.y = popupPosition.y;
		this.resize.initialDimension.w = $('content_'+this.widgetResize._id).offsetWidth;
		this.resize.initialDimension.h = $('content_'+this.widgetResize._id).offsetHeight;
		this.resize.resizing = true;
	},

	resizeApply: function ( event )
	{
		
		if (this.resize.resizing)
		{
			var eventPosition = this.positionWidget(event);
			var n, s;
			var offsetX, offsetY;
			var newWidth, newHeight;
			var newLeft, newTop;

			this.newHeight = this.resize.initialDimension.h + eventPosition.y - this.resize.initialMousePosition.y;
			newTop = this.resize.initialPopupPosition.y + eventPosition.y - this.resize.initialMousePosition.y;	

			//$('souris').innerHTML = 'content_'+this.widgetResize._id+' y: '+$(this.widgetResize._id).getHeight()+' y: '+eventPosition.y+' taille final: '+newTop+' direction '+this.resize.direction;
			
			//if(this.resize.direction == 's')$('content_'+this.widgetResize._id).setStyle({height: newHeight+ 'px'});
			//if(this.resize.direction == 'n')$('content_'+this.widgetResize._id).setStyle({top: newTop+ 'px'});
			//, top: newTop+'px'
			$('content_'+this.widgetResize._id).setStyle({height: this.newHeight+ 'px'});

			return this;

		}
	},

	resizeStop: function ( event )
	{
		this.resize.resizing = false;
	},

	redimentionneWidget: function(widget)
	{

		//if(!this.estreduit)
		idWidget = widget._id;

		if (this.estresizable) { 
		    this.resize =
				{
					hover : false,
					out : false,
					start : false,
					apply : false,
					stop : false,
					resizing : false,
					direction : '',
					initialPosition : { x : 0, y : 0 },
					initialMousePosition : { x : 0, y : 0 },
					initialPopupPosition : { x : 0, y : 0 },
					initialDimension : { w : 0, h : 0 }
				};
				
				this.objet = {};
				this.objet.bresizeHover = this.resizeHover.bindAsEventListener(this, widget);
				this.objet.bresizeOut = this.resizeOut.bindAsEventListener(this);
				this.objet.bresizeStart = this.resizeStart.bindAsEventListener(this);
				this.objet.bresizeApply = this.resizeApply.bindAsEventListener(this);
				this.objet.bresizeStop = this.resizeStop.bindAsEventListener(this);
			
 			  Event.observe($(idWidget), "mousemove", this.objet.bresizeHover);
				Event.observe($(idWidget), "mouseout", this.objet.bresizeOut);
				Event.observe($(idWidget), "mousedown", this.objet.bresizeStart);			
				Event.observe(document, "mousemove", this.objet.bresizeApply);
				Event.observe(document, "mouseup", this.objet.bresizeStop);		

		}
	},

	stopRedimentionneWidget: function(widget)
	{
				this.objet = {};
				this.objet.bresizeHover = this.resizeHover.bindAsEventListener(this, widget);
				this.objet.bresizeOut = this.resizeOut.bindAsEventListener(this);
				this.objet.bresizeStart = this.resizeStart.bindAsEventListener(this);
				this.objet.bresizeApply = this.resizeApply.bindAsEventListener(this);
				this.objet.bresizeStop = this.resizeStop.bindAsEventListener(this);
		//if(!this.estreduit)
		idWidget = widget._id;

		    this.resize =
				{
					hover : false,
					out : false,
					start : false,
					apply : false,
					stop : false,
					resizing : false,
					direction : '',
					initialPosition : { x : 0, y : 0 },
					initialMousePosition : { x : 0, y : 0 },
					initialPopupPosition : { x : 0, y : 0 },
					initialDimension : { w : 0, h : 0 }
				};
				
				Event.stopObserving($(idWidget), "mousemove", this.objet.bresizeHover);
				Event.stopObserving($(idWidget), "mouseout", this.objet.bresizeOut);
				Event.stopObserving($(idWidget), "mousedown", this.objet.bresizeStart);
				
				Event.stopObserving(document, "mousemove", this.objet.bresizeApply);
				Event.stopObserving(document, "mouseup", this.objet.bresizeStop);		
				
				//Event.unloadCache();		

	},	
	
  //fonction qui permet d'ajouer un widjet
  add: function(widget, columnIndex, widjetOptions) {  
  		
  	var widget;			
	idWidget = widget._id;		
    if(this.setOptions)
      this.setOptions(widjetOptions);
    else
      this.widjetOptions = widjetOptions || { };
      

	//on initialise les options du widjet
    this.draggable = typeof this.widjetOptions.draggable == "undefined" ? true : this.widjetOptions.draggable
    this.supprimable = typeof this.widjetOptions.supprimable == "undefined" ? false : this.widjetOptions.supprimable
    this.isparam = typeof this.widjetOptions.isparam == "undefined" ? true : this.widjetOptions.isparam
    this.refresh = typeof this.widjetOptions.refresh == "undefined" ? true : this.widjetOptions.refresh
    widget.refreshCallBack = typeof this.widjetOptions.refreshCallBack == "undefined" ? false : this.widjetOptions.refreshCallBack
    this.reduire = typeof this.widjetOptions.reduire == "undefined" ? true : this.widjetOptions.reduire
    this.estreduit = typeof this.widjetOptions.estreduit == "undefined" ? false : this.widjetOptions.estreduit
    this.estresizable = typeof this.widjetOptions.estresizable == "undefined" ? false : this.widjetOptions.estresizable
    
    // Add to widgets list
    this._widgets.push(widget);
    if (this.options.accept)
      widget.getElement().addClassName(this.options.accept)
    
    // Add element to column
    if(isNaN(columnIndex))
    {
    	columnIndex = this.get_colums(columnIndex);
    }
    //on ajoute le widget a la colonne
    this._columns[columnIndex].appendChild(widget.getElement());
    widget.updateHeight();
    
    // Make header draggable   
    if (this.draggable) {
      widget.draggable = new Draggable(widget.getElement(),{ handle: widget._titleDiv, revert: false});     
      widget.getTitle().addClassName("widget_draggable");   
    }
   
    //rendre le widjet supprimable
    if (this.supprimable) {
			widget.setOption('<a href="#" onclick="removeWidget(this); return false;" id="delete_button"></a>');
    } 
    //rendre le widjet parametrable
    if (this.isparam) {
    	//alert(this.getParam);
		if($('param_'+idWidget).innerHTML != "")widget.setOption('<a href="#" onclick="paramWidget(this); return false;" id="edit_button">');
    }     
    //rendre le widjet rafraichissable
    if (this.refresh) {
			widget.setOption('<a href="#" onclick="refreshWidget(this); return false;" id="refresh_button"></a>');
    }       
     //rendre le widjet reductible
    if (this.reduire) {
			widget.setOption('<a href="#" onclick="reduirehWidget(this); return false;"><img src="images/collapsen.png" class="reduire_button" border="0" id="reduire_button_'+idWidget+'"></a>');
    } 
     //rendre le widjet reductible
    if (this.estreduit) {   
	    $('content_'+idWidget).hide(); 
	    var vimg = $('reduire_button_'+idWidget);  
      vimg.src = 'images/expandn.png';
    }


    if (this.estresizable) { 
    	if(!this.estreduit)this.redimentionneWidget(widget);			
    	//this.redimentionneWidget(widget);			
    }   
       
    // Update columns heights
    this._updateColumnsHeight();  

    // Add mouse observers  
    if (this.options.onOverWidget)
      widget.getElement().childElements().invoke("observe", "mouseover", this._widgetMouseOver);
    if (this.options.onOutWidget)
      widget.getElement().childElements().invoke("observe", "mouseout",  this._widgetMouseOut);

    widget._optionDiv.style.display = 'none';//Fix pour IE
    widget._paramDiv.style.display = 'none';//Fix pour IE
    this.addWidgetControls(widget._optionDiv.id);
    
    return this;
  },  

  /* retourne id content en fonction de l'element
  *
  * @param typeContent defaut content
  * - Footer 
  * - Header 
  * 
  * pn l'appel de l'exterrieur en passant portal.$('element')
  */
  $:function(id, typeContent)
  {

   for (var index = 0, len = this._widgets.length; index < len; ++index) {
   	  var w = this._widgets[index];
      var wId = w.getId();    
      var wTitle = w.getTitle().innerHTML;
      var wContent = w.getContent().id;
      var wFooter = w.getFooter().id;
      var wHeader = w.getHeader().id;
      if(id == wId)
      {

      	switch(typeContent)
      	{
      		case "id":
      		return wId;
      		break;
      		case "content":
      		return wContent;
      		break;
      		case "Header":
      		return wHeader;
      		break;
      		case "Footer":
      		return wFooter;
      		break;
      		default:
      		return wContent;
      		break;
      	}
      	
      }
   }
   return false;
  },
  
  remove: function(widget) {
    // Remove from the list
    this._widgets.reject(function(w) { return w == widget});

    // Remove observers
    if (this.options.onOverWidget)
      widget.getElement().childElements().invoke("stopObserving", "mouseover", this._widgetMouseOver);
    if (this.options.onOutWidget)
      widget.getElement().childElements().invoke("stopObserving", "mouseout",  this._widgetMouseOut);

    // Remove draggable
    if (widget.draggable)
      widget.draggable.destroy();
      
    // Remove from the dom
    this.options.removeEffect(widget.getElement(), {afterFinish: function() {widget.destroy();}});
    
    // Update columns heights
    this._updateColumnsHeight();  
  },
    
  serialize: function() {
    parameters = ""
    this._columns.each(function(column) {   
      var p = column.childElements().collect(function(element) {
        return column.id + "[]=" + element.id
      }).join("&") 
      parameters += p + "&"
    });               
    
    return parameters;                      
  },     
  
  addWidgetControls: function(element) {
    $(element).observe("mouseover", this._widgetMouseOver); 
    $(element).observe("mouseout", this._widgetMouseOut); 
  },
  
  // EVENTS CALLBACKS
  widgetMouseOver: function(event) {   
    this._clearTimer();
      
    var element =  Event.element(event).up(".widget");
    if (this._currentOverWidget == null || this._currentOverWidget != element) {
      if (this._currentOverWidget && this._currentOverWidget != element)
        this.options.onOutWidget(this, this._currentOverWidget.widget)    
        
      this._currentOverWidget = element;
      this.options.onOverWidget(this, element.widget)
    }
  },

  widgetMouseOut: function(event) {    
    this._clearTimer();
    var element =  Event.element(event).up(".widget"); 
    this._outTimer = setTimeout(this._doWidgetMouseOut.bind(this, element), 100);
  },
  
  _doWidgetMouseOut: function(element) {
    this._currentOverWidget = null;
    this.options.onOutWidget(this, element.widget)    
  },                                               
  
  // DRAGGABLE OBSERVER CALLBACKS
  startDrag: function(eventName, draggable) { 
    var widget = draggable.element;
    
    if (!this._widgets.find(function(w) {return w == widget.widget}))
      return;

    var column = widget.parentNode;
    
    // Create and insert ghost widget
    var ghost = DIV({className: 'widget_ghost'}, ""); 
    $(ghost).setStyle({height: widget.getHeight()  + 'px'})

    column.insertBefore(ghost, widget);  

    // IE Does not absolutize properly the widget, needs to set width before
    widget.setStyle({width: widget.getWidth() + "px"});
    
    // Absolutize and move widget on body
    Position.absolutize(widget);  
    document.body.appendChild(widget);   
    
    // Store ghost to drag widget for later use
    draggable.element.ghost = ghost; 
    
    // Store current position
    this._savePosition = this.serialize();    
  },   

  endDrag: function(eventName, draggable) {
    var widget = draggable.element;      
    if (!this._widgets.find(function(w) {return w == widget.widget}))
      return;
    
    var column = widget.ghost.parentNode;
    
    column.insertBefore(draggable.element, widget.ghost); 
    widget.ghost.remove();   
    
    if (Prototype.Browser.Opera)     
      widget.setStyle({top: 0, left: 0, width: "100%", height: widget._originalHeight, zIndex: null, opacity: null, position: "relative"})
    else
      widget.setStyle({top: null, left: null, width: null, height: widget._originalHeight, zIndex: null, opacity: null, position: "relative"})
    
    widget.ghost = null;    

	//taille original du widget avant de deplacement afin de le conserver si drag&drop
   this.hOriginal = $('content_'+widget.widget._id).getHeight();

   widget.widget.updateHeight(this.hOriginal);
    this._updateColumnsHeight();
    
    // Fire events if changed
    if (this._savePosition != this.serialize()) {
      if (this.options.url)  
        new Ajax.Request(this.options.url, {evalScripts: true, parameters: this.serialize()});
      
      if (this.options.onUpdate)
        this.options.onUpdate(this);
    }
  },

  onHover: function(dragWidget, dropon, overlap) {  
    var offset = Position.cumulativeOffset(dropon);
    var x = offset[0] + 10;
    var y = offset[1] + (1 - overlap) * dropon.getHeight();

    // Check over ghost widget
    if (Position.within(dragWidget.ghost, x, y))
      return;
      
    // Find if it's overlapping a widget
    var found = false;
    var moved = false;
    for (var index = 0, len = this._widgets.length; index < len; ++index) {
      var w = this._widgets[index].getElement();
      if (w ==  dragWidget || w.parentNode != dropon)   
        continue;        

      if (Position.within(w, x, y)) {    
        var overlap = Position.overlap( 'vertical', w);     
        // Bottom of the widget
        if (overlap < 0.5) {         
          // Check if the ghost widget is not already below this widget
          if (w.next() != dragWidget.ghost) {
            w.parentNode.insertBefore(dragWidget.ghost, w.next());   
            moved = true;
          }
        } 
        // Top of the widget
        else {       
          // Check if the ghost widget is not already above this widget
          if (w.previous() != dragWidget.ghost) {      
            w.parentNode.insertBefore(dragWidget.ghost, w);   
            moved = true;
          }
        }
        found = true;
        break;
      }
    }
    // Not found a widget
    if (! found) {        
      // Check if dropon has ghost widget
      if (dragWidget.ghost.parentNode != dropon) {
        // Get last widget bottom value
        var last = dropon.childElements().last();
        var yLast = last ? Position.cumulativeOffset(last)[1] + last.getHeight() : 0; 
        if (y > yLast && last != dragWidget.ghost) {
          dropon.appendChild(dragWidget.ghost);
          moved = true;
        }
      }
    }  
    if (moved && this.options.onChange) 
      this.options.onChange(this)            

    this._updateColumnsHeight();
  },                
  
  // PRIVATE FUNCTIONS
  _updateColumnsHeight: function() {      
  	var h = 0;
    this._columns.each(function(col) {
    	colElement = col.id;
    	if(colElement)
    	{
    		//classvalue = $(colElement).className.toLowerCase();
    		//hasClassName()
    		if($(colElement).hasClassName("portal_container"))//on indique que cette div est un container
    		{
		      h = Math.max(h, col.childElements().inject(0, function(sum, element) { 
		        return sum + element.getHeight(); 
		      	}));
	    	}
    	}

    	

    	})
    	/* correction a apporteer important */
    	//this._columns.invoke("setStyle", {height: h + 'px'})
  },
  
  _clearTimer: function() {
    if (this._outTimer) {
      clearTimeout(this._outTimer);
      this._outTimer = null;
    }                        
  }
});     


/**ACTION SUR LES WIDGETS */

     //action sur les boutons
     function onOverWidget(portal, widget) {
     	idWidget = widget._id;
	     	try
				{
      				widget.getElement().insertBefore($('option_'+idWidget), widget.getElement().firstChild);
      				$('option_'+idWidget).show(); 
				}
				catch(err)
				{
				//Handle errors here
				} 

     } 
   
     function onOutWidget(portal, widget) {
     	idWidget = widget._id;
	     	try
				{
					$('option_'+idWidget).hide(); 
				}
				catch(err)
				{
				//Handle errors here
				}         
     } 
   
     function removeWidget(element) {
       	 var widget = $(element).up(".widget").widget;
       	 idWidget = widget._id;
       	 $('option_'+idWidget).hide();  
         //document.body.appendChild($('control_buttons').hide())
         portal.remove(widget);      
     }                                

     function paramWidget(idModule) {
 
       var vimg = $('param_button_'+idModule);
//,afterFinish: callBackEffetReduire(widget)

       if(Element.getStyle($('param_'+idModule), 'display') == "block")
       {    
       	
       	var effet = new Effect.BlindUp('param_'+idModule, {duration:0.15});    
       //	vimg.src = urlimages+'ico-fleche-droit.png';
       }
       else
       {
       	
       	var effet = new Effect.BlindDown('param_'+idModule, {duration:0.15});	
      // 	vimg.src = urlimages+'ico-fleche-bas.png';
       }
     } 
     
     
     function refreshWidget(element) {
     	
       var widget = $(element).up(".widget").widget;
       
       //alert(this.refreshCallBack);
       //idWidget = $(element).up(".widget").id;
			 widget.refreshContent(element);
     }


     function callBackEffetReduire(widget)
     {
     	portal._updateColumnsHeight();

     if(Element.getStyle($('content_'+widget._id), 'display') == "block")
       { //on rend le widget non redimentionnable
       	portal.stopRedimentionneWidget(widget);	
       }
       else
       { //on rend le widget redimentionnable
       	portal.redimentionneWidget(widget);
       }
      
     }

     function reduirehWidget(nomWidget) {
 
       var vimg = $('reduire_button_'+nomWidget);
//,afterFinish: callBackEffetReduire(widget)
       if(Element.getStyle($('content_'+nomWidget), 'display') == "block")
       {    
       	
       	var effet = new Effect.BlindUp('content_'+nomWidget, {duration:0.15});    
       	vimg.src = urlimages+'ico-fleche-droit.png';
       }
       else
       {
       	
       	var effet = new Effect.BlindDown('content_'+nomWidget, {duration:0.15});	
       	vimg.src = urlimages+'ico-fleche-bas.png';
       }
     } 
    

    function onChange() {
    
			//changement lors du deplacement
    }
    
    function widgetAlerte(element)
    {
    	
    	 var widget = $(element).up(".widget").widget;
       idWidget = $(element).up(".widget").id;
       //var effet = new Effect.Shake(idWidget, {duration:1});  
       var effet = new Effect.Pulsate(idWidget, {duration:1});  
    }
    

    
/*FIN ACTION SUR LES WIDGETS*/
       	var typeCss = '';
       	var isDrope = false;
       	var originalePosition = '';
       	
  function retourneIndex(style)
				{
						var urlcss = 'http://filerc2b/dev/Tests/V3-Interface/POC_ready/www/css/';
						var docStyleSheets = document.styleSheets;
						var arrayStyleSheets = Object.values(docStyleSheets);
						var href = '';
			
						//on retire les deux dernier elements du tableau
						arrayStyleSheets = arrayStyleSheets.slice(0,(arrayStyleSheets.length -2));	
			
						for(i=0; i<=arrayStyleSheets.length-1; i++)	
						{			
							element = arrayStyleSheets[i];
							if((typeof element == "object") && (typeof element != "number") && (typeof element != "function"))
							{
								
								href = element.href.toLowerCase();
								if((href.indexOf(style) != -1) && (typeof href == "string") )
								{
									return i;					
								}
							
							}				
						};
						
				}

	


				function reverseModule(typeAffichage)
				{

					if(typeAffichage == "")isDrope = true;
					var indexStyleDroitier = retourneIndex('page_droite');
					var indexStyleGauchier = retourneIndex('page_gauche');

					//document.styleSheets[indexStyleDroitier].disabled=true;					
					//document.styleSheets[indexStyleGauchier].disabled=true;	
		
					if(typeCss || typeAffichage=='droitier')
					{

						typeCss = false;
						if (navigator.appName=="Netscape")
						{
							document.styleSheets[indexStyleDroitier].disabled=false;
							document.styleSheets[indexStyleGauchier].disabled=true;							
						}
						else
						{
							document.styleSheets[indexStyleDroitier].disabled=true;
							document.styleSheets[indexStyleGauchier].disabled=false;							
						}
						alert('droitier indexStyleDroitier'+indexStyleDroitier+' indexStyleGauchier '+indexStyleGauchier+' typeCSS : '+typeCss);
					}
					else
					{

						typeCss = true;

						if (navigator.appName=="Netscape")
						{
							document.styleSheets[indexStyleDroitier].disabled=true;
							//document.styleSheets[indexStyleGauchier].disabled=false;							
						}
						else
						{
							document.styleSheets[indexStyleDroitier].disabled=false;
							document.styleSheets[indexStyleGauchier].disabled=true;							
						}		
						alert('gauchier indexStyleDroitier'+indexStyleDroitier+' indexStyleGauchier '+indexStyleGauchier+' typeCSS : '+typeCss);
					}

					return false;
				}
				
				
//fonction ambidextre
		       function starteffect(e){
	  
	       	  	originalePosition = e.positionedOffset();
		       	width = $('emplacement_module_gauche').getWidth();
		       	height = $('emplacement_module_gauche').getHeight();
		       	
						$('emplacement_module_gauche').setStyle({
						  width: width+'px',
						  height: height+'px'
						});
						
						$('module_selectionnes').hide();
			   		$('module_secondaire').hide();
	
	       }
	       
	       function revert(){
	       
	       	$('module_selectionnes').show();
					$('module_secondaire').show();

		
					return true;
					
	       }
	       
	       function reverteffect(e)
	       {
	       		$('module_selectionnes').show();
						$('module_secondaire').show();
					
	       }	

	         
//fonction ajout de module
	       
	function createDemos() {
		  //new Tip('module_dispo', '<ul><li><a class="module" href="#" onclick="portal.add(new Xilinus.Widget().setTitle(\'gainSite\').setContent(gainSite), \'module_selectionnes\',{estreduit:true});">gain site</a></li><li><a href="#" class="module" onclick="portal.add(new Xilinus.Widget().setTitle(\'kilukru\').setContent(kilukru), \'module_selectionnes\',{estreduit:true});">kilu kru</a></li></ul>', { title : 'Modules', hideOn: 'mouseover', hideAfter: 2, hook: { tip: 'topRight', target: 'topLeft'}, offset: { x: -5, y: 0 }});
	}/** 
 * Author and Version Information {{{
 * author: Antonio Ramirez http://webeaters.blogspot.com
 *
 * class: AutoComplete for Prototype 1.6.0
 *
 * version: 1.2.1 - 2007-11-11 
 * 		(based on AutoSuggest 2.1.3 - 2007-07-19)
 * version: 1.3.0 - 2008-01-03 by Andrew Nicols <andrew@nicols.co.uk>
 *  - Fixed incorrect title-casing - CSS is Case Sensitive!!!
 *  - Adjusted the way in which the Notifier images are loaded.
 *  - Changed json code to pass all json variables back instead of just id, value and name
 *  - Fixed 'GMAIL' code such that if valueSep is undefined, it is ignored
 *  - Changed the default for valueSep to null
 *  - Fixed the resetTimeout function
 *
 * REFERENCES AND THANKS 
 * this class is based on the work in AutoSuggest.js of
 * Timothy Groves - http://www.brandspankingnew.net
 * and adapted for use with prototype 1.6.0
 *
 * UPDATED by RŽéda HADJOUTI
 * GMAIL like AutoComplete (semicolon separator) Update
 *
 }}}*/

var AutoComplete = Class.create();

AutoComplete.prototype = { // {{{
  Version: '1.3.0',
  REQUIRED_PROTOTYPE: '1.6.0',

  initialize: function (id, param) { // {{{
  	// check whether we have the appropiate javascript libraries
  	this.PROTOTYPE_CHECK();
	
    // Get the field we're watching.
    // It needs to be a valid field so throw an error if it's not valid or can't be found.
    this.fld = $(id);
    if (!this.fld)
    {
      throw("AutoComplete requires a field id to initialize");
    }
	
    // Init variables
    this.sInp 	= ""; // input value 
    this.nInpC 	= 0;	// input value length
    this.aSug 	= []; // suggestions array 
    this.iHigh 	= 0;	// level of list selection 
	
  // Parameter Handling {{{
	// Set the use specified options
	this.options = param ? param : {};
	// These are the default settings {{{
  var k, def = {
    valueSep:null,
    minchars:1,
    meth:"get",
    varname:"input",
    className:"autocomplete",
    timeout:3000,
    delay:500,
    offsety:-5,
    shownoresults: true,
    noresults: "No results were found.",
    maxheight: 250,
    cache: true,
    maxentries: 25,
    onAjaxError:null,
    setWidth: false,
    minWidth: 100,
    maxWidth: 200,
    useNotifier: true
  };
  //}}}
  // Overlay any values which weren't user specified.
	for (k in def) 
	{
		if (typeof(this.options[k]) != typeof(def[k]))
			this.options[k] = def[k];
	}
  // End of Parameter Handling }}}

  // Not everyone wants to use the Notifier. Give them the option	
	if (this.options.useNotifier)
  {
    this.fld.addClassName('ac_field');
  }

	// set keyup handler for field
	// and prevent AutoComplete from client
	var p = this;
	
	// NOTE: not using addEventListener because UpArrow fired twice in Safari
	this.fld.onkeypress 	= function(ev){ return p.onKeyPress(ev); };
	this.fld.onkeyup      = function(ev){ return p.onKeyUp(ev); };
  // ARN-DEBUG Chances are we want to reset the timeout when they lose focus, at least that's what I prefer
	this.fld.onblur			  = function(ev){ p.resetTimeout(); return true; };	
  // ARN-DEBUG Not sure what this is about!
	this.fld.setAttribute("AutoComplete","off");

  }, //}}}

  convertVersionString: function (versionString){ // {{{
      var r = versionString.split('.');
      return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
  }, // }}}

  PROTOTYPE_CHECK: function() { // {{{
    if((typeof Prototype=='undefined') || 
       (typeof Element == 'undefined') || 
       (typeof Element.Methods=='undefined') ||
       (this.convertVersionString(Prototype.Version) < 
        this.convertVersionString(this.REQUIRED_PROTOTYPE)))
       throw("AutoComplete requires the Prototype JavaScript framework >= " +
        this.REQUIRED_PROTOTYPE);
  }, // }}}

  // set responses to keypress events in the field
  // this allows the user to use the arrow keys to scroll through the results
  // ESCAPE clears the list
  // RETURN sets the current highlighted value
  // UP/DOWN move around the list

  onKeyPress: function (e) { // {{{
  	if (!e) e = window.event;
  	var key	= e.keyCode || e.wich;
  	

    switch(key)
    {
      case Event.KEY_RETURN:
        this.setHighlightedValue();
        Event.stop(e);
        break;
      case Event.KEY_TAB:
        this.setHighlightedValue();
        //Event.stop(e);
        break;
      case Event.KEY_ESC:
        this.clearSuggestions();
        break;
    }
    return true;
  }, //}}}

  onKeyUp: function (e) { // {{{
  	if (!e) e = window.event;
  	
  	var key = e.keyCode || e.wich;
  	
  	if (key == Event.KEY_UP || key == Event.KEY_DOWN) 
  	{
  		this.changeHighlight(key);
  		Event.stop(e);
  	}
  	else this.getSuggestions(this.fld.value);
  	
	return true;
  }, //}}}

  getSuggestions: function(val) { // {{{
  	// input the same? do nothing
  	if(val==this.sInp) return false;
  	
  	// kill the old list
  	if($(this.acID)) $(this.acID).remove();
  	
  	this.sInp = val;
  	
  	// input length is less than the min required to trigger a request
  	// do nothing
  	if (val.length < this.options.minchars)
  	{
  		this.aSug 	= [];
  		this.nInpC	= val.length; 
  		return false;
  	}

  	// Here we will detect if there is a comma and the splitted value has a value to check
  	// comma stars a new search and val is converted to the new value after the comma
  	var ol	= this.nInpC; // old length
  	this.nInpC	= val.length ? val.length : 0;
  	
  	// if caching enabled, and we didn't receive the maxentries value
    // and user is typing (ie. length of input is increasing)
  	// filter results out of suggestions from last request
  	var l = this.aSug.length;
  	if( this.options.cache && ( this.nInpC > ol ) && l && ( l < this.options.maxentries ) )
  	{
  		var arr = new Array();
  		for (var i=0;i<l;i++) {
  			if (this.aSug[i].value.toLowerCase().indexOf(val.toLowerCase()) != -1)
        {
  				arr.push(this.aSug[i]);
        }
  		}
  		this.aSug = arr;
  		
  		// recreate the list
  		this.createList(this.aSug);
  	} else {
  		// do new request
  		var p = this;
  		//var input	= this.sInp; // send the converted new value (comma)
  		clearTimeout(this.ajID); // ajax id timer
  		this.ajID = setTimeout( function () {p.doAjaxRequest(p.sInp)}, this.options.delay);
  	}
    document.helper = this;	
  	return false;
  }, // }}}

  getLastInput : function(str) { // {{{
  	var ret = str;
  	if (undefined != this.options.valueSep) {
  		var idx = ret.lastIndexOf(this.options.valueSep);
      ret = idx == -1 ? ret : ret.substring(idx + 1, ret.length);
  	}
  	
  	return ret;
  }, // }}}

  doAjaxRequest: function (input) { // {{{
  	// we have to check here if there is a new splitted value (, or ;)
  	// always check against the last part of the comma and then check
  	// saved input is still the value of the field
  	if (input != this.fld.value) 
  		return false;
  	
  	// Gmail like : get only the last user's input
  	this.sInp = this.getLastInput(this.sInp);
 	
  	// create ajax request
  	// do we need to call a function to recreate the url?
  	if (typeof this.options.script == 'function')
  		var url = this.options.script(encodeURIComponent(this.sInp));
  	else
  		var url = this.options.script+this.options.varname+'='+encodeURIComponent(this.sInp);
  	
  	if(!url) return false;
  	
  	var p = this;
  	var m = this.options.meth;  // get or post?
    if( this.options.useNotifier )
    {
      this.fld.removeClassName('ac_field');
	    this.fld.addClassName('ac_field_busy');
    };
  	
  	var options = {
  		method: m,
  		onSuccess: function (req) { // {{{
        if( p.options.useNotifier )
        {
          p.fld.removeClassName('ac_field_busy');
          p.fld.addClassName('ac_field');
        };
        p.setSuggestions(req,input);
  		}, // }}}

  		onFailure: (typeof p.options.onAjaxError == 'function')? function (status) { // {{{
        if (p.options.useNotifier)
        {
          p.fld.removeClassName('ac_field_busy');
          p.fld.addClassName('ac_field');
        }
        p.options.onAjaxError(status)
      } : // }}}

      function (status) { // {{{
        if (p.options.useNotifier)
        {
          p.fld.removeClassName('ac_field_busy');
          p.fld.addClassName('ac_field');
        }
        alert("AJAX error: "+status); 
      } // }}}
    }
  	// make new ajax request
  	new Ajax.Request(url, options);
  }, // }}}

  setSuggestions: function (req, input) { // {{{
	  // if field input no longer matches what was passed to the request
	  // don't show the suggestions
	  // here we need to check against the splitted values if any (, or ;)
    if (input != this.fld.value)
      return false;
	
    this.aSug = [];
	
    if(this.options.json) 
    { // response in json format?
      var jsondata = eval('(' + req.responseText + ')');
      this.aSug = jsondata.results;
    } else {
      // response in xml format?
      var results = req.responseXML.getElementsByTagName('results')[0].childNodes;
    
      for(var i=0;i<results.length;i++)
      {
        if(results[i].hasChildNodes())
          this.aSug.push(  { 'id':results[i].getAttribute('id'), 'value':results[i].childNodes[0].nodeValue, 'info':results[i].getAttribute('info') }  );
      }
    }
    this.acID = 'ac_'+this.fld.id;
    this.createList(this.aSug);
  }, // }}}

  createDOMElement: function ( type, attr, cont, html ) { // {{{
    var ne = document.createElement( type );
	
    if (!ne)
      return 0;
      
    for (var a in attr)
      ne[a] = attr[a];
    
    var t = typeof(cont);
    
    if (t == "string" && !html)
      ne.appendChild( document.createTextNode(cont) );
    else if (t == "string" && html)
      ne.innerHTML = cont;
    else if (t == "object")
      ne.appendChild( cont );

    return ne;
  }, // }}}

  createList:	function(arr) { // {{{
    // get rid of the old list if any  
  	if($(this.acID)) $(this.acID).remove();
  	
  	// clear list removal timeout
  	this.killTimeout();
  	
  	// if no results, and showNoResults is false, do nothing
  	if (arr.length == 0 && !this.options.shownoresults) return false;
  	
  	// create holding div
  	var div	= this.createDOMElement('div', {id:this.acID, className:this.options.className});
  	
  	// create div header
  	var hcorner = this.createDOMElement('div', {className: 'ac_corner'});
  	var hbar	= this.createDOMElement('div', {className: 'ac_bar'});
  	var header	= this.createDOMElement('div', {className: 'ac_header'});
  	header.appendChild(hcorner);
  	header.appendChild(hbar);
  	div.appendChild(header);
  	
    // create and populate ul
    var ul	= this.createDOMElement('ul', {id:'ac_ul'});
    var p 	= this; // pointer that we will need later on
    // no results?
    if (arr.length == 0 && this.options.shownoresults)
    {
      var li = this.createDOMElement('li', {className: 'ac_warning'}, this.options.noresults );
      ul.appendChild(li);
    } else {
      // loop through arr of suggestions creating an LI element for each of them
      for (var i=0,l = arr.length; i<l; i++)
      {
        // format output with the input enclosed in a EM elementFromPoint
        // (as HTML not DOM)
        var val 	= arr[i].value;
        var st 		= val.toLowerCase().indexOf(this.sInp.toLowerCase()); // HERE WE CHECK AGAINST THE SPLITTED VALUE IF ANY***
        var output 	= val.substring(0,st) + '<em>' + val.substring(st,st+this.sInp.length) + '</em>' + val.substring(st+this.sInp.length);
			
        var span	= this.createDOMElement('span',{},output,true); // type of, properties, output, isHTML?
			
        if(arr[i].info != '') // do we need to add extra info?
        {
          var br	= this.createDOMElement('br',{});
          span.appendChild(br);
          
          var small = this.createDOMElement('small',{}, arr[i].info);
          span.appendChild(small);
        }
        var a 	= this.createDOMElement('a',{href:'#'});
        
        var tl	= this.createDOMElement('span',{className:'tl'},'&nbsp;',true);
        var tr	= this.createDOMElement('span',{className:'tr'},'&nbsp;',true);
        
        a.appendChild(tl);
        a.appendChild(tr);
        a.appendChild(span); // add the object span into the link
			
        a.name = i+1;
        
        a.onclick 		= function () { // {{{
          p.setHighlightedValue();
          return false; 
        }; // }}}
        a.onmouseover	= function () { // {{{
          p.setHighlight(this.name); 
        }; // }}} 
			
        var li = this.createDOMElement('li', {}, a); // add the link element to a li element
        
        // finally add the newly created li element to the ul element 
        ul.appendChild(li);
      }
    }
    
    div.appendChild(ul); // add the newly created list to the div element
    
    // create div footer
    var fcorner = this.createDOMElement('div', {className: 'ac_corner'});
  	var fbar	= this.createDOMElement('div', {className: 'ac_bar'});
  	var footer	= this.createDOMElement('div', {className: 'ac_footer'});
  	footer.appendChild(fcorner);
  	footer.appendChild(fbar);
  	div.appendChild(footer);
  	
  	// get position of target textfield
    // position holding div below it
    // set width of holding div to width of field 
    // if 
    
    var pos         = this.fld.cumulativeOffset();
    div.style.left 	= pos[0] + "px";
    div.style.top 	= pos[1] + this.fld.offsetHeight + "px";
    
    var w = 
    (
      this.options.setWidth && this.fld.offsetWidth < this.options.minWidth
    )
    ? this.options.minWidth : 
    (
      this.options.setWidth && this.fld.offsetWidth > this.options.maxWidth
    )
    ? this.options.maxWidth : 
    this.fld.offsetWidth;

    
    div.style.width 	= w + "px";
    
    // set mouseover functions for div
    // when mouse pointer leaves div, set a timeout to remove the list after an interval
    // when mouse enters div, kill the timeout so the list won't be removed
    //
    div.onmouseover 	= function(){ p.killTimeout() };
    div.onmouseout 		= function(){ p.resetTimeout() };
    
    // add DIV to document
    document.getElementsByTagName("body")[0].appendChild(div);
    
    // highlight first item
    this.iHigh = 1;
    this.setHighlight(1);
    
    // remove list after interval
    this.toID	= setTimeout(
      function () {
        p.clearSuggestions() 
      }, this.options.timeout
    );
	
  }, // }}}

  changeHighlight:	function(key) { // {{{
  	var list = $("ac_ul");
    if (!list)
      return false;
	
    var n;

    n = (key == Event.KEY_DOWN || key == Event.KEY_TAB)? this.iHigh + 1 : this.iHigh - 1; // false assumed to be Event.KEY_UP
    
    n = (n > list.childNodes.length)? list.childNodes.length : ((n < 1)? 1 : n);	
    
    this.setHighlight(n);
  }, // }}}

  setHighlight:		function(n) { // {{{
  	var list = $('ac_ul');
  	
  	if (!list) return false;
  	
  	if (this.iHigh > 0) this.clearHighlight();
  	
  	this.iHigh = Number(n);
  	
  	list.childNodes[this.iHigh-1].className = 'ac_highlight';
  	
  	this.killTimeout();
  }, // }}}

  clearHighlight:	function() { // {{{
  	var list = $('ac_ul');
  	
  	if(!list) return false;
  	
  	if(this.iHigh > 0)
  	{
  		list.childNodes[this.iHigh-1].className = '';
  		this.iHigh = 0;
  	}
  	
  }, // }}}

  setHighlightedValue:	function() { // {{{
  	if (this.iHigh)
  	{
  		// HERE WE NEED TO IMPLEMENT THE GMAIL LIKE SPLITTED VALUE
  		if (!this.aSug[this.iHigh - 1]) return;
  		
  		// Gmail like
      if (undefined != this.options.valueSep) {
        var str = this.getLastInput(this.fld.value);
        var idx = this.fld.value.lastIndexOf(str);
        str = this.aSug[ this.iHigh -1 ].value + this.options.valueSep;
        this.sInp = this.fld.value = idx == -1 ? str : this.fld.value.substring(0, idx) + str;
      } else {
        var str = this.getLastInput(this.fld.value);
        var idx = this.fld.value.lastIndexOf(str);
        str = this.aSug[ this.iHigh -1 ].value;
        this.sInp = this.fld.value = idx == -1 ? str : this.fld.value.substring(0, idx) + str;
      }
  		
  		// move cursor to end of input (safari)
  		this.fld.focus();
  		if(this.fld.selectionStart)
  			this.fld.setSelectionRange(this.sInp.length, this.sInp.length);
  			
  		this.clearSuggestions();
  		
  		// pass selected object to callback function, if exists
  		if (typeof this.options.callback == 'function')
  			this.options.callback(this.aSug[this.iHigh-1]); // the object has the properties we want, it will depend of
  	}
  }, // }}}

  killTimeout:	function() { // {{{
  	clearTimeout(this.toID);
  }, // }}}

  resetTimeout:	function() { // {{{
  	this.killTimeout();
  	var p = this;
  	this.toID = setTimeout(
      function () { 
        p.clearSuggestions();
      }, p.options.timeout
    );
    // ARN-DEBUG Added p.options.timeout back :|
  }, // }}}

  clearSuggestions:	function () { // {{{
	
    this.killTimeout();
    if ($(this.acID))
    {
      this.fadeOut(300,function () {
        $(this.acID).remove();
      } );
    }
  }, // }}}

  fadeOut:	function (milliseconds, callback) { // {{{
  	this._fadeFrom 	= 1;
  	this._fadeTo	= 0;
  	this._afterUpdateInternal = callback;
  	
  	this._fadeDuration	= milliseconds;
  	this._fadeInterval = 50;
  	this._fadeTime = 0;
  	var p = this;
  	this._fadeIntervalID = setInterval(
      function() {
        p._changeOpacity()
      }, this._fadeInterval
    );
  
  }, // }}}

  _changeOpacity: function() { // {{{
 
    if (!$(this.acID))
    {
  		this._fadeIntervalID=clearInterval(this._fadeIntervalID);
  		return;
  	} 
  	this._fadeTime += this._fadeInterval;
  	
  	var ieop = Math.round( (this._fadeFrom + ((this._fadeTo - this._fadeFrom) * (this._fadeTime/this._fadeDuration))) * 100)
  	var op = ieop / 100;
 
  	var el = $(this.acID);
  	if (el.filters) // internet explorer
  	{
      try {
        el.filters.item("DXImageTransform.Microsoft.Alpha").opacity = ieop;
      } catch (e) { 
        // If it is not set initially, the browser will throw an error.
        // This will set it if it is not set yet.
        el.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+ieop+')';
      }
    } else	{
      el.style.opacity = op;
    }
	
    if (this._fadeTime >= this._fadeDuration)
    {
      clearInterval( this._fadeIntervalID );
      if (typeof this._afterUpdateInternal == 'function')
        this._afterUpdateInternal();
    }

  } // }}}
 
} // }}}

// vim: set filetype=javascript foldmethod=marker foldlevel=5:
/**
 * DatePicker widget using Prototype and Scriptaculous.
 * (c) 2007 Mathieu Jondet <mathieu@eulerian.com>
 * Eulerian Technologies
 *
 * DatePicker is freely distributable under the same terms as Prototype.
 *
 */

/**
 * DatePickerFormatter class for matching and stringifying dates.
 *
 * By Arturas Slajus <x11@arturaz.net>.
 */
var DatePickerFormatter = Class.create();
DatePickerFormatter.prototype = {
    /**
     * Create a DatePickerFormatter.
     *
     * format: specify a format by passing 3 value array consisting of
     *   "yyyy", "mm", "dd". Default: ["yyyy", "mm", "dd"].
     *
     * separator: string for splitting the values. Default: "-".
     *
     * Use it like this:
     *   var df = new DatePickerFormatter(["dd", "mm", "yyyy"], "/");
     *   df.current_date();
     *   df.match("7/7/2007");
     */
    initialize: function(format, separator) {
        if (Object.isUndefined(format))
	 format = ["yyyy", "mm", "dd"];
        if (Object.isUndefined(separator))
	 separator = "-";

        this._format 	= format;
        this.separator	= separator;
                
        this._format_year_index	= format.indexOf("yyyy");
        this._format_month_index= format.indexOf("mm");
        this._format_day_index	= format.indexOf("dd");
                
        this._year_regexp	= /^\d{4}$/;
        this._month_regexp 	= /^0\d|1[012]|\d$/;
        this._day_regexp 	= /^0\d|[12]\d|3[01]|\d$/;
    },
    
    /**
     * Match a string against date format.
     * Returns: [year, month, day]
     */
    match: function(str) {
        var d = str.split(this.separator);
        
        if (d.length < 3)
	 return false;
        
        var year = d[this._format_year_index].match(this._year_regexp);
        if (year) { year = year[0] } else { return false }
        var month = d[this._format_month_index].match(this._month_regexp);
        if (month) { month = month[0] } else { return false }
        var day = d[this._format_day_index].match(this._day_regexp);
        if (day) { day = day[0] } else { return false }
        
        return [year, month, day];
    },
    
    /**
     * Return current date according to format.
     */
    current_date: function() {
        var d = new Date;
        return this.date_to_string(
            d.getFullYear(),
            d.getMonth() + 1,
            d.getDate()
       );
    },
    
    /**
     * Return a stringified date accordint to format.
     */
    date_to_string: function(year, month, day, separator) {
        if (Object.isUndefined(separator))
	 separator = this.separator;

        var a = [0, 0, 0];
        a[this._format_year_index]	= year;
        a[this._format_month_index] 	= month.toPaddedString(2);
        a[this._format_day_index] 	= day.toPaddedString(2);
        
        return a.join(separator);
    }
}; 


/**
 * DatePicker
 */

var DatePicker	= Class.create();

DatePicker.prototype	= {
 Version	: '0.9.4',
 _relative	: null,
 _div		: null,
 _zindex	: 1,
 _keepFieldEmpty: false,
 _daysInMonth	: [31,28,31,30,31,30,31,31,30,31,30,31],
 _dateFormat	: [ ["dd", "mm", "yyyy"], "/" ],
 /* language */
 _language	: 'fr',
 _language_month	: $H({
  'fr'	: [ 'Janvier', 'F&#233;vrier', 'Mars', 'Avril', 'Mai', 'Juin', 
   'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'D&#233;cembre' ],
  'en'	: [ 'January', 'February', 'March', 'April', 'May',
   'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
  'sp'	: [ 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 
   'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre' ],
  'it'	: [ 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno',
   'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre' ],
  'de'	: [ 'Januar', 'Februar', 'M&#228;rz', 'April', 'Mai', 'Juni',
   'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ],
  'pt'	: [ 'Janeiro', 'Fevereiro', 'Mar&#231;o', 'Abril', 'Maio', 'Junho',
   'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro' ],
  'hu'	: [ 'Janu&#225;r', 'Febru&#225;r', 'M&#225;rcius', '&#193;prilis', 
   'M&#225;jus', 'J&#250;nius', 'J&#250;lius', 'Augusztus', 'Szeptember', 
   'Okt&#243;ber', 'November', 'December' ],
  'lt'  : [ 'Sausis', 'Vasaris', 'Kovas', 'Balandis', 'Gegu&#382;&#279;',
   'Bir&#382;elis', 'Liepa', 'Rugj&#363;tis', 'Rus&#279;jis', 'Spalis', 
   'Lapkritis', 'Gruodis' ],
  'nl'	: [ 'januari', 'februari', 'maart', 'april', 'mei', 'juni',
   'juli', 'augustus', 'september', 'oktober', 'november', 'december' ],
  'dk'	: [ 'Januar', 'Februar', 'Marts', 'April', 'Maj',
   'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December' ],
  'no'	: [ 'Januar', 'Februar', 'Mars', 'April', 'Mai', 'Juni',
   'Juli', 'August', 'September', 'Oktober', 'November', 'Desember' ],
  'lv'	: [ 'Janv&#257;ris', 'Febru&#257;ris', 'Marts', 'Apr&#299;lis', 'Maijs',
   'J&#363;nijs', 'J&#363;lijs', 'Augusts', 'Septembris', 'Oktobris', 
   'Novembris', 'Decemberis' ],
  'ja'	: [ '1&#26376;', '2&#26376;', '3&#26376;', '4&#26376;', '5&#26376;',
   '6&#26376;', '7&#26376;', '8&#26376;', '9&#26376;', '10&#26376;', 
   '11&#26376;', '12&#26376;' ],
  'fi'	: [ 'Tammikuu', 'Helmikuu', 'Maaliskuu', 'Huhtikuu', 'Toukokuu',
   'Kes&#228;kuu', 'Hein&#228;kuu', 'Elokuu', 'Syyskuu', 'Lokakuu', 
   'Marraskuu', 'Joulukuu' ],
  'ro'	: [ 'Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Junie',
   'Julie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie' ],
  'zh'	: [ '1&#32;&#26376;', '2&#32;&#26376;', '3&#32;&#26376;', 
   '4&#32;&#26376;', '5&#32;&#26376;', '6&#32;&#26376;', '7&#32;&#26376;', 
   '8&#32;&#26376;', '9&#32;&#26376;', '10&#26376;', '11&#26376;', '12&#26376;'],
  'sv'	: [ 'Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni',
   'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December' ]
 }),
 _language_day	: $H({
  'fr'	: [ 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim' ],
  'en'	: [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ],
  'sp'	: [ 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'S&#224;b', 'Dom' ],
  'it'	: [ 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab', 'Dom' ],
  'de'	: [ 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam', 'Son' ],
  'pt'	: [ 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'S&#225;', 'Dom' ],
  'hu'	: [ 'H&#233;', 'Ke', 'Sze', 'Cs&#252;', 'P&#233;', 'Szo', 'Vas' ],
  'lt'  : [ 'Pir', 'Ant', 'Tre', 'Ket', 'Pen', '&Scaron;e&scaron;', 'Sek' ],
  'nl'	: [ 'ma', 'di', 'wo', 'do', 'vr', 'za', 'zo' ],
  'dk'	: [ 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'L&#248;r', 'S&#248;n' ],
  'no'	: [ 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'L&#248;r', 'Sun' ],
  'lv'	: [ 'P', 'O', 'T', 'C', 'Pk', 'S', 'Sv' ],
  'ja'	: [ '&#26376;', '&#28779;', '&#27700;', '&#26408;', '&#37329;', 
   '&#22303;', '&#26085;' ],
  'fi'	: [ 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La', 'Su' ],
  'ro'	: [ 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sam', 'Dum' ],
  'zh'	: [ '&#21608;&#19968;', '&#21608;&#20108;', '&#21608;&#19977;', 
   '&#21608;&#22235;', '&#21608;&#20116;', '&#21608;&#20845;', 
   '&#21608;&#26085;' ],
  'sv'	: [ 'M&#229;n', 'Tis', 'Ons', 'Tor', 'Fre', 'L&#246;r', 
   'S&#246;n' ]
 }),
 _language_close	: $H({
  'fr'	: 'fermer',
  'en'	: 'close',
  'sp'	: 'cierre',
  'it'	: 'fine',
  'de'	: 'schliessen',
  'pt'	: 'fim',
  'hu'	: 'bez&#225;r',
  'lt'  : 'udaryti',
  'nl'	: 'sluiten',
  'dk'	: 'luk',
  'no'	: 'lukk',
  'lv'	: 'aizv&#275;rt',
  'ja'	: '&#38281;&#12376;&#12427;',
  'fi'	: 'sulje',
  'ro'	: 'inchide',
  'zh'	: '&#20851;&#32;&#38381',
  'sv'	: 'st&#228;ng'
 }),
 /* date manipulation */
 _todayDate		: new Date(),
 _current_date		: null,
 _clickCallback		: Prototype.emptyFunction,
 _cellCallback		: Prototype.emptyFunction,
 _id_datepicker		: null,
 _disablePastDate	: false,
 _disableFutureDate	: true,
 _oneDayInMs		: 24 * 3600 * 1000,
 /* positionning */
 _topOffset		: 30,
 _leftOffset		: 0,
 _isPositionned		: false,
 _relativePosition 	: true,
 _setPositionTop 	: 0,
 _setPositionLeft	: 0,
 _bodyAppend		: false,
 /* Effects Adjustment */
 _showEffect		: "appear", 
 _showDuration		: 1,
 _enableShowEffect 	: true,
 _closeEffect		: "fade", 
 _closeEffectDuration	: 0.3,
 _enableCloseEffect 	: true,
 _closeTimer		: null,
 _enableCloseOnBlur	: false,
 /* afterClose : called when the close function is executed */
 _afterClose	: Prototype.emptyFunction,
 /* return the name of current month in appropriate language */
 getMonthLocale	: function ( month ) {
  return	this._language_month.get(this._language)[month];
 },
 getLocaleClose	: function () {
  return	this._language_close.get(this._language);
 },
 _initCurrentDate : function () {
  /* Create the DateFormatter */
  this._df = new DatePickerFormatter(this._dateFormat[0], this._dateFormat[1]);
  /* check if value in field is proper, if not set to today */
  this._current_date = $F(this._relative);
  if (! this._df.match(this._current_date)) {
    this._current_date = this._df.current_date();
   /* set the field value ? */
   if (!this._keepFieldEmpty)
    $(this._relative).value = this._current_date;
  }
  var a_date = this._df.match(this._current_date);
  this._current_year 	= Number(a_date[0]);
  this._current_mon	= Number(a_date[1]) - 1;
  this._current_day	= Number(a_date[2]);
 },
 /* init */
 initialize	: function ( h_p ) {
  /* arguments */
  this._relative= h_p["relative"];
  if (h_p["language"])
   this._language = h_p["language"];
  this._zindex	= ( h_p["zindex"] ) ? parseInt(Number(h_p["zindex"])) : 1;
  if (!Object.isUndefined(h_p["keepFieldEmpty"]))
   this._keepFieldEmpty	= h_p["keepFieldEmpty"];
  if (Object.isFunction(h_p["clickCallback"])) 
   this._clickCallback	= h_p["clickCallback"];
  if (!Object.isUndefined(h_p["leftOffset"]))
   this._leftOffset	= parseInt(h_p["leftOffset"]);
  if (!Object.isUndefined(h_p["topOffset"]))
   this._topOffset	= parseInt(h_p["topOffset"]);
  if (!Object.isUndefined(h_p["relativePosition"]))
   this._relativePosition = h_p["relativePosition"];
  if (!Object.isUndefined(h_p["showEffect"]))
   this._showEffect 	= h_p["showEffect"];
  if (!Object.isUndefined(h_p["enableShowEffect"]))
   this._enableShowEffect	= h_p["enableShowEffect"];
  if (!Object.isUndefined(h_p["showDuration"]))
   this._showDuration 	= h_p["showDuration"];
  if (!Object.isUndefined(h_p["closeEffect"]))
   this._closeEffect 	= h_p["closeEffect"];
  if (!Object.isUndefined(h_p["enableCloseEffect"]))
   this._enableCloseEffect	= h_p["enableCloseEffect"];
  if (!Object.isUndefined(h_p["closeEffectDuration"]))
   this._closeEffectDuration = h_p["closeEffectDuration"];
  if (Object.isFunction(h_p["afterClose"]))
   this._afterClose	= h_p["afterClose"];
  if (!Object.isUndefined(h_p["externalControl"]))
   this._externalControl= h_p["externalControl"];
  if (!Object.isUndefined(h_p["dateFormat"])) 
   this._dateFormat	= h_p["dateFormat"];
  if (Object.isFunction(h_p["cellCallback"]))
   this._cellCallback	= h_p["cellCallback"];
  this._setPositionTop	= ( h_p["setPositionTop"] ) ? 
   parseInt(Number(h_p["setPositionTop"])) : 0;
  this._setPositionLeft	= ( h_p["setPositionLeft"] ) ? 
   parseInt(Number(h_p["setPositionLeft"])) : 0;
  if (!Object.isUndefined(h_p["enableCloseOnBlur"]) && h_p["enableCloseOnBlur"])
   this._enableCloseOnBlur	= true;
  if (!Object.isUndefined(h_p["disablePastDate"]) && h_p["disablePastDate"])
   this._disablePastDate	= true;
  if (!Object.isUndefined(h_p["disableFutureDate"]) && 
   !h_p["disableFutureDate"])
   this._disableFutureDate	= false;
  this._id_datepicker		= 'datepicker-'+this._relative;
  this._id_datepicker_prev	= this._id_datepicker+'-prev';
  this._id_datepicker_next	= this._id_datepicker+'-next';
  this._id_datepicker_hdr	= this._id_datepicker+'-header';
  this._id_datepicker_ftr	= this._id_datepicker+'-footer';

  /* build up calendar skel */
  this._div = new Element('div', { 
   id : this._id_datepicker,
   className : 'datepicker',
   style : 'display: none; z-index:'+this._zindex });
  this._div.innerHTML = '<table><thead><tr><th width="10px" id="'+this._id_datepicker_prev+'" style="cursor: pointer;">&nbsp;&lt;&lt;&nbsp;</th><th id="'+this._id_datepicker_hdr+'" colspan="5"></th><th width="10px" id="'+this._id_datepicker_next+'" style="cursor: pointer;">&nbsp;&gt;&gt;&nbsp;</th></tr></thead><tbody id="'+this._id_datepicker+'-tbody"></tbody><tfoot><td colspan="7" id="'+this._id_datepicker_ftr+'"></td></tfoot></table>';
  /* finally declare the event listener on input field */
  Event.observe(this._relative, 
    'click', this.click.bindAsEventListener(this), false);
  /* need to append on body when doc is loaded for IE */
  document.observe('dom:loaded', this.load.bindAsEventListener(this), false);
  /* automatically close when blur event is triggered */
  if ( this._enableCloseOnBlur ) {
   Event.observe(this._relative, 'blur', function (e) { 
    this._closeTimer = this.close.bind(this).delay(1); 
   }.bindAsEventListener(this));
   Event.observe(this._div, 'click', function (e) { 
    if (this._closeTimer) { 
     window.clearTimeout(this._closeTimer); 
     this._closeTimer = null; 
    } 
   });
  }
 },
 /**
  * load	: called when document is fully-loaded to append datepicker
  *		  to main object.
  */
 load		: function () {
  /* if externalControl defined set the observer on it */
  if (this._externalControl) 
   Event.observe(this._externalControl, 'click',
    this.click.bindAsEventListener(this), false);
  /* append to page */
  if (this._relativeAppend) {
   /* append to parent node */
   if ($(this._relative).parentNode) {
    this._div.innerHTML = this._wrap_in_iframe(this._div.innerHTML);
    $(this._relative).parentNode.appendChild( this._div );
   }
  } else {
   /* append to body */
   var body	= document.getElementsByTagName("body").item(0);
   if (body) {
    this._div.innerHTML = this._wrap_in_iframe(this._div.innerHTML);
    body.appendChild(this._div);
   }
   if ( this._relativePosition ) {
     var a_pos = Element.cumulativeOffset($(this._relative));
     this.setPosition(a_pos[1], a_pos[0]);
   } else {
    if (this._setPositionTop || this._setPositionLeft)
     this.setPosition(this._setPositionTop, this._setPositionLeft);
   }
  }
  /* init the date in field if needed */
  this._initCurrentDate();
  /* set the close locale content */
  $(this._id_datepicker_ftr).innerHTML = this.getLocaleClose();
  /* declare the observers for UI control */
  Event.observe($(this._id_datepicker_prev), 
    'click', this.prevMonth.bindAsEventListener(this), false);
  Event.observe($(this._id_datepicker_next), 
    'click', this.nextMonth.bindAsEventListener(this), false);
  Event.observe($(this._id_datepicker_ftr), 
    'click', this.close.bindAsEventListener(this), false);
 },
 /* hack for buggy form elements layering in IE */
 _wrap_in_iframe	: function ( content ) {
  return	( Prototype.Browser.IE ) ?
   "<div style='height:167px;width:185px;background-color:white;align:left'><iframe width='100%' height='100%' marginwidth='0' marginheight='0' frameborder='0' src='about:blank' style='filter:alpha(Opacity=50);'></iframe><div style='position:absolute;background-color:white;top:2px;left:2px;width:180px'>" + content + "</div></div>" : content;
 },
 /**
  * visible	: return the visibility status of the datepicker.
  */
 visible	: function () {
  return	$(this._id_datepicker).visible();
 },
 /**
  * click	: called when input element is clicked
  */
 click		: function () {
  /* init the datepicker if it doesn't exists */
  if ( $(this._id_datepicker) == null ) this.load();
  if (!this._isPositionned && this._relativePosition) {
   /* position the datepicker relatively to element */
   var a_lt = Element.positionedOffset($(this._relative));
   $(this._id_datepicker).setStyle({
    'left'	: Number(a_lt[0]+this._leftOffset)+'px',
    'top'	: Number(a_lt[1]+this._topOffset)+'px'
   });
   this._isPositionned	= true;
  }
  if (!this.visible()) {
   this._initCurrentDate();
   this._redrawCalendar();
  }
  /* eval the clickCallback function */
  eval(this._clickCallback());
  /* Effect toggle to fade-in / fade-out the datepicker */
  if ( this._enableShowEffect ) {
   new Effect.toggle(this._id_datepicker, 
     this._showEffect, { duration: this._showDuration });
  } else {
   $(this._id_datepicker).show();
  }
 },
 /**
  * close	: called when the datepicker is closed
  */
 close		: function () {
  if ( this._enableCloseEffect ) {
   switch(this._closeEffect) {
    case 'puff': 
     new Effect.Puff(this._id_datepicker, { 
      duration : this._closeEffectDuration });
     break;
    case 'blindUp': 
     new Effect.BlindUp(this._id_datepicker, { 
      duration : this._closeEffectDuration });
     break;
    case 'dropOut': 
     new Effect.DropOut(this._id_datepicker, { 
      duration : this._closeEffectDuration }); 
     break;
    case 'switchOff': 
     new Effect.SwitchOff(this._id_datepicker, { 
      duration : this._closeEffectDuration }); 
     break;
    case 'squish': 
     new Effect.Squish(this._id_datepicker, { 
      duration : this._closeEffectDuration });
     break;
    case 'fold': 
     new Effect.Fold(this._id_datepicker, { 
      duration : this._closeEffectDuration });
     break;
    case 'shrink': 
     new Effect.Shrink(this._id_datepicker, { 
      duration : this._closeEffectDuration });
     break;
    default: 
     new Effect.Fade(this._id_datepicker, { 
      duration : this._closeEffectDuration });
     break;
   };
  } else {
   $(this._id_datepicker).hide();
  }
  eval(this._afterClose());
 },
 /**
  * setDateFormat
  */
 setDateFormat	: function ( format, separator ) {
  if (Object.isUndefined(format))
   format	= this._dateFormat[0];
  if (Object.isUndefined(separator))
   separator	= this._dateFormat[1];
  this._dateFormat	= [ format, separator ];
 },
 /**
  * setPosition	: set the position of the datepicker.
  *  param : t=top | l=left
  */
 setPosition	: function ( t, l ) {
  var h_pos	= { 'top' : '0px', 'left' : '0px' };
  if (!Object.isUndefined(t))
   h_pos['top']	= Number(t)+this._topOffset+'px';
  if (!Object.isUndefined(l))
   h_pos['left']= Number(l)+this._leftOffset+'px';
  $(this._id_datepicker).setStyle(h_pos);
  this._isPositionned	= true;
 },
 /**
  * _getMonthDays : given the year and month find the number of days.
  */
 _getMonthDays	: function ( year, month ) {
  if (((0 == (year%4)) && 
   ( (0 != (year%100)) || (0 == (year%400)))) && (month == 1))
   return 29;
  return this._daysInMonth[month];
 },
 /**
  * _buildCalendar	: draw the days array for current date
  */
 _buildCalendar		: function () {
  var _self	= this;
  var tbody	= $(this._id_datepicker+'-tbody');
  try {
   while ( tbody.hasChildNodes() )
    tbody.removeChild(tbody.childNodes[0]);
  } catch ( e ) {};
  /* generate day headers */
  var trDay	= new Element('tr');
  this._language_day.get(this._language).each( function ( item ) {
   var td	= new Element('td');
   td.innerHTML	= item;
   td.className	= 'wday';
   trDay.appendChild( td );
  });
  tbody.appendChild( trDay );
  /* generate the content of days */
  
  /* build-up days matrix */
  var a_d	= [ [ 0, 0, 0, 0, 0, 0, 0 ] ,[ 0, 0, 0, 0, 0, 0, 0 ]
   ,[ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ]
   ,[ 0, 0, 0, 0, 0, 0, 0 ]
  ];
  /* set date at beginning of month to display */
  var d		= new Date(this._current_year, this._current_mon, 1, 12);
  /* start the day list on monday */
  var startIndex	= ( !d.getDay() ) ? 6 : d.getDay() - 1;
  var nbDaysInMonth	= this._getMonthDays(
    this._current_year, this._current_mon);
  var daysIndex		= 1;
  for ( var j = startIndex; j < 7; j++ ) {
   a_d[0][j]	= { 
     d : daysIndex
    ,m : this._current_mon
    ,y : this._current_year 
   };
   daysIndex++;
  }
  var a_prevMY	= this._prevMonthYear();
  var nbDaysInMonthPrev	= this._getMonthDays(a_prevMY[1], a_prevMY[0]);
  for ( var j = 0; j < startIndex; j++ ) {
   a_d[0][j]	= { 
     d : Number(nbDaysInMonthPrev - startIndex + j + 1) 
    ,m : Number(a_prevMY[0])
    ,y : a_prevMY[1]
    ,c : 'outbound'
   };
  }
  var switchNextMonth	= false;
  var currentMonth	= this._current_mon;
  var currentYear	= this._current_year;
  for ( var i = 1; i < 6; i++ ) {
   for ( var j = 0; j < 7; j++ ) {
    a_d[i][j]	= { 
      d : daysIndex
     ,m : currentMonth
     ,y : currentYear
     ,c : ( switchNextMonth ) ? 'outbound' : ( 
      ((daysIndex == this._todayDate.getDate()) &&
        (this._current_mon  == this._todayDate.getMonth()) &&
        (this._current_year == this._todayDate.getFullYear())) ? 'today' : null)
    };
    daysIndex++;
    /* if at the end of the month : reset counter */
    if (daysIndex > nbDaysInMonth ) {
     daysIndex	= 1;
     switchNextMonth = true;
     if (this._current_mon + 1 > 11 ) {
      currentMonth = 0;
      currentYear += 1;
     } else {
      currentMonth += 1;
     }
    }
   }
  }
  /* generate days for current date */
  for ( var i = 0; i < 6; i++ ) {
   var tr	= new Element('tr');
   for ( var j = 0; j < 7; j++ ) {
    var h_ij	= a_d[i][j];
    var td	= new Element('td');
    /* id is : datepicker-day-mon-year or depending on language other way */
    /* don't forget to add 1 on month for proper formmatting */
    var id	= $A([
     this._relative,
     this._df.date_to_string(h_ij["y"], h_ij["m"]+1, h_ij["d"], '-')
    ]).join('-');
    /* set id and classname for cell if exists */
    td.setAttribute('id', id);
    if (h_ij["c"])
     td.className	= h_ij["c"];
    /* on onclick : rebuild date value from id of current cell */
    var _curDate	= new Date();
    _curDate.setFullYear(h_ij["y"], h_ij["m"], h_ij["d"]);
    if ( this._disablePastDate || this._disableFutureDate ) {
     if ( this._disablePastDate ) {
      var _res	= ( _curDate >= this._todayDate ) ? true : false;
      this._bindCellOnClick( td, true, _res, h_ij["c"] );
     }
     if ( this._disableFutureDate ) {
      var _res	= ( this._todayDate.getTime() + this._oneDayInMs > _curDate.getTime() ) ? true : false;
      this._bindCellOnClick( td, true, _res,  h_ij["c"] );
     }
    } else {
     this._bindCellOnClick( td, false );
    }
    td.innerHTML= h_ij["d"];
    tr.appendChild( td );
   }
   tbody.appendChild( tr );
  }
  return	tbody;
 },
 /**
  * _bindCellOnClick	: bind the cell onclick depending on status.
  */
 _bindCellOnClick	: function ( td, wcompare, compareresult, h_ij_c ) {
  var doBind	= false;
  if ( wcompare ) {
   if ( compareresult ) {
    doBind	= true;
   } else {
    td.className= ( h_ij_c ) ? 'nclick_outbound' : 'nclick';
   }
  } else {
   doBind	= true;
  }
  if ( doBind ) {
   var _self	= this;
   td.onclick	= function () { 
    $(_self._relative).value = String($(this).readAttribute('id')
      ).replace(_self._relative+'-','').replace(/-/g, _self._df.separator);
    /* if we have a cellCallback defined call it and pass it the cell */
    if (_self._cellCallback)
     _self._cellCallback(this);
    _self.close(); 
   };
  }
 },
 /**
  * nextMonth	: redraw the calendar content for next month.
  */
 _nextMonthYear	: function () {
  var c_mon	= this._current_mon;
  var c_year	= this._current_year;
  if (c_mon + 1 > 11) {
   c_mon	= 0;
   c_year	+= 1;
  } else {
   c_mon	+= 1;
  }
  return	[ c_mon, c_year ];
 },
 nextMonth	: function () {
  var a_next	= this._nextMonthYear();
  var _nextMon	= a_next[0];
  var _nextYear	= a_next[1];
  var _curDate	= new Date(); _curDate.setFullYear(_nextYear, _nextMon, 1);
  var _res	= ( this._todayDate.getTime() + this._oneDayInMs > _curDate.getTime() ) ? true : false;
  if ( this._disableFutureDate && !_res )
   return;
  this._current_mon	= _nextMon;
  this._current_year 	= _nextYear;
  this._redrawCalendar();
 },
 /**
  * prevMonth	: redraw the calendar content for previous month.
  */
 _prevMonthYear	: function () {
  var c_mon	= this._current_mon;
  var c_year	= this._current_year;
  if (c_mon - 1 < 0) {
   c_mon	= 11;
   c_year	-= 1;
  } else {
   c_mon	-= 1;
  }
  return	[ c_mon, c_year ];
 },
 prevMonth	: function () {
  var a_prev	= this._prevMonthYear();
  var _prevMon	= a_prev[0];
  var _prevYear	= a_prev[1];
  var _curDate	= new Date(); _curDate.setFullYear(_prevYear, _prevMon, 1);
  var _res	= ( _curDate >= this._todayDate ) ? true : false;
  if ( this._disablePastDate && !_res )
   return;
  this._current_mon	= _prevMon;
  this._current_year	= _prevYear;
  this._redrawCalendar();
 },
 _redrawCalendar	: function () {
  this._setLocaleHdr(); this._buildCalendar();
 },
 _setLocaleHdr	: function () {
  /* next link */
  var a_next	= this._nextMonthYear();
  $(this._id_datepicker_next).setAttribute('title',
   this.getMonthLocale(a_next[0])+' '+a_next[1]);
  /* prev link */
  var a_prev	= this._prevMonthYear();
  $(this._id_datepicker_prev).setAttribute('title',
   this.getMonthLocale(a_prev[0])+' '+a_prev[1]);
  /* header */
  $(this._id_datepicker_hdr).update('&nbsp;&nbsp;&nbsp;'+this.getMonthLocale(this._current_mon)+'&nbsp;'+this._current_year+'&nbsp;&nbsp;&nbsp;');
 }
};
/*
ModalBox - The pop-up window thingie with AJAX, based on prototype and script.aculo.us.

Copyright Andrey Okonetchnikov (andrej.okonetschnikow@gmail.com), 2006-2007
All rights reserved.
 
VERSION 1.6.0
Last Modified: 12/13/2007
*/

if (!window.Modalbox)
	var Modalbox = new Object();

Modalbox.Methods = {
	overrideAlert: false, // Override standard browser alert message with ModalBox
	focusableElements: new Array,
	currFocused: 0,
	initialized: false,
	active: true,
	options: {
		title: "ModalBox Window", // Title of the ModalBox window
		overlayClose: true, // Close modal box by clicking on overlay
		width: 500, // Default width in px
		height: 90, // Default height in px
		overlayOpacity: .65, // Default overlay opacity
		overlayDuration: .25, // Default overlay fade in/out duration in seconds
		slideDownDuration: .5, // Default Modalbox appear slide down effect in seconds
		slideUpDuration: .5, // Default Modalbox hiding slide up effect in seconds
		resizeDuration: .25, // Default resize duration seconds
		inactiveFade: true, // Fades MB window on inactive state
		transitions: true, // Toggles transition effects. Transitions are enabled by default
		loadingString: "Please wait. Loading...", // Default loading string message
		closeString: "Close window", // Default title attribute for close window link
		closeValue: "&times;", // Default string for close link in the header
		params: {},
		method: 'get', // Default Ajax request method
		autoFocusing: true, // Toggles auto-focusing for form elements. Disable for long text pages.
		aspnet: false // Should be use then using with ASP.NET costrols. Then true Modalbox window will be injected into the first form element.
	},
	_options: new Object,
	
	setOptions: function(options) {
		Object.extend(this.options, options || {});
	},
	
	_init: function(options) {
		// Setting up original options with default options
		Object.extend(this._options, this.options);
		this.setOptions(options);
		
		//Create the overlay
		this.MBoverlay = new Element("div", { id: "MB_overlay", opacity: "0" });
		
		//Create DOm for the window
		this.MBwindow = new Element("div", {id: "MB_window", style: "display: none"}).update(
			this.MBframe = new Element("div", {id: "MB_frame"}).update(
				this.MBheader = new Element("div", {id: "MB_header"}).update(
					this.MBcaption = new Element("div", {id: "MB_caption"})
				)
			)
		);
		this.MBclose = new Element("a", {id: "MB_close", title: this.options.closeString, href: "#"}).update("<span>" + this.options.closeValue + "</span>");
		this.MBheader.insert({'bottom':this.MBclose});
		
		this.MBcontent = new Element("div", {id: "MB_content"}).update(
			this.MBloading = new Element("div", {id: "MB_loading"}).update(this.options.loadingString)
		);
		this.MBframe.insert({'bottom':this.MBcontent});
		
		// Inserting into DOM. If parameter set and form element have been found will inject into it. Otherwise will inject into body as topmost element.
		// Be sure to set padding and marging to null via CSS for both body and (in case of asp.net) form elements. 
		var injectToEl = this.options.aspnet ? $(document.body).down('form') : $(document.body);
		injectToEl.insert({'top':this.MBwindow});
		injectToEl.insert({'top':this.MBoverlay});
		
		// Initial scrolling position of the window. To be used for remove scrolling effect during ModalBox appearing
		this.initScrollX = window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft;
		this.initScrollY = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
		
		//Adding event observers
		this.hideObserver = this._hide.bindAsEventListener(this);
		this.kbdObserver = this._kbdHandler.bindAsEventListener(this);
		this._initObservers();

		this.initialized = true; // Mark as initialized
	},
	
	show: function(content, options) {

		if(!this.initialized) this._init(options); // Check for is already initialized
		this.content = content;
		this.setOptions(options);
		
		if(this.options.title) // Updating title of the MB
			$(this.MBcaption).update(this.options.title);
		else { // If title isn't given, the header will not displayed
			$(this.MBheader).hide();
			$(this.MBcaption).hide();
		}
		
		if(this.MBwindow.style.display == "none") { // First modal box appearing
			this._appear();
			this.event("onShow"); // Passing onShow callback
		}
		else { // If MB already on the screen, update it
			this._update();
			this.event("onUpdate"); // Passing onUpdate callback
		} 
	},
	
	hide: function(options) { // External hide method to use from external HTML and JS
		if(this.initialized) {
			// Reading for options/callbacks except if event given as a pararmeter
			if(options && typeof options.element != 'function') Object.extend(this.options, options); 
			// Passing beforeHide callback
			this.event("beforeHide");
			if(this.options.transitions)
				Effect.SlideUp(this.MBwindow, { duration: this.options.slideUpDuration, transition: Effect.Transitions.sinoidal, afterFinish: this._deinit.bind(this) } );
			else {
				$(this.MBwindow).hide();
				this._deinit();
			}
		} else throw("Modalbox is not initialized.");
	},
	
	_hide: function(event) { // Internal hide method to use with overlay and close link
		event.stop(); // Stop event propaganation for link elements
		/* Then clicked on overlay we'll check the option and in case of overlayClose == false we'll break hiding execution [Fix for #139] */
		if(event.element().id == 'MB_overlay' && !this.options.overlayClose) return false;
		this.hide();
	},
	
	alert: function(message){
		var html = '<div class="MB_alert"><p>' + message + '</p><input type="button" onclick="Modalbox.hide()" value="OK" /></div>';
		Modalbox.show(html, {title: 'Alert: ' + document.title, width: 300});
	},
		
	_appear: function() { // First appearing of MB
		if(Prototype.Browser.IE && !navigator.appVersion.match(/\b7.0\b/)) { // Preparing IE 6 for showing modalbox
			window.scrollTo(0,0);
			this._prepareIE("100%", "hidden"); 
		}
		this._setWidth();
		this._setPosition();
		if(this.options.transitions) {
			$(this.MBoverlay).setStyle({opacity: 0});
			new Effect.Fade(this.MBoverlay, {
					from: 0, 
					to: this.options.overlayOpacity, 
					duration: this.options.overlayDuration, 
					afterFinish: function() {
						new Effect.SlideDown(this.MBwindow, {
							duration: this.options.slideDownDuration, 
							transition: Effect.Transitions.sinoidal, 
							afterFinish: function(){ 
								this._setPosition(); 
								this.loadContent();
							}.bind(this)
						});
					}.bind(this)
			});
		} else {
			$(this.MBoverlay).setStyle({opacity: this.options.overlayOpacity});
			$(this.MBwindow).show();
			this._setPosition(); 
			this.loadContent();
		}
		this._setWidthAndPosition = this._setWidthAndPosition.bindAsEventListener(this);
		Event.observe(window, "resize", this._setWidthAndPosition);
	},
	
	resize: function(byWidth, byHeight, options) { // Change size of MB without loading content
		var wHeight = $(this.MBwindow).getHeight();
		var wWidth = $(this.MBwindow).getWidth();
		var hHeight = $(this.MBheader).getHeight();
		var cHeight = $(this.MBcontent).getHeight();
		var newHeight = ((wHeight - hHeight + byHeight) < cHeight) ? (cHeight + hHeight - wHeight) : byHeight;
		if(options) this.setOptions(options); // Passing callbacks
		if(this.options.transitions) {
			new Effect.ScaleBy(this.MBwindow, byWidth, newHeight, {
					duration: this.options.resizeDuration, 
				  	afterFinish: function() { 
						this.event("_afterResize"); // Passing internal callback
						this.event("afterResize"); // Passing callback
					}.bind(this)
				});
		} else {
			this.MBwindow.setStyle({width: wWidth + byWidth + "px", height: wHeight + newHeight + "px"});
			setTimeout(function() {
				this.event("_afterResize"); // Passing internal callback
				this.event("afterResize"); // Passing callback
			}.bind(this), 1);
			
		}
		
	},
	
	resizeToContent: function(options){
		
		// Resizes the modalbox window to the actual content height.
		// This might be useful to resize modalbox after some content modifications which were changed ccontent height.
		
		var byHeight = this.options.height - this.MBwindow.offsetHeight;
		if(byHeight != 0) {
			if(options) this.setOptions(options); // Passing callbacks
			Modalbox.resize(0, byHeight);
		}
	},
	
	resizeToInclude: function(element, options){
		
		// Resizes the modalbox window to the camulative height of element. Calculations are using CSS properties for margins and border.
		// This method might be useful to resize modalbox before including or updating content.
		
		var el = $(element);
		var elHeight = el.getHeight() + parseInt(el.getStyle('margin-top')) + parseInt(el.getStyle('margin-bottom')) + parseInt(el.getStyle('border-top-width')) + parseInt(el.getStyle('border-bottom-width'));
		if(elHeight > 0) {
			if(options) this.setOptions(options); // Passing callbacks
			Modalbox.resize(0, elHeight);
		}
	},
	
	_update: function() { // Updating MB in case of wizards
		$(this.MBcontent).update("");
		this.MBcontent.appendChild(this.MBloading);
		$(this.MBloading).update(this.options.loadingString);
		this.currentDims = [this.MBwindow.offsetWidth, this.MBwindow.offsetHeight];
		Modalbox.resize((this.options.width - this.currentDims[0]), (this.options.height - this.currentDims[1]), {_afterResize: this._loadAfterResize.bind(this) });
	},
	
	loadContent: function () {
		if(this.event("beforeLoad") != false) { // If callback passed false, skip loading of the content
			if(typeof this.content == 'string') {
				var htmlRegExp = new RegExp(/<\/?[^>]+>/gi);
				if(htmlRegExp.test(this.content)) { // Plain HTML given as a parameter
					this._insertContent(this.content.stripScripts());
					this._putContent(function(){
						this.content.extractScripts().map(function(script) { 
							return eval(script.replace("<!--", "").replace("// -->", ""));
						}.bind(window));
					}.bind(this));
				} else // URL given as a parameter. We'll request it via Ajax
					new Ajax.Request( this.content, { method: this.options.method.toLowerCase(), parameters: this.options.params, 
						onSuccess: function(transport) {
							var response = new String(transport.responseText);
							this._insertContent(transport.responseText.stripScripts());
							this._putContent(function(){
								response.extractScripts().map(function(script) { 
									return eval(script.replace("<!--", "").replace("// -->", ""));
								}.bind(window));
							});
						}.bind(this),
						onException: function(instance, exception){
							Modalbox.hide();
							throw('Modalbox Loading Error: ' + exception);
						}
					});
					
			} else if (typeof this.content == 'object') {// HTML Object is given
				this._insertContent(this.content);
				this._putContent();
			} else {
				Modalbox.hide();
				throw('Modalbox Parameters Error: Please specify correct URL or HTML element (plain HTML or object)');
			}
		}
	},
	
	_insertContent: function(content){
		$(this.MBcontent).hide().update("");
		if(typeof content == 'string') {
			setTimeout(function() { // Hack to disable content flickering in Firefox
				this.MBcontent.update(content);
			}.bind(this), 1);
		} else if (typeof content == 'object') { // HTML Object is given
			var _htmlObj = content.cloneNode(true); // If node already a part of DOM we'll clone it
			// If clonable element has ID attribute defined, modifying it to prevent duplicates
			if(content.id) content.id = "MB_" + content.id;
			/* Add prefix for IDs on all elements inside the DOM node */
			$(content).select('*[id]').each(function(el){ el.id = "MB_" + el.id; });
			this.MBcontent.appendChild(_htmlObj);
			this.MBcontent.down().show(); // Toggle visibility for hidden nodes
			if(Prototype.Browser.IE) // Toggling back visibility for hidden selects in IE
				$$("#MB_content select").invoke('setStyle', {'visibility': ''});
		}
	},
	
	_putContent: function(callback){
		// Prepare and resize modal box for content
		if(this.options.height == this._options.height) {
			setTimeout(function() { // MSIE sometimes doesn't display content correctly
				Modalbox.resize(0, $(this.MBcontent).getHeight() - $(this.MBwindow).getHeight() + $(this.MBheader).getHeight(), {
					afterResize: function(){
						this.MBcontent.show().makePositioned();
						this.focusableElements = this._findFocusableElements();
						this._setFocus(); // Setting focus on first 'focusable' element in content (input, select, textarea, link or button)
						setTimeout(function(){ // MSIE fix
							if(callback != undefined)
								callback(); // Executing internal JS from loaded content
							this.event("afterLoad"); // Passing callback
						}.bind(this),1);
					}.bind(this)
				});
			}.bind(this), 1);
		} else { // Height is defined. Creating a scrollable window
			this._setWidth();
			this.MBcontent.setStyle({overflow: 'auto', height: $(this.MBwindow).getHeight() - $(this.MBheader).getHeight() - 13 + 'px'});
			this.MBcontent.show();
			this.focusableElements = this._findFocusableElements();
			this._setFocus(); // Setting focus on first 'focusable' element in content (input, select, textarea, link or button)
			setTimeout(function(){ // MSIE fix
				if(callback != undefined)
					callback(); // Executing internal JS from loaded content
				this.event("afterLoad"); // Passing callback
			}.bind(this),1);
		}
	},
	
	activate: function(options){
		this.setOptions(options);
		this.active = true;
		$(this.MBclose).observe("click", this.hideObserver);
		if(this.options.overlayClose)
			$(this.MBoverlay).observe("click", this.hideObserver);
		$(this.MBclose).show();
		if(this.options.transitions && this.options.inactiveFade)
			new Effect.Appear(this.MBwindow, {duration: this.options.slideUpDuration});
	},
	
	deactivate: function(options) {
		this.setOptions(options);
		this.active = false;
		$(this.MBclose).stopObserving("click", this.hideObserver);
		if(this.options.overlayClose)
			$(this.MBoverlay).stopObserving("click", this.hideObserver);
		$(this.MBclose).hide();
		if(this.options.transitions && this.options.inactiveFade)
			new Effect.Fade(this.MBwindow, {duration: this.options.slideUpDuration, to: .75});
	},
	
	_initObservers: function(){
		$(this.MBclose).observe("click", this.hideObserver);
		if(this.options.overlayClose)
			$(this.MBoverlay).observe("click", this.hideObserver);
		if(Prototype.Browser.IE)
			Event.observe(document, "keydown", this.kbdObserver);
		else
			Event.observe(document, "keypress", this.kbdObserver);
	},
	
	_removeObservers: function(){
		$(this.MBclose).stopObserving("click", this.hideObserver);
		if(this.options.overlayClose)
			$(this.MBoverlay).stopObserving("click", this.hideObserver);
		if(Prototype.Browser.IE)
			Event.stopObserving(document, "keydown", this.kbdObserver);
		else
			Event.stopObserving(document, "keypress", this.kbdObserver);
	},
	
	_loadAfterResize: function() {
		this._setWidth();
		this._setPosition();
		this.loadContent();
	},
	
	_setFocus: function() { 
		/* Setting focus to the first 'focusable' element which is one with tabindex = 1 or the first in the form loaded. */
		if(this.focusableElements.length > 0 && this.options.autoFocusing == true) {
			var firstEl = this.focusableElements.find(function (el){
				return el.tabIndex == 1;
			}) || this.focusableElements.first();
			this.currFocused = this.focusableElements.toArray().indexOf(firstEl);
			firstEl.focus(); // Focus on first focusable element except close button
		} else if($(this.MBclose).visible())
			$(this.MBclose).focus(); // If no focusable elements exist focus on close button
	},
	
	_findFocusableElements: function(){ // Collect form elements or links from MB content
		this.MBcontent.select('input:not([type~=hidden]), select, textarea, button, a[href]').invoke('addClassName', 'MB_focusable');
		return this.MBcontent.select('.MB_focusable');
	},
	
	_kbdHandler: function(event) {
		var node = event.element();
		switch(event.keyCode) {
			case Event.KEY_TAB:
				event.stop();
				
				/* Switching currFocused to the element which was focused by mouse instead of TAB-key. Fix for #134 */ 
				if(node != this.focusableElements[this.currFocused])
					this.currFocused = this.focusableElements.toArray().indexOf(node);
				
				if(!event.shiftKey) { //Focusing in direct order
					if(this.currFocused == this.focusableElements.length - 1) {
						this.focusableElements.first().focus();
						this.currFocused = 0;
					} else {
						this.currFocused++;
						this.focusableElements[this.currFocused].focus();
					}
				} else { // Shift key is pressed. Focusing in reverse order
					if(this.currFocused == 0) {
						this.focusableElements.last().focus();
						this.currFocused = this.focusableElements.length - 1;
					} else {
						this.currFocused--;
						this.focusableElements[this.currFocused].focus();
					}
				}
				break;			
			case Event.KEY_ESC:
				if(this.active) this._hide(event);
				break;
			case 32:
				this._preventScroll(event);
				break;
			case 0: // For Gecko browsers compatibility
				if(event.which == 32) this._preventScroll(event);
				break;
			case Event.KEY_UP:
			case Event.KEY_DOWN:
			case Event.KEY_PAGEDOWN:
			case Event.KEY_PAGEUP:
			case Event.KEY_HOME:
			case Event.KEY_END:
				// Safari operates in slightly different way. This realization is still buggy in Safari.
				if(Prototype.Browser.WebKit && !["textarea", "select"].include(node.tagName.toLowerCase()))
					event.stop();
				else if( (node.tagName.toLowerCase() == "input" && ["submit", "button"].include(node.type)) || (node.tagName.toLowerCase() == "a") )
					event.stop();
				break;
		}
	},
	
	_preventScroll: function(event) { // Disabling scrolling by "space" key
		if(!["input", "textarea", "select", "button"].include(event.element().tagName.toLowerCase())) 
			event.stop();
	},
	
	_deinit: function()
	{	
		this._removeObservers();
		Event.stopObserving(window, "resize", this._setWidthAndPosition );
		if(this.options.transitions) {
			Effect.toggle(this.MBoverlay, 'appear', {duration: this.options.overlayDuration, afterFinish: this._removeElements.bind(this) });
		} else {
			this.MBoverlay.hide();
			this._removeElements();
		}
		$(this.MBcontent).setStyle({overflow: '', height: ''});
	},
	
	_removeElements: function () {
		$(this.MBoverlay).remove();
		$(this.MBwindow).remove();
		if(Prototype.Browser.IE && !navigator.appVersion.match(/\b7.0\b/)) {
			this._prepareIE("", ""); // If set to auto MSIE will show horizontal scrolling
			window.scrollTo(this.initScrollX, this.initScrollY);
		}
		
		/* Replacing prefixes 'MB_' in IDs for the original content */
		if(typeof this.content == 'object') {
			if(this.content.id && this.content.id.match(/MB_/)) {
				this.content.id = this.content.id.replace(/MB_/, "");
			}
			this.content.select('*[id]').each(function(el){ el.id = el.id.replace(/MB_/, ""); });
		}
		/* Initialized will be set to false */
		this.initialized = false;
		this.event("afterHide"); // Passing afterHide callback
		this.setOptions(this._options); //Settings options object into intial state
	},
	
	_setWidth: function () { //Set size
		$(this.MBwindow).setStyle({width: this.options.width + "px", height: this.options.height + "px"});
	},
	
	_setPosition: function () {
		$(this.MBwindow).setStyle({left: Math.round((Element.getWidth(document.body) - Element.getWidth(this.MBwindow)) / 2 ) + "px"});
	},
	
	_setWidthAndPosition: function () {
		$(this.MBwindow).setStyle({width: this.options.width + "px"});
		this._setPosition();
	},
	
	_getScrollTop: function () { //From: http://www.quirksmode.org/js/doctypes.html
		var theTop;
		if (document.documentElement && document.documentElement.scrollTop)
			theTop = document.documentElement.scrollTop;
		else if (document.body)
			theTop = document.body.scrollTop;
		return theTop;
	},
	_prepareIE: function(height, overflow){
		$$('html, body').invoke('setStyle', {width: height, height: height, overflow: overflow}); // IE requires width and height set to 100% and overflow hidden
		$$("select").invoke('setStyle', {'visibility': overflow}); // Toggle visibility for all selects in the common document
	},
	event: function(eventName) {
		if(this.options[eventName]) {
			var returnValue = this.options[eventName](); // Executing callback
			this.options[eventName] = null; // Removing callback after execution
			if(returnValue != undefined) 
				return returnValue;
			else 
				return true;
		}
		return true;
	}
};

Object.extend(Modalbox, Modalbox.Methods);

if(Modalbox.overrideAlert) window.alert = Modalbox.alert;

Effect.ScaleBy = Class.create();
Object.extend(Object.extend(Effect.ScaleBy.prototype, Effect.Base.prototype), {
  initialize: function(element, byWidth, byHeight, options) {
    this.element = $(element)
    var options = Object.extend({
	  scaleFromTop: true,
      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
      scaleByWidth: byWidth,
	  scaleByHeight: byHeight
    }, arguments[3] || {});
    this.start(options);
  },
  setup: function() {
    this.elementPositioning = this.element.getStyle('position');
      
    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;
	
    this.dims = null;
    if(this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
	 if(/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if(!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
	  
	this.deltaY = this.options.scaleByHeight;
	this.deltaX = this.options.scaleByWidth;
  },
  update: function(position) {
    var currentHeight = this.dims[0] + (this.deltaY * position);
	var currentWidth = this.dims[1] + (this.deltaX * position);
	
	currentHeight = (currentHeight > 0) ? currentHeight : 0;
	currentWidth = (currentWidth > 0) ? currentWidth : 0;
	
    this.setDimensions(currentHeight, currentWidth);
  },

  setDimensions: function(height, width) {
    var d = {};
    d.width = width + 'px';
    d.height = height + 'px';
    
	var topd  = Math.round((height - this.dims[0])/2);
	var leftd = Math.round((width  - this.dims[1])/2);
	if(this.elementPositioning == 'absolute' || this.elementPositioning == 'fixed') {
		if(!this.options.scaleFromTop) d.top = this.originalTop-topd + 'px';
		d.left = this.originalLeft-leftd + 'px';
	} else {
		if(!this.options.scaleFromTop) d.top = -topd + 'px';
		d.left = -leftd + 'px';
	}
    this.element.setStyle(d);
  }
});var rwmDebug = false;



// Write out a script tag to load the specified file ONLY if the provided reference is undefined after evaluation.
function rwmIncludeScript ( ScriptFile , Reference )
{

	if (typeof(eval(Reference)) == "undefined")
	{
		document.write("<script language=\"javascript\" src=\"" + ScriptFile + "\"></script>");
	}

}


// Neutralise browser event argument handling. Send this the (e) parameter from an event handler.
function rwmEvent (evt)
{
	this.event = (evt) ? evt : ((window.event) ? event : null);
	if (this.event)
	{
		this.element = (this.event.target) ? this.event.target : this.event.srcElement;
		if (this.event.pageX || this.event.pageY)
		{
			this.x = this.event.pageX;
			this.y = this.event.pageY;
		}
		else if (this.event.clientX || this.event.clientY)
		{
			this.x = this.event.clientX + document.body.scrollLeft;
			this.y = this.event.clientY + document.body.scrollTop;
		}
	}
}


// Quick'n'dirty debugging. List an object's properties.
function rwmListProperties (obj, popup)
{
	var report = "";
	for (i in obj)
	{
		report += i + " = " + obj[i] + "\n";
	}
	if (popup)
	{
		var win = window.open("", "props");
		win.document.write(report.replace(/</g, "&lt;").replace(/\n/g, "<br>"));
	}
	return report;
}


function rwmElementPosition (element)
{
	/*
	 * Crudely determines location of an element.
	 * Needs further fudging for IE as values are not right yet!!
	 */
	var el = element;
	var x = el.offsetLeft;
	var y = el.offsetTop;
	// this loop builds up a cumulative offset (which might not be bang on!)
	while (el = el.offsetParent)
	{
		if (rwmDebug) alert("parent element " + el.tagName + " (" + el.id + ") at " + el.offsetLeft + " , " + el.offsetTop);
		x += el.offsetLeft;
		y += el.offsetTop;
	}
	if (rwmDebug) alert("cumulative offset = " + x + " , " + y);
	return {x: x, y: y};
}


/**
 * @author Ryan Johnson <http://saucytiger.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/core
 * @require prototype.js
 */

if(typeof(Control) == 'undefined')
	Control = {};
	
var $proc = function(proc){
	return typeof(proc) == 'function' ? proc : function(){return proc};
};

var $value = function(value){
	return typeof(value) == 'function' ? value() : value;
};

Object.Event = {
	extend: function(object){
		object._objectEventSetup = function(event_name){
			this._observers = this._observers || {};
			this._observers[event_name] = this._observers[event_name] || [];
		};
		object.observe = function(event_name,observer){
			if(typeof(event_name) == 'string' && typeof(observer) != 'undefined'){
				this._objectEventSetup(event_name);
				if(!this._observers[event_name].include(observer))
					this._observers[event_name].push(observer);
			}else
				for(var e in event_name)
					this.observe(e,event_name[e]);
		};
		object.stopObserving = function(event_name,observer){
			this._objectEventSetup(event_name);
			if(event_name && observer)
				this._observers[event_name] = this._observers[event_name].without(observer);
			else if(event_name)
				this._observers[event_name] = [];
			else
				this._observers = {};
		};
		object.observeOnce = function(event_name,outer_observer){
			var inner_observer = function(){
				outer_observer.apply(this,arguments);
				this.stopObserving(event_name,inner_observer);
			}.bind(this);
			this._objectEventSetup(event_name);
			this._observers[event_name].push(inner_observer);
		};
		object.notify = function(event_name){
			this._objectEventSetup(event_name);
			var collected_return_values = [];
			var args = $A(arguments).slice(1);
			try{
				for(var i = 0; i < this._observers[event_name].length; ++i)
					collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
			}catch(e){
				if(e == $break)
					return false;
				else
					throw e;
			}
			return collected_return_values;
		};
		if(object.prototype){
			object.prototype._objectEventSetup = object._objectEventSetup;
			object.prototype.observe = object.observe;
			object.prototype.stopObserving = object.stopObserving;
			object.prototype.observeOnce = object.observeOnce;
			object.prototype.notify = function(event_name){
				if(object.notify){
					var args = $A(arguments).slice(1);
					args.unshift(this);
					args.unshift(event_name);
					object.notify.apply(object,args);
				}
				this._objectEventSetup(event_name);
				var args = $A(arguments).slice(1);
				var collected_return_values = [];
				try{
					if(this.options && this.options[event_name] && typeof(this.options[event_name]) == 'function')
						collected_return_values.push(this.options[event_name].apply(this,args) || null);
					for(var i = 0; i < this._observers[event_name].length; ++i)
						collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
				}catch(e){
					if(e == $break)
						return false;
					else
						throw e;
				}
				return collected_return_values;
			};
		}
	}
};

/* Begin Core Extensions */

//Element.observeOnce
Element.addMethods({
	observeOnce: function(element,event_name,outer_callback){
		var inner_callback = function(){
			outer_callback.apply(this,arguments);
			Element.stopObserving(element,event_name,inner_callback);
		};
		Element.observe(element,event_name,inner_callback);
	}
});

//mouseenter, mouseleave
//from http://dev.rubyonrails.org/attachment/ticket/8354/event_mouseenter_106rc1.patch
Object.extend(Event, (function() {
	var cache = Event.cache;

	function getEventID(element) {
		if (element._prototypeEventID) return element._prototypeEventID[0];
		arguments.callee.id = arguments.callee.id || 1;
		return element._prototypeEventID = [++arguments.callee.id];
	}

	function getDOMEventName(eventName) {
		if (eventName && eventName.include(':')) return "dataavailable";
		//begin extension
		if(!Prototype.Browser.IE){
			eventName = {
				mouseenter: 'mouseover',
				mouseleave: 'mouseout'
			}[eventName] || eventName;
		}
		//end extension
		return eventName;
	}

	function getCacheForID(id) {
		return cache[id] = cache[id] || { };
	}

	function getWrappersForEventName(id, eventName) {
		var c = getCacheForID(id);
		return c[eventName] = c[eventName] || [];
	}

	function createWrapper(element, eventName, handler) {
		var id = getEventID(element);
		var c = getWrappersForEventName(id, eventName);
		if (c.pluck("handler").include(handler)) return false;

		var wrapper = function(event) {
			if (!Event || !Event.extend ||
				(event.eventName && event.eventName != eventName))
					return false;

			Event.extend(event);
			handler.call(element, event);
		};
		
		//begin extension
		if(!(Prototype.Browser.IE) && ['mouseenter','mouseleave'].include(eventName)){
			wrapper = wrapper.wrap(function(proceed,event) {	
				var rel = event.relatedTarget;
				var cur = event.currentTarget;			 
				if(rel && rel.nodeType == Node.TEXT_NODE)
					rel = rel.parentNode;	  
				if(rel && rel != cur && !rel.descendantOf(cur))	  
					return proceed(event);   
			});	 
		}
		//end extension

		wrapper.handler = handler;
		c.push(wrapper);
		return wrapper;
	}

	function findWrapper(id, eventName, handler) {
		var c = getWrappersForEventName(id, eventName);
		return c.find(function(wrapper) { return wrapper.handler == handler });
	}

	function destroyWrapper(id, eventName, handler) {
		var c = getCacheForID(id);
		if (!c[eventName]) return false;
		c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
	}

	function destroyCache() {
		for (var id in cache)
			for (var eventName in cache[id])
				cache[id][eventName] = null;
	}

	if (window.attachEvent) {
		window.attachEvent("onunload", destroyCache);
	}

	return {
		observe: function(element, eventName, handler) {
			element = $(element);
			var name = getDOMEventName(eventName);

			var wrapper = createWrapper(element, eventName, handler);
			if (!wrapper) return element;

			if (element.addEventListener) {
				element.addEventListener(name, wrapper, false);
			} else {
				element.attachEvent("on" + name, wrapper);
			}

			return element;
		},

		stopObserving: function(element, eventName, handler) {
			element = $(element);
			var id = getEventID(element), name = getDOMEventName(eventName);

			if (!handler && eventName) {
				getWrappersForEventName(id, eventName).each(function(wrapper) {
					element.stopObserving(eventName, wrapper.handler);
				});
				return element;

			} else if (!eventName) {
				Object.keys(getCacheForID(id)).each(function(eventName) {
					element.stopObserving(eventName);
				});
				return element;
			}

			var wrapper = findWrapper(id, eventName, handler);
			if (!wrapper) return element;

			if (element.removeEventListener) {
				element.removeEventListener(name, wrapper, false);
			} else {
				element.detachEvent("on" + name, wrapper);
			}

			destroyWrapper(id, eventName, handler);

			return element;
		},

		fire: function(element, eventName, memo) {
			element = $(element);
			if (element == document && document.createEvent && !element.dispatchEvent)
				element = document.documentElement;

			var event;
			if (document.createEvent) {
				event = document.createEvent("HTMLEvents");
				event.initEvent("dataavailable", true, true);
			} else {
				event = document.createEventObject();
				event.eventType = "ondataavailable";
			}

			event.eventName = eventName;
			event.memo = memo || { };

			if (document.createEvent) {
				element.dispatchEvent(event);
			} else {
				element.fireEvent(event.eventType, event);
			}

			return Event.extend(event);
		}
	};
})());

Object.extend(Event, Event.Methods);

Element.addMethods({
	fire:			Event.fire,
	observe:		Event.observe,
	stopObserving:	Event.stopObserving
});

Object.extend(document, {
	fire:			Element.Methods.fire.methodize(),
	observe:		Element.Methods.observe.methodize(),
	stopObserving:	Element.Methods.stopObserving.methodize()
});

//mouse:wheel
(function(){
	function wheel(event){
		var delta;
		// normalize the delta
		if(event.wheelDelta) // IE & Opera
			delta = event.wheelDelta / 120;
		else if (event.detail) // W3C
			delta =- event.detail / 3;
		if(!delta)
			return;
		var custom_event = event.element().fire('mouse:wheel',{
			delta: delta
		});
		if(custom_event.stopped){
			event.stop();
			return false;
		}
	}
	document.observe('mousewheel',wheel);
	document.observe('DOMMouseScroll',wheel);
})();

/* End Core Extensions */

//from PrototypeUI
var IframeShim = Class.create({
	initialize: function() {
		this.element = new Element('iframe',{
			style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
			src: 'javascript:void(0);',
			frameborder: 0 
		});
		$(document.body).insert(this.element);
	},
	hide: function() {
		this.element.hide();
		return this;
	},
	show: function() {
		this.element.show();
		return this;
	},
	positionUnder: function(element) {
		var element = $(element);
		var offset = element.cumulativeOffset();
		var dimensions = element.getDimensions();
		this.element.setStyle({
			left: offset[0] + 'px',
			top: offset[1] + 'px',
			width: dimensions.width + 'px',
			height: dimensions.height + 'px',
			zIndex: element.getStyle('zIndex') - 1
		}).show();
		return this;
	},
	setBounds: function(bounds) {
		for(prop in bounds)
			bounds[prop] += 'px';
		this.element.setStyle(bounds);
		return this;
	},
	destroy: function() {
		if(this.element)
			this.element.remove();
		return this;
	}
});/**
 * @author Ryan Johnson <http://saucytiger.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/control/rating
 * @require prototype.js, livepipe.js
 */

if(typeof(Prototype) == "undefined")
	throw "Control.Rating requires Prototype to be loaded.";
if(typeof(Object.Event) == "undefined")
	throw "Control.Rating requires Object.Event to be loaded.";

Control.Rating = Class.create({
	initialize: function(container,options){
		Control.Rating.instances.push(this);
		this.value = false;
		this.links = [];
		this.container = $(container);
		this.container.update('');
		this.options = {
			min: 1,
			max: 5,
			rated: false,
			input: false,
			reverse: false,
			capture: true,
			multiple: false,
			classNames: {
				off: 'rating_off',
				half: 'rating_half',
				on: 'rating_on',
				selected: 'rating_selected'
			},
			updateUrl: false,
			updateParameterName: 'value',
			afterChange: Prototype.emptyFunction
		};
		Object.extend(this.options,options || {});
		if(this.options.value){
			this.value = this.options.value;
			delete this.options.value;
		}
		if(this.options.input){
			this.options.input = $(this.options.input);
			this.options.input.observe('change',function(input){
				this.setValueFromInput(input);
			}.bind(this,this.options.input));
			this.setValueFromInput(this.options.input,true);
		}
		var range = $R(this.options.min,this.options.max);
		(this.options.reverse ? $A(range).reverse() : range).each(function(i){
			var link = this.buildLink(i);
			this.container.appendChild(link);
			this.links.push(link);
		}.bind(this));
		this.setValue(this.value || this.options.min - 1,false,true);
	},
	buildLink: function(rating){
		var link = $(document.createElement('a'));
		link.value = rating;
		if(this.options.multiple || (!this.options.rated && !this.options.multiple)){
			link.href = '';
			link.onmouseover = this.mouseOver.bind(this,link);
			link.onmouseout = this.mouseOut.bind(this,link);
			link.onclick = this.click.bindAsEventListener(this,link);
		}else{
			link.style.cursor = 'default';
			link.observe('click',function(event){
				Event.stop(event);
				return false;
			}.bindAsEventListener(this));
		}
		link.addClassName(this.options.classNames.off);
		return link;
	},
	disable: function(){
		this.links.each(function(link){
			link.onmouseover = Prototype.emptyFunction;
			link.onmouseout = Prototype.emptyFunction;
			link.onclick = Prototype.emptyFunction;
			link.observe('click',function(event){
				Event.stop(event);
				return false;
			}.bindAsEventListener(this));
			link.style.cursor = 'default';
		}.bind(this));
	},
	setValueFromInput: function(input,prevent_callbacks){
		this.setValue((input.options ? input.options[input.options.selectedIndex].value : input.value),true,prevent_callbacks);
	},
	setValue: function(value,force_selected,prevent_callbacks){
		this.value = value;
		if(this.options.input){
			if(this.options.input.options){
				$A(this.options.input.options).each(function(option,i){
					if(option.value == this.value){
						this.options.input.options.selectedIndex = i;
						throw $break;
					}
				}.bind(this));
			}else
				this.options.input.value = this.value;
		}
		this.render(this.value,force_selected);
		if(!prevent_callbacks){
			if(this.options.updateUrl){
				var params = {};
				params[this.options.updateParameterName] = this.value;
				new Ajax.Request(this.options.updateUrl,{
					parameters: params
				});
			}
			this.notify('afterChange',this.value);
		}
	},
	render: function(rating,force_selected){
		(this.options.reverse ? this.links.reverse() : this.links).each(function(link,i){
			if(link.value <= Math.ceil(rating)){
				link.className = this.options.classNames[link.value <= rating ? 'on' : 'half'];
				if(this.options.rated || force_selected)
					link.addClassName(this.options.classNames.selected);
			}else
				link.className = this.options.classNames.off;
		}.bind(this));
	},
	mouseOver: function(link){
		this.render(link.value,true);
	},
	mouseOut: function(link){
		this.render(this.value);
	},
	click: function(event,link){
		this.options.rated = true;
		this.setValue((link.value ? link.value : link),true);
		if(!this.options.multiple)
			this.disable();
		if(this.options.capture){
			Event.stop(event);
			return false;
		}
	}
});
Object.extend(Control.Rating,{
	instances: [],
	findByElementId: function(id){
		return Control.Rating.instances.find(function(instance){
			return (instance.container.id && instance.container.id == id);
		});
	}
});
Object.Event.extend(Control.Rating);/**
 * @author Ryan Johnson <http://saucytiger.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/control/tabs
 * @require prototype.js, livepipe.js
 */

if(typeof(Prototype) == "undefined")
	throw "Control.Tabs requires Prototype to be loaded.";
if(typeof(Object.Event) == "undefined")
	throw "Control.Tabs requires Object.Event to be loaded.";

Control.Tabs = Class.create({
	initialize: function(tab_list_container,options){
		if(!$(tab_list_container))
			throw "Control.Tabs could not find the element: " + tab_list_container;
		this.activeContainer = false;
		this.activeLink = false;
		this.containers = $H({});
		this.links = [];
		Control.Tabs.instances.push(this);
		this.options = {
			beforeChange: Prototype.emptyFunction,
			afterChange: Prototype.emptyFunction,
			hover: false,
			linkSelector: 'li a',
			setClassOnContainer: false,
			activeClassName: 'active',
			defaultTab: 'first',
			autoLinkExternal: true,
			targetRegExp: /#(.+)$/,
			showFunction: Element.show,
			hideFunction: Element.hide
		};
		Object.extend(this.options,options || {});
		(typeof(this.options.linkSelector == 'string')
			? $(tab_list_container).select(this.options.linkSelector)
			: this.options.linkSelector($(tab_list_container))
		).findAll(function(link){
			return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(window.location.href.split('#')[0],''));
		}).each(function(link){
			this.addTab(link);
		}.bind(this));
		this.containers.values().each(Element.hide);
		if(this.options.defaultTab == 'first')
			this.setActiveTab(this.links.first());
		else if(this.options.defaultTab == 'last')
			this.setActiveTab(this.links.last());
		else
			this.setActiveTab(this.options.defaultTab);
		var targets = this.options.targetRegExp.exec(window.location);
		if(targets && targets[1]){
			targets[1].split(',').each(function(target){
				this.setActiveTab(this.links.find(function(link){
					return link.key == target;
				}));
			}.bind(this));
		}
		if(this.options.autoLinkExternal){
			$A(document.getElementsByTagName('a')).each(function(a){
				if(!this.links.include(a)){
					var clean_href = a.href.replace(window.location.href.split('#')[0],'');
					if(clean_href.substring(0,1) == '#'){
						if(this.containers.keys().include(clean_href.substring(1))){
							$(a).observe('click',function(event,clean_href){
								this.setActiveTab(clean_href.substring(1));
							}.bindAsEventListener(this,clean_href));
						}
					}
				}
			}.bind(this));
		}
	},
	addTab: function(link){
		this.links.push(link);
		link.key = link.getAttribute('href').replace(window.location.href.split('#')[0],'').split('/').last().replace(/#/,'');
		var container = $(link.key);
		if(!container)
			throw "Control.Tabs: #" + link.key + " was not found on the page."
		this.containers.set(link.key,container);
		link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link){
			if(window.event)
				Event.stop(window.event);
			this.setActiveTab(link);
			return false;
		}.bind(this,link);
	},
	setActiveTab: function(link){
		if(!link && typeof(link) == 'undefined')
			return;
		if(typeof(link) == 'string'){
			this.setActiveTab(this.links.find(function(_link){
				return _link.key == link;
			}));
		}else if(typeof(link) == 'number'){
			this.setActiveTab(this.links[link]);
		}else{
			if(this.notify('beforeChange',this.activeContainer,this.containers.get(link.key)) === false)
				return;
			if(this.activeContainer)
				this.options.hideFunction(this.activeContainer);
			this.links.each(function(item){
				(this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName);
			}.bind(this));
			(this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName);
			this.activeContainer = this.containers.get(link.key);
			this.activeLink = link;
			this.options.showFunction(this.containers.get(link.key));
			this.notify('afterChange',this.containers.get(link.key));
		}
	},
	next: function(){
		this.links.each(function(link,i){
			if(this.activeLink == link && this.links[i + 1]){
				this.setActiveTab(this.links[i + 1]);
				throw $break;
			}
		}.bind(this));
	},
	previous: function(){
		this.links.each(function(link,i){
			if(this.activeLink == link && this.links[i - 1]){
				this.setActiveTab(this.links[i - 1]);
				throw $break;
			}
		}.bind(this));
	},
	first: function(){
		this.setActiveTab(this.links.first());
	},
	last: function(){
		this.setActiveTab(this.links.last());
	}
});
Object.extend(Control.Tabs,{
	instances: [],
	findByTabId: function(id){
		return Control.Tabs.instances.find(function(tab){
			return tab.links.find(function(link){
				return link.key == id;
			});
		});
	}
});
Object.Event.extend(Control.Tabs);// Copyright (c) 2006 SÃ©bastien Gruhier (http://xilinus.com, http://itseb.com)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// VERSION 1.3

var Window = Class.create();

Window.keepMultiModalWindow = false;
Window.hasEffectLib = (typeof Effect != 'undefined');
Window.resizeEffectDuration = 0.4;

Window.prototype = {
  // Constructor
  // Available parameters : className, blurClassName, title, minWidth, minHeight, maxWidth, maxHeight, width, height, top, left, bottom, right, resizable, zIndex, opacity, recenterAuto, wiredDrag
  //                        hideEffect, showEffect, showEffectOptions, hideEffectOptions, effectOptions, url, draggable, closable, minimizable, maximizable, parent, onload
  //                        add all callbacks (if you do not use an observer)
  //                        onDestroy onStartResize onStartMove onResize onMove onEndResize onEndMove onFocus onBlur onBeforeShow onShow onHide onMinimize onMaximize onClose
  
  initialize: function() {
    var id;
    var optionIndex = 0;
    // For backward compatibility like win= new Window("id", {...}) instead of win = new Window({id: "id", ...})
    if (arguments.length > 0) {
      if (typeof arguments[0] == "string" ) {
        id = arguments[0];
        optionIndex = 1;
      }
      else
        id = arguments[0] ? arguments[0].id : null;
    }
    
    // Generate unique ID if not specified
    if (!id)
      id = "window_" + new Date().getTime();
      
    if ($(id))
      alert("Window " + id + " is already registered in the DOM! Make sure you use setDestroyOnClose() or destroyOnClose: true in the constructor");

    this.options = Object.extend({
      className:         "dialog",
      blurClassName:     null,
      minWidth:          100, 
      minHeight:         20,
      resizable:         true,
      closable:          true,
      minimizable:       true,
      maximizable:       true,
      draggable:         true,
      userData:          null,
      showEffect:        (Window.hasEffectLib ? Effect.Appear : Element.show),
      hideEffect:        (Window.hasEffectLib ? Effect.Fade : Element.hide),
      showEffectOptions: {},
      hideEffectOptions: {},
      effectOptions:     null,
      parent:            document.body,
      title:             "&nbsp;",
      url:               null,
      onload:            Prototype.emptyFunction,
      width:             200,
      height:            300,
      opacity:           1,
      recenterAuto:      true,
      wiredDrag:         false,
      closeCallback:     null,
      destroyOnClose:    false,
      gridX:             1, 
      gridY:             1      
    }, arguments[optionIndex] || {});
    if (this.options.blurClassName)
      this.options.focusClassName = this.options.className;
      
    if (typeof this.options.top == "undefined" &&  typeof this.options.bottom ==  "undefined") 
      this.options.top = this._round(Math.random()*500, this.options.gridY);
    if (typeof this.options.left == "undefined" &&  typeof this.options.right ==  "undefined") 
      this.options.left = this._round(Math.random()*500, this.options.gridX);

    if (this.options.effectOptions) {
      Object.extend(this.options.hideEffectOptions, this.options.effectOptions);
      Object.extend(this.options.showEffectOptions, this.options.effectOptions);
      if (this.options.showEffect == Element.Appear)
        this.options.showEffectOptions.to = this.options.opacity;
    }
    if (Window.hasEffectLib) {
      if (this.options.showEffect == Effect.Appear)
        this.options.showEffectOptions.to = this.options.opacity;
    
      if (this.options.hideEffect == Effect.Fade)
        this.options.hideEffectOptions.from = this.options.opacity;
    }
    if (this.options.hideEffect == Element.hide)
      this.options.hideEffect = function(){ Element.hide(this.element); if (this.options.destroyOnClose) this.destroy(); }.bind(this)
    
    if (this.options.parent != document.body)  
      this.options.parent = $(this.options.parent);
      
    this.element = this._createWindow(id);       
    this.element.win = this;
    
    // Bind event listener
    this.eventMouseDown = this._initDrag.bindAsEventListener(this);
    this.eventMouseUp   = this._endDrag.bindAsEventListener(this);
    this.eventMouseMove = this._updateDrag.bindAsEventListener(this);
    this.eventOnLoad    = this._getWindowBorderSize.bindAsEventListener(this);
    this.eventMouseDownContent = this.toFront.bindAsEventListener(this);
    this.eventResize = this._recenter.bindAsEventListener(this);
 
    this.topbar = $(this.element.id + "_top");
    this.bottombar = $(this.element.id + "_bottom");
    this.content = $(this.element.id + "_content");
    
    Event.observe(this.topbar, "mousedown", this.eventMouseDown);
    Event.observe(this.bottombar, "mousedown", this.eventMouseDown);
    Event.observe(this.content, "mousedown", this.eventMouseDownContent);
    Event.observe(window, "load", this.eventOnLoad);
    Event.observe(window, "resize", this.eventResize);
    Event.observe(window, "scroll", this.eventResize);
    Event.observe(this.options.parent, "scroll", this.eventResize);
    
    if (this.options.draggable)  {
      var that = this;
      [this.topbar, this.topbar.up().previous(), this.topbar.up().next()].each(function(element) {
        element.observe("mousedown", that.eventMouseDown);
        element.addClassName("top_draggable");
      });
      [this.bottombar.up(), this.bottombar.up().previous(), this.bottombar.up().next()].each(function(element) {
        element.observe("mousedown", that.eventMouseDown);
        element.addClassName("bottom_draggable");
      });
      
    }    
    
    if (this.options.resizable) {
      this.sizer = $(this.element.id + "_sizer");
      Event.observe(this.sizer, "mousedown", this.eventMouseDown);
    }  
    
    this.useLeft = null;
    this.useTop = null;
    if (typeof this.options.left != "undefined") {
      this.element.setStyle({left: parseFloat(this.options.left) + 'px'});
      this.useLeft = true;
    }
    else {
      this.element.setStyle({right: parseFloat(this.options.right) + 'px'});
      this.useLeft = false;
    }
    
    if (typeof this.options.top != "undefined") {
      this.element.setStyle({top: parseFloat(this.options.top) + 'px'});
      this.useTop = true;
    }
    else {
      this.element.setStyle({bottom: parseFloat(this.options.bottom) + 'px'});      
      this.useTop = false;
    }
      
    this.storedLocation = null;
    
    this.setOpacity(this.options.opacity);
    if (this.options.zIndex)
      this.setZIndex(this.options.zIndex)

    if (this.options.destroyOnClose)
      this.setDestroyOnClose(true);

    this._getWindowBorderSize();
    this.width = this.options.width;
    this.height = this.options.height;
    this.visible = false;
    
    this.constraint = false;
    this.constraintPad = {top: 0, left:0, bottom:0, right:0};
    
    if (this.width && this.height)
      this.setSize(this.options.width, this.options.height);
    this.setTitle(this.options.title)
    Windows.register(this);      
  },
  
  // Destructor
  destroy: function() {
    this._notify("onDestroy");
    Event.stopObserving(this.topbar, "mousedown", this.eventMouseDown);
    Event.stopObserving(this.bottombar, "mousedown", this.eventMouseDown);
    Event.stopObserving(this.content, "mousedown", this.eventMouseDownContent);
    
    Event.stopObserving(window, "load", this.eventOnLoad);
    Event.stopObserving(window, "resize", this.eventResize);
    Event.stopObserving(window, "scroll", this.eventResize);
    
    Event.stopObserving(this.content, "load", this.options.onload);

    if (this._oldParent) {
      var content = this.getContent();
      var originalContent = null;
      for(var i = 0; i < content.childNodes.length; i++) {
        originalContent = content.childNodes[i];
        if (originalContent.nodeType == 1) 
          break;
        originalContent = null;
      }
      if (originalContent)
        this._oldParent.appendChild(originalContent);
      this._oldParent = null;
    }

    if (this.sizer)
        Event.stopObserving(this.sizer, "mousedown", this.eventMouseDown);

    if (this.options.url) 
      this.content.src = null

     if(this.iefix) 
      Element.remove(this.iefix);

    Element.remove(this.element);
    Windows.unregister(this);      
  },
    
  // Sets close callback, if it sets, it should return true to be able to close the window.
  setCloseCallback: function(callback) {
    this.options.closeCallback = callback;
  },
  
  // Gets window content
  getContent: function () {
    return this.content;
  },
  
  // Sets the content with an element id
  setContent: function(id, autoresize, autoposition) {
    var element = $(id);
    if (null == element) throw "Unable to find element '" + id + "' in DOM";
    this._oldParent = element.parentNode;

    var d = null;
    var p = null;

    if (autoresize) 
      d = Element.getDimensions(element);
    if (autoposition) 
      p = Position.cumulativeOffset(element);

    var content = this.getContent();
    // Clear HTML (and even iframe)
    this.setHTMLContent("");
    content = this.getContent();
    
    content.appendChild(element);
    element.show();
    if (autoresize) 
      this.setSize(d.width, d.height);
    if (autoposition) 
      this.setLocation(p[1] - this.heightN, p[0] - this.widthW);    
  },
  
  setHTMLContent: function(html) {
    // It was an url (iframe), recreate a div content instead of iframe content
    if (this.options.url) {
      this.content.src = null;
      this.options.url = null;
      
  	  var content ="<div id=\"" + this.getId() + "_content\" class=\"" + this.options.className + "_content\"> </div>";
      $(this.getId() +"_table_content").innerHTML = content;
      
      this.content = $(this.element.id + "_content");
    }
      
    this.getContent().innerHTML = html;
  },
  
  setAjaxContent: function(url, options, showCentered, showModal) {
    this.showFunction = showCentered ? "showCenter" : "show";
    this.showModal = showModal || false;
  
    options = options || {};

    // Clear HTML (and even iframe)
    this.setHTMLContent("");
 
    this.onComplete = options.onComplete;
    if (! this._onCompleteHandler)
      this._onCompleteHandler = this._setAjaxContent.bind(this);
    options.onComplete = this._onCompleteHandler;

    new Ajax.Request(url, options);    
    options.onComplete = this.onComplete;
  },
  
  _setAjaxContent: function(originalRequest) {
    Element.update(this.getContent(), originalRequest.responseText);
    if (this.onComplete)
      this.onComplete(originalRequest);
    this.onComplete = null;
    this[this.showFunction](this.showModal)
  },
  
  setURL: function(url) {
    // Not an url content, change div to iframe
    if (this.options.url) 
      this.content.src = null;
    this.options.url = url;
    var content= "<iframe frameborder='0' name='" + this.getId() + "_content'  id='" + this.getId() + "_content' src='" + url + "' width='" + this.width + "' height='" + this.height + "'> </iframe>";
    $(this.getId() +"_table_content").innerHTML = content;
    
    this.content = $(this.element.id + "_content");
  },

  getURL: function() {
  	return this.options.url ? this.options.url : null;
  },

  refresh: function() {
    if (this.options.url)
	    $(this.element.getAttribute('id') + '_content').src = this.options.url;
  },
  
  // Stores position/size in a cookie, by default named with window id
  setCookie: function(name, expires, path, domain, secure) {
    name = name || this.element.id;
    this.cookie = [name, expires, path, domain, secure];
    
    // Get cookie
    var value = WindowUtilities.getCookie(name)
    // If exists
    if (value) {
      var values = value.split(',');
      var x = values[0].split(':');
      var y = values[1].split(':');

      var w = parseFloat(values[2]), h = parseFloat(values[3]);
      var mini = values[4];
      var maxi = values[5];

      this.setSize(w, h);
      if (mini == "true")
        this.doMinimize = true; // Minimize will be done at onload window event
      else if (maxi == "true")
        this.doMaximize = true; // Maximize will be done at onload window event

      this.useLeft = x[0] == "l";
      this.useTop = y[0] == "t";

      this.element.setStyle(this.useLeft ? {left: x[1]} : {right: x[1]});
      this.element.setStyle(this.useTop ? {top: y[1]} : {bottom: y[1]});
    }
  },
  
  // Gets window ID
  getId: function() {
    return this.element.id;
  },
  
  // Detroys itself when closing 
  setDestroyOnClose: function() {
    this.options.destroyOnClose = true;
  },
  
  setConstraint: function(bool, padding) {
    this.constraint = bool;
    this.constraintPad = Object.extend(this.constraintPad, padding || {});
    // Reset location to apply constraint
    if (this.useTop && this.useLeft)
      this.setLocation(parseFloat(this.element.style.top), parseFloat(this.element.style.left));
  },
  
  // initDrag event

  _initDrag: function(event) {
    // No resize on minimized window
    if (Event.element(event) == this.sizer && this.isMinimized())
      return;

    // No move on maximzed window
    if (Event.element(event) != this.sizer && this.isMaximized())
      return;
      
    if (Prototype.Browser.IE && this.heightN == 0)
      this._getWindowBorderSize();
    
    // Get pointer X,Y
    this.pointer = [this._round(Event.pointerX(event), this.options.gridX), this._round(Event.pointerY(event), this.options.gridY)];
    if (this.options.wiredDrag) 
      this.currentDrag = this._createWiredElement();
    else
      this.currentDrag = this.element;
      
    // Resize
    if (Event.element(event) == this.sizer) {
      this.doResize = true;
      this.widthOrg = this.width;
      this.heightOrg = this.height;
      this.bottomOrg = parseFloat(this.element.getStyle('bottom'));
      this.rightOrg = parseFloat(this.element.getStyle('right'));
      this._notify("onStartResize");
    }
    else {
      this.doResize = false;

      // Check if click on close button, 
      var closeButton = $(this.getId() + '_close');
      if (closeButton && Position.within(closeButton, this.pointer[0], this.pointer[1])) {
        this.currentDrag = null;
        return;
      }

      this.toFront();

      if (! this.options.draggable) 
        return;
      this._notify("onStartMove");
    }    
    // Register global event to capture mouseUp and mouseMove
    Event.observe(document, "mouseup", this.eventMouseUp, false);
    Event.observe(document, "mousemove", this.eventMouseMove, false);
    
    // Add an invisible div to keep catching mouse event over iframes
    WindowUtilities.disableScreen('__invisible__', '__invisible__', this.overlayOpacity);

    // Stop selection while dragging
    document.body.ondrag = function () { return false; };
    document.body.onselectstart = function () { return false; };
    
    this.currentDrag.show();
    Event.stop(event);
  },
  
  _round: function(val, round) {
    return round == 1 ? val  : val = Math.floor(val / round) * round;
  },

  // updateDrag event
  _updateDrag: function(event) {
    var pointer =  [this._round(Event.pointerX(event), this.options.gridX), this._round(Event.pointerY(event), this.options.gridY)];  
    var dx = pointer[0] - this.pointer[0];
    var dy = pointer[1] - this.pointer[1];
    
    // Resize case, update width/height
    if (this.doResize) {
      var w = this.widthOrg + dx;
      var h = this.heightOrg + dy;
      
      dx = this.width - this.widthOrg
      dy = this.height - this.heightOrg
      
      // Check if it's a right position, update it to keep upper-left corner at the same position
      if (this.useLeft) 
        w = this._updateWidthConstraint(w)
      else 
        this.currentDrag.setStyle({right: (this.rightOrg -dx) + 'px'});
      // Check if it's a bottom position, update it to keep upper-left corner at the same position
      if (this.useTop) 
        h = this._updateHeightConstraint(h)
      else
        this.currentDrag.setStyle({bottom: (this.bottomOrg -dy) + 'px'});
        
      this.setSize(w , h);
      this._notify("onResize");
    }
    // Move case, update top/left
    else {
      this.pointer = pointer;
      
      if (this.useLeft) {
        var left =  parseFloat(this.currentDrag.getStyle('left')) + dx;
        var newLeft = this._updateLeftConstraint(left);
        // Keep mouse pointer correct
        this.pointer[0] += newLeft-left;
        this.currentDrag.setStyle({left: newLeft + 'px'});
      }
      else 
        this.currentDrag.setStyle({right: parseFloat(this.currentDrag.getStyle('right')) - dx + 'px'});
      
      if (this.useTop) {
        var top =  parseFloat(this.currentDrag.getStyle('top')) + dy;
        var newTop = this._updateTopConstraint(top);
        // Keep mouse pointer correct
        this.pointer[1] += newTop - top;
        this.currentDrag.setStyle({top: newTop + 'px'});
      }
      else 
        this.currentDrag.setStyle({bottom: parseFloat(this.currentDrag.getStyle('bottom')) - dy + 'px'});

      this._notify("onMove");
    }
    if (this.iefix) 
      this._fixIEOverlapping(); 
      
    this._removeStoreLocation();
    Event.stop(event);
  },

   // endDrag callback
   _endDrag: function(event) {
    // Remove temporary div over iframes
     WindowUtilities.enableScreen('__invisible__');
    
    if (this.doResize)
      this._notify("onEndResize");
    else
      this._notify("onEndMove");
    
    // Release event observing
    Event.stopObserving(document, "mouseup", this.eventMouseUp,false);
    Event.stopObserving(document, "mousemove", this.eventMouseMove, false);

    Event.stop(event);
    
    this._hideWiredElement();

    // Store new location/size if need be
    this._saveCookie()
      
    // Restore selection
    document.body.ondrag = null;
    document.body.onselectstart = null;
  },

  _updateLeftConstraint: function(left) {
    if (this.constraint && this.useLeft && this.useTop) {
      var width = this.options.parent == document.body ? WindowUtilities.getPageSize().windowWidth : this.options.parent.getDimensions().width;

      if (left < this.constraintPad.left)
        left = this.constraintPad.left;
      if (left + this.width + this.widthE + this.widthW > width - this.constraintPad.right) 
        left = width - this.constraintPad.right - this.width - this.widthE - this.widthW;
    }
    return left;
  },
  
  _updateTopConstraint: function(top) {
    if (this.constraint && this.useLeft && this.useTop) {        
      var height = this.options.parent == document.body ? WindowUtilities.getPageSize().windowHeight : this.options.parent.getDimensions().height;
      
      var h = this.height + this.heightN + this.heightS;

      if (top < this.constraintPad.top)
        top = this.constraintPad.top;
      if (top + h > height - this.constraintPad.bottom) 
        top = height - this.constraintPad.bottom - h;
    }
    return top;
  },
  
  _updateWidthConstraint: function(w) {
    if (this.constraint && this.useLeft && this.useTop) {
      var width = this.options.parent == document.body ? WindowUtilities.getPageSize().windowWidth : this.options.parent.getDimensions().width;
      var left =  parseFloat(this.element.getStyle("left"));

      if (left + w + this.widthE + this.widthW > width - this.constraintPad.right) 
        w = width - this.constraintPad.right - left - this.widthE - this.widthW;
    }
    return w;
  },
  
  _updateHeightConstraint: function(h) {
    if (this.constraint && this.useLeft && this.useTop) {
      var height = this.options.parent == document.body ? WindowUtilities.getPageSize().windowHeight : this.options.parent.getDimensions().height;
      var top =  parseFloat(this.element.getStyle("top"));

      if (top + h + this.heightN + this.heightS > height - this.constraintPad.bottom) 
        h = height - this.constraintPad.bottom - top - this.heightN - this.heightS;
    }
    return h;
  },
  
  
  // Creates HTML window code
  _createWindow: function(id) {
    var className = this.options.className;
    var win = document.createElement("div");
    win.setAttribute('id', id);
    win.className = "dialog";

    var content;
    if (this.options.url)
      content= "<iframe frameborder=\"0\" name=\"" + id + "_content\"  id=\"" + id + "_content\" src=\"" + this.options.url + "\"> </iframe>";
    else
      content ="<div id=\"" + id + "_content\" class=\"" +className + "_content\"> </div>";

    var closeDiv = this.options.closable ? "<div class='"+ className +"_close' id='"+ id +"_close' onclick='Windows.close(\""+ id +"\", event)'> </div>" : "";
    var minDiv = this.options.minimizable ? "<div class='"+ className + "_minimize' id='"+ id +"_minimize' onclick='Windows.minimize(\""+ id +"\", event)'> </div>" : "";
    var maxDiv = this.options.maximizable ? "<div class='"+ className + "_maximize' id='"+ id +"_maximize' onclick='Windows.maximize(\""+ id +"\", event)'> </div>" : "";
    var seAttributes = this.options.resizable ? "class='" + className + "_sizer' id='" + id + "_sizer'" : "class='"  + className + "_se'";
    var blank = "../themes/default/blank.gif";
    
    win.innerHTML = closeDiv + minDiv + maxDiv + "\
      <table id='"+ id +"_row1' class=\"top table_window\">\
        <tr>\
          <td class='"+ className +"_nw'></td>\
          <td class='"+ className +"_n'><div id='"+ id +"_top' class='"+ className +"_title title_window'>"+ this.options.title +"</div></td>\
          <td class='"+ className +"_ne'></td>\
        </tr>\
      </table>\
      <table id='"+ id +"_row2' class=\"mid table_window\">\
        <tr>\
          <td class='"+ className +"_w'></td>\
            <td id='"+ id +"_table_content' class='"+ className +"_content' valign='top'>" + content + "</td>\
          <td class='"+ className +"_e'></td>\
        </tr>\
      </table>\
        <table id='"+ id +"_row3' class=\"bot table_window\">\
        <tr>\
          <td class='"+ className +"_sw'></td>\
            <td class='"+ className +"_s'><div id='"+ id +"_bottom' class='status_bar'><span style='float:left; width:1px; height:1px'></span></div></td>\
            <td " + seAttributes + "></td>\
        </tr>\
      </table>\
    ";
    Element.hide(win);
    this.options.parent.insertBefore(win, this.options.parent.firstChild);
    Event.observe($(id + "_content"), "load", this.options.onload);
    return win;
  },
  
  
  changeClassName: function(newClassName) {    
    var className = this.options.className;
    var id = this.getId();
    $A(["_close", "_minimize", "_maximize", "_sizer", "_content"]).each(function(value) { this._toggleClassName($(id + value), className + value, newClassName + value) }.bind(this));
    this._toggleClassName($(id + "_top"), className + "_title", newClassName + "_title");
    $$("#" + id + " td").each(function(td) {td.className = td.className.sub(className,newClassName); });
    this.options.className = newClassName;
  },
  
  _toggleClassName: function(element, oldClassName, newClassName) { 
    if (element) {
      element.removeClassName(oldClassName);
      element.addClassName(newClassName);
    }
  },
  
  // Sets window location
  setLocation: function(top, left) {
    top = this._updateTopConstraint(top);
    left = this._updateLeftConstraint(left);

    var e = this.currentDrag || this.element;
    e.setStyle({top: top + 'px'});
    e.setStyle({left: left + 'px'});

    this.useLeft = true;
    this.useTop = true;
  },
    
  getLocation: function() {
    var location = {};
    if (this.useTop)
      location = Object.extend(location, {top: this.element.getStyle("top")});
    else
      location = Object.extend(location, {bottom: this.element.getStyle("bottom")});
    if (this.useLeft)
      location = Object.extend(location, {left: this.element.getStyle("left")});
    else
      location = Object.extend(location, {right: this.element.getStyle("right")});
    
    return location;
  },
  
  // Gets window size
  getSize: function() {
    return {width: this.width, height: this.height};
  },
    
  // Sets window size
  setSize: function(width, height, useEffect) {    
    width = parseFloat(width);
    height = parseFloat(height);
    
    // Check min and max size
    if (!this.minimized && width < this.options.minWidth)
      width = this.options.minWidth;

    if (!this.minimized && height < this.options.minHeight)
      height = this.options.minHeight;
      
    if (this.options. maxHeight && height > this.options. maxHeight)
      height = this.options. maxHeight;

    if (this.options. maxWidth && width > this.options. maxWidth)
      width = this.options. maxWidth;

    
    if (this.useTop && this.useLeft && Window.hasEffectLib && Effect.ResizeWindow && useEffect) {
      new Effect.ResizeWindow(this, null, null, width, height, {duration: Window.resizeEffectDuration});
    } else {
      this.width = width;
      this.height = height;
      var e = this.currentDrag ? this.currentDrag : this.element;

      e.setStyle({width: width + this.widthW + this.widthE + "px"})
      e.setStyle({height: height  + this.heightN + this.heightS + "px"})

      // Update content size
      if (!this.currentDrag || this.currentDrag == this.element) {
        var content = $(this.element.id + '_content');
        content.setStyle({height: height  + 'px'});
        content.setStyle({width: width  + 'px'});
      }
    }
  },
  
  updateHeight: function() {
    this.setSize(this.width, this.content.scrollHeight, true);
  },
  
  updateWidth: function() {
    this.setSize(this.content.scrollWidth, this.height, true);
  },
  
  // Brings window to front
  toFront: function() {
    if (this.element.style.zIndex < Windows.maxZIndex)  
      this.setZIndex(Windows.maxZIndex + 1);
    if (this.iefix) 
      this._fixIEOverlapping(); 
  },
   
  getBounds: function(insideOnly) {
    if (! this.width || !this.height || !this.visible)  
      this.computeBounds();
    var w = this.width;
    var h = this.height;

    if (!insideOnly) {
      w += this.widthW + this.widthE;
      h += this.heightN + this.heightS;
    }
    var bounds = Object.extend(this.getLocation(), {width: w + "px", height: h + "px"});
    return bounds;
  },
      
  computeBounds: function() {
     if (! this.width || !this.height) {
      var size = WindowUtilities._computeSize(this.content.innerHTML, this.content.id, this.width, this.height, 0, this.options.className)
      if (this.height)
        this.width = size + 5
      else
        this.height = size + 5
    }

    this.setSize(this.width, this.height);
    if (this.centered)
      this._center(this.centerTop, this.centerLeft);    
  },
  
  // Displays window modal state or not
  show: function(modal) {
    this.visible = true;
    if (modal) {
      // Hack for Safari !!
      if (typeof this.overlayOpacity == "undefined") {
        var that = this;
        setTimeout(function() {that.show(modal)}, 10);
        return;
      }
      Windows.addModalWindow(this);
      
      this.modal = true;      
      this.setZIndex(Windows.maxZIndex + 1);
      Windows.unsetOverflow(this);
    }
    else    
      if (!this.element.style.zIndex) 
        this.setZIndex(Windows.maxZIndex + 1);        
      
    // To restore overflow if need be
    if (this.oldStyle)
      this.getContent().setStyle({overflow: this.oldStyle});
      
    this.computeBounds();
    
    this._notify("onBeforeShow");   
    if (this.options.showEffect != Element.show && this.options.showEffectOptions)
      this.options.showEffect(this.element, this.options.showEffectOptions);  
    else
      this.options.showEffect(this.element);  
      
    this._checkIEOverlapping();
    WindowUtilities.focusedWindow = this
    this._notify("onShow");   
  },
  
  // Displays window modal state or not at the center of the page
  showCenter: function(modal, top, left) {
    this.centered = true;
    this.centerTop = top;
    this.centerLeft = left;

    this.show(modal);
  },
  
  isVisible: function() {
    return this.visible;
  },
  
  _center: function(top, left) {    
    var windowScroll = WindowUtilities.getWindowScroll(this.options.parent);    
    var pageSize = WindowUtilities.getPageSize(this.options.parent);    
    if (typeof top == "undefined")
      top = (pageSize.windowHeight - (this.height + this.heightN + this.heightS))/2;
    top += windowScroll.top
    
    if (typeof left == "undefined")
      left = (pageSize.windowWidth - (this.width + this.widthW + this.widthE))/2;
    left += windowScroll.left      
    this.setLocation(top, left);
    this.toFront();
  },
  
  _recenter: function(event) {     
    if (this.centered) {
      var pageSize = WindowUtilities.getPageSize(this.options.parent);
      var windowScroll = WindowUtilities.getWindowScroll(this.options.parent);    

      // Check for this stupid IE that sends dumb events
      if (this.pageSize && this.pageSize.windowWidth == pageSize.windowWidth && this.pageSize.windowHeight == pageSize.windowHeight && 
          this.windowScroll.left == windowScroll.left && this.windowScroll.top == windowScroll.top) 
        return;
      this.pageSize = pageSize;
      this.windowScroll = windowScroll;
      // set height of Overlay to take up whole page and show
      if ($('overlay_modal')) 
        $('overlay_modal').setStyle({height: (pageSize.pageHeight + 'px')});
      
      if (this.options.recenterAuto)
        this._center(this.centerTop, this.centerLeft);    
    }
  },
  
  // Hides window
  hide: function() {
    this.visible = false;
    if (this.modal) {
      Windows.removeModalWindow(this);
      Windows.resetOverflow();
    }
    // To avoid bug on scrolling bar
    this.oldStyle = this.getContent().getStyle('overflow') || "auto"
    this.getContent().setStyle({overflow: "hidden"});

    this.options.hideEffect(this.element, this.options.hideEffectOptions);  

     if(this.iefix) 
      this.iefix.hide();

    if (!this.doNotNotifyHide)
      this._notify("onHide");
  },

  close: function() {
    // Asks closeCallback if exists
    if (this.visible) {
      if (this.options.closeCallback && ! this.options.closeCallback(this)) 
        return;

      if (this.options.destroyOnClose) {
        var destroyFunc = this.destroy.bind(this);
        if (this.options.hideEffectOptions.afterFinish) {
          var func = this.options.hideEffectOptions.afterFinish;
          this.options.hideEffectOptions.afterFinish = function() {func();destroyFunc() }
        }
        else 
          this.options.hideEffectOptions.afterFinish = function() {destroyFunc() }
      }
      Windows.updateFocusedWindow();
      
      this.doNotNotifyHide = true;
      this.hide();
      this.doNotNotifyHide = false;
      this._notify("onClose");
    }
  },
  
  minimize: function() {
    if (this.resizing)
      return;
    
    var r2 = $(this.getId() + "_row2");
    
    if (!this.minimized) {
      this.minimized = true;

      var dh = r2.getDimensions().height;
      this.r2Height = dh;
      var h  = this.element.getHeight() - dh;

      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
        new Effect.ResizeWindow(this, null, null, null, this.height -dh, {duration: Window.resizeEffectDuration});
      } else  {
        this.height -= dh;
        this.element.setStyle({height: h + "px"});
        r2.hide();
      }

      if (! this.useTop) {
        var bottom = parseFloat(this.element.getStyle('bottom'));
        this.element.setStyle({bottom: (bottom + dh) + 'px'});
      }
    } 
    else {      
      this.minimized = false;
      
      var dh = this.r2Height;
      this.r2Height = null;
      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
        new Effect.ResizeWindow(this, null, null, null, this.height + dh, {duration: Window.resizeEffectDuration});
      }
      else {
        var h  = this.element.getHeight() + dh;
        this.height += dh;
        this.element.setStyle({height: h + "px"})
        r2.show();
      }
      if (! this.useTop) {
        var bottom = parseFloat(this.element.getStyle('bottom'));
        this.element.setStyle({bottom: (bottom - dh) + 'px'});
      }
      this.toFront();
    }
    this._notify("onMinimize");
    
    // Store new location/size if need be
    this._saveCookie()
  },
  
  maximize: function() {
    if (this.isMinimized() || this.resizing)
      return;
  
    if (Prototype.Browser.IE && this.heightN == 0)
      this._getWindowBorderSize();
      
    if (this.storedLocation != null) {
      this._restoreLocation();
      if(this.iefix) 
        this.iefix.hide();
    }
    else {
      this._storeLocation();
      Windows.unsetOverflow(this);
      
      var windowScroll = WindowUtilities.getWindowScroll(this.options.parent);
      var pageSize = WindowUtilities.getPageSize(this.options.parent);    
      var left = windowScroll.left;
      var top = windowScroll.top;
      
      if (this.options.parent != document.body) {
        windowScroll =  {top:0, left:0, bottom:0, right:0};
        var dim = this.options.parent.getDimensions();
        pageSize.windowWidth = dim.width;
        pageSize.windowHeight = dim.height;
        top = 0; 
        left = 0;
      }
      
      if (this.constraint) {
        pageSize.windowWidth -= Math.max(0, this.constraintPad.left) + Math.max(0, this.constraintPad.right);
        pageSize.windowHeight -= Math.max(0, this.constraintPad.top) + Math.max(0, this.constraintPad.bottom);
        left +=  Math.max(0, this.constraintPad.left);
        top +=  Math.max(0, this.constraintPad.top);
      }
      
      var width = pageSize.windowWidth - this.widthW - this.widthE;
      var height= pageSize.windowHeight - this.heightN - this.heightS;

      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow) {
        new Effect.ResizeWindow(this, top, left, width, height, {duration: Window.resizeEffectDuration});
      }
      else {
        this.setSize(width, height);
        this.element.setStyle(this.useLeft ? {left: left} : {right: left});
        this.element.setStyle(this.useTop ? {top: top} : {bottom: top});
      }
        
      this.toFront();
      if (this.iefix) 
        this._fixIEOverlapping(); 
    }
    this._notify("onMaximize");

    // Store new location/size if need be
    this._saveCookie()
  },
  
  isMinimized: function() {
    return this.minimized;
  },
  
  isMaximized: function() {
    return (this.storedLocation != null);
  },
  
  setOpacity: function(opacity) {
    if (Element.setOpacity)
      Element.setOpacity(this.element, opacity);
  },
  
  setZIndex: function(zindex) {
    this.element.setStyle({zIndex: zindex});
    Windows.updateZindex(zindex, this);
  },

  setTitle: function(newTitle) {
    if (!newTitle || newTitle == "") 
      newTitle = "&nbsp;";
      
    Element.update(this.element.id + '_top', newTitle);
  },
   
  getTitle: function() {
    return $(this.element.id + '_top').innerHTML;
  },
  
  setStatusBar: function(element) {
    var statusBar = $(this.getId() + "_bottom");

    if (typeof(element) == "object") {
      if (this.bottombar.firstChild)
        this.bottombar.replaceChild(element, this.bottombar.firstChild);
      else
        this.bottombar.appendChild(element);
    }
    else
      this.bottombar.innerHTML = element;
  },

  _checkIEOverlapping: function() {
    if(!this.iefix && (navigator.appVersion.indexOf('MSIE')>0) && (navigator.userAgent.indexOf('Opera')<0) && (this.element.getStyle('position')=='absolute')) {
        new Insertion.After(this.element.id, '<iframe id="' + this.element.id + '_iefix" '+ 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' + 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
        this.iefix = $(this.element.id+'_iefix');
    }
    if(this.iefix) 
      setTimeout(this._fixIEOverlapping.bind(this), 50);
  },

  _fixIEOverlapping: function() {
      Position.clone(this.element, this.iefix);
      this.iefix.style.zIndex = this.element.style.zIndex - 1;
      this.iefix.show();
  },
  
  _getWindowBorderSize: function(event) {
    // Hack to get real window border size!!
    var div = this._createHiddenDiv(this.options.className + "_n")
    this.heightN = Element.getDimensions(div).height;    
    div.parentNode.removeChild(div)

    var div = this._createHiddenDiv(this.options.className + "_s")
    this.heightS = Element.getDimensions(div).height;    
    div.parentNode.removeChild(div)

    var div = this._createHiddenDiv(this.options.className + "_e")
    this.widthE = Element.getDimensions(div).width;    
    div.parentNode.removeChild(div)

    var div = this._createHiddenDiv(this.options.className + "_w")
    this.widthW = Element.getDimensions(div).width;
    div.parentNode.removeChild(div);
    
    var div = document.createElement("div");
    div.className = "overlay_" + this.options.className ;
    document.body.appendChild(div);
    //alert("no timeout:\nopacity: " + div.getStyle("opacity") + "\nwidth: " + document.defaultView.getComputedStyle(div, null).width);
    var that = this;
    
    // Workaround for Safari!!
    setTimeout(function() {that.overlayOpacity = ($(div).getStyle("opacity")); div.parentNode.removeChild(div);}, 10);
    
    // Workaround for IE!!
    if (Prototype.Browser.IE) {
      this.heightS = $(this.getId() +"_row3").getDimensions().height;
      this.heightN = $(this.getId() +"_row1").getDimensions().height;
    }

    // Safari size fix
    if (Prototype.Browser.WebKit && Prototype.Browser.WebKitVersion < 420)
      this.setSize(this.width, this.height);
    if (this.doMaximize)
      this.maximize();
    if (this.doMinimize)
      this.minimize();
  },
 
  _createHiddenDiv: function(className) {
    var objBody = document.body;
    var win = document.createElement("div");
    win.setAttribute('id', this.element.id+ "_tmp");
    win.className = className;
    win.style.display = 'none';
    win.innerHTML = '';
    objBody.insertBefore(win, objBody.firstChild);
    return win;
  },
  
  _storeLocation: function() {
    if (this.storedLocation == null) {
      this.storedLocation = {useTop: this.useTop, useLeft: this.useLeft, 
                             top: this.element.getStyle('top'), bottom: this.element.getStyle('bottom'),
                             left: this.element.getStyle('left'), right: this.element.getStyle('right'),
                             width: this.width, height: this.height };
    }
  },
  
  _restoreLocation: function() {
    if (this.storedLocation != null) {
      this.useLeft = this.storedLocation.useLeft;
      this.useTop = this.storedLocation.useTop;
      
      if (this.useLeft && this.useTop && Window.hasEffectLib && Effect.ResizeWindow)
        new Effect.ResizeWindow(this, this.storedLocation.top, this.storedLocation.left, this.storedLocation.width, this.storedLocation.height, {duration: Window.resizeEffectDuration});
      else {
        this.element.setStyle(this.useLeft ? {left: this.storedLocation.left} : {right: this.storedLocation.right});
        this.element.setStyle(this.useTop ? {top: this.storedLocation.top} : {bottom: this.storedLocation.bottom});
        this.setSize(this.storedLocation.width, this.storedLocation.height);
      }
      
      Windows.resetOverflow();
      this._removeStoreLocation();
    }
  },
  
  _removeStoreLocation: function() {
    this.storedLocation = null;
  },
  
  _saveCookie: function() {
    if (this.cookie) {
      var value = "";
      if (this.useLeft)
        value += "l:" +  (this.storedLocation ? this.storedLocation.left : this.element.getStyle('left'))
      else
        value += "r:" + (this.storedLocation ? this.storedLocation.right : this.element.getStyle('right'))
      if (this.useTop)
        value += ",t:" + (this.storedLocation ? this.storedLocation.top : this.element.getStyle('top'))
      else
        value += ",b:" + (this.storedLocation ? this.storedLocation.bottom :this.element.getStyle('bottom'))
        
      value += "," + (this.storedLocation ? this.storedLocation.width : this.width);
      value += "," + (this.storedLocation ? this.storedLocation.height : this.height);
      value += "," + this.isMinimized();
      value += "," + this.isMaximized();
      WindowUtilities.setCookie(value, this.cookie)
    }
  },
  
  _createWiredElement: function() {
    if (! this.wiredElement) {
      if (Prototype.Browser.IE)
        this._getWindowBorderSize();
      var div = document.createElement("div");
      div.className = "wired_frame " + this.options.className + "_wired_frame";
      
      div.style.position = 'absolute';
      this.options.parent.insertBefore(div, this.options.parent.firstChild);
      this.wiredElement = $(div);
    }
    if (this.useLeft) 
      this.wiredElement.setStyle({left: this.element.getStyle('left')});
    else 
      this.wiredElement.setStyle({right: this.element.getStyle('right')});
      
    if (this.useTop) 
      this.wiredElement.setStyle({top: this.element.getStyle('top')});
    else 
      this.wiredElement.setStyle({bottom: this.element.getStyle('bottom')});

    var dim = this.element.getDimensions();
    this.wiredElement.setStyle({width: dim.width + "px", height: dim.height +"px"});

    this.wiredElement.setStyle({zIndex: Windows.maxZIndex+30});
    return this.wiredElement;
  },
  
  _hideWiredElement: function() {
    if (! this.wiredElement || ! this.currentDrag)
      return;
    if (this.currentDrag == this.element) 
      this.currentDrag = null;
    else {
      if (this.useLeft) 
        this.element.setStyle({left: this.currentDrag.getStyle('left')});
      else 
        this.element.setStyle({right: this.currentDrag.getStyle('right')});

      if (this.useTop) 
        this.element.setStyle({top: this.currentDrag.getStyle('top')});
      else 
        this.element.setStyle({bottom: this.currentDrag.getStyle('bottom')});

      this.currentDrag.hide();
      this.currentDrag = null;
      if (this.doResize)
        this.setSize(this.width, this.height);
    } 
  },
  
  _notify: function(eventName) {
    if (this.options[eventName])
      this.options[eventName](this);
    else
      Windows.notify(eventName, this);
  }
};

// Windows containers, register all page windows
var Windows = {
  windows: [],
  modalWindows: [],
  observers: [],
  focusedWindow: null,
  maxZIndex: 0,
  overlayShowEffectOptions: {duration: 0.5},
  overlayHideEffectOptions: {duration: 0.5},

  addObserver: function(observer) {
    this.removeObserver(observer);
    this.observers.push(observer);
  },
  
  removeObserver: function(observer) {  
    this.observers = this.observers.reject( function(o) { return o==observer });
  },
  
  // onDestroy onStartResize onStartMove onResize onMove onEndResize onEndMove onFocus onBlur onBeforeShow onShow onHide onMinimize onMaximize onClose
  notify: function(eventName, win) {  
    this.observers.each( function(o) {if(o[eventName]) o[eventName](eventName, win);});
  },

  // Gets window from its id
  getWindow: function(id) {
    return this.windows.detect(function(d) { return d.getId() ==id });
  },

  // Gets the last focused window
  getFocusedWindow: function() {
    return this.focusedWindow;
  },

  updateFocusedWindow: function() {
    this.focusedWindow = this.windows.length >=2 ? this.windows[this.windows.length-2] : null;    
  },
  
  // Registers a new window (called by Windows constructor)
  register: function(win) {
    this.windows.push(win);
  },
    
  // Add a modal window in the stack
  addModalWindow: function(win) {
    // Disable screen if first modal window
    if (this.modalWindows.length == 0) {
      WindowUtilities.disableScreen(win.options.className, 'overlay_modal', win.overlayOpacity, win.getId(), win.options.parent);
    }
    else {
      // Move overlay over all windows
      if (Window.keepMultiModalWindow) {
        $('overlay_modal').style.zIndex = Windows.maxZIndex + 1;
        Windows.maxZIndex += 1;
        WindowUtilities._hideSelect(this.modalWindows.last().getId());
      }
      // Hide current modal window
      else
        this.modalWindows.last().element.hide();
      // Fucking IE select issue
      WindowUtilities._showSelect(win.getId());
    }      
    this.modalWindows.push(win);    
  },
  
  removeModalWindow: function(win) {
    this.modalWindows.pop();
    
    // No more modal windows
    if (this.modalWindows.length == 0)
      WindowUtilities.enableScreen();     
    else {
      if (Window.keepMultiModalWindow) {
        this.modalWindows.last().toFront();
        WindowUtilities._showSelect(this.modalWindows.last().getId());        
      }
      else
        this.modalWindows.last().element.show();
    }
  },
  
  // Registers a new window (called by Windows constructor)
  register: function(win) {
    this.windows.push(win);
  },
  
  // Unregisters a window (called by Windows destructor)
  unregister: function(win) {
    this.windows = this.windows.reject(function(d) { return d==win });
  }, 
  
  // Closes all windows
  closeAll: function() {  
    this.windows.each( function(w) {Windows.close(w.getId())} );
  },
  
  closeAllModalWindows: function() {
    WindowUtilities.enableScreen();     
    this.modalWindows.each( function(win) {if (win) win.close()});    
  },

  // Minimizes a window with its id
  minimize: function(id, event) {
    var win = this.getWindow(id)
    if (win && win.visible)
      win.minimize();
    Event.stop(event);
  },
  
  // Maximizes a window with its id
  maximize: function(id, event) {
    var win = this.getWindow(id)
    if (win && win.visible)
      win.maximize();
    Event.stop(event);
  },

  // Closes a window with its id
  close: function(id, event) {
    var win = this.getWindow(id);
    if (win) 
      win.close();
    if (event)
      Event.stop(event);
  },
  
  blur: function(id) {
    var win = this.getWindow(id);  
    if (!win)
      return;
    if (win.options.blurClassName)
      win.changeClassName(win.options.blurClassName);
    if (this.focusedWindow == win)  
      this.focusedWindow = null;
    win._notify("onBlur");  
  },
  
  focus: function(id) {
    var win = this.getWindow(id);  
    if (!win)
      return;       
    if (this.focusedWindow)
      this.blur(this.focusedWindow.getId())

    if (win.options.focusClassName)
      win.changeClassName(win.options.focusClassName);  
    this.focusedWindow = win;
    win._notify("onFocus");
  },
  
  unsetOverflow: function(except) {    
    this.windows.each(function(d) { d.oldOverflow = d.getContent().getStyle("overflow") || "auto" ; d.getContent().setStyle({overflow: "hidden"}) });
    if (except && except.oldOverflow)
      except.getContent().setStyle({overflow: except.oldOverflow});
  },

  resetOverflow: function() {
    this.windows.each(function(d) { if (d.oldOverflow) d.getContent().setStyle({overflow: d.oldOverflow}) });
  },

  updateZindex: function(zindex, win) { 
    if (zindex > this.maxZIndex) {   
      this.maxZIndex = zindex;    
      if (this.focusedWindow) 
        this.blur(this.focusedWindow.getId())
    }
    this.focusedWindow = win;
    if (this.focusedWindow) 
      this.focus(this.focusedWindow.getId())
  }
};

var Dialog = {
  dialogId: null,
  onCompleteFunc: null,
  callFunc: null, 
  parameters: null, 
    
  confirm: function(content, parameters) {
    // Get Ajax return before
    if (content && typeof content != "string") {
      Dialog._runAjaxRequest(content, parameters, Dialog.confirm);
      return 
    }
    content = content || "";
    
    parameters = parameters || {};
    var okLabel = parameters.okLabel ? parameters.okLabel : "Ok";
    var cancelLabel = parameters.cancelLabel ? parameters.cancelLabel : "Cancel";

    // Backward compatibility
    parameters = Object.extend(parameters, parameters.windowParameters || {});
    parameters.windowParameters = parameters.windowParameters || {};

    parameters.className = parameters.className || "alert";

    var okButtonClass = "class ='" + (parameters.buttonClass ? parameters.buttonClass + " " : "") + " ok_button'" 
    var cancelButtonClass = "class ='" + (parameters.buttonClass ? parameters.buttonClass + " " : "") + " cancel_button'" 
    var content = "\
      <div class='" + parameters.className + "_message'>" + content  + "</div>\
        <div class='" + parameters.className + "_buttons'>\
          <input type='button' value='" + okLabel + "' onclick='Dialog.okCallback()' " + okButtonClass + "/>\
          <input type='button' value='" + cancelLabel + "' onclick='Dialog.cancelCallback()' " + cancelButtonClass + "/>\
        </div>\
    ";
    return this._openDialog(content, parameters)
  },
  
  alert: function(content, parameters) {
    // Get Ajax return before
    if (content && typeof content != "string") {
      Dialog._runAjaxRequest(content, parameters, Dialog.alert);
      return 
    }
    content = content || "";
    
    parameters = parameters || {};
    var okLabel = parameters.okLabel ? parameters.okLabel : "Ok";

    // Backward compatibility    
    parameters = Object.extend(parameters, parameters.windowParameters || {});
    parameters.windowParameters = parameters.windowParameters || {};
    
    parameters.className = parameters.className || "alert";
    
    var okButtonClass = "class ='" + (parameters.buttonClass ? parameters.buttonClass + " " : "") + " ok_button'" 
    var content = "\
      <div class='" + parameters.className + "_message'>" + content  + "</div>\
        <div class='" + parameters.className + "_buttons'>\
          <input type='button' value='" + okLabel + "' onclick='Dialog.okCallback()' " + okButtonClass + "/>\
        </div>";                  
    return this._openDialog(content, parameters)
  },
  
  info: function(content, parameters) {   
    // Get Ajax return before
    if (content && typeof content != "string") {
      Dialog._runAjaxRequest(content, parameters, Dialog.info);
      return 
    }
    content = content || "";
     
    // Backward compatibility
    parameters = parameters || {};
    parameters = Object.extend(parameters, parameters.windowParameters || {});
    parameters.windowParameters = parameters.windowParameters || {};
    
    parameters.className = parameters.className || "alert";
    
    var content = "<div id='modal_dialog_message' class='" + parameters.className + "_message'>" + content  + "</div>";
    if (parameters.showProgress)
      content += "<div id='modal_dialog_progress' class='" + parameters.className + "_progress'>  </div>";

    parameters.ok = null;
    parameters.cancel = null;
    
    return this._openDialog(content, parameters)
  },
  
  setInfoMessage: function(message) {
    $('modal_dialog_message').update(message);
  },
  
  closeInfo: function() {
    Windows.close(this.dialogId);
  },
  
  _openDialog: function(content, parameters) {
    var className = parameters.className;
    
    if (! parameters.height && ! parameters.width) {
      parameters.width = WindowUtilities.getPageSize(parameters.options.parent || document.body).pageWidth / 2;
    }
    if (parameters.id)
      this.dialogId = parameters.id;
    else { 
      var t = new Date();
      this.dialogId = 'modal_dialog_' + t.getTime();
      parameters.id = this.dialogId;
    }

    // compute height or width if need be
    if (! parameters.height || ! parameters.width) {
      var size = WindowUtilities._computeSize(content, this.dialogId, parameters.width, parameters.height, 5, className)
      if (parameters.height)
        parameters.width = size + 5
      else
        parameters.height = size + 5
    }
    parameters.effectOptions = parameters.effectOptions ;
    parameters.resizable   = parameters.resizable || false;
    parameters.minimizable = parameters.minimizable || false;
    parameters.maximizable = parameters.maximizable ||  false;
    parameters.draggable   = parameters.draggable || false;
    parameters.closable    = parameters.closable || false;
    
    var win = new Window(parameters);
    win.getContent().innerHTML = content;
    
    win.showCenter(true, parameters.top, parameters.left);  
    win.setDestroyOnClose();
    
    win.cancelCallback = parameters.onCancel || parameters.cancel; 
    win.okCallback = parameters.onOk || parameters.ok;
    
    return win;    
  },
  
  _getAjaxContent: function(originalRequest)  {
      Dialog.callFunc(originalRequest.responseText, Dialog.parameters)
  },
  
  _runAjaxRequest: function(message, parameters, callFunc) {
    if (message.options == null)
      message.options = {}  
    Dialog.onCompleteFunc = message.options.onComplete;
    Dialog.parameters = parameters;
    Dialog.callFunc = callFunc;
    
    message.options.onComplete = Dialog._getAjaxContent;
    new Ajax.Request(message.url, message.options);
  },
  
  okCallback: function() {
    var win = Windows.focusedWindow;
    if (!win.okCallback || win.okCallback(win)) {
      // Remove onclick on button
      $$("#" + win.getId()+" input").each(function(element) {element.onclick=null;})
      win.close();
    }
  },

  cancelCallback: function() {
    var win = Windows.focusedWindow;
    // Remove onclick on button
    $$("#" + win.getId()+" input").each(function(element) {element.onclick=null})
    win.close();
    if (win.cancelCallback)
      win.cancelCallback(win);
  }
}
/*
  Based on Lightbox JS: Fullsize Image Overlays 
  by Lokesh Dhakar - http://www.huddletogether.com

  For more information on this script, visit:
  http://huddletogether.com/projects/lightbox/

  Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
  (basically, do anything you want, just leave my name and link)
*/

if (Prototype.Browser.WebKit) {
  var array = navigator.userAgent.match(new RegExp(/AppleWebKit\/([\d\.\+]*)/));
  Prototype.Browser.WebKitVersion = parseFloat(array[1]);
}

var WindowUtilities = {  
  // From dragdrop.js
  getWindowScroll: function(parent) {
    var T, L, W, H;
    parent = parent || document.body;              
    if (parent != document.body) {
      T = parent.scrollTop;
      L = parent.scrollLeft;
      W = parent.scrollWidth;
      H = parent.scrollHeight;
    } 
    else {
      var w = window;
      with (w.document) {
        if (w.document.documentElement && documentElement.scrollTop) {
          T = documentElement.scrollTop;
          L = documentElement.scrollLeft;
        } else if (w.document.body) {
          T = body.scrollTop;
          L = body.scrollLeft;
        }
        if (w.innerWidth) {
          W = w.innerWidth;
          H = w.innerHeight;
        } else if (w.document.documentElement && documentElement.clientWidth) {
          W = documentElement.clientWidth;
          H = documentElement.clientHeight;
        } else {
          W = body.offsetWidth;
          H = body.offsetHeight
        }
      }
    }
    return { top: T, left: L, width: W, height: H };
  }, 
  //
  // getPageSize()
  // Returns array with page width, height and window width, height
  // Core code from - quirksmode.org
  // Edit for Firefox by pHaez
  //
  getPageSize: function(parent){
    parent = parent || document.body;              
    var windowWidth, windowHeight;
    var pageHeight, pageWidth;
    if (parent != document.body) {
      windowWidth = parent.getWidth();
      windowHeight = parent.getHeight();                                
      pageWidth = parent.scrollWidth;
      pageHeight = parent.scrollHeight;                                
    } 
    else {
      var xScroll, yScroll;

      if (window.innerHeight && window.scrollMaxY) {  
        xScroll = document.body.scrollWidth;
        yScroll = window.innerHeight + window.scrollMaxY;
      } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
        xScroll = document.body.scrollWidth;
        yScroll = document.body.scrollHeight;
      } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
        xScroll = document.body.offsetWidth;
        yScroll = document.body.offsetHeight;
      }


      if (self.innerHeight) {  // all except Explorer
        windowWidth = self.innerWidth;
        windowHeight = self.innerHeight;
      } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
        windowWidth = document.documentElement.clientWidth;
        windowHeight = document.documentElement.clientHeight;
      } else if (document.body) { // other Explorers
        windowWidth = document.body.clientWidth;
        windowHeight = document.body.clientHeight;
      }  

      // for small pages with total height less then height of the viewport
      if(yScroll < windowHeight){
        pageHeight = windowHeight;
      } else { 
        pageHeight = yScroll;
      }

      // for small pages with total width less then width of the viewport
      if(xScroll < windowWidth){  
        pageWidth = windowWidth;
      } else {
        pageWidth = xScroll;
      }
    }             
    return {pageWidth: pageWidth ,pageHeight: pageHeight , windowWidth: windowWidth, windowHeight: windowHeight};
  },

  disableScreen: function(className, overlayId, overlayOpacity, contentId, parent) {
    WindowUtilities.initLightbox(overlayId, className, function() {this._disableScreen(className, overlayId, overlayOpacity, contentId)}.bind(this), parent || document.body);
  },

  _disableScreen: function(className, overlayId, overlayOpacity, contentId) {
    // prep objects
    var objOverlay = $(overlayId);

    var pageSize = WindowUtilities.getPageSize(objOverlay.parentNode);

    // Hide select boxes as they will 'peek' through the image in IE, store old value
    if (contentId && Prototype.Browser.IE) {
      WindowUtilities._hideSelect();
      WindowUtilities._showSelect(contentId);
    }  
  
    // set height of Overlay to take up whole page and show
    objOverlay.style.height = (pageSize.pageHeight + 'px');
    objOverlay.style.display = 'none'; 
    if (overlayId == "overlay_modal" && Window.hasEffectLib && Windows.overlayShowEffectOptions) {
      objOverlay.overlayOpacity = overlayOpacity;
      new Effect.Appear(objOverlay, Object.extend({from: 0, to: overlayOpacity}, Windows.overlayShowEffectOptions));
    }
    else
      objOverlay.style.display = "block";
  },
  
  enableScreen: function(id) {
    id = id || 'overlay_modal';
    var objOverlay =  $(id);
    if (objOverlay) {
      // hide lightbox and overlay
      if (id == "overlay_modal" && Window.hasEffectLib && Windows.overlayHideEffectOptions)
        new Effect.Fade(objOverlay, Object.extend({from: objOverlay.overlayOpacity, to:0}, Windows.overlayHideEffectOptions));
      else {
        objOverlay.style.display = 'none';
        objOverlay.parentNode.removeChild(objOverlay);
      }
      
      // make select boxes visible using old value
      if (id != "__invisible__") 
        WindowUtilities._showSelect();
    }
  },

  _hideSelect: function(id) {
    if (Prototype.Browser.IE) {
      id = id ==  null ? "" : "#" + id + " ";
      $$(id + 'select').each(function(element) {
        if (! WindowUtilities.isDefined(element.oldVisibility)) {
          element.oldVisibility = element.style.visibility ? element.style.visibility : "visible";
          element.style.visibility = "hidden";
        }
      });
    }
  },
  
  _showSelect: function(id) {
    if (Prototype.Browser.IE) {
      id = id ==  null ? "" : "#" + id + " ";
      $$(id + 'select').each(function(element) {
        if (WindowUtilities.isDefined(element.oldVisibility)) {
          // Why?? Ask IE
          try {
            element.style.visibility = element.oldVisibility;
          } catch(e) {
            element.style.visibility = "visible";
          }
          element.oldVisibility = null;
        }
        else {
          if (element.style.visibility)
            element.style.visibility = "visible";
        }
      });
    }
  },

  isDefined: function(object) {
    return typeof(object) != "undefined" && object != null;
  },
  
  // initLightbox()
  // Function runs on window load, going through link tags looking for rel="lightbox".
  // These links receive onclick events that enable the lightbox display for their targets.
  // The function also inserts html markup at the top of the page which will be used as a
  // container for the overlay pattern and the inline image.
  initLightbox: function(id, className, doneHandler, parent) {
    // Already done, just update zIndex
    if ($(id)) {
      Element.setStyle(id, {zIndex: Windows.maxZIndex + 1});
      Windows.maxZIndex++;
      doneHandler();
    }
    // create overlay div and hardcode some functional styles (aesthetic styles are in CSS file)
    else {
      var objOverlay = document.createElement("div");
      objOverlay.setAttribute('id', id);
      objOverlay.className = "overlay_" + className
      objOverlay.style.display = 'none';
      objOverlay.style.position = 'absolute';
      objOverlay.style.top = '0';
      objOverlay.style.left = '0';
      objOverlay.style.zIndex = Windows.maxZIndex + 1;
      Windows.maxZIndex++;
      objOverlay.style.width = '100%';
      parent.insertBefore(objOverlay, parent.firstChild);
      if (Prototype.Browser.WebKit && id == "overlay_modal") {
        setTimeout(function() {doneHandler()}, 10);
      }
      else
        doneHandler();
    }    
  },
  
  setCookie: function(value, parameters) {
    document.cookie= parameters[0] + "=" + escape(value) +
      ((parameters[1]) ? "; expires=" + parameters[1].toGMTString() : "") +
      ((parameters[2]) ? "; path=" + parameters[2] : "") +
      ((parameters[3]) ? "; domain=" + parameters[3] : "") +
      ((parameters[4]) ? "; secure" : "");
  },

  getCookie: function(name) {
    var dc = document.cookie;
    var prefix = name + "=";
    var begin = dc.indexOf("; " + prefix);
    if (begin == -1) {
      begin = dc.indexOf(prefix);
      if (begin != 0) return null;
    } else {
      begin += 2;
    }
    var end = document.cookie.indexOf(";", begin);
    if (end == -1) {
      end = dc.length;
    }
    return unescape(dc.substring(begin + prefix.length, end));
  },
    
  _computeSize: function(content, id, width, height, margin, className) {
    var objBody = document.body;
    var tmpObj = document.createElement("div");
    tmpObj.setAttribute('id', id);
    tmpObj.className = className + "_content";

    if (height)
      tmpObj.style.height = height + "px"
    else
      tmpObj.style.width = width + "px"
  
    tmpObj.style.position = 'absolute';
    tmpObj.style.top = '0';
    tmpObj.style.left = '0';
    tmpObj.style.display = 'none';

    tmpObj.innerHTML = content;
    objBody.insertBefore(tmpObj, objBody.firstChild);

    var size;
    if (height)
      size = $(tmpObj).getDimensions().width + margin;
    else
      size = $(tmpObj).getDimensions().height + margin;
    objBody.removeChild(tmpObj);
    return size;
  }  
}

// Singleton class TooltipWindow
// This class works with special className. The tooltip content could be in your HTML page as an hidden element or
// can be retreive by an AJAX call.
//
// To work, You just need to set two class name on elements that should show tooltips
// - One to say to TooltipManager that this element must have a tooltip ('tooltip' by default)
// - Another to indicate how to find the tooltip content
//   It could be html_XXXX if tootltip content is somewhere hidden in your page, XXX must be DOM ID of this hidden element
//   It could be ajax_XXXX if tootltip content must be find by an ajax request, XXX will be the string send as id parameter to your server. 
// Check samples/tooltips/tooltip.html to see how it works
//
TooltipManager = {
  options: {cssClassName: 'tooltip', delayOver: 200, delayOut: 1000, shiftX: 10, shiftY: 10,
            className: 'alphacube', width: 200, height: null, 
            draggable: false, minimizable: false, maximizable: false, showEffect: Element.show, hideEffect: Element.hide},
  ajaxInfo: null,
  elements: null,
  showTimer: null,
  hideTimer: null,

  // Init tooltip manager
  // parameters:
  // - cssClassName (string) : CSS class name where tooltip should be shown. 
  // - ajaxOptions  (hash)   : Ajax options for ajax tooltip. 
  //                           For examples {url: "/tooltip/get.php", options: {method: 'get'}} 
  //                           see Ajax.Request documentation for details
  //- tooltipOptions (hash)  : available keys
  //                           - delayOver: int in ms (default 10) delay before showing tooltip
  //                           - delayOut:  int in ms (default 1000) delay before hidding tooltip
  //                           - shiftX:    int in pixels (default 10) left shift of the tooltip window 
  //                           - shiftY:    int in pixels (default 10) top shift of the tooltip window 
  //                           and All window options like showEffect: Element.show, hideEffect: Element.hide to remove animation
  //                           default: {className: 'alphacube', width: 200, height: null, draggable: false, minimizable: false, maximizable: false}
  
  init: function(cssClassName, ajaxInfo, tooltipOptions) {
    TooltipManager.options = Object.extend(TooltipManager.options, tooltipOptions || {});
    
    cssClassName = TooltipManager.options.cssClassName || "tooltip";
    TooltipManager.ajaxInfo = ajaxInfo;
    TooltipManager.elements = $$("." + cssClassName);
    TooltipManager.elements.each(function(element) {
      element = $(element)
      var info = TooltipManager._getInfo(element);
      if (info.ajax) {
        element.ajaxId = info.id;
        element.ajaxInfo = ajaxInfo;
      }
      else {
        element.tooltipElement = $(info.id);
      }
      element.observe("mouseover", TooltipManager._mouseOver);
      element.observe("mouseout", TooltipManager._mouseOut);
    });
    Windows.addObserver(this);
  },
  
  addHTML: function(element, tooltipElement) {
    element = $(element);
    tooltipElement = $(tooltipElement);
    element.tooltipElement = tooltipElement;
    
    element.observe("mouseover", TooltipManager._mouseOver);
    element.observe("mouseout", TooltipManager._mouseOut);
  },
  
  addAjax: function(element, ajaxInfo) {
    element = $(element);
    element.ajaxInfo = ajaxInfo;
    element.observe("mouseover", TooltipManager._mouseOver);
    element.observe("mouseout", TooltipManager._mouseOut);    
  },
    
  addURL: function(element, url, width, height) {
    element = $(element);
    element.url = url;
    element.frameWidth = width;
    element.frameHeight = height;
    element.observe("mouseover", TooltipManager._mouseOver);
    element.observe("mouseout", TooltipManager._mouseOut);    
  },
    
  close: function() {
    if (TooltipManager.tooltipWindow)
      TooltipManager.tooltipWindow.hide();
  },
  
  preloadImages: function(path, images, extension) {
    if (!extension)
      extension = ".gif";
      
    //preload images
    $A(images).each(function(i) {
      var image = new Image(); 
      image.src= path + "/" + i + extension; 
    });
  },
  
  _showTooltip: function(element) {
    if (this.element == element)
      return;
    // Get original element
    while (element && (!element.tooltipElement && !element.ajaxInfo && !element.url)) 
      element = element.parentNode;
    this.element = element;
    
    TooltipManager.showTimer = null;
    if (TooltipManager.hideTimer)
      clearTimeout(TooltipManager.hideTimer);
    
    var position = Position.cumulativeOffset(element);
    var dimension = element.getDimensions();

    if (! this.tooltipWindow)
      this.tooltipWindow = new Window("__tooltip__", TooltipManager.options);
      
    this.tooltipWindow.hide();
    this.tooltipWindow.setLocation(position[1] + dimension.height + TooltipManager.options.shiftY, position[0] + TooltipManager.options.shiftX);

    Event.observe(this.tooltipWindow.element, "mouseover", function(event) {TooltipManager._tooltipOver(event, element)});
    Event.observe(this.tooltipWindow.element, "mouseout", function(event) {TooltipManager._tooltipOut(event, element)});

    // Reset width/height for computation
    this.tooltipWindow.height = TooltipManager.options.height;
    this.tooltipWindow.width = TooltipManager.options.width;

    // Ajax content
    if (element.ajaxInfo) {
      var p = element.ajaxInfo.options.parameters;
      var saveParam = p;
      
      // Set by CSS
      if (element.ajaxId) {
        if (p)
          p += "&id=" + element.ajaxId;
        else
          p = "id=" + element.ajaxId;
      }
      element.ajaxInfo.options.parameters = p || "";
      this.tooltipWindow.setHTMLContent("");
      this.tooltipWindow.setAjaxContent(element.ajaxInfo.url, element.ajaxInfo.options);
      element.ajaxInfo.options.parameters = saveParam;    
    } 
    // URL content
    else if (element.url) {
      this.tooltipWindow.setURL(element.url);
      this.tooltipWindow.setSize(element.frameWidth, element.frameHeight);

      // Set tooltip size
      this.tooltipWindow.height = element.frameHeight;
      this.tooltipWindow.width = element.frameWidth;
    }
    // HTML content
    else
      this.tooltipWindow.setHTMLContent(element.tooltipElement.innerHTML);

    if (!element.ajaxInfo) {
      this.tooltipWindow.show();
      this.tooltipWindow.toFront();
    }
  },
  
  _hideTooltip: function(element) {
    if (this.tooltipWindow) {
      this.tooltipWindow.hide();
      this.element = null;
    }
  },
  
  _mouseOver: function (event) {
    var element = Event.element(event);
    if (TooltipManager.showTimer) 
      clearTimeout(TooltipManager.showTimer);
    
    TooltipManager.showTimer = setTimeout(function() {TooltipManager._showTooltip(element)}, TooltipManager.options.delayOver)
  },
  
  _mouseOut: function(event) {
    var element = Event.element(event);
    if (TooltipManager.showTimer) {
      clearTimeout(TooltipManager.showTimer);
      TooltipManager.showTimer = null;
      return;
    }
    if (TooltipManager.tooltipWindow)
      TooltipManager.hideTimer = setTimeout(function() {TooltipManager._hideTooltip(element)}, TooltipManager.options.delayOut)
  },
  
  _tooltipOver: function(event, element) {
    if (TooltipManager.hideTimer) {
      clearTimeout(TooltipManager.hideTimer);
      TooltipManager.hideTimer = null;
    }
  },
  
  _tooltipOut: function(event, element) {
    if (TooltipManager.hideTimer == null)
      TooltipManager.hideTimer = setTimeout(function() {TooltipManager._hideTooltip(element)}, TooltipManager.options.delayOut)
  },
  
  _getInfo: function(element) {
    // Find html_ for static content
    var id = element.className.split(' ').detect(function(name) {return name.indexOf("html_") == 0});
    var ajax = true;
    if (id)
      ajax = false;
    else 
      // Find ajax_ for ajax content
      id = element.className.split(' ').detect(function(name) {return name.indexOf("ajax_") == 0});
    
    id = id.substr(id.indexOf('_')+1, id.length)
    return id ? {ajax: ajax, id: id} : null;
  },
  
  onBeforeShow: function(eventName, win) {
     var top = parseFloat(win.getLocation().top);
     var dim = win.element.getDimensions();
    
     if (top + dim.height > TooltipManager._getScrollTop() + TooltipManager._getPageHeight()) {
       var position = Position.cumulativeOffset(this.element);

       var top = position[1] - TooltipManager.options.shiftY - dim.height;
       win.setLocation(top, position[0] + TooltipManager.options.shiftX)
     }
   },

	_getPageWidth: function(){
		return window.innerWidth || document.documentElement.clientWidth || 0;
	},
	
	_getPageHeight: function(){
		return window.innerHeight || document.documentElement.clientHeight || 0;
	},

	_getScrollTop: function(){
		return document.documentElement.scrollTop || window.pageYOffset || 0;
	},

	_getScrollLeft: function(){
		return document.documentElement.scrollLeft || window.pageXOffset || 0;
	}	
};
Effect.ResizeWindow = Class.create();
Object.extend(Object.extend(Effect.ResizeWindow.prototype, Effect.Base.prototype), {
  initialize: function(win, top, left, width, height) {
    this.window = win;
    this.window.resizing = true;
    
    var size = win.getSize();
    this.initWidth    = parseFloat(size.width);
    this.initHeight   = parseFloat(size.height);

    var location = win.getLocation();
    this.initTop    = parseFloat(location.top);
    this.initLeft   = parseFloat(location.left);

    this.width    = width != null  ? parseFloat(width)  : this.initWidth;
    this.height   = height != null ? parseFloat(height) : this.initHeight;
    this.top      = top != null    ? parseFloat(top)    : this.initTop;
    this.left     = left != null   ? parseFloat(left)   : this.initLeft;

    this.dx     = this.left   - this.initLeft;
    this.dy     = this.top    - this.initTop;
    this.dw     = this.width  - this.initWidth;
    this.dh     = this.height - this.initHeight;
    
    this.r2      = $(this.window.getId() + "_row2");
    this.content = $(this.window.getId() + "_content");
        
    this.contentOverflow = this.content.getStyle("overflow") || "auto";
    this.content.setStyle({overflow: "hidden"});
    
    // Wired mode
    if (this.window.options.wiredDrag) {
      this.window.currentDrag = win._createWiredElement();
      this.window.currentDrag.show();
      this.window.element.hide();
    }

    this.start(arguments[5]);
  },
  
  update: function(position) {
    var width  = Math.floor(this.initWidth  + this.dw * position);
    var height = Math.floor(this.initHeight + this.dh * position);
    var top    = Math.floor(this.initTop    + this.dy * position);
    var left   = Math.floor(this.initLeft   + this.dx * position);

    if (window.ie) {
      if (Math.floor(height) == 0)  
        this.r2.hide();
      else if (Math.floor(height) >1)  
        this.r2.show();
    }      
    this.r2.setStyle({height: height});
    this.window.setSize(width, height);
    this.window.setLocation(top, left);
  },
  
  finish: function(position) {
    // Wired mode
    if (this.window.options.wiredDrag) {
      this.window._hideWiredElement();
      this.window.element.show();
    }

    this.window.setSize(this.width, this.height);
    this.window.setLocation(this.top, this.left);
    this.r2.setStyle({height: null});
    
    this.content.setStyle({overflow: this.contentOverflow});
      
    this.window.resizing = false;
  }
});

Effect.ModalSlideDown = function(element) {
  var windowScroll = WindowUtilities.getWindowScroll();    
  var height = element.getStyle("height");  
  element.setStyle({top: - (parseFloat(height) - windowScroll.top) + "px"});
  
  element.show();
  return new Effect.Move(element, Object.extend({ x: 0, y: parseFloat(height) }, arguments[1] || {}));
};


Effect.ModalSlideUp = function(element) {
  var height = element.getStyle("height");
  return new Effect.Move(element, Object.extend({ x: 0, y: -parseFloat(height) }, arguments[1] || {}));
};

PopupEffect = Class.create();
PopupEffect.prototype = {    
  initialize: function(htmlElement) {
    this.html = $(htmlElement);      
    this.options = Object.extend({className: "popup_effect", duration: 0.4}, arguments[1] || {});
    
  },
  show: function(element, options) { 
    var position = Position.cumulativeOffset(this.html);      
    var size = this.html.getDimensions();
    var bounds = element.win.getBounds();
    this.window =  element.win;      
    // Create a div
    if (!this.div) {
      this.div = document.createElement("div");
      this.div.className = this.options.className;
      this.div.style.height = size.height + "px";
      this.div.style.width  = size.width  + "px";
      this.div.style.top    = position[1] + "px";
      this.div.style.left   = position[0] + "px";   
      this.div.style.position = "absolute"
      document.body.appendChild(this.div);
    }                                                   
    if (this.options.fromOpacity)
      this.div.setStyle({opacity: this.options.fromOpacity})
    this.div.show();          
    var style = "top:" + bounds.top + ";left:" +bounds.left + ";width:" + bounds.width +";height:" + bounds.height;
    if (this.options.toOpacity)
      style += ";opacity:" + this.options.toOpacity;
    
    new Effect.Morph(this.div ,{style: style, duration: this.options.duration, afterFinish: this._showWindow.bind(this)});    
  },

  hide: function(element, options) {     
    var position = Position.cumulativeOffset(this.html);      
    var size = this.html.getDimensions();    
    this.window.visible = true; 
    var bounds = this.window.getBounds();
    this.window.visible = false; 

    this.window.element.hide();

    this.div.style.height = bounds.height;
    this.div.style.width  = bounds.width;
    this.div.style.top    = bounds.top;
    this.div.style.left   = bounds.left;
    
    if (this.options.toOpacity)
      this.div.setStyle({opacity: this.options.toOpacity})

    this.div.show();                                 
    var style = "top:" + position[1] + "px;left:" + position[0] + "px;width:" + size.width +"px;height:" + size.height + "px";

    if (this.options.fromOpacity)
      style += ";opacity:" + this.options.fromOpacity;
    new Effect.Morph(this.div ,{style: style, duration: this.options.duration, afterFinish: this._hideDiv.bind(this)});    
  },
  
  _showWindow: function() {
    this.div.hide();
    this.window.element.show(); 
  },
  
  _hideDiv: function() {
    this.div.hide();
  }
}

var debugWindow = null;
function debug(text, reverse) {
	if (debugWindow == null)
 		return;

	time = "-"; //new Date();
	if (reverse) {
		$('debug').innerHTML = time + " " + text + "<br>"+ 	$('debug').innerHTML;
		debugWindow.getContent().scrollTop=0;
	}
	else {
		$('debug').innerHTML +=  time + " " + text + "<br>";
		debugWindow.getContent().scrollTop=10000; // Far away 
	}
}

function hideDebug() {
	if (debugWindow) {
		debugWindow.destroy();
		debugWindow = null;
	}
}

function showDebug(bShow) {
 if (debugWindow == null) {
  debugWindow = new Window('debug_window', {className: 'dialog',width:250, height:100, right:4, bottom:42, zIndex:1000, opacity:1, showEffect: Element.show, resizable: true, title: "Debug"})
  debugWindow.getContent().innerHTML = "<style>#debug_window .dialog_content {background:#000;}</style> <div id='debug'></div>";
  date=new Date;
    date.setMonth(date.getMonth()+3);
    
  //debugWindow.setCookie(null, date);
 }
 if( typeof bShow == 'undefined' || bShow)debugWindow.show()
}


function clearDebug() {
	if (debugWindow == null)
 		return;
	$('debug').innerHTML = "";
}

/**
 * document.createElement convenience wrapper
 *
 * The data parameter is an object that must have the "tag" key, containing
 * a string with the tagname of the element to create.  It can optionally have
 * a "children" key which can be: a string, "data" object, or an array of "data"
 * objects to append to this element as children.  Any other key is taken as an
 * attribute to be applied to this tag.
 *
 * Available under an MIT license:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @param {Object} data The data representing the element to create
 * @return {Element} The element created.
 */
function $E(data) {
  var el;
  if ('string'==typeof data) {
      el=document.createTextNode(data);
  } else {
    //create the element
    el=document.createElement(data.tag);
    delete(data.tag);

    //append the children
    if ('undefined'!=typeof data.children) {
      if ('string'==typeof data.children ||'undefined'==typeof data.children.length) {
        //strings and single elements
        el.appendChild($E(data.children));
      } else {
        //arrays of elements
        for (var i=0, child=null; 'undefined'!=typeof (child=data.children[i]); i++) {
            el.appendChild($E(child));
        }
      }
      delete(data.children);
    }

    //any other data is attributes
    for (attr in data) {
      el[attr]=data[attr];
    }
  }

  return el;
}

// FROM Nick Hemsley
var Debug = {
	inspectOutput: function (container, within) {
		within = within || debugWindow.getContent()
		
		if (debugWindow == null)
 			return;

		within.appendChild(container)
	},
	
	inspect: function(object) {
		var cont = $E({tag: "div", className: "inspector"})
		Debug.inspectObj(object, cont)
		debugWindow.getContent().appendChild(cont)
	},
	
	inspectObj: function (object, container) {
		for (prop in object) {
			Debug.inspectOutput(Debug.inspectable(object, prop), container)
		}
	},
	
	inspectable: function(object, prop) {
		cont = $E({tag: 'div', className: 'inspectable', children: [prop + " value: " + object[prop] ]})
		cont.toInspect = object[prop]
		Event.observe(cont, 'click', Debug.inspectClicked, false)
		return cont
	},
	
	inspectClicked: function(e) {
		Debug.inspectContained(Event.element(e))
		Event.stop(e)
	},
	
	inspectContained: function(container) {
		if (container.opened) {
			container.parentNode.removeChild(container.opened)
			delete(container.opened)
		} else {
			sibling = container.parentNode.insertBefore($E({tag: "div", className: "child"}), container.nextSibling)
			if (container.toInspect)
				Debug.inspectObj(container.toInspect, sibling)
			container.opened = sibling
		}
	}
}
var inspect = Debug.inspect;
/*
	Blackbird - Open Source JavaScript Logging Utility
	Author: G Scott Olson
	Web: http://blackbirdjs.googlecode.com/
	     http://www.gscottolson.com/blackbirdjs/
	Version: 1.0

	The MIT License - Copyright (c) 2008 Blackbird Project
*/
( function() {
	var NAMESPACE = 'log';
	var IE6_POSITION_FIXED = true; // enable IE6 {position:fixed}
	
	var bbird;
	var outputList;
	var cache = [];
	
	var state = getState();
	var classes = {};
	var profiler = {};
	var IDs = {
		blackbird: 'blackbird',
		checkbox: 'bbVis',
		filters: 'bbFilters',
		controls: 'bbControls',
		size: 'bbSize'
	}
	var messageTypes = { //order of these properties imply render order of filter controls
		debug: true,
		info: true,
		warn: true,
		error: true,
		profile: true
	};
	
	function generateMarkup() { //build markup
		var spans = [];
		for ( type in messageTypes ) {
			spans.push( [ '<span class="', type, '" type="', type, '"></span>'].join( '' ) );
		}

		var newNode = document.createElement( 'DIV' );
		newNode.id = IDs.blackbird;
		newNode.style.display = 'none';
		newNode.innerHTML = [
			'<div class="header">',
				'<div class="left">',
					'<div id="', IDs.filters, '" class="filters" title="click to filter by message type">', spans.join( '' ), '</div>',
				'</div>',
				'<div class="right">',
					'<div id="', IDs.controls, '" class="controls">',
						'<span id="', IDs.size ,'" title="contract" op="resize"></span>',
						'<span class="clear" title="clear" op="clear"></span>',
						'<span class="close" title="close" op="close"></span>',
					'</div>',
				'</div>',
			'</div>',
			'<div class="mainDebug">',
				'<div class="left"></div><div class="mainBody">',
					'<ol>', cache.join( '' ), '</ol>',
				'</div><div class="right"></div>',
			'</div>',
			'<div class="footer">',
				'<div class="left"><label for="', IDs.checkbox, '"><input type="checkbox" id="', IDs.checkbox, '" />Visible on page load</label></div>',
				'<div class="right"></div>',
			'</div>'
		].join( '' );
		return newNode;
	}

	function backgroundImage() { //(IE6 only) change <BODY> tag's background to resolve {position:fixed} support
		var bodyTag = document.getElementsByTagName( 'BODY' )[ 0 ];
		
		if ( bodyTag.currentStyle && IE6_POSITION_FIXED ) {
			if (bodyTag.currentStyle.backgroundImage == 'none' ) {
				bodyTag.style.backgroundImage = 'url(about:blank)';
			}
			if (bodyTag.currentStyle.backgroundAttachment == 'scroll' ) {
				bodyTag.style.backgroundAttachment = 'fixed';
			}
		}
	}

	function addMessage( type, content ) { //adds a message to the output list
		content = ( content.constructor == Array ) ? content.join( '' ) : content;
		if ( outputList ) {
			var newMsg = document.createElement( 'LI' );
			newMsg.className = type;
			newMsg.innerHTML = [ '<span class="icon"></span>', content ].join( '' );
			outputList.appendChild( newMsg );
			scrollToBottom();
		} else {
			cache.push( [ '<li class="', type, '"><span class="icon"></span>', content, '</li>' ].join( '' ) );
		}
	}
	
	function clear() { //clear list output
		outputList.innerHTML = '';
	}
	
	function clickControl( evt ) {
		if ( !evt ) evt = window.event;
		var el = ( evt.target ) ? evt.target : evt.srcElement;

		if ( el.tagName == 'SPAN' ) {
			switch ( el.getAttributeNode( 'op' ).nodeValue ) {
				case 'resize': resize(); break;
				case 'clear':  clear();  break;
				case 'close':  hide();   break;
			}
		}
	}
	
	function clickFilter( evt ) { //show/hide a specific message type
		if ( !evt ) evt = window.event;
		var span = ( evt.target ) ? evt.target : evt.srcElement;

		if ( span && span.tagName == 'SPAN' ) {

			var type = span.getAttributeNode( 'type' ).nodeValue;

			if ( evt.altKey ) {
				var filters = document.getElementById( IDs.filters ).getElementsByTagName( 'SPAN' );

				var active = 0;
				for ( entry in messageTypes ) {
					if ( messageTypes[ entry ] ) active++;
				}
				var oneActiveFilter = ( active == 1 && messageTypes[ type ] );

				for ( var i = 0; filters[ i ]; i++ ) {
					var spanType = filters[ i ].getAttributeNode( 'type' ).nodeValue;

					filters[ i ].className = ( oneActiveFilter || ( spanType == type ) ) ? spanType : spanType + 'Disabled';
					messageTypes[ spanType ] = oneActiveFilter || ( spanType == type );
				}
			}
			else {
				messageTypes[ type ] = ! messageTypes[ type ];
				span.className = ( messageTypes[ type ] ) ? type : type + 'Disabled';
			}

			//build outputList's class from messageTypes object
			var disabledTypes = [];
			for ( type in messageTypes ) {
				if ( ! messageTypes[ type ] ) disabledTypes.push( type );
			}
			disabledTypes.push( '' );
			outputList.className = disabledTypes.join( 'Hidden ' );

			scrollToBottom();
		}
	}

	function clickVis( evt ) {
		if ( !evt ) evt = window.event;
		var el = ( evt.target ) ? evt.target : evt.srcElement;

		state.load = el.checked;
		setState();
	}
	
	
	function scrollToBottom() { //scroll list output to the bottom
		outputList.scrollTop = outputList.scrollHeight;
	}
	
	function isVisible() { //determine the visibility
		return ( bbird.style.display == 'block' );
	}

	function hide() { 
	  bbird.style.display = 'none';
	}
			
	function show() {
		var body = document.getElementsByTagName( 'BODY' )[ 0 ];
		body.removeChild( bbird );
		body.appendChild( bbird );
		bbird.style.display = 'block';
	}
	
	//sets the position
	function reposition( position ) {
		if ( position === undefined || position == null ) {
			position = ( state && state.pos === null ) ? 1 : ( state.pos + 1 ) % 4; //set to initial position ('topRight') or move to next position
		}
				
		switch ( position ) {
			case 0: classes[ 0 ] = 'bbTopLeft'; break;
			case 1: classes[ 0 ] = 'bbTopRight'; break;
			case 2: classes[ 0 ] = 'bbBottomLeft'; break;
			case 3: classes[ 0 ] = 'bbBottomRight'; break;
		}
		state.pos = position;
		setState();
	}

	function resize( size ) {
		if ( size === undefined || size === null ) {
			size = ( state && state.size == null ) ? 0 : ( state.size + 1 ) % 2;
	  	}

		classes[ 1 ] = ( size === 0 ) ? 'bbSmall' : 'bbLarge'

		var span = document.getElementById( IDs.size );
		span.title = ( size === 1 ) ? 'small' : 'large';
		span.className = span.title;	  

		state.size = size;
		setState();
		scrollToBottom();
	}

	function setState() {
		var props = [];
		for ( entry in state ) {
			var value = ( state[ entry ] && state[ entry ].constructor === String ) ? '"' + state[ entry ] + '"' : state[ entry ]; 
			props.push( entry + ':' + value );
		}
		props = props.join( ',' );
		
		var expiration = new Date();
		expiration.setDate( expiration.getDate() + 14 );
		document.cookie = [ 'blackbird={', props, '}; expires=', expiration.toUTCString() ,';' ].join( '' );

		var newClass = [];
		for ( word in classes ) {
			newClass.push( classes[ word ] );
		}
		bbird.className = newClass.join( ' ' );
	}
	
	function getState() {
		var re = new RegExp( /blackbird=({[^;]+})(;|\b|$)/ );
		var match = re.exec( document.cookie );
		return ( match && match[ 1 ] ) ? eval( '(' + match[ 1 ] + ')' ) : { pos:null, size:null, load:null };
	}
	
	//event handler for 'keyup' event for window
	function readKey( evt ) {
		if ( !evt ) evt = window.event;
		var code = 113; //F2 key
					
		if ( evt && evt.keyCode == code ) {
					
			var visible = isVisible();
					
			if ( visible && evt.shiftKey && evt.altKey ) clear();
			else if	 (visible && evt.shiftKey ) reposition();
			else if ( !evt.shiftKey && !evt.altKey ) {
			  ( visible ) ? hide() : show();
			}
		}
	}

	//event management ( thanks John Resig )
	function addEvent( obj, type, fn ) {
		var obj = ( obj.constructor === String ) ? document.getElementById( obj ) : obj;
		if ( obj.attachEvent ) {
			obj[ 'e' + type + fn ] = fn;
			obj[ type + fn ] = function(){ obj[ 'e' + type + fn ]( window.event ) };
			obj.attachEvent( 'on' + type, obj[ type + fn ] );
		} else obj.addEventListener( type, fn, false );
	}
	function removeEvent( obj, type, fn ) {
		var obj = ( obj.constructor === String ) ? document.getElementById( obj ) : obj;
		if ( obj.detachEvent ) {
			obj.detachEvent( 'on' + type, obj[ type + fn ] );
			obj[ type + fn ] = null;
	  } else obj.removeEventListener( type, fn, false );
	}

	window[ NAMESPACE ] = {
		toggle:
			function() { ( isVisible() ) ? hide() : show(); },
		resize:
			function() { resize(); },
		clear:
			function() { clear(); },
		move:
			function() { reposition(); },
		debug: 
			function( msg ) { addMessage( 'debug', msg ); },
		warn:
			function( msg ) { addMessage( 'warn', msg ); },
		info:
			function( msg ) { addMessage( 'info', msg ); },
		error:
			function( msg ) { addMessage( 'error', msg ); },
		profile: 
			function( label ) {
				var currentTime = new Date(); //record the current time when profile() is executed
				
				if ( label == undefined || label == '' ) {
					addMessage( 'error', '<b>ERROR:</b> Please specify a label for your profile statement' );
				}
				else if ( profiler[ label ] ) {
					addMessage( 'profile', [ label, ': ', currentTime - profiler[ label ],	'ms' ].join( '' ) );
					delete profiler[ label ];
				}
				else {
					profiler[ label ] = currentTime;
					addMessage( 'profile', label );
				}
				return currentTime;
			}
	}

	addEvent( window, 'load', 
		/* initialize Blackbird when the page loads */
		function() {
			var body = document.getElementsByTagName( 'BODY' )[ 0 ];
			bbird = body.appendChild( generateMarkup() );
			outputList = bbird.getElementsByTagName( 'OL' )[ 0 ];
		
			backgroundImage();
		
			//add events
			addEvent( IDs.checkbox, 'click', clickVis );
			addEvent( IDs.filters, 'click', clickFilter );
			addEvent( IDs.controls, 'click', clickControl );
			addEvent( document, 'keyup', readKey);

			resize( state.size );
			reposition( state.pos );
			if ( state.load ) {
				show();
				document.getElementById( IDs.checkbox ).checked = true; 
			}

			scrollToBottom();

			window[ NAMESPACE ].init = function() {
				show();
				window[ NAMESPACE ].error( [ '<b>', NAMESPACE, '</b> can only be initialized once' ] );
			}

			addEvent( window, 'unload', function() {
				removeEvent( IDs.checkbox, 'click', clickVis );
				removeEvent( IDs.filters, 'click', clickFilter );
				removeEvent( IDs.controls, 'click', clickControl );
				removeEvent( document, 'keyup', readKey );
			});
		});
})();

//stop debug
/*
var log = {
  toggle: function() {},
  move: function() {},
  resize: function() {},
  clear: function() {},
  debug: function() {},
  info: function() {},
  warn: function() {},
  error: function() {},
  profile: function() {}
};
*//*
  Proto!MultiSelect 0.2
  - Prototype version required: 6.0
  
  Credits:
  - Idea: Facebook + Apple Mail
  - Caret position method: Diego Perini <http://javascript.nwbox.com/cursor_position/cursor.js>
  - Guillermo Rauch: Original MooTools script
  - Ran Grushkowsky/InteRiders Inc. : Porting into Prototype and further development
  
  Changelog:
  - 0.1: translation of MooTools script
  - 0.2: renamed from Proto!TextboxList to Proto!MultiSelect, added new features/bug fixes
        added feature: support to fetch list on-the-fly using AJAX    Credit: Cheeseroll
        added feature: support for value/caption
        added feature: maximum results to display, when greater displays a scrollbar   Credit: Marcel
        added feature: filter by the beginning of word only or everywhere in the word   Credit: Kiliman
        added feature: shows hand cursor when going over options
        bug fix: the click event stopped working
        bug fix: the cursor does not 'travel' when going up/down the list   Credit: Marcel
*/

/* Copyright: InteRiders <http://interiders.com/> - Distributed under MIT - Keep this message! */

var ResizableTextbox = Class.create({
  
  options: $H({
    min: 5,
    max: 500,
    step: 7
  }),
  
  initialize: function(element, options) {
    var that = this;
    this.options.update(options);
    this.el = $(element);
    this.width = this.el.offsetWidth;
    this.el.observe(
      'keyup', function() {
        var newsize = that.options.get('step') * $F(this).length;
        if(newsize <= that.options.get('min')) newsize = that.width;
        if(! ($F(this).length == this.retrieveData('rt-value') || newsize <= that.options.min || newsize >= that.options.max))
          this.setStyle({'width': newsize});
      }).observe('keydown', function() {
        this.cacheData('rt-value', $F(this).length);
      });
  }
});

var TextboxList = Class.create({ 
  
  options: $H({/*
    onFocus: $empty,
    onBlur: $empty,
    onInputFocus: $empty,
    onInputBlur: $empty,
    onBoxFocus: $empty,
    onBoxBlur: $empty,
    onBoxDispose: $empty,*/
    resizable: {},
    className: 'bit',
    separator: '###',
    extrainputs: true,
    startinput: true,
    hideempty: true,
    fetchFile: undefined,
    results: 10,
    wordMatch: false
  }),
  
  initialize: function(element, options) {
    this.options.update(options);
    this.element = $(element).hide();    
    this.bits = new Hash();
    this.events = new Hash();
    this.count = 0;
    this.current = false;
    this.maininput = this.createInput({'class': 'maininput'});
    this.holder = new Element('ul', {
      'class': 'holder'
    }).insert(this.maininput);
    this.element.insert({'before':this.holder});
    this.holder.observe('click', function(event){
          event.stop();
          if(this.maininput != this.current) this.focus(this.maininput);     
    }.bind(this));
    this.makeResizable(this.maininput);
    this.setEvents();
  },
  
  setEvents: function() {
    document.observe(Prototype.Browser.IE ? 'keydown' : 'keypress', function(e) {      
      if(! this.current) return;
      if(this.current.retrieveData('type') == 'box' && e.keyCode == Event.KEY_BACKSPACE) e.stop();
    }.bind(this));      
         
    document.observe(
      'keyup', function(e) {
        e.stop();
        if(! this.current) return;
        switch(e.keyCode){
          case Event.KEY_LEFT: return this.move('left');
          case Event.KEY_RIGHT: return this.move('right');
          case Event.KEY_DELETE:
          case Event.KEY_BACKSPACE: return this.moveDispose();
        }
      }.bind(this)).observe(  
      'click', function() { document.fire('blur'); }.bindAsEventListener(this)
    );
  },
  
  update: function() {
    this.element.value = this.bits.values().join(this.options.get('separator'));
    return this;
  },
  
  add: function(text, html) {
    var id = this.options.get('className') + '-' + this.count++;
    var el = this.createBox($pick(html, text), {'id': id});
    (this.current || this.maininput).insert({'before':el});
    el.observe('click', function(e) {
      e.stop();
      this.focus(el);
    }.bind(this));
    this.bits.set(id, text.value);    
    if(this.options.get('extrainputs') && (this.options.get('startinput') || el.previous())) this.addSmallInput(el,'before');
    return el;
  },
  
  addSmallInput: function(el, where) {
    var input = this.createInput({'class': 'smallinput'});
    el.insert({}[where] = input);
    input.cacheData('small', true);
    this.makeResizable(input);
    if(this.options.get('hideempty')) input.hide();
    return input;
  },
  
  dispose: function(el) {
    this.bits.unset(el.id);
    if(el.previous() && el.previous().retrieveData('small')) el.previous().remove();
    if(this.current == el) this.focus(el.next());
    if(el.retrieveData('type') == 'box') el.onBoxDispose(this);
    el.remove();    
    return this;
  },
  
  focus: function(el, nofocus) {
    if(! this.current) el.fire('focus');
    else if(this.current == el) return this;
    this.blur();
    el.addClassName(this.options.get('className') + '-' + el.retrieveData('type') + '-focus');
    if(el.retrieveData('small')) el.setStyle({'display': 'block'});
    if(el.retrieveData('type') == 'input') {
      el.onInputFocus(this);      
      if(! nofocus) this.callEvent(el.retrieveData('input'), 'focus');
    }
    else el.fire('onBoxFocus');
    this.current = el;    
    return this;
  },
  
  blur: function(noblur) {
    if(! this.current) return this;
    if(this.current.retrieveData('type') == 'input') {
      var input = this.current.retrieveData('input');
      if(! noblur) this.callEvent(input, 'blur');   
      input.onInputBlur(this);
    }
    else this.current.fire('onBoxBlur');
    if(this.current.retrieveData('small') && ! input.get('value') && this.options.get('hideempty')) 
      this.current.hide();
    this.current.removeClassName(this.options.get('className') + '-' + this.current.retrieveData('type') + '-focus');
    this.current = false;
    return this;
  },
  
  createBox: function(text, options) {
    return new Element('li', options).addClassName(this.options.get('className') + '-box').update(text.caption).cacheData('type', 'box');
  },
  
  createInput: function(options) {
    var li = new Element('li', {'class': this.options.get('className') + '-input'});
    var el = new Element('input', Object.extend(options,{'type': 'text'}));
    el.observe('click', function(e) { e.stop(); }).observe('focus', function(e) { if(! this.isSelfEvent('focus')) this.focus(li, true); }.bind(this)).observe('blur', function() { if(! this.isSelfEvent('blur')) this.blur(true); }.bind(this)).observe('keydown', function(e) { this.cacheData('lastvalue', this.value).cacheData('lastcaret', this.getCaretPosition()); });
    var tmp = li.cacheData('type', 'input').cacheData('input', el).insert(el);
    return tmp;
  },
  
  callEvent: function(el, type) {
    this.events.set(type, el);
    el[type]();
  },
  
  isSelfEvent: function(type) {
    return (this.events.get(type)) ? !! this.events.unset(type) : false;
  },
  
  makeResizable: function(li) {
    var el = li.retrieveData('input');
    el.cacheData('resizable', new ResizableTextbox(el, Object.extend(this.options.get('resizable'),{min: el.offsetWidth, max: (this.element.getWidth()?this.element.getWidth():0)})));
    return this;
  },
  
  checkInput: function() {
    var input = this.current.retrieveData('input');
    return (! input.retrieveData('lastvalue') || (input.getCaretPosition() === 0 && input.retrieveData('lastcaret') === 0));
  },
  
  move: function(direction) {
    var el = this.current[(direction == 'left' ? 'previous' : 'next')]();
    if(el && (! this.current.retrieveData('input') || ((this.checkInput() || direction == 'right')))) this.focus(el);
    return this;
  },
  
  moveDispose: function() {
    if(this.current.retrieveData('type') == 'box') return this.dispose(this.current);
    if(this.checkInput() && this.bits.keys().length && this.current.previous()) return this.focus(this.current.previous());
  }
  
});

//helper functions 
Element.addMethods({
  getCaretPosition: function() {
    if (this.createTextRange) {
      var r = document.selection.createRange().duplicate();
        r.moveEnd('character', this.value.length);
        if (r.text === '') return this.value.length;
        return this.value.lastIndexOf(r.text);
    } else return this.selectionStart;
  },
  cacheData: function(element, key, value) { 
    if (Object.isUndefined(this[$(element).identify()]) || !Object.isHash(this[$(element).identify()]))
        this[$(element).identify()] = $H();
    this[$(element).identify()].set(key,value);
    return element;
  },
  retrieveData: function(element,key) {
    return this[$(element).identify()].get(key);
  }  
});

function $pick(){for(var B=0,A=arguments.length;B<A;B++){if(!Object.isUndefined(arguments[B])){return arguments[B];}}return null;}/*
  Proto!MultiSelect 0.2
  - Prototype version required: 6.0
  
  Credits:
  - Idea: Facebook
  - Guillermo Rauch: Original MooTools script
  - Ran Grushkowsky/InteRiders Inc. : Porting into Prototype and further development
  
  Changelog:
  - 0.1: translation of MooTools script
  - 0.2: renamed from Proto!TextboxList to Proto!MultiSelect, added new features/bug fixes
        added feature: support to fetch list on-the-fly using AJAX    Credit: Cheeseroll
        added feature: support for value/caption
        added feature: maximum results to display, when greater displays a scrollbar   Credit: Marcel
        added feature: filter by the beginning of word only or everywhere in the word   Credit: Kiliman
        added feature: shows hand cursor when going over options
        bug fix: the click event stopped working
        bug fix: the cursor does not 'travel' when going up/down the list   Credit: Marcel
*/

/* Copyright: InteRiders <http://interiders.com/> - Distributed under MIT - Keep this message! */

var FacebookList = Class.create(TextboxList, { 
  
  loptions: $H({    
    autocomplete: {
      'opacity': 0.8,
      'maxresults': 10,
      'minchars': 1
    }
  }),
  
  initialize: function($super,element, autoholder, options, func) {
    $super(element, options);
    this.data = [];    
    this.autoholder = $(autoholder).setOpacity(this.loptions.get('autocomplete').opacity); 
    this.autoholder.observe('mouseover',function() {this.curOn = true;}.bind(this)).observe('mouseout',function() {this.curOn = false;}.bind(this));
    this.autoresults = this.autoholder.select('ul').first();
    var children = this.autoresults.select('li');
    children.each(function(el) { this.add({value:el.readAttribute('value'),caption:el.innerHTML}); }, this); 
  },
  
  autoShow: function(search) {
    this.autoholder.setStyle({'display': 'block'});
    this.autoholder.descendants().each(function(e) { e.hide() });
    if(! search || ! search.strip() || (! search.length || search.length < this.loptions.get('autocomplete').minchars)) 
    {
      this.autoholder.select('.default').first().setStyle({'display': 'block'});
      this.resultsshown = false;
    } else {
      this.resultsshown = true;
      this.autoresults.setStyle({'display': 'block'}).update('');
      if (this.options.get('wordMatch'))
        var regexp = new RegExp("(^|\\s)"+search,'i')
      else
        var regexp = new RegExp(search,'i')
      var count = 0;
      this.data.filter(function(str) { return str ? regexp.test(str.evalJSON(true).caption) : false; }).each(function(result, ti) {
        count++;
        if(ti >= this.loptions.get('autocomplete').maxresults) return;
        var that = this;
        var el = new Element('li');
        el.observe('click',function(e) { 
            e.stop();
            that.autoAdd(this); 
        }).observe('mouseover',function() { 
            that.autoFocus(this);
        }).update(this.autoHighlight(result.evalJSON(true).caption, search));
        this.autoresults.insert(el);
        el.cacheData('result', result.evalJSON(true));
        if(ti == 0) this.autoFocus(el);
      }, this);
    }
    if (count > this.options.get('results'))
        this.autoresults.setStyle({'height': (this.options.get('results')*24)+'px'});
    else
        this.autoresults.setStyle({'height': (count?(count*24):0)+'px'});
    return this;
  },
  
  autoHighlight: function(html, highlight) {
    return html.gsub(new RegExp(highlight,'i'), function(match) {
      return '<em>' + match[0] + '</em>';
    });
  },
  
  autoHide: function() {    
    this.resultsshown = false;
    this.autoholder.hide();    
    return this;
  },
  
  autoFocus: function(el) {
    if(! el) return;
    if(this.autocurrent) this.autocurrent.removeClassName('auto-focus');
    this.autocurrent = el.addClassName('auto-focus');
    return this;
  },
  
  autoMove: function(direction) {    
    if(!this.resultsshown) return;
    this.autoFocus(this.autocurrent[(direction == 'up' ? 'previous' : 'next')]());
    this.autoresults.scrollTop = this.autocurrent.positionedOffset()[1]-this.autocurrent.getHeight();         
    return this;
  },
  
  autoFeed: function(text) {
    if (this.data.indexOf(Object.toJSON(text)) == -1)
        this.data.push(Object.toJSON(text));
    return this;
  },
  
  autoAdd: function(el) {
    if(!el || ! el.retrieveData('result')) return;
    this.add(el.retrieveData('result'));
    delete this.data[this.data.indexOf(Object.toJSON(el.retrieveData('result')))];
    this.autoHide();
    var input = this.lastinput || this.current.retrieveData('input');
    input.clear().focus();
    return this;
  },
  
  createInput: function($super,options) {
    var li = $super(options);
    var input = li.retrieveData('input');
    input.observe('keydown', function(e) {
        this.dosearch = false;
        switch(e.keyCode) {
          case Event.KEY_UP: e.stop(); return this.autoMove('up');
          case Event.KEY_DOWN: e.stop(); return this.autoMove('down');        
          case Event.KEY_RETURN:
            e.stop();
            if(! this.autocurrent) break;
            this.autoAdd(this.autocurrent);
            this.autocurrent = false;
            this.autoenter = true;
            break;
          case Event.KEY_ESC: 
            this.autoHide();
            if(this.current && this.current.retrieveData('input'))
              this.current.retrieveData('input').clear();
            break;
          default: this.dosearch = true;
        }
    }.bind(this));
    input.observe('keyup',function(e) {
        
        switch(e.keyCode) {
          case Event.KEY_UP: 
          case Event.KEY_DOWN: 
          case Event.KEY_RETURN:
          case Event.KEY_ESC: 
            break;              
          default: 
                if (!Object.isUndefined(this.options.get('fetchFile'))) {
                  new Ajax.Request(this.options.get('fetchFile'), {
                    parameters: {keyword: input.value},
                    onSuccess: function(transport) {
                        transport.responseText.evalJSON(true).each(function(t){this.autoFeed(t)}.bind(this));
                        this.autoShow(input.value);
                    }.bind(this)
                  });        
                }
                else
                    if(this.dosearch) this.autoShow(input.value);          
        }        
    }.bind(this));
    input.observe(Prototype.Browser.IE ? 'keydown' : 'keypress', function(e) { 
      if(this.autoenter) e.stop();
      this.autoenter = false;
    }.bind(this));
    return li;
  },
  
  createBox: function($super,text, options) {
    var li = $super(text, options);
    li.observe('mouseover',function() { 
        this.addClassName('bit-hover');
    }).observe('mouseout',function() { 
        this.removeClassName('bit-hover') 
    });
    var a = new Element('a', {
      'href': '#',
      'class': 'closebutton'
      }
    );
    a.observe('click',function(e) {
          e.stop();
          if(! this.current) this.focus(this.maininput);
          this.dispose(li);
    }.bind(this));
    li.insert(a).cacheData('text', Object.toJSON(text));
    return li;
  }
  
});

Element.addMethods({
    onBoxDispose: function(item,obj) { obj.autoFeed(item.retrieveData('text').evalJSON(true)); },
    onInputFocus: function(el,obj) { obj.autoShow(); },    
    onInputBlur: function(el,obj) { 
        obj.lastinput = el;
        if(!obj.curOn) {
            obj.blurhide = obj.autoHide.bind(obj).delay(0.1);
        }
    },
    filter:function(D,E){var C=[];for(var B=0,A=this.length;B<A;B++){if(D.call(E,this[B],B,this)){C.push(this[B]);}}return C;}
});  /*]]>*/