﻿/**************************************************
	File: DakisApi.js
	Provide independant components to be assembled to form a
	complete DHE application or to be integrated one piece at
	a time into a website

	Javascript Dependencies:

	- prototype.js
	- effects.js
	- swfobject.js

***************************************************/

// Section: Public

function addEvent(oTarget, sType, fpDest) {
  var oOldEvent = oTarget[sType];
  if (typeof oOldEvent != "function") {
    oTarget[sType] = fpDest;
  } else {
    oTarget[sType] = function(e) {
      oOldEvent(e);
      fpDest(e);
    }
  }
}

/*
	Function: dakisInit
	First function to call. Initialize the machine!

	Parameters:

	retailerId - your unique identifier
	serverUrl - the dakis server to use or the proxy path
	lang - language to use. "en" for english; "fr" for french.
	initSuccessCallback - Callback when the dakisInit sequence is completed successfully
*/
function dakisInit( retailerId, serverUrl, lang, initSuccessCallback )
{
	dakisAssert(g_dakisServerUrl === "", "dakisInit: must be called only once");
	g_dakisServerUrl = serverUrl;

	// make sure the server url ends width a slash...
	if( g_dakisServerUrl.substr(g_dakisServerUrl.length-1, 1) != '/' ){ g_dakisServerUrl += '/';}

	g_dakisRetailerId = retailerId;
	g_dakisLang = lang;

	addEvent( window, "onload", function(){ g_dakisStubLoadingDiv = createHiddenDiv(g_dakisStubLoadingDivId); } );

	addEvent( window, "onload", function(){
		g_dakisTrace.setVisible(g_dakisDebug);
		g_dakisTrace.minimized = true;
		g_dakisTrace.setTraceErrorListener(onDakisTraceError);
		g_dakisTrace.create();
	});

	window.onerror = onDakisJsError;

	g_dakisTrace.traceInfo(navigator.userAgent);
	g_dakisTrace.traceInfo("Retailer id: "+retailerId);
	g_dakisTrace.traceInfo("Language: "+lang);
	g_dakisTrace.traceInfo("Server URL: "+serverUrl);
	g_dakisTrace.traceInfo("initializing...");

	// the only ajax request not guarded... all other server calls wait for this one to finish
	var url = getActionUrl({ action:'init', lang: g_dakisLang });
	new Ajax.Request( url, { method:'get', onComplete: function(request){onDakisInitialized(request,initSuccessCallback);}} );
}

function onDakisInitialized(request, initSuccessCallback)
{
	if( request.status == 200 )
	{
		g_dakisTrace.traceInfo("initialization ok");
		g_dakisGlobalExecutionGuard.onDakisInitialized();

		// The request.responseText will contain the retailer config in JSON notation
		g_dakisRetailerInfo = eval('('+ request.responseText +')');
		g_dakisTrace.traceInfo('retailer name: ' + g_dakisRetailerInfo.name );
		g_dakisTrace.traceInfo('has checkout:  ' + (g_dakisRetailerInfo.hasCheckout ? 'yes' : 'no') );
		g_dakisTrace.traceInfo('webdhe version: ' + g_dakisRetailerInfo.webdheVersion);

		// Make sure that this set of JS files is compatible with the WebDHE version we are communicating
		// with.
		if( EXPECTEDWEBDHEVERSION.indexOf(g_dakisRetailerInfo.webdheVersion) == -1 )
		{
		//dakisAssert( EXPECTEDWEBDHEVERSION.indexOf(g_dakisRetailerInfo.webdheVersion) != -1, '' );
			dakisAssert( false, 'This version of the WebDHE javascript files is not compatible with the WebDHE server version (server: ' + g_dakisRetailerInfo.webdheVersion + ', supported: ' + EXPECTEDWEBDHEVERSION.toString() + ')' );
		}
		else
		{
			// All is good, initialization was completed successfully
			if( initSuccessCallback != null )
				initSuccessCallback();			
		}
	}
	else
	{
		g_dakisTrace.traceError("initialization failed.  Request response text: "+request.responseText);
	}
}

//added to fix cart indicator bug
function onDakisCartInitialized(request)
{
	if( request.status == 200 )
		g_dakisGlobalExecutionGuard.onDakisCartInitialized();
	else
		g_dakisTrace.traceError("cart initialization failed.  Request response text: "+request.responseText);
}

// handler for javascript errors
function onDakisJsError(msg, url, lineNo)
{
	g_dakisTrace.traceError("Javascript error - msg: "+msg+", url: "+url+", line number: "+lineNo);
}

function onDakisTraceError()
{
	sendActionRequest("user_error_traces", {traces: g_dakisTrace.getTracesAsText()});
}

// Prototype.js extensions
// Changes to the Ajax.Updater class
// 1) Added an onBeforeUpdate callback that is called before updating the receiver element
// 2) containers are now initialized in the onComplete method
Ajax.Updater.prototype = Object.extend( Ajax.Updater.prototype, {

	initialize: function(container, url, options) {
		this.transport = Ajax.getTransport();
		this.setOptions(options);

		var onBeforeUpdate = this.options.onBeforeUpdate || Prototype.emptyFunction;
		var onComplete = this.options.onComplete || Prototype.emptyFunction;
		this.options.onComplete = (function(transport, object) {

			onBeforeUpdate(transport, object);

			this.containers = {
			  success: container.success ? $(container.success) : $(container),
			  failure: container.failure ? $(container.failure) :
				(container.success ? null : $(container))
			};

			this.updateContent();
			onComplete(transport, object);

		}).bind(this);

		this.request(url);
  }

});

/*
	Function: resetForm
	Resets text, check, and combobox inputs from a form

	Parameters:
	formReset - Form to be reset (HTML FORM)
*/
function resetForm(formReset)
{
	 for(i=0; i<formReset.elements.length; i++)
	 {
		if(formReset.elements[i].type == "text")
		{
			formReset.elements[i].value = "";
		}
		else if(formReset.elements[i].type == "checkbox")
		{
			formReset.elements[i].checked = false;
		}
		else if(formReset.elements[i].type == "select-one")
		{
			formReset.elements[i].selectedIndex = 0;
		}
	 }
}

//	Function: addOverlay
//	Adds the overlaying DIV used during the loading screen
function addOverlay()
{
	var overlay_id = 'dhe_overlay';
	var overlay = $( overlay_id );
	if( !overlay )
	{
		overlay = document.createElement("div");
		overlay.className = "dhe_overlay";
		overlay.setAttribute('id', overlay_id);
		overlay.style.display = 'none';
		overlay.style.position = 'absolute';
		overlay.style.zIndex = '100';
		overlay.style.left = "0px";
		overlay.style.top = "0px";

		var bodyElem = document.getElementsByTagName("body")[0];
		bodyElem.appendChild( overlay );
	}

	//We reset the height and width according to the new content
	overlay.style.height = document.body.offsetHeight + "px";
	overlay.style.width = "100%";
	new Effect.Appear( overlay_id, { duration: 0.3, from:0.0, to:0.45 } );
}

