/*
 Modified: Thao Pham
 Update:
	- 11/11/02: 
		support Netscape 7.
		fixes various issues with layer overlapping the glossary.

 Modified: Josh Brown Kramer
 Update:  07/24/03
          Moved to course common, and made changes, so that this single copy of
		  popup.js can be used by all of the courses.
	
 Description: Glossary popup functions for both Netscape Communicator 4.0+ and Internet Explorer 4.0+
 */
var thisFile = "../_CourseCommon/popup.js" //Location of file relative to the course root folder
var fileToInclude = "findccfs.js" //Location of the file to include relative to current file
document.write('<SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript" SRC="' + URLRelativeToCallingFile(thisFile,fileToInclude) + '"></SCRIPT>');
function URLRelativeToCallingFile(thisFile,fileToInclude)
{
	//Returns a URL relative to the file which is including this file
	//thisFile should contain the location of this file relative to the course root file.
	//fileToInclude should be a URL relative to this file pointing to the file whose URL
	//we will return.
	var scriptTags = document.getElementsByTagName("script")
	var i,j,k
	var dirChar,includeDirList,thisFileDirList,fileToIncludeDirList,includeLength,thisFileLength

	if (thisFile.indexOf("\\") != -1) dirChar = "\\" 
	else dirChar = "/"
	thisFileDirList = thisFile.split(dirChar);

	for (i=0;i<scriptTags.length;i++)
	{
		if (scriptTags[i].src && scriptTags[i].src.length)  //Make sure there actually is a script attribute.
		{
			if (scriptTags[i].src.indexOf("\\") != -1) dirChar = "\\"
			else dirChar = "/"
			includeDirList = scriptTags[i].src.split(dirChar)
			thisFileLength = thisFileDirList.length
			includeLength = includeDirList.length
			for (j=includeLength-1;j>=0 && j + thisFileLength - includeLength >= 0;j--)
			{
				if (includeDirList[j] == ".." || thisFileDirList[j+thisFileLength-includeLength] == "..") {j = -1;  break;}
				if(includeDirList[j] != thisFileDirList[j+thisFileLength-includeLength]) break;
			}
			if (j < 0 || j + thisFileLength - includeLength < 0) break;
		}
	}

	if (i < scriptTags.length)
	{//We have found the correct script tag.
		if (fileToInclude.indexOf("\\") != -1) dirChar = "\\"; else dirChar = "/"
		fileToIncludeDirList = fileToInclude.split(dirChar)
		var endIndex = includeLength - 2
		j = 0
		while (fileToIncludeDirList[j] == ".." && includeDirList[endIndex]!= ".." && j < fileToIncludeDirList.length && endIndex >= 0)
		{
			endIndex--
			j++
		}
		var returnString = ""
		for (k=0;k<=endIndex;k++) returnString += includeDirList[k] + dirChar;
		for (k=j;k<fileToIncludeDirList.length-1;k++) returnString += fileToIncludeDirList[k] + dirChar;
		returnString += fileToIncludeDirList[k];
		return returnString
	}
	else {return empty}
}

function showDiv(divID)
{  //Makes the indicated div visible
   //Note: be careful when changing this:  it is called directly from some html files
	if(document.layers)
	{	//NS 4.x
		document.layers[divID].visibility="show"
	}
	else if (document.getElementById)
	{	//Standards compliant
		var divObj = getTag("div",divID)
		divObj.style.visibility = "visible"
	}
}

function showDivs()
{	//Takes a list of div IDs, makes each associated div visible.
	var args = showDivs.arguments
	var i
	for (i=0;i<args.length;i++)
	{
		showDiv(args[i])
	}
}

function getTag(tagName,id)
{	//Returns the first tag of type tagName, with id id.
	var firstTry = document.getElementById(id)
  if (firstTry==null) return null; // There's no tag (of any kind) with this id
	if (tagName.toLowerCase() == firstTry.tagName.toLowerCase()) return firstTry
	tags = document.getElementsByTagName(tagName);
	for (var i=0;i<tags.length;i++)
	{
		if (tags[i].getAttribute("id") == id) return tags[i];
	}
	return null;
}

