//DYNAMIC GENERATED FUNCTIONS MUST BE DEFINED BEFORE MAIN CLASS

/*
 * browser detection object, from quirksmode, http://www.quirksmode.org/js/detect.html   
 */
var BrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{
			string: navigator.userAgent,
			subString: "Chrome",
			identity: "Chrome"
		},
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari",
			versionSearch: "Version"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			   string: navigator.userAgent,
			   subString: "iPhone",
			   identity: "iPhone/iPod"
	    },
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]
};

/*
* get elements of a certain class
*	Developed by Robert Nyman, http://www.robertnyman.com
*	Code/licensing: http://code.google.com/p/getelementsbyclassname/
* 
* @param string className
* @param string tag: optional tag name to filter class elements by
* @param string elemnent: optional parent object to search class elements into 
* 
* @return array with objects
*/
var getElementsByClassName = function (className, tag, elm){
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
};
/*
* creates an element with specified attributes
* 
* @param string tag: tag name
* @param boolean bEmtpy: whether tag is an empty one
* @param mixed aoAttrs: attributes container, it can be an array or an object
*                      [[attribute_1_name,attribute_1_value],[attribute_2_name,attribute_2_value],...]
*                      {attribute_1_name:attribute_1_value,attribute_2_name:attribute_2_value,...}
*                      WARNING: if aoAttrs is an object and contains a 'class' attribute, class *MUST*
*                      be enclosed between ' into object definition otherwise IE will rise an error                        
* 
* @return array with objects
*/
function createElementWithAttributes(){}
(function(){
  try {
    var el=document.createElement( '<div name="foo">' );
    if( 'DIV'!=el.tagName ||
        'foo'!=el.name ){
      throw 'create element error';
    }
    createElementWithAttributes = function(tag,bEmpty,aoAttrs){
      var sAttrs = '';
      for(i in aoAttrs){
        if(typeof(aoAttrs[i]) == 'object'){
          sAttrs += aoAttrs[i][0]+'="'+aoAttrs[i][1]+'"';
        }else{
          sAttrs += i+'="'+aoAttrs[i]+'"';
        }
      }
      var sTag = '<'+tag+' '+sAttrs;
      if(bEmpty == true) sTag += ' />';
      else sTag += '></'+tag+'>';
      return document.createElement(sTag);
    }
  }catch( e ){
    createElementWithAttributes = function( tag,bEmpty, aoAttrs ){
      var el = document.createElement(tag);
      var aAttr;
      var attr;
      var value;
      for(i in aoAttrs){
        if(typeof(aoAttrs[i]) == 'object'){
          el.setAttribute(aoAttrs[i][0],aoAttrs[i][1]);
        }else{
          el.setAttribute(i,aoAttrs[i]);
        }
      }
      return el;
    }
  }
})();


//object available to page
var oDisplayManager = new displayManager();
/**
 * the displayManager class provides methods for javascript interaction with diplaying/ed html elements
 *
 */
function displayManager(){
  //properties
  this.browserDetect = BrowserDetect;
  //methods
  this.cleanId = cleanId;
  this.buildUrl = buildUrl;
  this.createElementWithAttributes = createElementWithAttributes;
  this.getElementsByClassName = getElementsByClassName;
  this.getBody = getBody;
  this.getHighestZIndex = getHighestZIndex;
  this.switchElementDisplay = switchElementDisplay;
  this.getDocumentDimensions = getDocumentDimensions;
  this.getWindowDimensions = getWindowDimensions;
  this.getPageScrolling = getPageScrolling;
  this.removeElementById = removeElementById;
  this.removeElementByObject = removeElementByObject;
  this.setElementClass = setElementClass;
  this.centerElement = centerElement;
  this.getElementDimensions = getElementDimensions;
  this.fadeElement = fadeElement;
  this.changeElementOpacity = changeElementOpacity;
  this.addEventSimple = addEventSimple;
  this.removeEventSimple = removeEventSimple;
  this.displaySwitchManage = displaySwitchManage;
  this.displayCustomTitle = displayCustomTitle;
  this.hideCustomTitle = hideCustomTitle;
  //init
  this.browserDetect.init();
}

/*
 * gets body object
 *  
 * 
 * @return object   
 */
