/*
  Copyright INRA/CNRS

 Emmanuel.Courcelle@toulouse.inra.fr
 Jerome.Gouzy@toulouse.inra.fr
 Thomas.Faraut@toulouse.inra.fr

 This software is a computer program whose purpose is to provide a
 web-based interface for analyzing the different levels of genome
 conservations.

 This software is governed by the CeCILL license under French law and
 abiding by the rules of distribution of free software.  You can  use,
 modify and/ or redistribute the software under the terms of the CeCILL
 license as circulated by CEA, CNRS and INRIA at the following URL
 "http://www.cecill.info".

 As a counterpart to the access to the source code and  rights to copy,
 modify and redistribute granted by the license, users are provided only
 with a limited warranty  and the software's author,  the holder of the
 economic rights,  and the successive licensors  have only  limited
 liability.

 In this respect, the user's attention is drawn to the risks associated
 with loading,  using,  modifying and/or developing or reproducing the
 software by the user in light of its specific status of free software,
 that may mean  that it is complicated to manipulate,  and  that  also
 therefore means  that it is reserved for developers  and  experienced
 professionals having in-depth computer knowledge. Users are therefore
 encouraged to load and test the software's suitability as regards their
 requirements in conditions enabling the security of their systems and/or
 data to be ensured and,  more generally, to use and operate it in the
 same conditions as regards security.

 The fact that you are presently reading this means that you have had
 knowledge of the CeCILL license and that you accept its terms

*/

/*

=pod

=head1 NAME

 LipmAjax.js - Objects useful for ajax-based interactions
               LipmAjax objects are VERY USEFUL in conjunction with WebBuilder (server side)

=head1 SYNOPSIS

 LipmAjaxBaseClass                       An abstract class, base class for all other classes
     LipmAjaxDataClass                   A concrete class, the result of the request is stored in a data structure
     LipmAjaxPopupClass                  An abstract class, the reult of the request is displayed in a LipmPopup
         LipmAjaxSimpleClass             A concrete class, a simple class for ajax requests
             LipmAjaxPartialRequestClass A concrete class, same as SimpleClass but it calls the LipmPopup method PartialDisplay instead of Display
			                             Used internally, not sure you'll need using it explicitly
         LipmAjaxFormClass               A concrete class, a more complete class for ajax requests (IT IS REALLY USEFUL)

 DEPENDENCIES:  InitForm.js, LipmLed.js, LipmPopup.js, LipmHistory.js
 
 IMPORTANT - From Mars 2009, the fiel parameter used by Submit must be separated by &, NOT by ,:
             o_ajax.SubmitAjax('param1=1,param2=2') IS NOT CORRECTLY PARSED
			 o_ajax.SubmitAjax('param1=1&param2=2') is correctly parsed

=cut
*/


/*
=pod

=head1 class LipmAjaxBaseClass

 Title        : LipmAjaxBaseClass
 Usage        : This class is a Base class for most ajax requests
 Constructor arg: o_error (optional) An already built LipmPopupBaseClass object
                  o_led (optional) An already build LipmLed object (only used by the derived classes)
                  o_error.Close() is called by the object constructor, and the led is put off
 Member functions: SubmitAjax   for submitting an ajax request
                                SubmitAjax adds an onComplete handler to the o_parameters object, then a little object is queued to LipmAjaxBaseClass.__a_ajax_queue
								If there is no ajax request running yet, the complete handler is called to trigger the process
								However, The **REAL** submit code lives in the derived classes, who should call the super SubmitAjax
				   SubmitFunction It is possible to insert a function in the queue, to defer execution and to synchronize
				                  the execution of this function with the Ajax requests
                   SetDefaultParams Set default fields name=value, those fields should be used by the SubmitAjax requests in the derived objects
                   SetSubmitUrl Set the url for Ajax requests (or ordinary requests, see LipmAjaxFormClass.Submit)
                   AjaxFailure could be connected to the failure handler (in the derived classes)
 Globals      :    none

=cut
*/