/*
	Function: removeOverlay
	Fades the overlay used in the loading screen

	Parameters:
	blockedId - Doesn't do anything anymore (HTML Element)
*/
function removeOverlay( blockedId )
{
	var overlay_id = 'dhe_overlay';
	new Effect.Fade( overlay_id, { duration: 0.4 } );
}

/***************************************************
	Class: DakisPopupWindow
	Manages a simple popup layer that fetches
	its content via Ajax Calls
***************************************************/
DakisPopupWindow = Class.create();
DakisPopupWindow.prototype = {

	overlayId: 'popupOverlay',
	popupId: 'popupWin',
	popupContentId: 'popupContent',
	popupWidth: 500,
	popupHeight: 400,

	initialize: function()
	{
		var objBody = document.getElementsByTagName("body").item(0);
		var objOverlay = this.createHiddenDivision( this.overlayId );
		objOverlay.onclick = hidePopupWindow;
		objPopup = this.createHiddenDivision( this.popupId );
		objPopup.appendChild( this.createHiddenDivision( this.popupContentId ) );
		objBody.appendChild(objOverlay);
		objBody.appendChild(objPopup);
	},

	createHiddenDivision: function( id )
	{
		var obj = document.createElement("div");
		obj.setAttribute('id', id );
		obj.style.display = 'none';
		return obj
	},

	/*
		Method: showHTML

		Parameters:

		url - the url to the web content. The content is download via an Ajax Call
		width - the width of the popup window (defaults to 500)
		height - the height of the popop window (defaults ot 400)
	*/
	showHTML: function( url, width, height )
	{
		if( width == null )
			width = this.popupWidth;

		if( height == null )
			height = this.popupHeight;

		var self = this;
		Element.update( this.popupContentId, "" );
		dakisAjaxUpdater( this.popupContentId, url, { onComplete:function(){ self.show( width, height ); } } );
	},

	hide: function()
	{
		Element.hide( this.overlayId, this.popupId, this.popupContentId );
	},

	show: function( width, height )
	{
		this.repositionFrame( width, height );
		var self = this;
		Element.show( this.overlayId );

		new Effect.Parallel(
		[ new Effect.Appear( this.popupId, { duration:0.3 } ),
		  new Effect.Scale( this.popupId, 100, { scaleFromCenter:true, scaleFrom:10, scaleContent:false, duration:0.3, scaleMode: {  originalWidth: width, originalHeight: height } } ) ],
		  { afterFinish:function(){ self.showContent(); }, queue:'end' } );

	},

	repositionFrame: function( width, height )
	{
		var widthPercent = 100 - ( width / screen.availWidth ) * 100;
		var heightPercent = 100 - ( height / screen.availHeight ) * 100;

		if( widthPercent < 0 )
			widthPercent = 0;

		if( heightPercent < 0 )
			heightPercent = 0;

		var leftPx = ( widthPercent / 2 ) + "%";
		var topPx = ( heightPercent / 2 ) + "%";

		Element.setStyle( this.popupId, { left:leftPx, top:topPx } );
	},

	showContent: function()
	{
		new Effect.Appear( this.popupContentId, { duration:0.3 } );
	}
};

var popupWin;
function hidePopupWindow()
{
	popupWindow().hide();
}

function popupWindow()
{
	if( popupWin == null )
		popupWin = new DakisPopupWindow();

	return popupWin;
}

//====  Questionnaire ======//
//==========================//
var DakisQuestionnaire = Class.create();
DakisQuestionnaire.prototype = {
	effectDuration: 0.3,
	currentSection: null,
	sections: null,
	questionnaireElementId: 'dhe_questionnaire',
	productLineId: null,

	initialize: function(product_line_id) {
		this.sections = [];
		this.currentSection = -1;
		this.productLineId = product_line_id;
		var url = getActionUrl({ action: 'questionnaire', product_line_id: product_line_id });
		var self = this;
		dakisAjaxUpdater( CONTENT, url, { onLoading:onLoading, onComplete: function() { onComplete(); initLightboxAnchors(); self.parseSections(); self.showSection(0,0);}});
	},

	parseSections: function() {
		var questionnaire = $(this.questionnaireElementId);
		for (var i = 0; i < questionnaire.childNodes.length; ++i)
		{
			var node = questionnaire.childNodes[i];

			if (node.nodeType == 1 && node.id.indexOf('section_') === 0)
			{
				this.sections.push( new DakisQuestionnaireSection(node));
			}
		}
	},

	showSection: function(newSection, oldSection ) {
		new Effect.Fade( this.sections[oldSection].id, {duration: this.effectDuration} );
		//Element.hide( this.sections[oldSection].id );
		this.currentSection = newSection;
		//Element.show( this.sections[this.currentSection].id );

		new Effect.Appear( this.sections[this.currentSection].id, {duration: this.effectDuration, queue: 'end'} );

		this.sections[this.currentSection].visited = true;
		for (var i = this.currentSection + 1; i < this.sections.length; ++i){
			this.sections[i].visited = false;}

		this.onSectionChanged();
	},

	nextSection: function() {

		var needs = this.getNeeds();

		var nextSection = this.currentSection + 1;
		while (nextSection < this.sections.length && !this.sections[nextSection].isUnlocked(needs))
		{
			nextSection++;
		}

		if (nextSection < this.sections.length)
		{
			this.showSection(nextSection, this.currentSection);
		}
		else
		{
			this.onQuestionnaireFinished(this.productLineId, needs, this.getBudget());
		}
	},

	previousSection: function() {
		var previousSection = this.currentSection -1;
		while (previousSection >= 0 && !this.sections[previousSection].visited)
		{
			previousSection--;
		}

		if (previousSection >= 0){
			this.showSection(previousSection, this.currentSection);}
	},

	clearInputs: function(){
		inputs = $(this.questionnaireElementId).getElementsByTagName('input');
		inputs = $A(inputs);
		inputs.each( function(input)
		{
			if( input.type == 'radio' || input.type == 'checkbox' )
			{
				input.checked = false;
			}
			else if( input.type == 'text' )
			{
				input.value = '';
			}
		});
	},

	reset: function() {
		this.clearInputs();
		this.showSection(0, this.currentSection);
	},

	onSectionChanged: function()
	{
		OnSectionChanged(); //defined in behavior.js
	},

	getNeeds: function() {
		var needs = [];
		for (var i = 0; i <= this.currentSection; i++)
		{
			if (this.sections[i].visited){
				needs = needs.concat( this.sections[i].getNeeds() );}
		}

		return needs;
	},

	getBudget: function(){
		if( $('questionnaire_budget') !== undefined )
		{
			return $F('questionnaire_budget');
		}
		else
		{
			return 1000000; //return something huge
		}
	},

	onQuestionnaireFinished: function(productLineId, needs, budget) {}
};


