/*
	--- Overview ---
	This Javascript will create a field of bubbles continuously rising up the document.  Pointer movement over or near bubbles will temporarily disrupt their regular flow, giving the pointer a magnetic effect on the bubbles.  
	
	--- Use ---
	This Javascript is originally supplied with a transparent PNG graphic of a bubble and is intended to be used with an additional Javascript that fixes a PNG transparency problem found in Microsoft Internet Explorer versions 5 and 6.  
	If there are margins or paddings for the body, they may affect the bubble area.  

	--- Legal Notice ---
	David L. Burkhart is the artist and creator of the transparent PNG bubble graphic and water bubble sound originally supplied with this code and therefore the owner of their respective rights.  
	David L. Burkhart is the original author and sole owner of this code.  Any public access to or use of this code, in part or in whole, or any derivative thereof is hereby prohibited, except by explicit written permission directly by and from the author.  Permission is hereby granted for private, non-commercial use only.  This notice in full must remain with this code.  
	
	*/

var BubbleArea, BubbleAreaWidth=0, BubbleAreaHeight=0;
var Bubble = new Array(), i;
var PointerX=0, PointerY=0;
var BackgroundSound, BubbleIntervalId;
var EffectsOff, EffectsOn;

// User settings
var MaxBubbles 				= 25;
var MinBubbleSize 			=  .10; // Percentage of source image size
var MaxBubbleSize 			= 1.00; // Percentage of source image size
var SpreadWidth				= 1.00; // Percentage of bubble area width
var SpreadPosition			=  .50; // Percentage of bubble area width
var MaxSwayWidth			=  .005; // Percentage of bubble area width
var SwayRate				= 200; // Number of pixels along the vertical axis for a complete sway cycle
var SpeedFactor				= 3.00; 
var DisruptionProximity		= 100; // Pixels from center of bubbles
var DisruptionDecayRate		=  .95; // Closer to 1 for a slower decay rate
var DisruptionStrength		=  1.0 // Positive (+) values for magnetic disruption, negative for repulsive


// Create a bubble area and fill it with bubbles
CreateBubbleArea();
for ( i=0; i<MaxBubbles; i++ ) {
	Bubble[i] = new CreateBubble();
	BubbleArea.appendChild(Bubble[i].Image);
	}

if ( window.addEventListener ) window.addEventListener( "load", LaunchBubbles, false );
else window.attachEvent( "onload", LaunchBubbles );


function CreateBubbleArea() {
	BubbleArea 					= document.createElement("div");
	BubbleArea.id				= "BubbleArea";
	BubbleArea.style.overflow	= "hidden";
	BubbleArea.style.position	= "absolute";
	BubbleArea.style.zIndex		= "10";
	BubbleArea.style.left		= "0px";
	BubbleArea.style.top		= "0px";
	BubbleArea.style.width		= "100%";
	BubbleArea.style.height		= "100%";
	}


function CreateBubble() {
	// Properties
	this.Image					= document.createElement("img");
	this.Image.src				= "./BTSEffects/Bubbles/Bubble.png";
	this.Image.className		= "TransparentPNG";
	this.Image.style.position	= "absolute";
	this.Image.style.left		= "0px";
	this.Image.style.top		= "0px";
	this.Size					= 0;
	this.AscentionRate 			= 0;
	this.SwayWidth				= 0;
	this.DisruptionX			= 0;
	this.DisruptionY			= 0;
	this.DisruptionDuration		= 0;
	// Methods
	this.Reset = ResetBubble;
	this.Raise = RaiseBubble;
	}


function LaunchBubbles() {
	
	// Add background sound effects for Internet Explorer
	if (IEVersion>0) {
		var DocumentHead = document.getElementsByTagName("head")[0];
		BackgroundSound = document.createElement("bgsound");
		BackgroundSound.src	= "./BTSEffects/Bubbles/WaterBubbling.mp3";
		DocumentHead.appendChild(BackgroundSound);
		}
	
	// Make room in the body for a bubble area
	if (document.body.style.height=="") document.body.style.height = "100%";
	
	// Add bubble area to document body
	BubbleArea = document.body.appendChild(BubbleArea);
	UpdateBubbleAreaDimensions();
	
	// Randomize bubble settings
	var i;
	for ( i=0; i<MaxBubbles; i++ ) {
		var RelativeSize = Math.random() * (MaxBubbleSize-MinBubbleSize) + MinBubbleSize;
		var Width = Bubble[i].Image.clientWidth * RelativeSize
		var Height = Bubble[i].Image.clientHeight * RelativeSize
		var RandomX = ( Math.random() - .5 ) * SpreadWidth + SpreadPosition;
		var RandomLeft = RandomX * ( BubbleAreaWidth - Bubble[i].Image.clientWidth );
		Bubble[i].Image.style.width	= Math.round( Width ) + "px";
		Bubble[i].Image.style.height	= Math.round( Height ) + "px";
		Bubble[i].Image.style.left		= Math.round( RandomLeft ) + "px";
		Bubble[i].Image.style.top		= Math.round( Math.random() * BubbleAreaHeight ) + "px";
		Bubble[i].AscentionRate			= Math.abs( ( MaxBubbleSize / RelativeSize * SpeedFactor ) + Math.random()*5 ) + 1;
		Bubble[i].SwayWidth				= Math.round( Math.random() * BubbleAreaWidth*MaxSwayWidth );
		}
	
	// Get reference to HTML toggle switch for effects
	EffectsOff = document.getElementById("EffectsOff");
	EffectsOn = document.getElementById("EffectsOn");
	
	// Default bubbles to be on or off according to the last setting
	if ( EffectsOff && EffectsOn && GetCookie("BubbleEffects")=="off" ) TurnBubblesOff();
	else TurnBubblesOn();
	
	// Add event listeners
	if ( window.addEventListener ) {
		window.addEventListener( "resize", UpdateBubbleAreaDimensions, false );
		BubbleArea.addEventListener( "mousemove", UpdatePointerLocation, false );
		if (EffectsOff) EffectsOff.addEventListener( "click", TurnBubblesOff, false );
		if (EffectsOn) EffectsOn.addEventListener( "click", TurnBubblesOn, false );
		}
	else {
		window.attachEvent( "onresize", UpdateBubbleAreaDimensions );
		BubbleArea.attachEvent( "onmousemove", UpdatePointerLocation );
		if (EffectsOff) EffectsOff.attachEvent( "onclick", TurnBubblesOff );
		if (EffectsOn) EffectsOn.attachEvent( "onclick", TurnBubblesOn );
		}
	
	}