LipmAjaxBaseClass = Class.create({
	initialize: function(o_error,o_led)
	{
		this._o_error = o_error;
		this._o_led   = o_led;	
		this.__asynchronous=true;
		
		//__a_ajax_queue is a "static" property
		if (LipmAjaxBaseClass.__a_ajax_queue==undefined)
		{
			LipmAjaxBaseClass.__a_ajax_queue = $A();
		};

		if (this._o_error != undefined) {this._o_error.Close();};
		if (this._o_led   != undefined) {this._o_led.SetStatus('off');};
		//this._submit_url = document.URL;	// This may be redefined by LipmAjaxFormClass to form.action
		this._submit_url = window.location.pathname;
	},
	SubmitAjax: function(url,o_parameters)
	{
		o_parameters.onComplete = this.__AjaxCompleted.bind(this);
		o_parameters.asynchronous = this.__asynchronous;
		var o_ajax_request = {
			led: this._o_led,
			url: url,
			prm: o_parameters
		};
		LipmAjaxBaseClass.__a_ajax_queue.unshift(o_ajax_request);
		if (Ajax.activeRequestCount==0)
		{
			// Call __AjaxCompleted in order to start the Ajax request if there is no request now running
			this.__AjaxCompleted();
		}
	},
	SubmitFunction: function(o_fct)
	{
		var o_call_request = {
			fct: o_fct
		};
		LipmAjaxBaseClass.__a_ajax_queue.unshift(o_call_request);
	},
	/*
=pod

=head2 ClearAjaxQueue

 	Title     : ClearAjaxQueue
	Usage     : o_ajax.clearAjaxQueue()
	Procedure : Clears the queued requests, cancelling every planned request
	            this is very useful in the case of planned partial requests, if you do not want to wait for the execution of the whole set of planned requests
				before launching a new full request
	Args      : none

=cut
	*/
	ClearAjaxQueue: function() { LipmAjaxBaseClass.__a_ajax_queue.clear(); },
		
	/*
=pod

=head2 __AjaxCompleted

 	Title     : __Ajaxcompleted
	Usage     : This procedure is called when an ajax request is terminated
	Procedure : Check the STATIC member LipmAjaxBaseClass.__a_ajax_queue, and if not empty fire the next request
	            Manage the led status if necessary
	Args      : none

=cut
	*/
	__AjaxCompleted: function()
	{
		//var sts="";
		//if ( LipmAjaxBaseClass.__a_ajax_queue.length == 0 ) 
		//{
			if (this._o_led != undefined) {this._o_led.SetStatus('off');};
		//}
		//else
		if ( LipmAjaxBaseClass.__a_ajax_queue.length != 0 )
		{
			var o_request = LipmAjaxBaseClass.__a_ajax_queue.pop();
			if (o_request.fct != undefined)
		{
				o_request.fct.call();
				this.__AjaxCompleted();
		}
		else
		{
				if (o_request['led'] != undefined) {
					o_request.led.SetStatus('running');
		};
				new Ajax.Request(o_request.url,o_request.prm);
			}
		};
		//console.log (this);
	},

	SetSubmitUrl: function(url)
	{
		this._submit_url = url;
	},

	/*
=pod

=head2 SetAsynchronous, UnsetAsynchronous

    Title    :  SetAsynchronous, UnsetAsynchronous
    Procedures: The next SubmitAjax request will be sent in an asynchronous or synchronous mode
                THE DEFAULT IS TO RUN ASYNCHRONOUSLY

=cut

*/
	SetAsynchronous: function(){this.__asynchronous=true;},
	UnsetAsynchronous: function(){this.__asynchronous=false;},

	/*
=pod

=head2 SetDefaultParams

	Title: SetDefaultParams
	Usage: o_obj.SetDefaultParams("login=xxx&password=xxx");
	Procedure: Set default parameters, they will be added to the parameters when calling SubmitAjax
	Args:      param1=val1&param2=val2...
	Control:   public
	Globals:   none

=cut
	*/
	SetDefaultParams: function(prms)
	{
		this._def_params = prms;
	},

	/*
	Title: _AddSessionToFieldValues
	Usage: field_values = this._AddSessionToFieldValues(field_values);
    Function: Return the filed_values passed by parameter, with the __wb_session= parameter appended
              -If already in field_values, return the parameter unchanged
              -If not in field_values but in o_param, take __wb_session from o_param and return field_values appended
              -If not in field_values and not in o_param, take __wb_session from form and return field_values appended
              -If nowhere, return field_values unchanged
	Args:      form    (may be undefined): a form element
               o_param (may be undefined): a javascript object, the fiels __wb_session will be looed for
               field_values              : cf. Submitajax
    return:    the (may be) appended field_values
	Control:   protected
	Globals:   none

	*/
	_AddSessionToFieldValues: function(form,o_param,field_values)
	{
		if (field_values.include('__wb_session=')) {
			return field_values;
		}
		else
		{
			if (o_param != undefined && o_param['__wb_session'] != undefined)
			{
				return field_values + '&__wb_session=' + o_param['__wb_session'];
			}
			else
			{
				if (form != undefined && form['__wb_session']!=undefined)
				{
					return field_values + '&__wb_session=' + form['__wb_session'];
				}
				else
				{
					return field_values;
				}
			}
		}
	},
	/*
	Title: _GetSessionId
	Usage: params['__wb_session'] = _GetSessionId(o_param,form)
    Function: Return the session id, if found:
              -If in o_param
              -If not in o_param, in form (looking for a probably hidden field)
              If found nowhere, retrun undefined
	Args:     form    (may be undefined): a form element
              o_param (may be undefined): a javascript object, the field __wb_session will be looked for
    return:   The session id
	Control:  protected
	Globals:  none

	*/
	_GetSessionId: function(o_param,form)
	{
		if (o_param != undefined && o_param['__wb_session'] != undefined)
		{
			return o_param['__wb_session'];
		};
		if (form != undefined && form['__wb_session']!=undefined)
		{
			return form['__wb_session'];
		};
		return undefined;
	},


	/*
	Title: _AjaxFailure
	Usage: onFailure handler for an Ajax request
	Procedure: Update and show the error container, if any
	Args:      response
	Control:   Protected
	Globals:   O-CFG

	*/
	_AjaxFailure: function (response)
	{
		if (this._o_error != undefined) {this._o_error.Display(response.responseText,'ERROR');};
		if (this._o_led != undefined) {this._o_led.SetStatus('failed');};

	},

	/*
=pod

=head2 CloseError

 	Title     : CloseError
	Usage     : Handler of the event 'click' on a Close link from the error container
	            This is NOT useful if the ajax container is a YUI popup
	Procedure : hide the container
	Args      : none

=cut
	*/
	CloseError: function()
	{
		if (this._o_error != undefined)  {this._o_error.Close();}
	}

});