var DakisQuestionnaireSection = Class.create();
DakisQuestionnaireSection.prototype = {
	node: null,
	id: null,
	requiredNeeds: [],
	visited: false,

	initialize: function(node) {
		this.node = node;
		this.id = node.id;
		s = new Selector('div.required_needs');
		divArray = s.findElements(node);
		if (divArray.length > 0){
			this.requiredNeeds = divArray[0].innerHTML.split(',');}
		this.requiredNeeds = this.purgeAllEmptyNeeds( this.requiredNeeds );
	},

	getNeeds: function() {
		var needs = [];
		var s = new Selector('input');
		var inputs = s.findElements(this.node);
		for (var i=0; i < inputs.length; ++i)
		{
			if (inputs[i].checked)
			{
				if( inputs[i].value.length > 0 )
				{
					values =  inputs[i].value.split(',');
					needs = needs.concat( values );
				}
			}
		}
		return needs;
	},

	isUnlocked: function(needs) {
		for ( var i = 0; i < this.requiredNeeds.length; ++i)
		{
			if (needs.indexOf(this.requiredNeeds[i]) == -1 ){
				return false;}
		}
		return true;
	},

	purgeAllEmptyNeeds: function( requiredNeeds )
	{
		requiredNeeds = requiredNeeds.compact();
		return requiredNeeds.select(function(value) {
			return value.length > 1;
		});
	}
};

/***************************************************
	Class: DakisProductLineMenu
	Display the product line menu
***************************************************/
var DakisProductLineMenu = Class.create();
DakisProductLineMenu.prototype = {

	SEARCH: 'dhe_search_',
	SEARCH_HOLDER_ID: 'div.dhe_search_form_holder',
	SEARCH_ACTION_NAME: 'search_panel',
	MENU_ACTION_NAME: 'show_product_lines',

	listenerId: null,
	htmlElementId: null,
	painted: false, //indicates if the menu is drawed on the screen (if the ajax call is complete)
	pendingMethods: null,
	currentSearchPanelId: '',
	preloadSearch: false,

	/*
		Method: initialize
		Constructor

		Parameters:

		htmlElementId - html element id where to display the product line menu
	*/
	initialize: function(htmlElementId, preloadSearch)
	{
		this.preloadSearch = preloadSearch || false;
		this.currentSearchPanelId = '';
		this.painted = false;
		this.htmlElementId = htmlElementId;
		this.listenerId = g_dakisListenerManager.getListenerId(this);
		this.pendingMethods = [];
	},

	/*
		Method: paint
		Display the menu inside the specified html element
	*/
	paint : function()
	{
		var self = this;
		var url = getActionUrl({ action: self.MENU_ACTION_NAME, lang: g_dakisLang, include_search: (this.preloadSearch?'true':'false')});
		dakisAjaxUpdater( this.htmlElementId, url , { asynchronous:true, method:'GET', onComplete: ( function(){ self.onMenuPainted(); replaceListener(this.htmlElementId, this.listenerId);}).bind(this) }  );
	},

	onMenuPainted: function()
	{
		this.painted = true; //the menu now appears in the dom
		var self = this;
		window.setTimeout( function(){ self.executePendingMethods(); }, 10 );
	},

	executePendingMethods: function()
	{
		//We now invoke method calls that were made before the component was drawed
		for( var i = 0; i < this.pendingMethods.length; i++ ){
			this.pendingMethods[i]();}

		this.pendingMethods = [];
	},

	/*
		Function: showSearchPanel
		Sends an Ajax.Updater request to server in order to display the search screen for a product line
		if the search screen is not yet loaded in the DOM

		Parameters:
		product_line_id - Id of the product line to display the search for (Integer)
		department_id - Id of the product line's department (Integer)
	*/
	showSearchPanel: function( product_line_id, department_id )
	{
		var self = this;
		if( this.painted )
		{
			var searchPanelId = this.getSearchPanelId( product_line_id, department_id );
			var searchPanel = $(searchPanelId);

			if( searchPanel === undefined )
			{
				//We may have just receive a product line id
				searchPanelId = this.findEquivalentPanel( product_line_id );
				department_id = this.retrieveDepartmentId( searchPanelId );
				searchPanel = $(searchPanelId);
				if(searchPanel === undefined ){
					return;}
			}

			var s = new Selector( this.SEARCH_HOLDER_ID );
			var results = s.findElements(searchPanel);

			if( results.length > 0 ) //We already have the search panel
			{
				this.setVisibleSearchPanel( searchPanelId );
			}
			else //We need to get the html code from the server
			{
				var url = getActionUrl({ action: self.SEARCH_ACTION_NAME, product_line_id: product_line_id, department_id:department_id });
				dakisAjaxUpdater( searchPanelId, url, { asynchronous:true, method:'get', onComplete: function(){
					self.setVisibleSearchPanel(searchPanelId);
					OnSearchUpdate();
					replaceListener( searchPanelId, self.listenerId );
				} } );
			}
		}
		else
		{
			this.pendingMethods.push( function(){ self.showSearchPanel( product_line_id, department_id ); } );
		}
	},

	retrieveDepartmentId: function( searchPanelId )
	{
		return searchPanelId.substring( searchPanelId.lastIndexOf("_")+1, searchPanelId.length );
	},

	/*
		Function: setVisibleSearchPanel
		function that changes the visible search panel.

		Parameters:
		newSearchPanelId - The id of the panel to show
	*/
	setVisibleSearchPanel: function( newSearchPanelId )
	{
		if( this.currentSearchPanelId != newSearchPanelId )
		{
			//Close previously opened search
			if( this.currentSearchPanelId !== '' )
			{
				new Effect.BlindUp( this.currentSearchPanelId, {duration: 0.3, queue:'end'});
			}

			new Effect.BlindDown( newSearchPanelId, {duration: 0.3, queue:'end'});
			this.currentSearchPanelId = newSearchPanelId;
		}
	},

	/*
		Function: getSearchPanelId
		gets the id of the department and product line search panel

		Parameters:
		productLineId - Id of the product line
		departmentId - Id of the department
	*/
	getSearchPanelId: function( productLineId, departmentId )
	{
		var base = this.SEARCH + productLineId + "_";
		if( departmentId !== undefined ){
			return  base + departmentId;}

		return base;
	},

	/*
		Function: findEquivalentPanel
		gets a search panel for a specified productLineId, regardless of the department

		Parameters:
		productLineId - Id of the product line
	*/
	findEquivalentPanel: function( productLineId )
	{
		// we will try to find a search panel for the given product line, regardless of the department
		var s = new Selector( "div.dhe_search_div" );
		var results = s.findElements( $(this.htmlElementId) );
		var toMatch = this.getSearchPanelId( productLineId );

		for( var i=0; i<results.length; i++ )
		{
			var id = results[i].id;
			if( id.indexOf( toMatch ) != -1 ){
				return results[i].id;}
		}

		return null;
	},

	// Group: Events

	/*
		Method: onClick
		Called when a product line item has been clicked inside
		the product line menu.
	*/
	onClick: function(productLineId, departmentId)
	{
	},

	/*
		Method: onSearchSubmitted
		Called when a search is executed, that is, when the submit
		button is clicked
	*/
	onSearchSubmitted: function( formObj, productLineId, departmentId )
	{
	}
};