function TurnBubblesOn() {
	BubbleIntervalId = setInterval( RaiseBubbles, 50 );
	BubbleArea.style.display = "block";
	if ( EffectsOff && EffectsOn ) {
		EffectsOn.style.display = "none";
		EffectsOff.style.display = "inline";
		SetCookie( "BubbleEffects", "on", 12*60*60 /* 12 hours */);
		}
	if (IEVersion>0) {
		BackgroundSound.loop = -1; // Infinate looping
		BackgroundSound.volume	= -3500; // Medium amplitude
		}
	}


function TurnBubblesOff() {
	if (BubbleIntervalId) clearInterval(BubbleIntervalId);
	BubbleArea.style.display = "none";
	if ( EffectsOff && EffectsOn ) {
		EffectsOff.style.display = "none";
		EffectsOn.style.display = "inline";
		SetCookie( "BubbleEffects", "off", 12*60*60 /* 12 hours */);
		}
	if (IEVersion>0) {
		BackgroundSound.loop = 1; // Turns off looping
		BackgroundSound.volume	= -10000; // Turns sound off immediately
		}
	}


function RaiseBubbles() {
	var i;
	for (i in Bubble) Bubble[i].Raise();
	}


function RaiseBubble() {
		
	// Determine center point of bubble
	var X = ( this.Image.offsetLeft + this.Image.clientWidth/2 );
	var Y = ( this.Image.offsetTop + this.Image.clientHeight/2 );
	
	// Limit the disruption duration of a particular bubble
	if ( this.DisruptionDuration < 25 ) {
		// Enable close proximity of the pointer to disrupt the regular movement of the bubble
		if ( Math.abs( PointerX - X ) <= DisruptionProximity 
				&& Math.abs( PointerY - Y ) <= DisruptionProximity ) 
				{
			this.DisruptionX = DisruptionStrength * ( PointerX - X ) / this.Image.clientWidth;
			this.DisruptionY = DisruptionStrength * ( PointerY - Y ) / this.Image.clientHeight;
			this.DisruptionDuration++;
			}
		}
	
	// Drift bubble location
	var NewTop = this.Image.offsetTop + this.DisruptionY - this.AscentionRate;
	var NewLeft = this.Image.offsetLeft + this.DisruptionX 
			+ Math.sin( Math.PI * 2 * (NewTop % SwayRate) / SwayRate ) * this.SwayWidth;
	
	// Update bubble location or reset when out of view
	if ( NewLeft < -this.Image.clientWidth || NewLeft > BubbleAreaWidth 
			|| NewTop < -this.Image.clientHeight || NewTop > BubbleAreaHeight ) 
			{
		this.Reset();
		}
	else {
		this.Image.style.left = Math.round(NewLeft) + "px";
		this.Image.style.top  = Math.round(NewTop) + "px";
		// Diminish disruption (if any)
		this.DisruptionX *= DisruptionDecayRate;
		this.DisruptionY *= DisruptionDecayRate;
		}
	
	}


function ResetBubble() {
	var RandomX = ( Math.random() - .5 ) * SpreadWidth + SpreadPosition;
	var RandomLeft = RandomX * ( BubbleAreaWidth - this.Image.clientWidth );
	this.Image.style.left	= Math.round(RandomLeft) + "px";
	this.Image.style.top	= BubbleAreaHeight + "px";
	this.DisruptionX		= 0;
	this.DisruptionY		= 0;
	this.DisruptionDuration	= 0;
	}


function UpdateBubbleAreaDimensions() {
	var BubbleArea = document.getElementById("BubbleArea");
	BubbleAreaWidth = BubbleArea.clientWidth;
	BubbleAreaHeight = BubbleArea.clientHeight;
	}


function UpdatePointerLocation(EventObject) {
	if (window.event) EventObject = window.event;
	PointerX = document.body.scrollLeft + (EventObject.X || EventObject.clientX);
	PointerY = document.body.scrollTop + (EventObject.Y || EventObject.clientY);
	}
