/*
Script Name: Full Featured Javascript Browser/OS detection
Authors: Harald Hope, Tapio Markula, Websites: http://techpatterns.com/
http://www.nic.fi/~tapio1/Teaching/index1.php3
Script Source URI: http://techpatterns.com/downloads/javascript_browser_detection.php
Version 4.2.4
Copyright (C) 29 June 2007

This program is free software; you can redistribute it and/or modify it under 
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

Get the full text of the GPL here: http://www.gnu.org/licenses/gpl.txt

Coding conventions:
http://cvs.sourceforge.net/viewcvs.py/phpbb/phpBB2/docs/codingstandards.htm?rev=1.3
*/

/*************************************************************
Full version, use it if you are pushing css to its functional limits, and/or are using 
specialized javascript.

Remember, always use method or object testing as your first choice, for example, if ( dom ) { statement; };

This browser detection includes all possibilities I think for most browsers.
Let me know if you find an error or a failure to properly detect, or if there
is a relevant browser that has special needs for detection at our tech forum:
http://techpatterns.com/forums/forum-11.html
The main script is separated from the initial netscape 4 detection due to certain bugs in
netscape 4 when it comes to unknown things like d.getElementById. The variable declarations
of course are made first to make sure that all the variables are global through the page, 
otherwise a javascript error will occur because you are trying to use an undeclared variable.

We test for both browser type (ie, op, or moz/netscape > 6) and version number, then place 
the version number into a variable which can be tested for < or > values, such as 
if (moz && nu> 1.1){....statement....;}
This seems quite reliable, especially for Opera and Mozilla, where there is no other
easy way to get the actual version number.

For more in depth discussion of css and browser issues go to:
http://www.nic.fi/~tapio1/Teaching/DynamicMenusb.php#detections
http://www.nic.fi/~tapio1/Teaching/FAQ.php3

***************************************************************/
//initialization, browser, os detection
var d, dom, nu='', brow='', ie, ie4, ie5, ie5x, ie6, ie7;
var ns4, moz, moz_rv_sub, release_date='', moz_brow, moz_brow_nu='', moz_brow_nu_sub='', rv_full=''; 
var mac, win, old, lin, ie5mac, ie5xwin, konq, saf, op, op4, op5, op6, op7;

d=document;
n=navigator;
nav=n.appVersion;
nan=n.appName;
nua=n.userAgent;
old=(nav.substring(0,1)<4);
mac=(nav.indexOf('Mac')!=-1);
win=( ( (nav.indexOf('Win')!=-1) || (nav.indexOf('NT')!=-1) ) && !mac)?true:false;
lin=(nua.indexOf('Linux')!=-1);
// begin primary dom/ns4 test
// this is the most important test on the page
if ( !document.layers )
{
	dom = ( d.getElementById ) ? d.getElementById : false;
}
else { 
	dom = false; 
	ns4 = true;// only netscape 4 supports document layers
}
// end main dom/ns4 test