/***************************************************
	Class: DakisCartIndicator
	Display the cart indicator (cart image with the number of items)
***************************************************/
var DakisCartIndicator = Class.create();
DakisCartIndicator.prototype = {

	/*
		Method: initialize
		Constructor

		Parameters:

		htmlElementId - html element id where to display the cart indicator
	*/
	initialize: function(htmlElementId)
	{
		this.listenerId = g_dakisListenerManager.getListenerId(this);
		this.htmlElementId = htmlElementId;
	},

	/*
		Method: paint
		Display the cart indicator inside the specified html element
	*/
	paint: function()
	{
		var url = getActionUrl({ controller: 'cart', action: 'show_cart_indicator', lang: g_dakisLang });
		dakisAjaxUpdater( this.htmlElementId, url, {onComplete: (function(request){replaceListener(this.htmlElementId, this.listenerId);onDakisCartInitialized(request);}).bind(this) } );
	},

	show: function()
	{
		$(this.htmlElementId).style.visibility = 'visible';
	},

	hide: function()
	{
		$(this.htmlElementId).style.visibility = 'hidden';
	},

	// Group: Events

	/*
		Method: onClick
		Called when user clicks on the cart to see what's inside
	*/
	onClick: function()
	{
	},

	listenerId: null,
	htmlElementId: null

};

/***************************************************
	Class: DakisProductAdvertiser
	Display a product advertiser.  Showcase products.
***************************************************/
var DakisProductAdvertiser = Class.create();
DakisProductAdvertiser.prototype = {
	/*
		Method: initialize
		Constructor

		Parameters:

		adTimeout - time in millisecond to wait before switching the ad
	*/
	initialize: function( htmlElementId, adTimeout )
	{
		var adLoader = htmlElementId + "_loader";
		this.listenerId = g_dakisListenerManager.getListenerId(this);
		this.htmlElementId = htmlElementId;
		this.adTimeout = adTimeout;
		this.loaderHtmlElementId = adLoader;
	},

	/*
		Method: load
		Load and display the advertiser.  It will automatically refresh itself according
		to the timeout.

		Call this method in the body onload.
	*/
	load: function()
	{
		// Loading div must be created after body on load
		if( !this.loaderCreated ){
			this.createLoader();}

		this.refresh();
	},

	// Group: Events

	/*
		Method: onShowSpecSheet
		Called when the user wants to see the product spec sheet
	*/
	onShowSpecSheet: function(merchandiseId)
	{
	},

	/*
		Method: onAddToCart
		Called when the user wants to add this product to the cart
	*/
	onAddToCart: function(merchandiseId)
	{
	},

	// Private section...

	refresh: function()
	{
		if( this.currentAjaxRequest ){
			this.currentAjaxRequest.transport.abort();}

		var self = this;
		this.currentAjaxRequest = dakisAjaxUpdater( this.loaderHtmlElementId, getActionUrl({ action: 'product_ad' }), {onComplete:function(){ replaceListener(self.loaderHtmlElementId, self.listenerId); self.fade(); setTimeout( function(){ self.refresh(); }, self.adTimeout ); }, asynchronous:true, method:'GET'} );

	},

	createLoader: function()
	{
		var self = this;
		var bodyElem = document.getElementsByTagName("body")[0];
		var createFct = function(){
			var bodyElem = document.getElementsByTagName("body")[0];
			var adLoader = document.createElement("div");
			adLoader.setAttribute( 'id', self.loaderHtmlElementId );
			adLoader.style.display = "none";
			bodyElem.appendChild( adLoader );
			self.loaderCreated = true;	
		}
		
		if( bodyElem )		
			createFct();
		else
			setTimeout( createFct, 500 );		
	},

	fade: function()
	{
		var self = this;
		if( $(this.htmlElementId).innerHTML != $(this.loaderHtmlElementId).innerHTML &&
			$(this.loaderHtmlElementId).innerHTML.toLowerCase().indexOf('div') != -1 )
		{
			new Effect.Fade( this.htmlElementId, { to:0.05, duration:0.5, queue:'end', afterFinish:function(){
				self.changeProduct();
				self.appear();
		}} );
		}
	},

	changeProduct: function()
	{
		$(this.htmlElementId).innerHTML = $(this.loaderHtmlElementId).innerHTML;
	},

	appear: function()
	{
		new Effect.Appear( this.htmlElementId, { duration:0.5, queue:'end' } );
	},

	listenerId: null,
	htmlElementId: null,
	adTimeout: 10000,
	loaderHtmlElementId: null,
	loaderCreated: false,
	currentAjaxRequest: null

};

