// parameters

ballCenterXPct = .60; // fraction of window
ballCenterYPct = .60;
ballHeight = 220; // actually half height, pixels
ballWidth = 220;
debug = 0;
delay = 100;
divWidth = 100;
fontMax = 25; // pixels
fontMin = 15;
rotationDirection = "XY";
rotationX = 10000; // milliseconds for one rotation about x axis
rotationY = 20000;
rotationBanner1 = 25000;
rotationBanner2 = 40000;
rotationBanner3 = 55000;
startUpWait = 0; // milliseconds
startUpEnd = 3000; // milliseconds
ttscpTopAdjust = fontMax * 3 / 2;
ttscpWidth = 10 * fontMax;
ttscpHeight = 3 * fontMax;

// globals

ballCenterX = 0;
ballCenterY = 0;
clientWidth = 0;
diskIds = [];
diskLetters = [];
diskLengths = [];
doBannerRotation = true;
elapsedTime = 0;
fontBase = ( fontMin + fontMax ) / 2;
fontDelta = fontMax - fontMin;
fStart = 0.;
PI2 = 2 * Math.PI;
rotationLimitX = rotationX;
rotationLimitY = rotationY;
showThirdDisk = true;
startUp = 0;
startUpBase = startUpWait / delay;
startUpLimit = startUpEnd / delay;
xmouse = 0;
ymouse = 0;
wordsLimit = 0;
wordsMax = 0;

charDelta = [];
charDelta[ ' ' ] = -.4;
charDelta[ '.' ] = -.5;
charDelta[ 'A' ] = .2;
charDelta[ 'b' ] = .1;
charDelta[ 'f' ] = -.15;
charDelta[ 'i' ] = -.3;
charDelta[ 'j' ] = - .35;
charDelta[ 'l' ] = - .3;
charDelta[ 'm' ] = .45;
charDelta[ 'o' ] = .05;
charDelta[ 'r' ] = -.2;
charDelta[ 's' ] = -.1;
charDelta[ 'T' ] = .3;
charDelta[ 't' ] = -.25;
charDelta[ 'u' ] = .1;
charDelta[ 'v' ] = -.1;
charDelta[ 'W' ] = .8;
charDelta[ 'w' ] = .45;

var diskId;

// function, etc definitions

//change the rotation

function changeRotation( dir ){
	rotationDirection = dir;
	setRotation();
}

function setRotation( ){
	if( rotationDirection == "X" ){
		rotationLimitX = rotationX;
		rotationLimitY = 1;
	}
	else if( rotationDirection == "Y" ){
		rotationLimitX = 1;
		rotationLimitY = rotationY;
	}
	else if( rotationDirection == "XY" ){
		rotationLimitX = rotationX;
		rotationLimitY = rotationY;
	}
	else if( rotationDirection == "M" ){
		rotationLimitX = 1;
		rotationLimitY = 1;
	}
	else if( rotationDirection == "MXY" ){
		rotationLimitX = rotationX;
		rotationLimitY = rotationY;
	}
}

function startUpAdjustTo( finalValue, currValue ){
	returnValue = finalValue;
	if( startUp < startUpLimit ){
		currValue = parseFloat( currValue );
		if( startUp < startUpBase ){
			returnValue = currValue;
		}
		else {
			returnValue = currValue + 3 * (finalValue - currValue)/(startUpLimit - startUp);
		}
	}
	return returnValue;
}

function Mouse(evnt){
	ie=(document.all);
	if( ie ){
		ymouse = event.y; // pageY;
		xmouse = event.x; // pageX;
	}
	else {
		ymouse = evnt.pageY;
		xmouse = evnt.pageX;
	}
}

function SetDisk( top, id, msg ){
	nD = diskIds.length;
	letters = msg.split( '' );
	diskIds[nD] = id;
	diskLengths[nD] = letters.length;
	diskLetters[nD] = [];
	if( letters.length > wordsLimit ){
		wordsLimit = letters.length;
	}
	left = 50;
	for( i = 0; i < letters.length; ++i ){
		idLetter = id + i;
		fontSize = ( fontMax + fontMin ) / 2 + "px";
		styleLetter = 'position:absolute;left:' + left + 'px;top:' + top + 'px;font-size:' + fontSize;
		document.write( '<span id=' + idLetter
				+ ' style="' + styleLetter + '">' + letters[i] + '</span>\n' );
		if( charDelta[ letters[i] ] ){
			f = charDelta[ letters[i] ];
		}
		else {
			f = 0;
		}
		left += fontBase * (.465+f*.6045 );
	}
}