/*
=pod

=head1 class LipmAjaxDataClass

 Title        : LipmAjaxDataClass
 Usage        : This class, deriving from LipmAjaxBaseClass, implements the details of the Ajax communication
                when you want to initialize a data structure from an Ajax request
                The method GetData is used to retrieve the data
 Constructor arg: o_error (optional) The LipmPopupBaseClass which will be used to display the error
                  o_led (optional)   If defined, this LipmLed led changes its status
 Globals      :

=cut
*/

LipmAjaxDataClass = Class.create(LipmAjaxBaseClass,{
	initialize: function($super,o_error,o_led)
	{
		$super(o_error,o_led);
		this.__o_response_data="";
	},

	/*
=pod

=head2 SubmitAjax

    Title    : SubmitAjax
    Usage    : obj.SubmitAjax(field1=value1&field2=value2);
    Procedure: start an ajax request, specifying arguments
               The parameter __wba_ajax=j is added to the parameters, driving WebBuilder to the JSON-return ajax mode
    Args     : field_values (string)   : field1=value1&field2=value2
               on_success (optional)   : If specified, this function is called by the on_success handler, thus enabling
                                         some specific post-processing - Useful to get the data retrieved in an asychronous way

	Globals:   O_PARAM

=cut

	*/
	SubmitAjax: function($super,field_values,on_success)
	{
		if (field_values == undefined){return;};

		// Computing the parameters
		var params = $H();

		// Default parameters
		if (this._def_params != undefined)
		{
			params.update(this._def_params.toQueryParams());
		}

		// field_values
		params.update(field_values.toQueryParams());

		// Append __wb_session if possible
		if (params.get('__wb_session')==undefined)
		{
			var session=undefined;
			try
			{
				session = this._GetSessionId(O_PARAM);
			}
			catch(e){};
			if (session!=undefined){params.set('__wb_session',session);};
		}

		// Apending __wba_ajax
		params.set('__wba_ajax','j');

		// Call an ajax request - We add the on_success field to the object
		$super(this._submit_url,
		{
			method:  'post',
			evalJS:  true,
			parameters: params,
			onSuccess: this._AjaxSuccess.bind(this),
			onFailure: this._AjaxFailure.bind(this),
			on_success: on_success
		});
	},

	/*
	Title: _AjaxSuccess
	Usage: onSuccess handler for an Ajax request
	Procedure: Init the data with the Ajax request return, which should be JSON-formatted
	           Call the on_success handler, if possible
	Args:      response
	Control:   protected

	*/
	_AjaxSuccess: function(response)
	{
		this.__o_response_data = response.responseJSON;

		// Call the function that was passed to SubmitAjax
		var on_success = response.request.options.on_success;
		if (on_success != undefined)
		{
			on_success.call(response);
		}
		//if (this._o_led != undefined) {this._o_led.SetStatus('off');};

	},

		/*
=pod

=head2 GetData

    Title    : GetData
    Usage    : var a_data = obj.GetData();
    Function : Copy the requested data to a_data
               WARNING - If the (asynchronous) Ajax request is NOT terminated when GetData is called, the result is unpredictable
    Args     : none
    Return   : The data
    Globals  : none

=cut

	*/
	GetData: function()
	{
		return this.__o_response_data;
	}
});