/***************************************************
	Class: DakisProductAdvertiser2
	Rotate showcased products in a container section using
    a product sheet template.
**************************************************/
var DakisProductAdvertiser2 = Class.create();
DakisProductAdvertiser2.prototype = {

	/*
		Method: initialize

		Parameters:

		containerElementId - html element id where to display the products

	*/
	initialize: function(containerElementId, productTemplateElementId)
	{
		this.containerElementId = containerElementId;
        this.productTemplateElementId = productTemplateElementId;
	},	

	 /*
		Method: start
		Begin the slideshow.
	*/
	start: function()
	{		
		this.loadProducts();
	},
    
     /*
        Method: afterMerchandiseImported
        Called after each merchandise import.
        
        Parameters:
        
        id - the imported merchandise html element id
        merchandise - <DakisMerchandise> object.  Allow to access all data from the merchandise.
        nbMerchandises - total number of merchandises to be imported.  Usefull to set the proper display style.
    */
	afterMerchandiseImported: function(id, merchandise, nbMerchandises)
	{
	},

	// Private methods	

	// set the timer to show the next image
	setTimer: function()
	{
		setTimeout((function() {this.showNextProduct()}).bind(this), this.delay);
	},

	showNextProduct: function()
	{   
        containerElement = $(this.containerElementId);
        curProduct = containerElement.childNodes[this.curDisplayedIndex];
        
		new Effect.Fade(    curProduct, 
                            {queue: 'end', duration: 0.5, afterFinish:(function(){this.showNextProductAfterFade()}).bind(this)});        
        
	},	
    
    showNextProductAfterFade: function()
    {        
        containerElement = $(this.containerElementId);     
        
        nbProducts = containerElement.childNodes.length;                        
        this.curDisplayedIndex = (this.curDisplayedIndex+1) % nbProducts;
        
        curProduct = containerElement.childNodes[this.curDisplayedIndex];
        
        new Effect.Appear(curProduct, {queue: 'end', duration: 0.5});		
        this.setTimer();
    },
    
    
    loadProducts: function()
    {
        // clear existing product...
        containerElement = $(this.containerElementId);
        containerElement.innerHTML = "";
        containerElement.style.display = "none";
        
        // get the new one...
        var importer = new DakisShowcasedMerchandiseImporter(this.productTemplateElementId, this.containerElementId);
        importer.serverAction = "random_ad_product"; 
        importer.imageWidth = this.imageWidth;
        importer.imageHeight = this.imageHeight;
        importer.afterMerchandiseImported = this.afterMerchandiseImported;
        importer.afterFinish = (this.afterAllProductImported).bind(this);
        importer.start();
    },
    
    afterAllProductImported: function()
    {
        containerElement = $(this.containerElementId); 
    
        for(i=1; i<containerElement.childNodes.length; i++ )
		{            
            containerElement.childNodes[i].style.display = "none";
        }
        
        containerElement.style.display = "";
        this.setTimer();
    },


	// Group: Attributes
	// Set atribuite values before <start>

	// Variable: delay
	// Time in msec before an image switch
	delay: 5000,

	// Variable: imageWidth
	// Desired displayed image width in pixels
	imageWidth: 100,

	// Variable: imageHeight
	// Desired displayed image height in pixels
	imageHeight: 100,

	// Private variables

	containerElementId: null,
    productTemplateElementId: null,
    curDisplayedIndex: 0
};


/***************************************************
	Class: DakisSlideshow
	Show multiple images, one at a time.
**************************************************/
var DakisSlideshow = Class.create();
DakisSlideshow.prototype = {

	/*
		Method: initialize

		Parameters:

		htmlElementId - html element id where to display the slideshow

	*/
	initialize: function(htmlElementId)
	{
		this.htmlElementId = htmlElementId;
	},

	/*
		Method: addImage
		Add an image to the slideshow.  Call before <start>.

		Parameters:

		src - image src attribute.  Where to find the image.

	*/
	addImage: function(src)
	{
		this.imageSources.push(src);
	},

	 /*
		Method: start
		Begin the slideshow.  Images must have been added and attributes configured.
	*/
	start: function()
	{
		dakisAssert(this.curImageId == -1, "DakisSlideshow - start: already started.  Cannot call the start method twice.");

		this.loadImages();
		this.showNextImage();
	},

	// Private methods

	// load all images into the container.  Images are hidden at first.  Only the current image will
	// be visible.
	loadImages: function()
	{
		var container = $(this.htmlElementId);
		dakisAssert(container !== undefined, "DakisSlideshow - loadImages: null container");

		for(i=0; i<this.imageSources.length; i++ )
		{
			var imgElement = document.createElement("img");
			imgElement.setAttribute('src', this.imageSources[i]);
			imgElement.style.display = "none";
			imgElement.style.styleFloat = "left";
			imgElement.style.width = this.imageWidth+"px";
			imgElement.style.height = this.imageHeight+"px";

			container.appendChild(imgElement);
			this.imageElements.push(imgElement);
		}
	},

	// set the timer to show the next image
	setTimer: function()
	{
		setTimeout((function() {this.showNextImage()}).bind(this), this.delay);
	},

	showNextImage: function()
	{
		var nextImgId = this.curImageId + 1;

		if( nextImgId >= this.imageSources.length )
		{
			nextImgId = 0;
		}

		this.switchImage(nextImgId);
		this.setTimer();
	},

	// Show this image.  Hide the current image if any and make the new image visible.
	switchImage: function(id)
	{
		var imgElement = null;

		if( this.curImageId != -1 )
		{
			imgElement = this.getImage(this.curImageId);
			new Effect.Fade(imgElement, {queue: 'end', duration: 0.5});
		}

		imgElement = this.getImage(id);

		if( this.curImageId != -1 )
		{
			new Effect.Appear(imgElement, {queue: 'end', duration: 0.5, afterFinish: function() {imgElement.style.display = "block";}});
		}
		else
		{
			imgElement.style.display = "block";
		}

		this.curImageId = id;
	},

	getImage: function(id)
	{
		return this.imageElements[id];
	},


	// Group: Attributes
	// Set atribuite values before <start>

	// Variable: delay
	// Time in msec before an image switch
	delay: 4000,

	// Variable: imageWidth
	// Desired displayed image width in pixels
	imageWidth: 100,

	// Variable: imageHeight
	// Desired displayed image height in pixels
	imageHeight: 100,

	// Private variables

	imageSources: [],
	imageElements: [],
	curImageId: -1,
	htmlElementId: null
};

//***************************************************
// Section: Internal functionalities


/*
	Function: sendActionRequest
	Call this function to send an empty action to the server. This is mainly used
	to report user actions that do not have server functionnalities

	Parameters:
	action - the name of the action to report
	custom_options - JSON options to pass along with the action
*/
function sendActionRequest( action, custom_options )
{
	options = { action:action };
	Object.extend( options, custom_options );

	if( options.postData !== null )
	{
		var postData = options.postData;
		options.postData = null;
		url = getActionUrl( options );
		dakisAjaxRequest( url, { metod:'post', postBody:postData } );
	}
	else
	{
		url = getActionUrl( options );
		dakisAjaxRequest( url );
	}
}

/*
	Function: dakisAjaxUpdater

	Helper to call an ajax updater.  Execute through the execution guard.

	Parameters:

	htmlElementId - the inner html of this element will be updated with the request result
	url - the server url
	options - AJAX options.  See http://www.sergiopereira.com/articles/prototype.js.html#Ajax.options for more info.
*/
function dakisAjaxUpdater(htmlElementId, url, options)
{
	g_dakisGlobalExecutionGuard.execute(    function(){new Ajax.Updater( htmlElementId, url, options );},
											[g_dakisGlobalExecutionGuard.dakisInitializedEvent] );
}

/*
	Function: dakisAjaxRequest

	Helper to call an ajax request.  Execute through the execution guard.

	Parameters:

	url - the server url
	options - AJAX options.  See http://www.sergiopereira.com/articles/prototype.js.html#Ajax.options for more info.
*/
function dakisAjaxRequest(url, options)
{
	g_dakisGlobalExecutionGuard.execute(    function(){new Ajax.Request( url, options );},
											[g_dakisGlobalExecutionGuard.dakisInitializedEvent] );
}