op=(nua.indexOf('Opera')!=-1);
saf=(nua.indexOf('Safari')!=-1);
konq=(!saf && (nua.indexOf('Konqueror')!=-1) ) ? true : false;
moz=( (!saf && !konq ) && ( nua.indexOf('Gecko')!=-1 ) ) ? true : false;
ie=((nua.indexOf('MSIE')!=-1)&&!op);
if (op)
{
	str_pos=nua.indexOf('Opera');
	nu=nua.substr((str_pos+6),4);
	brow = 'Opera';
}
else if (saf)
{
	str_pos=nua.indexOf('Safari');
	nu=nua.substr((str_pos+7),5);
	brow = 'Safari';
}
else if (konq)
{
	str_pos=nua.indexOf('Konqueror');
	nu=nua.substr((str_pos+10),3);
	brow = 'Konqueror';
}
// this part is complicated a bit, don't mess with it unless you understand regular expressions
// note, for most comparisons that are practical, compare the 3 digit rv nubmer, that is the output
// placed into 'nu'.
else if (moz)
{
	// regular expression pattern that will be used to extract main version/rv numbers
	pattern = /[(); \n]/;
	// moz type array, add to this if you need to
	moz_types = new Array( 'Firebird', 'Phoenix', 'Firefox', 'Iceweasel', 'Galeon', 'K-Meleon', 'Camino', 'Epiphany', 'Netscape6', 'Netscape', 'MultiZilla', 'Gecko Debian', 'rv' );
	rv_pos = nua.indexOf( 'rv' );// find 'rv' position in nua string
	rv_full = nua.substr( rv_pos + 3, 6 );// cut out maximum size it can be, eg: 1.8a2, 1.0.0 etc
	// search for occurance of any of characters in pattern, if found get position of that character
	rv_slice = ( rv_full.search( pattern ) != -1 ) ? rv_full.search( pattern ) : '';
	//check to make sure there was a result, if not do  nothing
	// otherwise slice out the part that you want if there is a slice position
	( rv_slice ) ? rv_full = rv_full.substr( 0, rv_slice ) : '';
	// this is the working id number, 3 digits, you'd use this for 
	// number comparison, like if nu >= 1.3 do something
	nu = rv_full.substr( 0, 3 );
	for (i=0; i < moz_types.length; i++)
	{
		if ( nua.indexOf( moz_types[i]) !=-1 )
		{
			moz_brow = moz_types[i];
			break;
		}
	}
	if ( moz_brow )// if it was found in the array
	{
		str_pos=nua.indexOf(moz_brow);// extract string position
		moz_brow_nu = nua.substr( (str_pos + moz_brow.length + 1 ) ,3);// slice out working number, 3 digit
		// if you got it, use it, else use nu
		moz_brow_nu = ( isNaN( moz_brow_nu ) ) ? moz_brow_nu = nu: moz_brow_nu;
		moz_brow_nu_sub = nua.substr( (str_pos + moz_brow.length + 1 ), 8);
		// this makes sure that it's only the id number
		sub_nu_slice = ( moz_brow_nu_sub.search( pattern ) != -1 ) ? moz_brow_nu_sub.search( pattern ) : '';
		//check to make sure there was a result, if not do  nothing
		( sub_nu_slice ) ? moz_brow_nu_sub = moz_brow_nu_sub.substr( 0, sub_nu_slice ) : '';
	}
	if ( moz_brow == 'Netscape6' )
	{
		moz_brow = 'Netscape';
	}
	else if ( moz_brow == 'rv' || moz_brow == '' )// default value if no other gecko name fit
	{
		moz_brow = 'Mozilla';
	} 
	if ( !moz_brow_nu )// use rv number if nothing else is available
	{
		moz_brow_nu = nu;
		moz_brow_nu_sub = nu;
	}
	if (n.productSub)
	{
		release_date = n.productSub;
	}
}
else if (ie)
{
	str_pos=nua.indexOf('MSIE');
	nu=nua.substr((str_pos+5),3);
	brow = 'Microsoft Internet Explorer';
}
// default to navigator app name
else 
{
	brow = nan;
}
op5=(op&&(nu.substring(0,1)==5));
op6=(op&&(nu.substring(0,1)==6));
op7=(op&&(nu.substring(0,1)==7));
op8=(op&&(nu.substring(0,1)==8));
op9=(op&&(nu.substring(0,1)==9));
ie4=(ie&&!dom);
ie5=(ie&&(nu.substring(0,1)==5));
ie6=(ie&&(nu.substring(0,1)==6));
ie7=(ie&&(nu.substring(0,1)==7));
// default to get number from navigator app version.
if(!nu) 
{
	nu = nav.substring(0,1);
}
/*ie5x tests only for functionavlity. dom or ie5x would be default settings. 
Opera will register true in this test if set to identify as IE 5*/
ie5x=(d.all&&dom);
ie5mac=(mac&&ie5);
ie5xwin=(win&&ie5x);