/*
=pod

=head1 class LipmAjaxPopupClass

 Title        : LipmAjaxPopupClass
 Usage        : This class is a Base class for LipmAjaxSimpleClass and LipmAjaxFormClass
                This class derives from LipmAjaxBaseClass
 Constructor arg: o_ajax_container  An already built LipmPopupBaseClass object
                  o_error           An already built LipmPopupBaseClass object
                                    o_error.Close() is called by the object constructor
                  o_led             An already built LipmLedBaseClass object
 Member functions: SubmitAjax   Call the $super function, that's all
                   SetPopupHdFt the header and footer of the ajax_container popup are set by this function
                                You may specify (undefined,'some_thing') to set only the footer
                   _AjaxSuccess could be connected to the success handler (in the derived classes)
 Globals      : O_PARAM

=cut
*/

LipmAjaxPopupClass = Class.create(LipmAjaxBaseClass,{
	initialize: function($super,o_ajax_container,o_error,o_led)
	{
		$super(o_error,o_led);
		this._o_ajax_container = o_ajax_container;
		this.__PopupHeader = undefined;
		this.__PopupFooter = undefined;
		if (this._o_error != undefined) {this._o_error.Close();};
	},
	SetPopupHdFt: function(header,footer)
	{
		this.__PopupHeader = header;
		this.__PopupFooter = footer;
	},

	/*
	Title: _AjaxSuccess
	Usage: onSuccess handler for an Ajax request
	Procedure: Update and show the ajax container
	Args:      response
	Control:   protected
	Globals:   O-CFG

	*/
	_AjaxSuccess: function(response)
	{
		//console.log('this._o_ajax_container %o', this._o_ajax_container);
		//console.log('response %o', response);

		// PROVISOIRE !!! cf. narcisse.cgi pour les details
		if (response.responseText.endsWith(" ===")==false)
		{
			// NOTE - This should not be important, because this._o_ajax_container.Display evaluates the scripts, too
			//        However, Display calls update(), and the evaluation is done through a call to defer(), and this may be too late
			//        when the server asks for partial requests (see _Ajaxsuccess in LipmAjaxFormClass !)
			response.responseText.evalScripts();
			this._o_ajax_container.Display(response.responseText,this.__PopupHeader,this.__PopupFooter);
		}
		if (this._o_error != undefined) {this._o_error.Close();};
		//if (this._o_led != undefined) {this._o_led.SetStatus('off');};

	},

	/*
=pod

=head2 CloseSuccess

 	Title     : CloseSuccess
	Usage     : Handler of the event 'click' on a Close link from the ajax container
	            This is NOT useful if the ajax container is a YUI popup
	Procedure : hide the container
	Args      : none

=cut
	*/
	CloseSuccess: function()
	{
		this._o_ajax_container.Close();
	}
});