function hideDiv(divID)
{	//  Hide the div with the given ID
	// exit if not supported browser
	if (!(document.all || document.layers || document.getElementById)) return;

	if (document.getElementById) {
    // Standards Compliant 
		glossObj = getTag("div",divID)
		if(glossObj == null) {
			alert("ERROR: Can't find " + divID + " div tag.");
			return;
		}
		glossObj.style.visibility = "hidden";
	}
	else if (document.all) {
		// IE 4/5
		document.all[divID].style.visibility = 'hidden';
	}
	else {
		// Nav 4.x
		 document[divID].visibility = "hidden";
	}
}

function hideDivs()
{	//Takes a list of div IDs, makes each associated div hidden.
	var args = hideDivs.arguments
	var i
	for (i=0;i<args.length;i++)
	{
		hideDiv(args[i])
	}
}

function divX(divID)
{
	if (document.getElementById)
	{
		var divObj = getTag("div",divID)
		return divObj.offsetLeft
	}
	else if (document.layers)
	{
		return document.layers(divID).pageX
	}
	return 0
}

function divY(divID)
{
	if (document.getElementById)
	{
		divObj = getTag("div",divID)
		return divObj.offsetTop
	}
	else if (document.layers)
	{
		return document.layers(divID).pageY
	}
	return 0
}

function hideMoveWriteShowDiv(divID,x,y,text)
{
	hideDiv(divID)
	moveDiv(divID,x,y)
	writeDiv(divID,text)
	showDiv(divID)
}

function moveDiv(divID,x,y)
{
	//Move the Div from its current coordinates to the ones passed
	if(document.layers)
	{
		document.layers[divID].moveTo(x,y)
	}
	else if(document.getElementById)
	{
		var theDiv = getTag("div",divID)
		theDiv.style.left = x + "px"; // "px" required by Firefox!
		theDiv.style.top = y + "px";
	}
	//Otherwise it doesn't do anything.
}

function writeDiv(divID,text)
{//Writes the innerHTML for the div with the passed ID
	if (document.getElementById)
	{  //Standards compliant
		var divObj = getTag("div",divID)
		divObj.innerHTML = text
	}
	else if (document.layers)
	{  //Netscape 4.x
		document[divID].document.open();
		document[divID].document.write(textTable);
		document[divID].document.close();
	}
}

function readDiv(divID)
{
	if (document.getElementById)
	{  //Standards compliant
		var divObj = getTag("div",divID)
		return divObj.innerHTML
	}
	else if (document.layers)
	{  //Netscape 4.x
		return document[divID].innerHTML
	}
	else return ""
}

//params is an array of arrays.  The first entry is the name of the parameter.
//The second entry is the default value of the parameter.  The order should be the
//order in which you take in the parameters.

var params = new Array(
	["text",null],
	["e",null],
	["y_offset",0],
	["x_offset",0],
	["borderColor",'#000000'],
	["bgColor",'#ffcc66'],
	["fontColor",''],
	["border",1],
	["padding",3],
	["Font",'face="Verdana, Arial, Helvetica, sans-serif" size=2'],
	["tableWidth",250],
	["layerName",'glossary']);
var initialized = false;
var defaults = new Array()

function init()
{
	//Determine the default values for parameters passed to popupon

	//Take care of the parameters
	var i
	for (i=0;i<params.length;i++)
	{
		if (eval("typeof local_popupjs_" + params[i][0]) != "undefined")
			eval("defaults[i] = local_popupjs_" + params[i][0]);
		else if (typeof eval("CCFS.popupjs_" + params[i][0]) != "undefined")
			eval("defaults[i] = CCFS.popupjs_" + params[i][0]);
		else
			eval("defaults[i] = params[i][1]");
	}
	initialized = true
}