/********************************************************
here is a sample use of the browser detector, it would load a browser specific stylesheet
for certain unsupported or improperly supported mac ie 5 css styles. The depth variable
is used so that the javascript library file can be used from anywhere in the website, you simply
insert the depth of the file like this, 
...
 <head>
 <title>Browser information Page</title>

 <meta http-equiv = "Content-Type" content = "text/html; charset = iso-8859-1" />
 <link rel = "stylesheet" type = "text/css" href = "css/main.css" />
 <script type = "text/javascript" src = "/js/browser_detection.js"> </script>
 <script type = "text/javascript>browser_css( ); </script>
 </head>

in the head of the web page after the js file is loaded.
Or if you are always referring your site to the root, you wouldn't need that
 and could delete the depth variable and just use the absolute path to the root.

function browser_css( ) {
	d = document;
	if ( ie5mac ) {
		d.write('<link rel = "stylesheet" type = "text\/css" href = "/css/ie5mac.css" />');
	}
	else if ( document.layers ){
		d.write('<link rel = "stylesheet" type = "text\/css" href = "/css/ns4x.css" />');
	}
	else if ( ie4 ){
		d.write('<link rel = "stylesheet" type = "text\/css" href = "/css/ie4.css" />');
	}
	else if ( moz && ( nu < 1 ) ){
		d.write('<link rel = "stylesheet" type = "text\/css" href = "/css/moz_pre1-0.css" />');
	}
	else {
		d.write('<link rel = "stylesheet" type = "text\/css" href = "/css/moz5.css" />');
	}
}
********************************************************/
if ( ie7 ) {

}
else {

	function switchcontent(className, filtertag){
		this.className=className
		this.collapsePrev=false //Default: Collapse previous content each time
		this.persistType="none" //Default: Disable persistence
		//Limit type of element to scan for on page for switch contents if 2nd function parameter is defined, for efficiency sake (ie: "div")
		this.filter_content_tag=(typeof filtertag!="undefined")? filtertag.toLowerCase() : ""
	}
	switchcontent.prototype.setStatus=function(openHTML, closeHTML){ //PUBLIC: Set open/ closing HTML indicator. Optional
		this.statusOpen=openHTML
		this.statusClosed=closeHTML
	}
	switchcontent.prototype.setColor=function(openColor, closeColor){ //PUBLIC: Set open/ closing color of switch header. Optional
		this.colorOpen=openColor
		this.colorClosed=closeColor
	}
	switchcontent.prototype.setPersist=function(bool, days){ //PUBLIC: Enable/ disable persistence. Default is false.
		if (bool==true){ //if enable persistence
			if (typeof days=="undefined") //if session only
				this.persistType="session"
			else{ //else if non session persistent
				this.persistType="days"
				this.persistDays=parseInt(days)
			}
		}
		else
			this.persistType="none"
	}
	switchcontent.prototype.collapsePrevious=function(bool){ //PUBLIC: Enable/ disable collapse previous content. Default is false.
		this.collapsePrev=bool
	}
	switchcontent.prototype.sweepToggle=function(setting){ //PUBLIC: Expand/ contract all contents method. (Values: "contract"|"expand")
		if (typeof this.headers!="undefined" && this.headers.length>0){ //if there are switch contents defined on the page
			for (var i=0; i<this.headers.length; i++){
				if (setting=="expand")
					this.expandcontent(this.headers[i]) //expand each content
				else if (setting=="contract")
					this.contractcontent(this.headers[i]) //contract each content
			}
		}
	}
	// -------------------------------------------------------------------
	// PUBLIC: defaultExpanded(indices_of_contents)- Set contents that should be expanded by default when the page loads.
	// Note that the persistence feature (if enabled) overrides this setting.
	// Pass in the position of the contents relative to the rest of the contents ie: defaultExpanded(0,2,3) would expand the 1st, 3rd, and 4th contents by default
	// -------------------------------------------------------------------
	switchcontent.prototype.defaultExpanded=function(){
		var expandedindices=[] //Array to hold indices (position) of content to be expanded by default
		//Loop through function arguments, and store each one within array
		//Two test conditions: 1) End of Arguments array, or 2) If "collapsePrev" is enabled, only the first entered index (as only 1 content can be expanded at any time)
		for (var i=0; (!this.collapsePrev && i<arguments.length) || (this.collapsePrev && i==0); i++)
			expandedindices[expandedindices.length]=arguments[i]
		this.expandedindices=expandedindices.join(",") //convert array into a string of the format: "0,2,3" for later parsing by script
	}
	//PRIVATE: Sets color of switch header.
	switchcontent.prototype.togglecolor=function(header, status){
		if (typeof this.colorOpen!="undefined")
			header.style.color=status
	}
	//PRIVATE: Sets status indicator HTML of switch header.
	switchcontent.prototype.togglestatus=function(header, status){
		if (typeof this.statusOpen!="undefined")
			header.firstChild.innerHTML=status
	}
	//PRIVATE: Contracts a content based on its corresponding header entered
	switchcontent.prototype.contractcontent=function(header){
		var innercontent=document.getElementById(header.id.replace("-title", "")) //Reference content for this header
		innercontent.style.display="none"
		this.togglestatus(header, this.statusClosed)
		this.togglecolor(header, this.colorClosed)
	}
	//PRIVATE: Expands a content based on its corresponding header entered
	switchcontent.prototype.expandcontent=function(header){
		var innercontent=document.getElementById(header.id.replace("-title", ""))
		innercontent.style.display="block"
		this.togglestatus(header, this.statusOpen)
		this.togglecolor(header, this.colorOpen)
	}
	// -------------------------------------------------------------------
	// PRIVATE: toggledisplay(header)- Toggles between a content being expanded or contracted
	// If "Collapse Previous" is enabled, contracts previous open content before expanding current
	// -------------------------------------------------------------------
	switchcontent.prototype.toggledisplay=function(header){
		var innercontent=document.getElementById(header.id.replace("-title", "")) //Reference content for this header
		if (innercontent.style.display=="block")
			this.contractcontent(header)
		else{
			this.expandcontent(header)
			if (this.collapsePrev && typeof this.prevHeader!="undefined" && this.prevHeader.id!=header.id) // If "Collapse Previous" is enabled and there's a previous open content
				this.contractcontent(this.prevHeader) //Contract that content first
		}
		if (this.collapsePrev)
			this.prevHeader=header //Set current expanded content as the next "Previous Content"
	}
	// -------------------------------------------------------------------
	// PRIVATE: collectElementbyClass()- Searches and stores all switch contents (based on shared class name) and their headers in two arrays
	// Each content should carry an unique ID, and for its header, an ID equal to "CONTENTID-TITLE"
	// -------------------------------------------------------------------
	switchcontent.prototype.collectElementbyClass=function(classname){ //Returns an array containing DIVs with specified classname
		var classnameRE=new RegExp("(^|\\s+)"+classname+"($|\\s+)", "i") //regular expression to screen for classname within element
		this.headers=[], this.innercontents=[]
		if (this.filter_content_tag!="") //If user defined limit type of element to scan for to a certain element (ie: "div" only)
			var allelements=document.getElementsByTagName(this.filter_content_tag)
		else //else, scan all elements on the page!
			var allelements=document.all? document.all : document.getElementsByTagName("*")
		for (var i=0; i<allelements.length; i++){
			if (typeof allelements[i].className=="string" && allelements[i].className.search(classnameRE)!=-1){
				if (document.getElementById(allelements[i].id+"-title")!=null){ //if header exists for this inner content
					this.headers[this.headers.length]=document.getElementById(allelements[i].id+"-title") //store reference to header intended for this inner content
					this.innercontents[this.innercontents.length]=allelements[i] //store reference to this inner content
				}
			}
		}
	}
	//PRIVATE: init()- Initializes Switch Content function (collapse contents by default unless exception is found)
	switchcontent.prototype.init=function(){
		var instanceOf=this
		this.collectElementbyClass(this.className) //Get all headers and its corresponding content based on shared class name of contents
		if (this.headers.length==0) //If no headers are present (no contents to switch), just exit
			return
		//If admin has changed number of days to persist from current cookie records, reset persistence by deleting cookie
		if (this.persistType=="days" && (parseInt(switchcontent.getCookie(this.className+"_dtrack"))!=this.persistDays))
			switchcontent.setCookie(this.className+"_d", "", -1) //delete cookie
		// Get ids of open contents below. Four possible scenerios:
		// 1) Session only persistence is enabled AND corresponding cookie contains a non blank ("") string
		// 2) Regular (in days) persistence is enabled AND corresponding cookie contains a non blank ("") string
		// 3) If there are contents that should be enabled by default (even if persistence is enabled and this IS the first page load)
		// 4) Default to no contents should be expanded on page load ("" value)
		var opencontents_ids=(this.persistType=="session" && switchcontent.getCookie(this.className)!="")? ','+switchcontent.getCookie(this.className)+',' : (this.persistType=="days" && switchcontent.getCookie(this.className+"_d")!="")? ','+switchcontent.getCookie(this.className+"_d")+',' : (this.expandedindices)? ','+this.expandedindices+',' : ""
		for (var i=0; i<this.headers.length; i++){ //BEGIN FOR LOOP
			if (typeof this.statusOpen!="undefined") //If open/ closing HTML indicator is enabled/ set
				this.headers[i].innerHTML='<span class="status"></span>'+this.headers[i].innerHTML //Add a span element to original HTML to store indicator
			if (opencontents_ids.indexOf(','+i+',')!=-1){ //if index "i" exists within cookie string or default-enabled string (i=position of the content to expand)
				this.expandcontent(this.headers[i]) //Expand each content per stored indices (if ""Collapse Previous" is set, only one content)
				if (this.collapsePrev) //If "Collapse Previous" set
				this.prevHeader=this.headers[i]  //Indicate the expanded content's corresponding header as the last clicked on header (for logic purpose)
			}
			else //else if no indices found in stored string
				this.contractcontent(this.headers[i]) //Contract each content by default
			this.headers[i].onclick=function(){instanceOf.toggledisplay(this)}
		} //END FOR LOOP
		switchcontent.dotask(window, function(){instanceOf.rememberpluscleanup()}, "unload") //Call persistence method onunload
	}
	// -------------------------------------------------------------------
	// PRIVATE: rememberpluscleanup()- Stores the indices of content that are expanded inside session only cookie
	// If "Collapse Previous" is enabled, only 1st expanded content index is stored
	// -------------------------------------------------------------------
	//Function to store index of opened ULs relative to other ULs in Tree into cookie:
	switchcontent.prototype.rememberpluscleanup=function(){
		//Define array to hold ids of open content that should be persisted
		//Default to just "none" to account for the case where no contents are open when user leaves the page (and persist that):
		var opencontents=new Array("none")
		for (var i=0; i<this.innercontents.length; i++){
			//If persistence enabled, content in question is expanded, and either "Collapse Previous" is disabled, or if enabled, this is the first expanded content
			if (this.persistType!="none" && this.innercontents[i].style.display=="block" && (!this.collapsePrev || (this.collapsePrev && opencontents.length<2)))
				opencontents[opencontents.length]=i //save the index of the opened UL (relative to the entire list of ULs) as an array element
			this.headers[i].onclick=null //Cleanup code
		}
		if (opencontents.length>1) //If there exists open content to be persisted
			opencontents.shift() //Boot the "none" value from the array, so all it contains are the ids of the open contents
		if (typeof this.statusOpen!="undefined")
			this.statusOpen=this.statusClosed=null //Cleanup code
		if (this.persistType=="session") //if session only cookie set
			switchcontent.setCookie(this.className, opencontents.join(",")) //populate cookie with indices of open contents: classname=1,2,3,etc
		else if (this.persistType=="days" && typeof this.persistDays=="number"){ //if persistent cookie set instead
			switchcontent.setCookie(this.className+"_d", opencontents.join(","), this.persistDays) //populate cookie with indices of open contents
			switchcontent.setCookie(this.className+"_dtrack", this.persistDays, this.persistDays) //also remember number of days to persist (int)
		}
	}
	// -------------------------------------------------------------------
	// A few utility functions below:
	// -------------------------------------------------------------------
	switchcontent.dotask=function(target, functionref, tasktype){ //assign a function to execute to an event handler (ie: onunload)
		var tasktype=(window.addEventListener)? tasktype : "on"+tasktype
		if (target.addEventListener)
			target.addEventListener(tasktype, functionref, false)
		else if (target.attachEvent)
			target.attachEvent(tasktype, functionref)
	}
	switchcontent.getCookie=function(Name){ 
		var re=new RegExp(Name+"=[^;]+", "i"); //construct RE to search for target name/value pair
		if (document.cookie.match(re)) //if cookie found
			return document.cookie.match(re)[0].split("=")[1] //return its value
		return ""
	}
	switchcontent.setCookie=function(name, value, days){
		if (typeof days!="undefined"){ //if set persistent cookie
			var expireDate = new Date()
			var expstring=expireDate.setDate(expireDate.getDate()+days)
			document.cookie = name+"="+value+"; expires="+expireDate.toGMTString()
		}
		else //else if this is a session only cookie
			document.cookie = name+"="+value
	}

}