/*
=pod

=head1 class LipmAjaxSimpleClass

 Title        : LipmAjaxSimpleClass
 Usage        : This class, deriving from LipmAjaxPopupClass, implements the details of the Ajax communication
                in very simple situations. No form, we just use a container to display the result and a container to display the error if any.
				The latter is optional, if not specified there is no error handling (but this is a ugly thing to do)
 Constructor arg: o_ajax_container       The LipmPopupBaseClass which will be updated by the Ajax request
				  o_error (optional)     The LipmPopupBaseClass which will be used to display the error
 Globals      :

=cut
*/

LipmAjaxSimpleClass = Class.create(LipmAjaxPopupClass,{
	initialize: function($super,o_ajax_container,o_error,o_led)
	{
		$super(o_ajax_container,o_error,o_led);
	},

	/*
=pod

=head2 SubmitAjax

    Title    : SubmitAjax
    Usage    : obj.SubmitAjax(field1=value1&field2=value2);
	Procedure: start an ajax request, specifying arguments
	           The parameter __wba_ajax=1 is added to the parameters, informing WebBuilder that we are driving an ajax-based request
	Args     : field_values (string)   : field1=value1&field2=value2

	Globals: O_PARAM

=cut

	*/
	SubmitAjax: function($super,field_values)
	{
		if (field_values == undefined){return;};

		// Computing the parameters
		var params = $H();

		// Default parameters
		if (this._def_params != undefined)
		{
			params.update(this._def_params.toQueryParams());
		}

		// field_values
		params.update(field_values.toQueryParams());

		// Append __wb_session if possible
		if (params.get('__wb_session')==undefined)
		{
			var session=undefined;
			try
			{
				session = this._GetSessionId(O_PARAM,undefined);
			}
			catch(e){};
			if (session!=undefined){params.set('__wb_session',session);};
		}

		// Apending __wba_ajax
		params.set('__wba_ajax',1);

		// Call an ajax request
		$super(this._submit_url,
		{
			method:  'post',
			parameters: params,
			onSuccess: this._AjaxSuccess.bind(this),
			onFailure: this._AjaxFailure.bind(this)
		});
	}
});

/*
=pod

=head1 class LipmAjaxPartialRequestClass

 Title        : LipmAjaxPartialRequestClass
 Usage        : This class, deriving from LipmAjaxSimpleClass, redefines _AjaxFailure and _AjaxSuccess: either method uses
                this._o_ajax_container.PartialDisplay to display the returned html, it is used in conjuction with the __wba_index parameter
 Globals      : none

=cut
*/
LipmAjaxPartialRequestClass = Class.create(LipmAjaxSimpleClass,{
		initialize:function($super,o_ajax_container,o_error,o_led){$super(o_ajax_container,o_error,o_led);},
		_AjaxFailure: function(response)
		{
			this._o_ajax_container.PartialDisplay(response.request.options.wba_index,'<div class="wb_error">ERROR</div>');
		},
		_AjaxSuccess: function(response)
		{
			var index = response.request.parameters.__wba_index;
			this._o_ajax_container.PartialDisplay(index,response.responseText);
		}
});

/*
=pod

=head1 class LipmAjaxFormClass

 Title        : LipmAjaxFormClass
 Usage        : This class is related to a form
                It implements the details of the form submit AND Ajax communication
                This object is particularly interesting in conjunction with WebBuilder based applications

 Constructor arg: form                    The form
                  o_ajax_container        The LipmPopupBaseClass which will be updated by the Ajax request
                  o_error (optional)      Used to display the errors
                  o_led                   (optional) A LipmLedClass object
                  o_ajax_history (optional) A LipmHistoryManagerClass object which will be called on success to store the request in a history manager
                  If O_PARAM and Initform exist, InitForm is called to initialize the form from the parameters
                  If O_PARAM.__wba_ajax exists and is > 1, we call SubmitAjax
                  If O_PARAM does not exist if it created (and set to 0), just to avoid using a lot of try's in the code

 Member functions: UpdatePage, MAY BE overloaded - Update the displayed page from the form parameters, called after each request
 Globals      : O_PARAM (managed by WebBuilder.pm)

=cut
*/