function popupon()
{ 
	//text:  If this is null, then the contents of the indicated layer is not changed.
	//The parameters below may be specified in names.js, in the file calling popupon
	//or through parameters passed to the function, in increasing order of precedence
	//Note that, for example, to change borderColor in names.js, you
	//should set popupjs_borderColor in names.js.  To set it in the calling file, you
	//should set local_popupjs_borderColor in the calling file.  If no value is specified 
	//for a parameter, either in the function call, in the calling file, or in names.js, 
	//it takes a default value as follows:

	/*
		"text":null
		"e",null  //This is the passed event
		"y_offset":0
		"x_offset":0
		"borderColor":'#000000'
		"bgColor":'#ffcc66'
		"fontColor":''"//use body text color
		"border":1
		"padding":3
		"Font":'face="Verdana, Arial, Helvetica, sans-serif" size=2'
		"tableWidth":250
		"layerName":'glossary'
	*/

  var gs, scrollTop, scrollLeft
  var is_mobile_device = (CCFS && CCFS.NAV_TYPE && CCFS.NAV_TYPE=="mobile")

	//Take care of the passed parameters
	if (!initialized)
		init();
	var i
	var args = popupon.arguments
	var l = args.length, l2 = params.length
	for (i=0;i<l;i++)
	{
		if (args[i] != null)  //This parameter has been passed
			eval(params[i][0] + " = args[i]");
		else
			eval(params[i][0] + " = defaults[i]");
	}

	for (i=l;i<l2;i++)
	{
		eval(params[i][0] + " = defaults[i]");
	}


	//Dynamically create the div tag if it doesn't exist.
	if (document.getElementById)  //Test for DHTML ability
	{
		if ((theDiv=getTag("div",layerName))==null)
		{
			var theDiv
			if (document.all != null && navigator.platform.indexOf("Mac") == -1)
			{  //IE in windows
				theDiv = document.createElement('<div id="' + layerName + '" style="position:absolute; z-index:1; visibility:hidden">')
			}
			else
			{//Netscape & Mac
				theDiv = document.createElement("div")
				theDiv.id = layerName
				theDiv.style.position = "absolute"
				theDiv.style.zindex = 1
				theDiv.style.visibility = "hidden"
			}
			document.body.appendChild(theDiv)
		}
    if (is_mobile_device) {
      // mobile devices generally don't support "onmouseout" events, so
      // set up the div so it will go away when clicked:
      theDiv.onclick = function() {this.style.visibility="hidden"}
    }
  }

  // Get positions of scrollbars
  gs = GetScroll()
  scrollTop = gs.top; scrollLeft = gs.left

	// return if browser is not IE 4 above, Nav 4.x above
	// document.getElementById is for Nav 6, 7.x 
	if (!(document.all || document.layers || document.getElementById)) return;
	var textTable = "";
  	var posX=0;
 	var posY=0;
	var goodBrowser = true;
 	
	if (document.all != null) {
		if (navigator.platform.indexOf("Mac") != -1)
		{
			//If this is a mac, we see if it is explorer 5.2 or greater
			var MSIEVersion = /MSIE\s*(\d*)\.(\d*)/
			MSIEVersion.exec(navigator.userAgent)
			if (parseInt(RegExp.$1) > 5) goodBrowser = true
			else if (parseInt(RegExp.$1) == 5 && parseInt(RegExp.$2) >= 2) goodBrowser = true
			else goodBrowser = false
		}
	}

	var oldContents = null
	if (text == null)
	{	//If the text parameter is null we do not change the content of the layer EXCEPT
		//that we wrap it in a table, which is needed to calculate the position of the
		//layer later.
		text = readDiv(layerName)
		oldContents = text
		border = 0
		tableWidth  = 0
		padding = 0
		Font = ""
	}

	// 7/16/04
	// imgages are relative to glossary folder, need to concatenate the relative path from current html document
	if(typeof CCFS.GLOSSARY_CONFIG != "undefined")
		text = replaceDocRelSrc(text);

  // Make popup somewhat wider for mobile devices:
  if (is_mobile_device) tableWidth *= 2

	// In MAC IE, table borders will appear like a skeleton above the layer. Bug.
	if (!goodBrowser)
  		textTable += "<table" + " id='" + layerName + "_table'" +  " width=" + tableWidth + " cellpadding="+ padding +" cellspacing=0" +">";
	else
		textTable += "<table" + " id='" + layerName + "_table'" + " width=" + tableWidth + " cellpadding="+ padding +" border="+ border +" cellspacing=0 bordercolor="+ borderColor +">";	
//	var fontColor = 0xffffff-("0x"+bgColor.substring(1,7));
//	textTable += "<tr><td class='BodyText' bgcolor="+ bgColor +"><font color=#"+fontColor.toString(16)+">" + text + "</font></td></tr></table>";

	textTable += "<tr><td class='BodyText' bgcolor="+ bgColor +">";
  if (is_mobile_device) {
    // Make the text a little bigger than normal
    textTable += '<span style="' + ((fontColor=='')?(''):('color:'+fontColor+';')) +
      'font-family:Verdana,Arial,Helvetica,sans-serif;font-size:110%">' + '(1.3)' + text + '</span>';
  }
  else {
    // (should probably switch to using CSS here eventually, as soon as we can standardize and/or eliminate the "Font" variable!)
    textTable += "<font" + ((fontColor=="")?(""):(' color="'+fontColor+'"')) + " " + Font + ">" + text + "</font>";
  }
	textTable += "</td></tr></table>";

	writeDiv(layerName,textTable);
	// calculate the position
	if (document.all != null) {
		// for Internet Explorer 4.0 or above
		posX = e.clientX;
		posX += scrollLeft;

		var windowWidth = document.body.clientWidth;
		// substract page-offset windows 8, Mac 10;
		if (navigator.platform.indexOf("Mac") != -1)
			windowWidth -= 20;
		else
		    windowWidth -= 16;
		
		var tableRightX = e.clientX + document.all[layerName + "_table"].clientWidth;

		if (tableRightX > windowWidth) 
			posX -=  tableRightX - windowWidth;
		else
			posX += 18
			
		if (posX < scrollLeft) posX = scrollLeft;

		posY = e.clientY;
		posY += scrollTop;
		var windowHeight = document.body.clientHeight;

		var tableBottomY = e.clientY + document.all[layerName + "_table"].clientHeight;
		//alert("tableBottomY: " + tableBottomY + "windowHeight: " + windowHeight)
		// line height = 18
		if ((tableBottomY + 18)> windowHeight) 
			posY -= document.all[layerName + "_table"].clientHeight + 18; 
		else
			posY += 18;

		// In MAC IE, table  will appear above the layer. Bug. 
		if (!goodBrowser) {
			posY -= document.all[layerName + "_table"].clientHeight;
		}
		if (posY < scrollTop) posY = scrollTop;
		
		//offset the layer by a user specified amount
		if(y_offset) 
			posY-=y_offset;
		if(x_offset)
			posX-=x_offset;

		//alert(document.all[layerName].outerHTML)
		moveDiv(layerName,posX,posY);
		showDiv(layerName);
	} 
	else if (document.layers) {
		// for Netscape 4.x

		posX = e.pageX;
		var windowWidth = window.innerWidth;
		// substract scrollbar width = 16
		windowWidth -= 16;
		// check relative position tableBottomX
		var tableRightX = (posX - window.pageXOffset) + document.layers[layerName].clip.width;
		 // 16: scrollbar width
		if (tableRightX > windowWidth )
			posX -= tableRightX - windowWidth;
		else
			posX += 18
			
		if (posX < 0) posX = 0;

		posY = e.pageY;
		var windowHeight = window.innerHeight;
		// check relative position tableBottomY
		var tableBottomY =(posY - window.pageYOffset) + document.layers[layerName].clip.height;
		// line height = 18
 		if ((tableBottomY + 18) > windowHeight)
			posY -= document.layers[layerName].clip.height + 18;
		else
			posY += 18;
		if (posY < 0) posY = 0;

		if(y_offset) 
			posY-=y_offset;
		if(x_offset)
			posX-=x_offset;	

		moveDiv(layerName,posX,posY);
		showDiv(layerName)
	}
	else {
		 // Nav 7.x and Safari
		var glossObj = getTag("div",layerName)
		
		if(glossObj == null) {
			alert("ERROR: Can't find " + layerName + " div tag.");
			return;
		}

		posX = e.pageX;
		var windowWidth = document.body.clientWidth;
		
		var tableObj = getTag("table",layerName + "_table");
		if(tableObj == null) {
			alert("ERROR: Can't find the " + layerName + "_table" + " object.");
			return;
		}
		
		var tableRightX = e.clientX + parseInt(tableObj.width);
		// case where the
		if (tableRightX > windowWidth) posX -=  tableRightX - windowWidth;
		else posX += 18
		if (posX < 0) posX = 0;
		posY = e.pageY;
		var windowHeight = document.body.clientHeight;
		// estimate table height:
		// font width = 8;
		// line height = 18
		var tableHeight = tableObj.offsetHeight; //Math.ceil(text.length*8/tableWidth)*18;
		//alert(e.pageY + "\n " + e.clientY);
		var tableBottomY = e.clientY + tableHeight;
		// move the layer above the word if it would appear below the visible area
 		if ((tableBottomY + 18) > windowHeight || (CCFS.inSafari() && tableHeight + 18 > e.screenY - 20))
			posY -= (tableHeight + 18);
		else
			posY += 18; 

		if (posY < 0) posY = 0;
		// take care of special offset from arguments
		if(y_offset) 
			posY-=y_offset;
		if(x_offset)
			posX-=x_offset;	

		moveDiv(layerName,posX,posY);
		showDiv(layerName)
	}

	//If we weren't supposed to change the contents, we write 
	//back the original contents
	if (oldContents != null)
		writeDiv(layerName,oldContents)
}