/*
	Function: replaceListener
	Call this function to replace listener placeholders after an AJAX call

	Parameters:

	htmlElementId - html element containing the raw html returned by the server.  This html
					inludes listener placeholders.
	listenerId - the listener id of the object to replace listener placeholders
*/
function replaceListener(htmlElementId, listenerId)
{
	var element = $(htmlElementId);
	dakisAssert(element !== undefined, "replaceListener("+htmlElementId+", "+listenerId+"): the provided htmlElementId element doesn't exist");

	var html = element.innerHTML;
	dakisAssert(html.indexOf(LISTENERPLACEHOLDER) != -1, "replaceListener("+htmlElementId+", "+listenerId+"): the element's inner html contains no listener placeholder to replace...");

	html = stringReplace(html, LISTENERPLACEHOLDER, "g_dakisListenerManager['"+listenerId+"']");
	element.innerHTML = html;
}

/*
	Function: stringReplace
	Replace all substrings equal to a specified value by a new substring.

	Parameters:

	string - the original input string
	oldValue - substring to be replaced.  The input string may contain zero or multiple oldValue substrings.
	newValue - substring to replace each oldValue substring

	Returns:

	A new string
*/
function stringReplace(string, oldValue, newValue)
{
	var parts = string.split(oldValue);
	var newString = parts.join(newValue);
	return newString;
}

/*
	Function: getActionUrl
	Get the url of a rails controller's action.

	Parameters:

	hash - action's name and its parameters.
	For example, getActionUrl({ action: 'questionnaire', product_line_id: product_line_id }); will
	return the url for the questionnaire action using the product_line_id parameter.

	Returns:

	Url string to call the action
*/
function getActionUrl( hash )
{
	dakisAssert(g_dakisServerUrl !== "", "getActionUrl: dakis server url is uninitialized...  Have you called dakisInit first?");

	hash = $H(hash);
	dakisAssert(hash.action !== undefined, "getActionUrl("+hash.inspect()+"): the 'action' value is missing");

	// Remove entries with null values
	hash.keys().each( function(key)	{	if( hash[key] === undefined || hash[key] === null ){	delete hash[key]; }} );

	var action = hash.action;
	delete hash.action;
	var controller = hash.controller;
	delete hash.controller;

	return dakisBuildUrl( controller, action, hash );
}

// default implementation
dakisBuildUrl = dakisBuildDHEUrl;

/*
	Method that builds the final url. Overide to modify the url

	Parameters:

	controller - the controller being called
	action - the rails action to be executed
	params - the parameters going with the url
*/
function dakisBuildDHEUrl( controller, action, params )
{
	if( controller === undefined || controller === null ){
		controller = 'dhe';}

	var queryString = params.toQueryString()
	url = g_dakisServerUrl + 'app_base/' + controller + '/' + g_dakisRetailerId + '/' + action + '?' + queryString;
	return url;
}

// create a hidden division.  Useful to transfer/store raw data.
function createHiddenDiv(id)
{
	var element = document.createElement("div");
	element.style.display = "none";
	element.id = id;
	document.body.appendChild(element);

	return element;
}

function dakisSetLanguage( lang )
{
	g_dakisLang = lang;
}

/*
	Function: dakisGetDocDomain
	Return the document domain including the port if specified

	Example: if the url is http://mydakis.com:6000/index.html
	returns: http://mydakis.com:6000
*/
function dakisGetDocDomain()
{
	return document.location.protocol + '//' + document.location.host;
}

/*
	Function: dakisAssert
	Debugging aid.  Display a message box only if the <g_dakisDebug> variable is set to true.

	Parameters:

	condition - boolean value.  False will trigger an assertion failed.
	message - Debug message to display when the assertion failed.
*/
function dakisAssert(condition, message)
{
	if( condition === false )
	{
		if (g_dakisDebug === true )
		{
			alert("ASSERTION FAILED: "+message);
		}

		g_dakisTrace.traceError(message);
	}
}

/*
	Function: dakisGetDate
	Get the today's date.  Format: month/day/year
*/
function dakisGetDate()
{
	var today = new Date();
	return today.getMonth()+ "/"+ today.getDay() + "/" + (today.getYear()+1900);
}

/*
	Function: dakisGetTime
	Get the actual time.  Format: hours:minute:seconds
*/
function dakisGetTime()
{
	var today = new Date();
	var minutes = today.getMinutes();
	var seconds = today.getSeconds();
	if( minutes < 10 ){minutes = "0"+minutes;}
	if( seconds < 10 ){seconds = "0"+seconds;}

	return today.getHours()+ ":" + minutes+":"+seconds;
}


function submitForm( formName, action, options )
{
	var serializedInputs = { postData:Form.serialize( formName ) };
	if( options ){
		Object.extend( options, serializedInputs );}
	else{
		options = serializedInputs; }
	if(action !== undefined){
		sendActionRequest( action, options ); }
	document.forms[formName].submit();
}

function printPage( options )
{
	sendActionRequest( 'print_page', options );
	window.print();
}

function IncludeJScript(url, id)
{
	//RemoveHeadElement(id);
	AddHeadElement("script", id, "text/javascript", url);
}

function AddHeadElement(tagName, id, type, source)
{
	var head = document.getElementsByTagName("head")[0];
	var element = document.createElement(tagName);

	element.id = id;
	element.type = type;
	element.src = source;
	head.appendChild(element);
}

function PositionTopRight( element )
{
	if( ie )
	{
		element.style.top = document.documentElement.scrollTop + "px";
		element.style.right = document.body.scrollLeft + "px";
	}
	else
	{
		element.style.top = pageYOffset + "px";
		element.style.right = pageXOffset + "px";
	}
}

/****************************************************
	Class: DakisListenerManager

	Singleton object managing listener ids associated with
	the concrete listener objects.
****************************************************/
DakisListenerManager = Class.create();
DakisListenerManager.prototype = {

	initialize: function()
	{
		this.nextId = 0;
	},

	/*
		Method: getListenerId

		Get a unique listener id for this object.  Use the DakisListenerManager["listenerId"] to
		get back the associated object.

		Parameters:

		object - object to bind with the returned id

		Returns:

		A unique string identifier.
	*/
	getListenerId: function(object)
	{
		this.nextId++;

		var listenerId = "listener"+this.nextId;
		this[listenerId] = object;
		return listenerId;
	},

	nextId: 0
};