LipmAjaxFormClass = Class.create(LipmAjaxPopupClass,{
	initialize: function($super,form,o_ajax_container,o_error,o_led,o_ajax_history)
	{
		$super(o_ajax_container,o_error,o_led);
		this._form = form;
		this.__hidden_fields = this._form.down('p');	// used to store the hidden fields, first p under the tag form
		this._o_ajax_history = o_ajax_history;
		if (o_ajax_history != undefined) {o_ajax_history.RegisterAjax(this);};
		
		// If form.action is specified in the html code, we redefine this._submit_url to form.action, if form.action is specified
		// However, with IE8, if form.action is "" in the html, it is redefined to the base URI, terminating with / - And this does not work 
		// for the following ajax requests !!!
		// So, if form.action ends with '/', we ignore it
		if (form.action != "" && form.action.endsWith('/') == false)
		{
			this._submit_url     = form.action;         // Previously set to document.URL
		}

		// If O_PARAM.__wba_ajax > 1 the server wants other ajax requests (probably WebBuilded based)
		try
		{
			if (O_PARAM.__wba_ajax != undefined && O_PARAM.__wba_ajax > 1) {this.SubmitAjax(Object.toQueryString(O_PARAM));};
		}
		catch (e){
			// If O_PARAM does not exist, create a dummy O_PARAM, just to avoid other errors
			O_PARAM = 0;
		}

		// Try to init the form from O_PARAM, ignoring errors (may be we don't know InitForm)
		try
		{
			InitForm(this._form,O_PARAM);
		}
		catch (e){};
	},

	/*
=pod

=head2 GetForm

        Title   : GetForm
        Usage   : var form = obj.GetForm();
        Function: Getter for the form
        Args    : none

=cut
    */
	 GetForm: function() { return this._form; },

	/*
=pod

=head2 Submit

    Title: Submit
    Usage: obj.Submit();
           obj.Submit('field1=value1&field2=value2','action_name');
    Procedure: Call submit on the form ==> Ajax is NOT used here
               If field_values is defined, it must be something like field1=value1&field2=value2,
               and this.SetValue is called for every pair fieldn=valuen
    Args:      field_values (string): field1=value1&field2=value2
               action_name (string, optional): The name of the Action field (default = don't change the name)

=cut
	*/

	Submit: function(field_values,action_name)
	{
		if (field_values != undefined)
		{
			// Keep the new parameters in the form
			var a_pairs = field_values.split('&');
			var thisLipmAjaxFormClass = this;
			a_pairs.each(function(pair)
			{
				//alert(p+' '+pairs[p]);
				thisLipmAjaxFormClass.SetValue(pair);
			});
		}

		// If an action name was provided, change the action name just for this request
		// NOTE - If an action name was NOT provided, we DO NOT CHANGE the url anyway

		var sav_action;
		if (action_name != undefined)
		{
			sav_action = this.GetForm().action;
			this.GetForm().action = this._submit_url + '/' + action_name;
		}

		// Submit the form
		this._form.submit();

		// If it was changed, restore the action
		if (action_name != undefined)
		{
			this.GetForm().action = sav_action;
		}
	},

	/*
=pod

=head2 SubmitAjax

    Title: SubmitAjax
    Usage: obj.SubmitAjax('field1=value1,field2=value2');
	       obj.SubmitAjax('field1=value1,field2=value2','history_text',callback);
    Procedure: start an ajax request, specifying arguments and maybe a history text and a callback function
    Args:      field_values (string)   : field1=value1,field2=value2 or
                                         field1=value1&field2=value2
                                         If undefined, the form is serialized to field_values
               history_text (optional) : If specified, the history Add function is called with this text
                                         If not specified, the history Add function is called with undefined
               on_success (optional)   : If specified, this function is called by the on_success handler, thus enabling
                                         some specific post-processing

    Globals: none

=cut

	*/
	SubmitAjax: function($super,field_values,history_text,on_success)
	{
		var form = this._form;
		if (field_values == undefined)
		{
			field_values = form.serialize();
		};

		// Computing the parameters
		var params = $H();

		// Default parameters
		if (this._def_params != undefined)
		{
			params.update(this._def_params.toQueryParams());
		}

		// field_values
		params.update(field_values.toQueryParams());

		// Append __wb_session if possible
		if (params.get('__wb_session')==undefined)
		{
			var session=undefined;
			try
			{
				session = this._GetSessionId(O_PARAM,form);
			}
			catch(e){};
			if (session!=undefined){params.set('__wb_session',session);};
		}

		// Apending __wba_ajax
		params.set('__wba_ajax',1);

		// If __wb_ajax is already in O_PARAM AND > 1, we call directly __TriggerPartialRequests
		// SUPPRIME CAR on se fait des noeuds lorsque update(), appele par this._o_ajax_container.Display (cf. __AjaxSuccess de la classe mere)
		// appelle le javascript en mode defer, O_PARAM.__wba_ajax se remet a une valeur != 0 et ca merdouille
		// Pb = Si la requete initiale charge un morceau de photo, celui-ci sera charge une nouvelle fois. Deux requetes au lieu d'une seule donc
		/*var wba_ajax=undefined;
		try
		{
			wba_ajax = O_PARAM['__wba_ajax'];
		}
		catch(e){};
		if (wba_ajax!=undefined && wba_ajax>1)
		{
			this.__TriggerPartialRequests(params);
		}
		else
		{*/
			// Call an ajax request - We add 2 fields to the object: history_text and on_success, they will be retrieved by the success handler
			var history_stamp = "";
			if (history_text != undefined){history_stamp=form.serialize();};

			//new Ajax.Request(this._submit_url,
			$super(this._submit_url,
				{
					method:  'post',
					parameters: params,
					onSuccess: this._AjaxSuccess.bind(this),
					onFailure: this._AjaxFailure.bind(this),
					history_text: history_text,
					history_stamp: history_stamp,
					on_success: on_success
				});
		/*}*/
	},

	/*
=pod

=head2 SubmitAjaxKeys

    Title: SubmitAjaxKeys
    Usage: obj.SubmitAjaxKeys('key1&key2');
	       obj.SubmitAjaxKeys('key1&key2','history_text',callback);
    Procedure: build the field/values pairs from a list of keys, then call SubmitAjax
	           The key/value pairs are taken from the global variable O_PARAM, if some key is undefined it is ignored
			   Except from the fact that we look for values from O_PARAM, this method has exactly the same behaviour as SubmitAjax
    Args:      keys (string)   : key1&key2
               history_text (optional) : See SubmitAjax
               OnSuccess (optional)    : See Submitajax

    Globals: O_PARAM

=cut

	*/

	SubmitAjaxKeys: function(keys,history_text,OnSuccess)
	{
		var a_field_values=$A();
		keys.split(new RegExp("&", "g")).each(function(k) {
			if (O_PARAM[k] != undefined) {a_field_values.push(k+'='+O_PARAM[k]);}
		});
		this.SubmitAjax(a_field_values.join('&'),history_text,OnSuccess);
	},

	/*
=pod

=head2 SetPartialHandler

    Title: SetPartialHandler
    Usage: obj.SetPartialHandler(handler);
    Procedure: The PartialHandler will be executed after each partial request
    Args:      handler : the handler

=cut

	*/
	
	SetPartialHandler: function(handler) { this.__PartialHandler = handler; },
	
	/*
	Title: _AjaxSuccess
	Usage: onSuccess handler for an Ajax request
	Procedure: Change the color of the led to 'off'
	           Update the history, if possible
	           Update the specified container
			   Call the on_success handler, if possible
			   Keep the control form status in this.__backup
	Args:      response
	Control:   protected
	Globals:   O-PARAM

	*/
	_AjaxSuccess: function($super,response)
	{
		$super(response);

		this._AddToHistory(response.request.options.history_text,response.request.options.history_stamp);

		// Try to init the form from O_PARAM, ignoring errors (may be we don't know InitForm)
		try
		{
			InitForm(this._form,O_PARAM);
			this.UpdatePage();
		}
		catch (e){};

		this.__backup = this._form.serialize(true);

		// The server changes __wba_ajax to trigger a set of ajax requests (partial image retrieving)
		if (O_PARAM.__wba_ajax != undefined && O_PARAM.__wba_ajax > 1)
		{
			this.__TriggerPartialRequests(response.request.body);
		}

		// Call the function that was passed to SubmitAjax
		var on_success = response.request.options.on_success;
		if (on_success != undefined)
		{
			on_success.call(response);
		}

	},

	/*
	Title: _AddToHistory
	Usage: Called ONLY by this._AjaxSuccess
	Procedure: Add a text and a stamp to the history
               The DEFAULT behaviour is to serialize the form and use the serialized form as the history stamp
               However, it is legal to overload this function in a derived class, if the standard behaviour is not correct
	Args:      history_text: the text that was given to SubmitAjax
	           history_stamp: the stamp that was computed by SubmitAjax
	Control:   protected
	Globals:   none

	*/
	
	_AddToHistory: function(history_text, history_stamp)
	{
		if (this._o_ajax_history != undefined)
		{
			this._o_ajax_history.Add(history_text,history_stamp);
		};
	},		

	/*
	Title: __TriggerPartialRequests
	Usage: __TriggerPartialRequests(response)
	Procedure: Extract the parameters of the ajax request, encapsulated inside the response
	           Compute start, end from the __wba_start and __wba_end parameters
			   Loop from start to end, triggering a request at each step, using a local LipmAjaxPartialRequestClass object
	Args:      req_params The parameters that were used for the main request
	Control:   protected
	Globals:   O_PARAM

	*/
	__TriggerPartialRequests: function(req_params)
	{
		var parameters = req_params + '&__wba_index=';
		var start      = (O_PARAM.__wba_start != undefined) ? O_PARAM.__wba_start : 0;
		var end        = (O_PARAM.__wba_end   != undefined) ? O_PARAM.__wba_end   : O_PARAM.__wba_ajax;
		var o_ajax_partial = new LipmAjaxPartialRequestClass(this._o_ajax_container,this._o_error,this._o_led);
		for (var i=start; i<end; ++i)
		{
			o_ajax_partial.SubmitAjax(parameters+i);
		}
		if (this.__PartialHandler != undefined)
		{
			o_ajax_partial.SubmitFunction(this.__PartialHandler);
		}
		O_PARAM.__wba_ajax = 0;
	},

	/*
	Title: _AjaxFailure
	Usage: onFailure handler for an Ajax request
	Procedure: Change the color of the led to 'error'
	           Update and show the error container
	Args:      response
	Control:   Protected
	Globals:   O-CFG

	*/
	_AjaxFailure: function ($super,response)
	{
		$super(response);
		// Try to init the form from the backup, 
		try
		{
			InitForm(this._form,this.__backup);
			this.UpdatePage();
		}
		catch (e){};
	},

	/*
=pod

=head2 CloseError

       Title: CloseError
       Usage: Called when the user clicks the 'close' link on the error div, aknowledging the error
       Procedure: hide the container
               Restore the form status and update the page
               change the led status to 'off'
    Args:      none
   Globals:   O-CFG

=cut
*/
	CloseError: function($super)
	{
		$super();
		if (this._o_led != undefined) {this._o_led.SetStatus('off');};
	},


	/*
	Title: Setvalue
	Usage:     this.SetValue('some_field=some_value')
	Procedure: Look for some_field in this._form, set the value to some_value
	           If some_field does not exist, it is created as a hidden field
	Args:      A string field=value

	*/
	SetValue: function(pair)
	{
		var members = pair.split('=');
		var nme  = members[0];
		var val  = members[1];
		var form = this._form;
		for (var i=0;i<form.elements.length;i++)
		{
			var elt = form.elements[i];
			if (elt.name == nme)
			{
				SetValue(elt,val);
				//alert('found name='+nme+' value='+val);
				//if (elt.value != val){elt.value = val};
				return;
			}
		}

		var f = document.createElement('input');
		f.setAttribute('type','hidden');
		f.setAttribute('name',nme);
		f.setAttribute('id',nme);
		f.setAttribute('value',val);

		var first_hidden = this.__hidden_fields.appendChild(f);
	},


/*
=pod

=head2 UpdatePage

    UpdatePage should be redefined by the derived classes
	  - It is called by _AjaxFailure, to be sure that the displayed status of the form is synchronized with the fields

=cut
*/
	UpdatePage: function(){}

});

/*
=pod

=head1 COPYRIGHT NOTICE

This software is governed by the CeCILL license under French law - www.cecill.info

=cut
*/