function popupoff(p_layerName) {
  //You may specify the name of the layer to hide with the p_layerName parameter.
  //If no parameter is passed, it pulls its value from the local_popupjs_layerName
  //global variable, which should be set in the file calling popupoff.
  //If this is not set, it pulls it from the popupjs_layerName global
  //variable, which is set in names.js.  If the variable is not set there, then
  //layerName takes on the default value "glossary"
  var layerName = "glossary"
  if (typeof CCFS.popupjs_layerName != "undefined") layerName = CCFS.popupjs_layerName;
  if (typeof local_popupjs_layerName != "undefined") layerName = local_popupjs_layerName;
  if (p_layerName != null) layerName = p_layerName;

  hideDiv(layerName)
}

function openLink(gterm,gletter) {
	 /*Created: 6/28/04
	Description:  open glossary page in the glossary_folder in a new window.
	gterm: glossary term
	gletter (optional): glossary alphabetical order
	*/
	var anchorStr = getAnchor(gterm);
	// if the glossary is not split alphabetically, then it will be in  "all" definition file
	var uletter = "a";
	if(typeof CCFS.GLOSSARY_CONFIG.split != "undefined") {
		if(CCFS.GLOSSARY_CONFIG.split) {
			if(typeof gletter == "undefined") {
				uletter = anchorStr.charAt(0);
			}
			else {
				uletter = gletter;
			}
		}
		else {
		    uletter = "all";
		}
	}
	else {
		uletter = "all";
	}
	var prefix = "definition";
	if(typeof CCFS.GLOSSARY_CONFIG.module_name != "undefined")
		prefix = CCFS.GLOSSARY_CONFIG.module_name + "_definition";
	var  glossaryURL = getDocRelToGlossFolder() + prefix + "_" + uletter + ".htm" + "#" + anchorStr;
    var popUp_Window = window.open(glossaryURL, 'windowa', 'scrollbars=yes,width=620,height=400');
	popUp_Window.focus();
	return false;
}