function getBody(){
  return document.getElementsByTagName('body')[0];
}

/*
 * replaces illegal characters into an id value
 *  
 * @param string id
 * 
 * @return string cleaned id   
 */
function cleanId(id){
  var sId = new String(id);
  sId = sId.replace(/\'/,'_');
  sId = sId.replace(/\[/,'_');
  sId = sId.replace(/\]/,'_');
	sId = sId.replace(/ /,'_');
	sId = sId.replace(/,/,'_');
	sId = sId.replace(/&/,'_');
	sId = sId.replace(/\(/,'_');
	sId = sId.replace(/\)/,'_');
	sId = sId.replace(/`/,'_');
	sId = sId.replace(/à/,'a');
	sId = sId.replace(/è/,'e');
	sId = sId.replace(/é/,'e');
	sId = sId.replace(/ì/,'i');
	sId = sId.replace(/ò/,'o');
	sId = sId.replace(/ù/,'u');
  return sId;
}

/**
 * builds a relative url
 *
 * @param string pagePath: from site KERNEL ROOT
 * @param object oParameters
 *    
 * @return string the url    
 *
 * @access public
 */
function buildUrl(pagePath,oParameters){
  var code = '';
  code += oApplication.pathToRoot+pagePath;
	if(oVarManipulator.isDefined(oParameters) && !oVarManipulator.isEmpty(oParameters)){
		code += '?';
	  var aParameters = new Array();
	  for(i in oParameters){
	    aParameters.push(encodeURIComponent(i)+'='+encodeURIComponent(oParameters[i]));
	  }
	  code += aParameters.join('&');
	}
  return code;
}

/**********************************
 *      CSS manipulation          *
 *********************************/
 
/* by Lasse Reichstein Nielsen - lrn@hotpop.com
 * found at http://bytes.com/topic/javascript/answers/93827-get-hi-est-zindex-page
 * gets highest z-index value on page
 *  
 * 
 * @return integer max z-index value
 */
function getHighestZIndex(){
  var allElems = document.getElementsByTagName ? document.getElementsByTagName("*"): document.all;
  var maxZIndex = 0;
  for(var i=0;i<allElems.length;i++){
    var elem = allElems[i];
    var cStyle = null;
    if(elem.currentStyle) cStyle = elem.currentStyle;
    else if(document.defaultView && document.defaultView.getComputedStyle){
      cStyle = document.defaultView.getComputedStyle(elem,"");
    }
    var sNum;
    if(cStyle){
      sNum = Number(cStyle.zIndex);
    }else{
      sNum = Number(elem.style.zIndex);
    }
    if(!isNaN(sNum)){
      maxZIndex = Math.max(maxZIndex,sNum);
    }
  }
  return maxZIndex;
}

/*
 * sets css class for an element  
 *  
 * @param object oElement   
 * @param string className
 * 
 * @return void
 */
function setElementClass(oElement,className){
	switch(this.browserDetect.browser){
		case 'Explorer':
			if(this.browserDetect.version <= 7) oElement.setAttribute("className",className);
			else oElement.setAttribute("class",className);
		break;
		default:
			oElement.setAttribute("class",className);
		break;
	}
}

/*
 * switches element display none / block
 *  
 * @param string id
 * @param string default the default state for element display
 *                       in case style has not yet been set   
 * 
 * @return string new display value
 */
function switchElementDisplay(id,defaultValue){
  //get element
  var oElement = document.getElementById(id);
  //if default is not provided set it to none
  defaultValue = defaultValue ? defaultValue : 'none'; 
  //get current
  var currentDisplay = oElement.style.display ? oElement.style.display : defaultValue;
  var newDisplay = currentDisplay == 'none' ? 'block' : 'none';
  oElement.style.display = newDisplay;
  return newDisplay;
}

/*
 * gets an element dimensions 
 *  
 * @param string elementId
 * 
 * @return object {width:value,height:value}
 */
function getElementDimensions(elementId) {
	var oElement = document.getElementById(elementId);
	return {width:oElement.clientWidth,height:oElement.clientHeight};
}

/* Core code from - quirksmode.org
 * Edit for Firefox by pHaez
 * got from http://www.huddletogether.com/projects/lightbox/lightbox.js 
 *
 * gets body dimensions 
 *  
 * @param string elementId
 * 
 * @return object {width:value,height:value}
 */
function getDocumentDimensions(){
	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;
	}
	var windowWidth, windowHeight;
	if (self.innerHeight) {	// all except Explorer
		//windowWidth = self.innerWidth;
		windowWidth = document.body.clientWidth;
		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;
	}

	oPageSize = {width:pageWidth,height:pageHeight}; 
	return oPageSize;
 
}

/* by Paul Clark (pclark@polyfex.com)
 * got from http://www.developersweb.co.uk/window_scroll.html 
 *
 * gets visible browser window dimension
 * 
 * @return object {width:value,height:value}
 */
function getWindowDimensions(){
	theHeight = ( typeof( window.innerHeight ) == 'number' )?window.innerHeight:( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) )?document.documentElement.clientHeight:document.body.clientHeight;
  theWidth = ( typeof( window.innerWidth ) == 'number' )?window. innerWidth:( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) )?document.documentElement.clientWidth:document.body. clientWidth;
  return {width:theWidth,height:theHeight};
}

/* by Paul Clark (pclark@polyfex.com)
 * got from http://www.developersweb.co.uk/window_scroll.html 
 *
 * gets window scroll position 
 * 
 * @return object {x:value,y:value}
 */
function getPageScrolling(){
  var scrOfX = 0, scrOfY = 0;
  if(typeof(window.pageYOffset) == 'number'){
  //Netscape compliant
    scrOfY = window.pageYOffset;
    scrOfX = window.pageXOffset;
  }else if(document.body && (document.body.scrollLeft || document.body.scrollTop)){
  //DOM compliant
    scrOfY = document.body.scrollTop;
    scrOfX = document.body.scrollLeft;
  }else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)){
  //IE6 standards compliant mode
    scrOfY = document.documentElement.scrollTop;
    scrOfX = document.documentElement.scrollLeft;
  }
  return {x:scrOfX,y:scrOfY};
}

/*
 * removes an element by id
 *  
 * @param string elementId
 * 
 * @return void
 */
function removeElementById(elementId){
	if(document.getElementById(elementId)){
		var oElement = document.getElementById(elementId);
		this.removeElementByObject(oElement);
	}
}

/*
 * removes an element given the element object
 *  
 * @param string elementId
 * 
 * @return void
 */
function removeElementByObject(oElement){
	oElement.parentNode.removeChild(oElement);
}

/* by Paul Clark (pclark@polyfex.com)
 * got from http://www.developersweb.co.uk/window_scroll.html 
 *
 * @param object oElement
 *  
 * centers an absolute positioned element into page 
 * 
 */
function centerElement(oElement){
  oScrolls = this.getPageScrolling();
  oWinsize = this.getWindowDimensions();
  elementTop = (oElement.clientHeight > oWinsize.height) ? oScrolls.y : ((oWinsize.height - oElement.clientHeight)/2)+ oScrolls.y;
  if (elementTop < 10) elementTop = 10;
  elementLeft =((document.body.offsetWidth - oElement.clientWidth) / 2);
  if (elementLeft < 0) elementLeft = 0;
  oElement.style.left = elementLeft + "px";
  oElement.style.top = elementTop + "px";
}
/*
 * fades an element changing opacity 
 *  
 * @param string elementId
 * @param integer opacStart opacity start value
 * @param integer opacEnd opacity end value
 * @param integer time fade duration in milliseconds
 * @param string callbackFunction function to be executed at the end of fading      
 * 
 * @return void
 */
function fadeElement(elementId,opacStart,opacEnd,time,callbackFunction) {
  //speed for each frame
  var speed = Math.round(time / 100);
  var timer = 0;
  //determine the direction for the blending, if start and end are the same nothing happens
  if(opacStart > opacEnd){
    for(i = opacStart; i >= opacEnd; i--){
      setTimeout("oDisplayManager.changeElementOpacity('"+elementId+"',"+i+",'"+callbackFunction+"',"+opacEnd+")",(timer * speed));
      timer++;
    }
  }else if(opacStart < opacEnd){
    for(i = opacStart; i <= opacEnd; i++){
      setTimeout("oDisplayManager.changeElementOpacity('"+elementId+"',"+i+",'"+callbackFunction+"',"+opacEnd+")",(timer * speed));
      timer++;
    }
  }
}

/*
 * sets an element opacity 
 *  
 * @param string elementId
 * @param integer opacity: opacity value (0 - 100)
 * @param string callbackFunction function to be executed at the last fading cycle 
 * @param integer finalValue last fading cycle value
 * 
 * @return void
 */
function changeElementOpacity(elementId,opacity,callbackFunction,finalValue){
  if(document.getElementById(elementId)){
    var oStyle = document.getElementById(elementId).style;
    oStyle.opacity = (opacity / 100);
    oStyle.MozOpacity = (opacity / 100);
    oStyle.KhtmlOpacity = (opacity / 100);
    oStyle.filter = "alpha(opacity=" + opacity + ")";
    if(callbackFunction && opacity == finalValue){
      eval(callbackFunction);
    }
  }
}

/**********************************
 *            EVENTS              *
 *********************************/ 

/*
 * adds an event listener to an html object
 * FROM www.quirksmode.org (http://www.quirksmode.org/js/eventSimple.html) 
 *  
 * @param object obj html DOM object
 * @param event evt   
 * @param string fn function name  
 * 
 * @return void
 */
function addEventSimple(obj,evt,fn) {
	if (obj.addEventListener)
		obj.addEventListener(evt,fn,false);
	else if (obj.attachEvent)
		obj.attachEvent('on'+evt,fn);
}

/*
 * removes an event listener from an html object
 * FROM www.quirksmode.org (http://www.quirksmode.org/js/eventSimple.html) 
 *  
 * @param object obj html DOM object
 * @param event evt   
 * @param string fn function name  
 * 
 * @return void
 */
function removeEventSimple(obj,evt,fn) {
	if (obj.removeEventListener)
		obj.removeEventListener(evt,fn,false);
	else if (obj.detachEvent)
		obj.detachEvent('on'+evt,fn);
}

/*
 * activates the open/close functionality on an element  
 *  
 * @param object oHandle switch div handle obj html DOM object   
 * @param string elementId element to be switched
 * @param atring displayMsg   
 * @param atring hideMsg  
 * @param string switchElementId element used as switch if not built-on-purpose one
 * @param string closeClass: all elements with such class will be closed on opening
 * 
 * @return void
 */
function displaySwitchManage(oHandle,elementId,displayMsg,hideMsg,switchElementId,closeClass,displayValue){
	var oElement = document.getElementById(elementId);
	//get image
	//var oImg = this.getElementsByClassName('display_switch_handle','img',oHandle)[0];
	var msg,operator;
	var bOpen = false;
	//open
	if(oElement.style.display == 'none'){
		bOpen = true;
		if(closeClass){
			var aElements = this.getElementsByClassName(closeClass);
			for(i in aElements){
				aElements[i].style.display = 'none';
			}
		}
		oElement.style.display = displayValue ? displayValue : 'block';
		msg = hideMsg;
		operator = 'minus';
	}else{
	//close
		oElement.style.display = 'none';
		msg = displayMsg;
		operator = 'plus';
	}
	if(!switchElementId){
		this.getElementsByClassName('display_switch_label','span',oHandle)[0].innerHTML = msg;
		this.setElementClass(oHandle,'display_switch_'+operator);
		//oImg.src = this.buildUrl('kernel/_etc/images/icons/'+operator+'.gif');
	}else{
		document.getElementById(switchElementId).title = msg;
	}
}

/*
 * displays a custom defined title over an element  
 *  
 * @param object oElement element DOM object
 * @param string content     
 * 
 * @return void
 */
function displayCustomTitle(oElement,content){
	var aAttrs = [['class','custom_title']];
	var oTitleDiv = this.createElementWithAttributes('div',false,aAttrs);
	oTitleDiv.innerHTML = content;
	oElement.parentNode.insertBefore(oTitleDiv,oElement);
	this.addEventSimple(oTitleDiv,'mouseout',function(){oDisplayManager.hideCustomTitle(oTitleDiv)});
}

/*
 * hides a custom defined title over an element  
 *  
 * @param object oElement element DOM object   
 * 
 * @return void
 */
function hideCustomTitle(oTitleDiv){
	if(oTitleDiv.parentNode){
		this.removeElementByObject(oTitleDiv);
	}
}
