/*
JavaScript code for sites participating in the Tangent network
(http://www.tangent.cx/). This code is subject to the terms of
the Tangent Source Code License at http://www.tangent.cx/legal/license.php.
If you find bugs or make changes to this code, it would be
appreciated if you resubmitted them to admin@tangent.cx so that
all can benefit.
*/



////////////////// CONFIG OPTIONS \\\\\\\\\\\\\\\\\

// set this to false if the boxes are appearing too slowly for you.
bDoWipe = true;

// if the above is false, set this to the number of milliseconds the
// mouse must be over the link before the box appears.
iShowDelay = 500;

// the number of milliseconds the box should remain onscreen after the
// mouse has moved off the link
iHideDelay = 700;

//////////////////// END CONFIG \\\\\\\\\\\\\\\\\\\



// track mouse movements
iMouseLeft = iMouseTop = 0;
if(document.addEventListener) {
	document.addEventListener("mousemove", trackMouse, false);
} else {
	document.onmousemove = trackMouse;
}

function trackMouse(e) {
	if(e) {
		iMouseLeft = e.clientX;
		iMouseTop = e.clientY;
		if(document.body) {
			document.body.scrollTop = e.pageY - e.clientY;
			document.body.scrollLeft = e.pageX - e.clientX;
		}
	} else if(event) {
		iMouseLeft = event.clientX;
		iMouseTop = event.clientY;
	}
}

// handle tangent rollovers
hidetangent = false;
function doTangent() {
	// Don't even bother trying on IE 5.1 or 5.2 on OSX. There is a bug that makes text re-render itself unpredictably
	// when the document's contents are changed in any way, and I haven't found a workaround for it.
	if(((navigator.userAgent.indexOf("5.1") != -1) || (navigator.userAgent.indexOf("5.2") != -1)) && (navigator.userAgent.indexOf("Mac") != -1)) { return; }

	if((document.documentElement) && (document.documentElement.scrollTop)) {
		var iScrollTop = document.documentElement.scrollTop;
		var iScrollLeft = document.documentElement.scrollLeft;
		var iPageWidth = document.documentElement.offsetWidth;
		var iPageHeight = document.documentElement.offsetHeight;
	} else {
		var iScrollTop = document.body.scrollTop;
		var iScrollLeft = document.body.scrollLeft;
		var iPageWidth = (window.innerWidth) ? window.innerWidth : document.body.offsetWidth;
		var iPageHeight = (window.innerHeight) ? window.innerHeight : document.body.offsetHeight;
	}
	
	if(!document.getElementById("tangentbox")) {
	// create the tangent box if it doesn't exist
		var oTangentBox = document.createElement("div");
		oTangentBox.id = "tangentbox";
		var oTangentWrite = document.createElement("span");
		oTangentWrite.id = "tangentwrite";
		oTangentBox.appendChild(oTangentWrite);
		document.body.appendChild(oTangentBox);
	} else {
	// use the existing one
		var oTangentBox = document.getElementById("tangentbox");
	}

	if((oTangentBox.boolIsClipping) && (!arguments.length)) {
// if a tangent box is in the midst of clipping io view during a mouseout,
// abort the animation. otherwise, the next mouseover could display incorrectly
		clearTimeout(oTangentBox.timeout);
		oTangentBox.boolIsClipping = false;
		if(bDoWipe) {
			oTangentBox.style.visibility = "hidden";
		}
	}

	if(arguments.length) {
// rolling over a tangent link - parse the arguments passed in, write the links,
// position the tangent box appropriately, and use clipTo to show it slickly.
		aTangents = arguments;
		oTangentBox.style.visibility = "hidden";
		oTangentBox.style.top = oTangentBox.style.left = "0px";
		if(hidetangent) { clearTimeout(hidetangent); }

		var iFrom = parseInt(arguments[1].split('=')[1]);

		// write the links to the tangent box
		var sTangents = '<p class="tangentlink"><nobr>';
		for(var i=2; i<aTangents.length; i+=4) {
			sTangents += aTangents[i+2].replace(/-/g, ".") + ' - <a href="http://tangent.cx/t/r.php?from=' + iFrom + '&amp;to=' + aTangents[i] + '&amp;tw=' + aTangents[0] + '" onmouseover="clearTimeout(hidetangent); window.status=\'http://' + aTangents[i] + '\'; return true" onmouseout="doTangent(); window.status=\'\'" class="tangentlink" title="' + aTangents[i+3] + '">' + aTangents[i+1] + '</a>';
			if(i<aTangents.length-3) { sTangents += "<br />"; }
		}
		sTangents += '</nobr></p>';
		document.getElementById("tangentwrite").innerHTML = sTangents;

		// initially position it below and to the right of the cursor
		var iNewLeft = iMouseLeft + 8 + iScrollLeft;
		var iNewTop = iMouseTop + 8 + iScrollTop;
		var iClipLeft = iClipTop = iClipRight = iClipBottom = 0;

		// figure out the page dimensions and object dimensions to possibly move the tangent
		// box in order to keep it from appearing offscreen
		var iWidth = oTangentBox.offsetWidth;
		var iHeight = oTangentBox.offsetHeight;

		// move box to the left of the cursor if it'll go off to the right
		if(iNewLeft + iWidth > iPageWidth + iScrollLeft - 20) {
			iNewLeft = iNewLeft - iWidth - 10;
			iClipRight = iClipLeft = iWidth;
		}
		// move box above the cursor if it'll go off the bottom
		if(iNewTop + iHeight > iPageHeight + iScrollTop - 20) {
			iNewTop = iNewTop - iHeight - 10;
			iClipTop = iClipBottom = iHeight;
		}

		// now that that's all figured out, actually show the thing
		oTangentBox.style.top = iNewTop + "px";
		oTangentBox.style.left = iNewLeft + "px";
		oTangentBox.style.clip = "rect(" + iClipTop + "px " + iClipRight + "px " + iClipBottom + "px " + iClipLeft + "px)";
		oTangentBox.style.visibility = "visible";
		if(bDoWipe) {
			clipTo("tangentbox", 0, iWidth, iHeight, 0, 1, 10, 50);
		} else {
			oTangentBox.boolIsClipping = true;
			oTangentBox.timeout = setTimeout('document.getElementById("tangentbox").style.clip = "rect(0px ' + iWidth + "px " + iHeight + 'px 0px)"', iShowDelay);
		}
	} else {
// onmouseout, hide the box after a half-second - this timeout gets cleared by the tangentlinks to
// keep it onscreen when rolling over them.
		hidetangent = setTimeout('document.getElementById("tangentbox").style.visibility = "hidden";', iHideDelay);
	}
}