function DiskStartUp(){
	setRotation( );
	for( nD = 0; nD < diskIds.length; ++nD ){
		for( i = 0; i < diskLengths[nD]; ++i ){
			diskLetters[nD][i] = document.getElementById( diskIds[nD] + i );
		}
	}
	oneCycle();
}

function XCoord( pX, pY, pZ ){
	return Math.cos(rX)*pX + Math.sin(rX)*pZ;
}
function YCoord( pX, pY, PZ ){
	return Math.sin(rY)*Math.sin(rX)*pX
		+ Math.cos(rY)*pY
		- Math.sin(rY)*Math.cos(rX)*pZ;
}
function ZCoord( pX, pY, PZ ){
	return -Math.cos(rY)*Math.sin(rX)*pX
		+ Math.sin(rY)*pY
		+ Math.cos(rY)*Math.cos(rX)*pZ;
}

//The size and position of each word depends on its position
//in the words array, the cycle and rotation.

function oneArray( rX, rY ){

	for( i = 0; i < wordsLimit; ++i ){

		// turn the fractions into circular relations
		// we depend on the trig functions repeating
		// cycles for values > 2*PI

		// xy plane

		element = diskLetters[0][i];

		if( element ){

			rW = ( 1 - i / ( diskLengths[0] + 1 ) );
			rW += doBannerRotation ? elapsedTime / rotationBanner1 : 0;
			rW *= PI2;

			pX = Math.sin(rW);
			pY = Math.cos(rW);
			pZ = 0;
			rLeft = XCoord( pX, pY, pZ );
			rTop  = YCoord( pX, pY, pZ );
			rSize = ZCoord( pX, pY, pZ );

			// place on screen adjusting for startup

			element.style.fontSize = startUpAdjustTo(
					fontBase + fontDelta * rSize, element.style.fontSize ) + "px";
			element.style.top = startUpAdjustTo(
					ballCenterY + ballHeight * rTop, element.style.top ) + "px";
			element.style.left = startUpAdjustTo(
					ballCenterX + ballWidth * rLeft - divWidth / 2, element.style.left ) + "px";
		}

		// yz plane

		element = diskLetters[1][i];

		if( element ){

			rW = ( 1 - i / ( diskLengths[1] + 1 ) );
			rW += doBannerRotation ? elapsedTime / rotationBanner2 : 0;
			rW *= PI2;

			pX = 0;
			pY = Math.cos(rW);
			pZ = Math.sin(rW);
			rLeft = XCoord( pX, pY, pZ );
			rTop  = YCoord( pX, pY, pZ );
			rSize = ZCoord( pX, pY, pZ );

			// place on screen adjusting for startup

			element.style.fontSize = startUpAdjustTo(
					fontBase + fontDelta * rSize, element.style.fontSize ) + "px";
			element.style.top = startUpAdjustTo(
					ballCenterY + ballHeight * rTop, element.style.top ) + "px";
			element.style.left = startUpAdjustTo(
					ballCenterX + ballWidth * rLeft - divWidth / 2, element.style.left ) + "px";
		}

		// xz plane

		element = diskLetters[2][i];

		if( element ){

			rW = 1 - i / ( diskLengths[2] + 1 );
			rW += doBannerRotation ? elapsedTime / rotationBanner3 : 0;
			rW *= PI2;

			pX = -Math.cos(rW);
			pY = 0;
			pZ = Math.sin(rW);
			rLeft = XCoord( pX, pY, pZ );
			rTop  = YCoord( pX, pY, pZ );
			rSize = ZCoord( pX, pY, pZ );


			// place on screen adjusting for startup

			element.style.fontSize = startUpAdjustTo(
					fontBase + fontDelta * rSize, element.style.fontSize ) + "px";
			element.style.top = startUpAdjustTo(
					ballCenterY + ballHeight * rTop, element.style.top ) + "px";
			element.style.left = startUpAdjustTo(
					ballCenterX + ballWidth * rLeft - divWidth / 2, element.style.left ) + "px";
		}
	}
}