function getAnchor(gterm,max) {
    // anchors for glossary are alphanumerical. 
	// Spaces between the words are substituted with underscores)
	// if the anchor has more character then max, then the substr is return.
	var retstr = gterm;
	retstr = retstr.toLowerCase();
	retstr = retstr.replace(/\s+/g,"_");  // Delete spaces
	if (max && max>3 && retstr.length>max) retstr = retstr.substring(0,max);
	return retstr;
}

function getDocRelToGlossFolder() {
	//pre-condition: glossary_folder var contains the url path to the glossary folder relative to the course folder
	//else default folder is set.  When every course is changed to have "glossary" folder, 
	//then default folder will be changed.
	//and glossary_folder is only set when the glossary points to other course's glossary. 
    var glossary_folder = "00common/0004glossary/"
	if (typeof CCFS.GLOSSARY_FOLDER != "undefined") 
		glossary_folder = CCFS.GLOSSARY_FOLDER
	if (glossary_folder.length && glossary_folder.slice(-1) != "/")
		glossary_folder += "/";
	var relDocURL = document.URL.substring(CCFS.folderURL(CCFS).length);
	//document.URL returns url with "\" changed to "/"
	relDocURL = relDocURL.replace(/\\/g,"/");
	var retURL = getRelativePath(relDocURL,glossary_folder);
	return retURL;
}
function replaceDocRelSrc(txt) {
	/* description: search for all the (src="path relative to glossary folder"} strings
					replace it with url relative to current document.
	   precondition:  -src value is enclosed by double quote ".
					  -path is relative to glossary folder
	*/
	var searchRegEx = /src="/g;
	var rettxt = txt.replace(searchRegEx,"src=\"" + getDocRelToGlossFolder());
	//alert(searchRegEx.toString());
	return rettxt;
}