/****************************************************
	Class: DakisTrace
	Debugging aid displaying trace information

	Don't use asserts in this class since the assertion failed
	add a trace (infinite loop!)

	See http://www.joehewitt.com/software/firebug/docs.php for the complete
	documentation to integrate with the firebug log.
****************************************************/
DakisTrace = Class.create();
DakisTrace.prototype = {

	// Group: Configuration before creation

	initialize: function()
	{
	},

	/*
		Method: setPosition
		Set the trace window position in absolute pixel coordinates
	*/
	setPosition: function(x, y, width, height)
	{
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	},

	/*
		Method: setVisible
		Set whether the trace window will be visible or not.  If not visible, traces are registered
		anyway.

		Parameters:

		visible - true to set the window to a visible state
	*/
	setVisible: function(visible)
	{
		if( visible )
		{
			this.display = "";
		}
		else
		{
			this.display = "none";
		}

		if( this.containerDiv !== null )
		{
			this.containerDiv.style.display = this.display;
		}
	},

	/*
		Method: setTraceErrorListener
		Set the function called when a trace error happened.  Useful to take
		actions like sending the traces to the server.

		Parameters:

		callbackFct - function to call
	*/
	setTraceErrorListener: function(callbackFct)
	{
		this.traceErrorListener = callbackFct;
	},

	/*
		Method: create
		Initialize the trace window with the specified configuration
	*/
	create: function()
	{
		dakisAssert(this.traceDiv === null, "DakisTrace - already created");

		this.traceDiv = document.createElement("div");

		this.traceDiv.style.width = this.width+"px";
		this.traceDiv.style.height = (this.height)+"px";
		this.traceDiv.style.borderTop = this.border;
		this.traceDiv.style.borderBottom = this.border;
		this.traceDiv.style.overflow = "auto";
		this.traceDiv.style.padding = "5px";

		this.containerDiv = document.createElement("div");
		this.containerDiv.id = this.id;
		this.containerDiv.style.display = this.display;
		this.containerDiv.style.zIndex = this.zIndex;
		this.containerDiv.style.position = "absolute";
		this.containerDiv.style.left = this.x+"px";
		this.containerDiv.style.top = this.y+"px";
		this.containerDiv.style.background = this.background;
		this.containerDiv.style.border = this.border;

		var titleDiv = document.createElement("div");
		var listenerId = g_dakisListenerManager.getListenerId(this);
		titleDiv.innerHTML = '<p>TRACE <a id="'+this.viewlinkId+'" style="color: blue" href="" onclick="g_dakisListenerManager['+"'"+listenerId+"'"+'].onViewLinkClick(); return false;">hide</a></p>';
		titleDiv.style.padding = "5px";

		this.containerDiv.appendChild(titleDiv);
		this.containerDiv.appendChild(this.traceDiv);
		document.body.appendChild(this.containerDiv);

		if( this.minimized )
		{
			this.hideTraces();
		}
		else
		{
			this.showTraces();
		}
	},

	// Group: Trace

	/*
		Method: traceInfo
	*/
	traceInfo: function(message)
	{
		// firebug trace...
		if(window.console && console.log && console.info)
		{
			console.info(message);
		}

		this.trace(message, this.infoStyle);
	},

	/*
		Method: traceWarning
	*/
	traceWarning: function(message)
	{
		// firebug trace...
		if(window.console && console.log && console.warning)
		{
			console.warning(message);
		}

		this.trace(message, this.warningStyle);

	},

	/*
		Method: traceError
	*/
	traceError: function(message)
	{
		// firebug trace...
		if(window.console && console.log && console.error)
		{
			console.error(message);
		}

		this.trace(message, this.errorStyle);

		if( this.traceErrorListener !== null )
		{
			this.traceErrorListener();
		}


	},

	trace: function(message, style)
	{
		if( this.traceDiv !== null )
		{
			var html = '<p style="'+style+'"><font style="color: #f2f2f2">'+dakisGetTime()+'&nbsp;</font>'+message+'</p>';
			this.traceDiv.innerHTML += html;
		}

		var msg = "["+dakisGetTime() + " "+message+"]";
		this.textTraceStr += msg;
	},

	/*
		Method: getTracesAsText
		Get traces in a text-only format
	*/
	getTracesAsText: function()
	{
		return this.textTraceStr;
	},

	// Private

	refreshViewLink: function()
	{
		var text = "hide";

		if( this.minimized )
		{
			text = "show";
		}

		var viewLink = $(this.viewlinkId);
		viewLink.innerHTML = text;
	},

	onViewLinkClick: function()
	{
		this.minimized = !this.minimized;

		if( this.minimized )
		{
			this.hideTraces();
		}
		else
		{
			this.showTraces();
		}
	},

	hideTraces: function()
	{
		this.traceDiv.style.display = "none";
		this.containerDiv.style.width = "";
		this.minimized = true;
		this.refreshViewLink();

		Element.setOpacity(this.containerDiv, 0.5);
	},

	showTraces: function()
	{
		this.traceDiv.style.display = "";
		this.containerDiv.style.width = this.traceDiv.offsetWidth+"px";
		this.minimized = false;
		this.refreshViewLink();

		Element.setOpacity(this.containerDiv, 1);
	},

	display: "",
	background: "rgb(190, 190, 190)",
	border: "1px solid blue",
	infoStyle: "color: gray",
	warningStyle: "color: yellow",
	errorStyle: "color: red",
	minimized: false,

	traceDiv: null,
	containerDiv: null,
	id: "dakisTraceWindow",
	x: 0,
	y: 0,
	width: 400,
	height: 200,
	zIndex: "100",
	viewlinkId: "dakisTraceWindowViewLink",
	// keep a separated text-only trace
	textTraceStr: "",
	traceErrorListener: null
};

/****************************************************
	Class: DakisExecutionGuard

	Guard function executions until some events are signaled.
****************************************************/
DakisExecutionGuard = Class.create();
DakisExecutionGuard.prototype = {

	initialize: function()
	{
	},

	/*
		Method: registerEvent

		Register a guard event

		Parameters:

		name - event's name
	*/
	registerEvent: function(name)
	{
		this.eventNames.push(name);
		this.eventValues.push(false);
	},

	/*
		Method: signalEvent
	*/
	signalEvent: function(name)
	{
		this.eventValues[this.getEventIndex(name)] = true;
		this.executeReadyFunctions();
	},

	/*
		Method: execute

		Execute a function as soon as all its events are signaled.

		Parameters:

		fct - function to be executed
		events - event array like ["event1", "event2", ... ]
	*/
	execute: function(fct, events)
	{
		this.executionQueueFuncs.push(fct);
		this.executionQueueEvents.push(events);

		this.executeReadyFunctions();
	},

	// Private

	executeReadyFunctions: function()
	{
		for(var i=0; i<this.executionQueueFuncs.length; i++ )
		{
			if( this.areAllEventsSignaled(this.executionQueueEvents[i]) )
			{
				// remove before execution since the execution could trigger another
				// call to this function -> infinite loop
				var fct = this.executionQueueFuncs[i];
				this.removeFromQueue(i);
				i--;

				fct();
			}
		}
	},

	removeFromQueue: function(index)
	{
		this.executionQueueFuncs.splice(index, 1);
		this.executionQueueEvents.splice(index, 1);
	},

	areAllEventsSignaled: function(events)
	{
		for(var i=0; i<events.length; i++ )
		{
			if( !this.isEventSignaled(events[i]) )
			{
				return false;
			}
		}

		return true;
	},

	isEventSignaled: function(name)
	{
		return this.eventValues[this.getEventIndex(name)];
	},

	getEventIndex: function(name)
	{
		for(var i=0; i<this.eventNames.length; i++ )
		{
			if( this.eventNames[i] == name )
			{
				return i;
			}
		}

		dakisAssert(false, "DakisExecutionGuard - getEventIndex: event name not found: "+name);
		return -1;
	},

	eventNames: [],
	eventValues: [],
	executionQueueFuncs: [],
	executionQueueEvents: []
};