/* - - - - -
clipTo - Clip an object from its current clipping area to a new new one.
Arguments:
	sId - The value of the ID attribute of the HTML element to be moved.
	iEndT - The top of the final clipping area.
	iEndR - The right of the final clipping area.
	iEndB - The bottom of the final clipping area.
	iEndL - The left of the final clipping area.
	iClipType - The type of motion: 1 = slow-to-fast, 2 = fast-to-slow, 3 = linear.
	iFrames - The number of frames of animation. This is how many times the object will be repositioned (50 is a good default).
	iTimePerFrame - The amount of time between frames (in ms, 20 is a good default).
	sFrameCode - Optional. Code to be evaluated after each frame of animation (for example, to syncronize animation of multiple objects)
	sFinishCode - Optional. Code to be evaluated when the glide is finished (eg, "alert()").

Note: The remaining arguments are used by the function itself when it recurses,
and should not be passed in.
- - - - - */
function clipTo(sId, iEndT, iEndR, iEndB, iEndL, iClipType, iFrames, iTimePerFrame, sFrameCode, sFinishCode, iDistT, iDistR, iDistB, iDistL, iScaleT, iScaleR, iScaleB, iScaleL, iFrameCount) {
	var o = document.getElementById(sId);
// The function is being called for the first time. Initialization of the clip.
	if(!iFrameCount) {
		if(o.boolIsClipping) { return; } // Cancel the clip if we're already animating.
	// Set default starting values.
		if((o.style.clip == "") || (o.style.clip == "auto")) {
			var aClipVals = [0, o.offsetWidth, o.offsetHeight, 0];
		} else {
			var aClipVals = o.style.clip.split("rect(")[1].split(" "); // Split the clipping values on the object io an array...
		}
		for(var i=0; i<aClipVals.length; i++) { aClipVals[i] = parseInt(aClipVals[i]); } // ...and convert them to integers.
	// Round off any decimals that we end up with.
		iEndT = Math.round(iEndT);
		iEndR = Math.round(iEndR);
		iEndB = Math.round(iEndB);
		iEndL = Math.round(iEndL);
	// Set the new clipping values.
		o.iNewT = aClipVals[0];
		o.iNewR = aClipVals[1];
		o.iNewB = aClipVals[2];
		o.iNewL = aClipVals[3];
	// Computer the animation arguments.
		// Set the distance to clip each side.
		var iDistT = iEndT - o.iNewT;
		var iDistR = o.iNewR - iEndR;
		var iDistB = o.iNewB - iEndB;
		var iDistL = iEndL - o.iNewL;
		// Compute the scaling factors.
		var iScaleFactor = ((Math.pow(iFrames, 2) + 2 * iFrames + 1) / (4 * iFrames));
		var iScaleT = iDistT / iScaleFactor;
		var iScaleR = iDistR / iScaleFactor;
		var iScaleB = iDistB / iScaleFactor;
		var iScaleL = iDistL / iScaleFactor;
	// Call the function again to play the first frame.
		o.boolIsClipping = true;
		
		clipTo(sId, iEndT, iEndR, iEndB, iEndL, iClipType, iFrames, iTimePerFrame, sFrameCode, sFinishCode, iDistT, iDistR, iDistB, iDistL, iScaleT, iScaleR, iScaleB, iScaleL, 1);
	} else {
// The function is calling itself to execute a frame of the animation.
		if(iFrameCount < iFrames) { // Make sure the loop isnt completed.
			switch(parseInt(iClipType)) {
			// Slow-to-fast clip.
				case 1:
					var iScaleFactor = Math.pow(iFrameCount / iFrames, 3);
					o.iNewT += iScaleT * iScaleFactor;
					o.iNewR -= iScaleR * iScaleFactor;
					o.iNewB -= iScaleB * iScaleFactor;
					o.iNewL += iScaleL * iScaleFactor;
					break;
				case 2:
			// Fast-to-slow clip.
					var iScaleFactor = Math.pow(((iFrames-iFrameCount) + 1) / iFrames, 3);
					o.iNewT += iScaleT * iScaleFactor;
					o.iNewR -= iScaleR * iScaleFactor;
					o.iNewB -= iScaleB * iScaleFactor;
					o.iNewL += iScaleL * iScaleFactor;
					if((Math.round(o.iNewT) == iEndT) && (Math.round(o.iNewR) == iEndR) && (Math.round(o.iNewB) == iEndB) && (Math.round(o.iNewL) == iEndL)) {
						iFrameCount = iFrames;
					}
					break;
				case 3:
			// Linear clip.
					o.iNewT += iDistT / iFrames;
					o.iNewR -= iDistR / iFrames;
					o.iNewB -= iDistB / iFrames;
					o.iNewL += iDistL / iFrames;
					break;
			}
			// Set the new clipping properties for this frame.
			o.style.clip = "rect(" + Math.round(o.iNewT) + "px " + Math.round(o.iNewR) + "px " + Math.round(o.iNewB) + "px " + Math.round(o.iNewL) + "px)";
			iFrameCount++;
			// Evaluate the per-frame code.
			if(sFrameCode != "undefined") {
				eval(sFrameCode);
			}
			// Call the function again for the next frame.
			o.timeout = setTimeout("clipTo(\""+sId+"\","+iEndT+","+iEndR+","+iEndB+","+iEndL+","+iClipType+","+iFrames+","+iTimePerFrame+",\""+sFrameCode+"\",\""+sFinishCode+"\","+iDistT+","+iDistR+","+iDistB+","+iDistL+","+iScaleT+","+iScaleR+","+iScaleB+","+iScaleL+","+iFrameCount+")", iTimePerFrame);
		} else { // Move to the final frame.
			o.boolIsClipping = false;
			o.style.clip = "rect(" + iEndT + "px " + iEndR + "px " + iEndB + "px " + iEndL + "px)"; // Make sure it ends at the proper .clip.
			// Evaluate the per-frame code.
			if(sFrameCode != "undefined") {
				eval(sFrameCode);
			}
			if(sFinishCode != "undefined") {
				eval(sFinishCode); // Evaluate the ending code.
			}
		}
	}
};