/* 
Function getRelativePath(fromURL, toURL)
Precondition:
	-toURL and fromURL are not empty strings
	-toURL and  fromURL both are course-folder-relative url
	-
Algorithm:
	2 cases:
		-case1: toURL is outside of course_folder
		-case 2: toURL is inside course_folder
	case1: 
		-chop the common part + filename
		-from the fromURL, traverse up to with ../
		-append the rest of toURL to it.
	case2: 
		-from fromURL traverse up to course folder with "../"
		-append toURL to fromURL.
*/
function getRelativePath(fromURL, toURL) {
	if(toURL.substr(0,3) == "../") {
		//case 2:
		var index = fromURL.lastIndexOf("/");
		var temp;
		if(index != -1)
			temp = fromURL.slice(0,index);
		var fromArr = temp.split("/");
		// traverse up course folder
		var retPath = ""
		for (var i = 0; i < fromArr.length; i++) {
			retPath += "../"
		}
		retPath += toURL;
		return retPath;
	}
	else {
		//case 1:
	    // chop to the last "/" and turn into arrays
		var index = fromURL.lastIndexOf("/");
		var temp;
		if(index != -1)
			temp = fromURL.slice(0,index);
		var fromArr = temp.split("/");
		index = toURL.lastIndexOf("/");
		if(index != -1)
			temp = toURL.slice(0,index);
		var toArr = temp.split("/");

		// chop common part
		var maxloop = (fromArr.length < toArr.length)? fromArr.length: toArr.length;
		var i = 0;
		while(fromArr[i] == toArr[i] && i < maxloop) {
			i++;
		}
		fromArr = fromArr.slice(i);
		toArr = toArr.slice(i);

		// traverse up 
		var retPath = ""
		for (var i = 0; i < fromArr.length; i++) {
			retPath += "../"
		}
		// concate with toArr
		retPath += toArr.join("/") + "/";
		return retPath;
	}
}
//-----------------------------------------------------------
function GetScroll()
{
  var x,y;
  if (self.pageYOffset) // all except Explorer
  {
    x = self.pageXOffset;
    y = self.pageYOffset;
  }
  else if (document.documentElement && document.documentElement.scrollTop)
    // Explorer 6 Strict
  {
    x = document.documentElement.scrollLeft;
    y = document.documentElement.scrollTop;
  }
  else if (document.body) // all other Explorers
  {
    x = document.body.scrollLeft;
    y = document.body.scrollTop;
  }
  return {left:x, top:y}
}