/****************************************************
	Class: DakisGlobalExecutionGuard

	Guard function executions for global events (window loaded and dakis initialized)
****************************************************/
DakisGlobalExecutionGuard = Class.create();
Object.extend( DakisGlobalExecutionGuard.prototype, DakisExecutionGuard.prototype );
Object.extend( DakisGlobalExecutionGuard.prototype,
{
	initialize: function()
	{
		this.registerEvent(this.windowLoadedEvent);
		this.registerEvent(this.dakisInitializedEvent);
		this.registerEvent(this.dakisCartLoadedEvent);

		Event.observe(window, 'load', (function(){this.onWindowLoaded();}).bind(this), false);
	},

	onWindowLoaded: function()
	{
		this.signalEvent(this.windowLoadedEvent);
	},

	onDakisInitialized: function()
	{
		this.signalEvent(this.dakisInitializedEvent);
	},

	onDakisCartInitialized: function()
	{
		this.signalEvent(this.dakisCartLoadedEvent);
	},

	// Constant: windowLoadedEvent
	// Window loaded event string constant
	windowLoadedEvent: "windowLoaded",

	// Constant: dakisInitializedEvent
	// Dakis initialized event string constant
	dakisInitializedEvent: "dakisInitialized",

	// Constant: onCartLoadedEvent
	// Cart initialized event string constant
	dakisCartLoadedEvent: "cartInitialized"

});


/****************************************************
	Class: DakisPositionner

	Singleton object managing smooth scrolls
****************************************************/
var DakisPositionner = {

	intervalMS:10,
	speedRatio:0.05, //Manages the speed ratio of the scrolling. final speed is calculated according to difference

	/*
		Method: scrollTo

		Scrolls the user to a specified position

		Parameters:

		position_y - the y position to scroll to
	*/
	scrollTo: function( position_y ){
		var current = this.getBrowserPositionY();
		var increment = parseInt( ( position_y - current ) * this.speedRatio, 10 );
		var self = this;
		this.interval = setInterval( function(){ self.doScrolling( position_y, increment ); }, this.intervalMS );
	},

	doScrolling: function( position_y, increment ){
		var oldPosition = this.getBrowserPositionY();
		var wasAbove = ( position_y - oldPosition ) < 0;

		this.directScrollTo( oldPosition + increment );

		var newPosition = this.getBrowserPositionY();
		var isAbove = ( position_y - newPosition ) < 0;

		if( wasAbove != isAbove || oldPosition == newPosition )
		{
			this.directScrollTo( position_y );
			this.stopScrolling();
		}
	},

	/*
		Method: scrollToElement

		Scrolls the user to a specified element in the DOM

		Parameters:

		element_id - the id of the element to scroll to
	*/
	scrollToElement: function( element_id ){
		var position_y = this.getPositionY( element_id );
		this.scrollTo( position_y );
	},

	/*
		Method: scrollTop

		Scrolls the user to the top of the page
	*/
	scrollTop: function(){
		this.scrollTo(0);
	},

	directScrollTo: function( position_y ){
		if( ie ){
			window.scrollTo(0,position_y);}
		else
			{document.documentElement.scrollTop = position_y;}
	},

	stopScrolling: function(){
		clearInterval(this.interval);
	},

	getPositionY: function( element_id ){
		var obj = $( element_id );
		var curtop = 0;
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				curtop += obj.offsetTop;
				obj = obj.offsetParent;
			}
		}
		else if (obj.y){
			curtop += obj.y;}
		return curtop;
	},

	getBrowserPositionY: function() {
	if (document.body && document.body.scrollTop){
		return document.body.scrollTop;}
	if (document.documentElement && document.documentElement.scrollTop){
		return document.documentElement.scrollTop;}
	if (window.pageYOffset){
		return window.pageYOffset;}
	return 0;
	}
};


//**********************************************************
// Section: Global variables and constants

// Variable: ie
// Indicates whether the use browser is internet explorer
var ie=document.all&&navigator.userAgent.indexOf("Opera")==-1;

// Variable: g_dakisServerUrl
// The dakis server or the proxy url
var g_dakisServerUrl = "";

// Variable: g_dakisRetailerId
// The retailer guid
var g_dakisRetailerId = "";

// Variable: g_dakisRetailerInfo
// Configuration informations for the current retailer
var g_dakisRetailerInfo = null;

// Variable: g_dakisLang
// The current language identifier string
var g_dakisLang = "en";

// Variable: g_dakisStubLoadingDiv
// Invisible div to temporary receive ajax resulting html, allowing further processing
var g_dakisStubLoadingDiv;

// Variable: g_dakisStubLoadingDivId
// id to retrieve the invisible div
var g_dakisStubLoadingDivId = "stubLoadingDivId";

// Variable: g_dakisListenerManager
// Manage listener objects. Unique instance.
// * must be created before all other UI components since they need it
var g_dakisListenerManager = new DakisListenerManager();

// Variable: g_dakisGlobalExecutionGuard
// Use this guard to make sure the library is properly initialized before making a server call
var g_dakisGlobalExecutionGuard = new DakisGlobalExecutionGuard();

// Variable: g_dakisDebug
// Turn on/off debugging information (assertions, extra info...)
var g_dakisDebug = false;

// Variable: g_dakisTrace
var g_dakisTrace = new DakisTrace();

// Constant: LISTENERPLACEHOLDER
// Html returned by the server contain this token to be
//replaced by the caller actual listener id
var LISTENERPLACEHOLDER = "listenerPlaceholder";

// Constant: EXPECTEDWEBDHEVERSION
// This constant contains the WebDHE version number(s)
// with which this JS files are compatible. (ARRAY)
var EXPECTEDWEBDHEVERSION = ['3.12']