function oneCycle(){

	// screen position

	clientWidth = document.compatMode == 'CSS1Compat'
		? document.documentElement.clientWidth
		: document.body.clientWidth;
  	clientHeight = document.compatMode=='CSS1Compat'
  		? document.documentElement.clientHeight
  		: document.body.clientHeight;
  	ballCenterY = ballCenterYPct * ( clientHeight - ballHeight / 2 );
  	ballCenterX = ballCenterXPct * ( clientWidth - divWidth / 2 );

	// mouse position

	xmd = xmouse - ballCenterX;
	ymd = ymouse - ballCenterY;
	distance = Math.sqrt( xmd*xmd + ymd*ymd );
	xPhase = xmd / clientWidth / 2;
	yPhase = - ymd / clientHeight / 2;

	// counter fractions and angles (radians) for this cycle

	fX = elapsedTime / rotationLimitX;
	fY = elapsedTime / rotationLimitY;
	if( rotationDirection == "M" ){
		fX = xPhase * 1.25;
		fY = yPhase * 1.25;
	}
	else if( rotationDirection == "MXY" ){
		fX += xPhase * 1.25;
		fY += yPhase * 1.25;
	}
	rX = PI2 * fX;
	rY = PI2 * fY;

	fStart = 1.0;
	if( startUp < startUpLimit ){
		fStart = ( startUp - startUpBase ) / ( startUpLimit - startUpBase );
	}

	// put the home link on the page

	element = document.getElementById( "ttscpIndexLink" );
	if( element ){
		elementStyle = element.style;
	  	ttscpLeft = ballCenterX - ttscpWidth / 2;
	  	ttscpTop = ballCenterY - ttscpHeight / 2;
		element.style.top = startUpAdjustTo( ttscpTop, element.style.top ) + "px";
		element.style.left = startUpAdjustTo( ttscpLeft, element.style.left ) + "px";
		element.style.fontSize = startUpAdjustTo( ttscpHeight, element.style.fontSize ) + "px";
	}

	// position the words from the array

	oneArray( rX, rY );

	// update elapsed time

	if( ++startUp > startUpBase ){
		++elapsedTime;
	}

	// schedule the next cycle

	elapsedTime += delay;
	setTimeout('oneCycle()',delay);

	// show xy positions

	circleRadius = 25;
	circleX = clientWidth - circleRadius - 10;
	circleY = circleRadius + .5;

	element = document.getElementById( "lx" );
	if( rotationDirection != "Y" ){
		element.style.top = Math.cos(rX) * circleRadius + circleY + "px";
		element.style.left = Math.sin(rX) * circleRadius + circleX + "px";
	}
	else {
		element.style.top = circleY + "px";
		element.style.left = circleX + circleRadius + "px";
	}

	element = document.getElementById( "ly" );
	if( rotationDirection != "X" ){
		element.style.top = Math.cos(rY) * circleRadius + circleY + "px";
		element.style.left = Math.sin(rY) * circleRadius + circleX + "px";
	}
	else {
		element.style.top = circleY + circleRadius + "px";
		element.style.left = circleX + "px";
	}

	element = document.getElementById( "lo" );
	element.style.top = circleY + "px";
	element.style.left = circleX + "px";

}

// set up page

document.write( "<span id='lx' class='ttsWordBall3d_Locater'>x</span>" );
document.write( "<span id='ly' class='ttsWordBall3d_Locater'>y</span>" );
document.write( "<span id='lo' class='ttsWordBall3d_Locater'>o</span>" );
document.write( "<div id=ttsWordBall3d_Buttons><form id=buttons>" );
document.write( "<input type='button' value='X' onClick=changeRotation('Y')>" );
document.write( "<input type='button' value='Y' onClick=changeRotation('X')>" );
document.write( "<input type='button' value='XY' onClick=changeRotation('XY')>" );
document.write( "<input type='button' value='M' onClick=changeRotation('M')>" );
document.write( "</form></div>" );

document.onmousemove=Mouse;

