/*jslint browser: true */

//Copyright (c) 2007 Lewis Linn White Jr.
//Author: Lewis Linn White Jr.

//Permission is hereby granted, free of charge, to any person
//obtaining a copy of this software and associated documentation
//files (the "Software"), to deal in the Software without
//restriction, including without limitation the rights to use,
//copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the
//Software is furnished to do so, subject to the following
//conditions:

//The above copyright notice and this permission notice shall be
//included in all copies or substantial portions of the Software.
//Except as contained in this notice, the name(s) of the above 
//copyright holders shall not be used in advertising or otherwise 
//to promote the sale, use or other dealings in this Software without 
//prior written authorization.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.

//All images distributed with this project are public domain

//Constructor.  Sets up a few methods and registers a few events that need to be registered
//at create time.  Also creates a internal namespace for our internal class/objects
function JCritter(agent)
{
    var me, div, divArray, i, e;
	me = this;
	
	//States
	this.isHidden = true;
	this.isSpeaking = false;
	this.isMute = false;

	//create an internal namespace that we can reference in our prototype
	this.internal = {};
	
	//Cretae an IE6 flag for use later
	this.internal.IE6 = (document.all && window.external && (typeof document.documentElement.style.maxHeight === 'undefined')) ? true : false;	
	
	//Assign agent
	this.internal.agent = agent;
	
	//Semi-internal page functions
	this.internal.getPageWidth = function ()
	{
		return window.innerWidth || (document.documentElement.clientWidth || (document.body.clientWidth || 0));
	};
	
	this.internal.getPageHeight = function ()
	{
	    return window.innerHeight || (document.documentElement.clientHeight || (document.body.clientHeight || 0));
	};
	
	//Create divs for our agent
    divArray = ['bubbleDiv', 'bubbleTop', 'bubbleBottom', 'bubbleText', 'critterDiv'];
    for(i = 0, e = divArray.length; i < e; i++)
    {
            this.internal[divArray[i]] = document.createElement('div');
    }
	this.internal.critterImg = document.createElement('img');
	
	//bubbleDiv  Holds top and bottom bubble divs
	this.internal.bubbleDiv.style.position = this.internal.IE6 ? 'absolute' : 'fixed';
	this.internal.bubbleDiv.style.visibility = 'hidden';
	this.internal.bubbleDiv.style.width = '275px';
	
	//bubbleTop
	//this.internal.bubbleTop.style.textAlign = 'center';
	this.internal.bubbleTop.style.background = 'url(bubble.gif) no-repeat top';
	this.internal.bubbleTop.style.padding = '25px 8px 0px';
	
	//bubbleBottom
	//this.internal.bubbleBottom.style.textAlign = 'center';
	this.internal.bubbleBottom.innerHTML = '&nbsp;';
	this.internal.bubbleBottom.style.background = 'url(bubble.gif) no-repeat bottom';
	this.internal.bubbleBottom.style.padding = '35px 8px 0px';
	
	//bubbleText
	this.internal.bubbleText.style.paddingLeft = '10px';
	this.internal.bubbleText.style.paddingRight = '10px';
	this.internal.bubbleText.style.textAlign = 'center';
	
	//critterDiv
	this.internal.critterDiv.style.position = this.internal.IE6 ? 'absolute' : 'fixed';
	this.internal.critterDiv.style.visibility = 'hidden';
	
	//critterImg
	this.internal.critterImg.onclick = function ()
	{
		me.onClick();
	};
	this.internal.critterImg.onmouseover = function ()
	{
		me.onMouseIn();
	};
	this.internal.critterImg.onmouseout = function ()
	{
		me.onMouseOut();
	};
	
	//Add critter to page
	this.internal.bubbleTop.appendChild(this.internal.bubbleText);
	this.internal.bubbleDiv.appendChild(this.internal.bubbleTop);
	this.internal.bubbleDiv.appendChild(this.internal.bubbleBottom);
	this.internal.critterDiv.appendChild(this.internal.critterImg);
	document.body.appendChild(this.internal.critterDiv);
	document.body.appendChild(this.internal.bubbleDiv);
	
	//If we are IE6, we need to add the draw() event to the window.onscroll event.
	if (this.internal.IE6)
	{
		window.onscroll = function ()
		{
			me.draw();
		};
	}
}

JCritter.prototype =
{
	//Drawing functions
	drawBalloon: function ()
	{
		this.internal.bubbleDiv.style.left = this.internal.critterDiv.offsetLeft - this.internal.bubbleDiv.offsetWidth + this.internal.agent.speechLeft + 'px';
		this.internal.bubbleDiv.style.top = this.internal.critterDiv.offsetTop - this.internal.bubbleDiv.offsetHeight + this.internal.agent.speechTop + 'px';
	},
	drawAgent: function ()
	{
		var pageY, pageX;
		this.internal.critterImg.src = this.internal.agent.src;
		this.internal.critterImg.style.width = this.internal.agent.width + 'px';
		this.internal.critterImg.style.height = this.internal.agent.height + 'px';
		pageY = this.internal.IE6 ? (window.pageYOffset || (document.documentElement.scrollTop || 0)) : 0;
		pageX = this.internal.IE6 ? (window.pageXOffset || (document.documentElement.scrollLeft || 0)) : 0;
		this.internal.critterDiv.style.left = this.internal.getPageWidth() + pageX - this.internal.agent.width - this.internal.agent.adjustLeft + 'px';
		this.internal.critterDiv.style.top = this.internal.getPageHeight() + pageY - this.internal.agent.height - this.internal.agent.adjustTop  + 'px';
	},
	draw: function ()
	{
		this.drawAgent();
		this.drawBalloon();
	},
	
	//Methods
	show: function ()
	{
		this.isHidden = false;
		this.internal.critterDiv.style.visibility = 'visible';
	},
	say: function (text, align)
	{
		if (!text)
		{
			return this.internal.bubbleText.innerHTML;
		}
		if (this.isHidden || this.isMute)
		{ 
			return;
		}
		this.isSpeaking = true;
		this.show();
		if (align)
		{
			this.internal.bubbleText.style.textAlign = align;
		}
		this.internal.bubbleText.innerHTML = text;
		this.drawBalloon();
		this.internal.bubbleDiv.style.visibility = 'visible';		
	},
	hush: function ()
	{
		this.isSpeaking = false;
		this.internal.bubbleText.innerHTML = '';
		this.internal.bubbleDiv.style.visibility = 'hidden';
	},
	hide: function ()
	{
		this.isHidden = true;
		this.hush();
		this.internal.critterDiv.style.visibility = 'hidden';
	},
	play: function (animationName)
	{
		this.internal.critterImg.src = this.internal.agent.animations[animationName];
		this.draw();
	},
	mute: function ()
	{
		this.isMute = true;
		this.hush();
	},
	unMute: function ()
	{
		this.isMute = false;
	},
	setFontColor: function (color)
	{
		this.internal.bubbleText.style.color = color;
	},
	setFontSize: function (size)
	{
		this.internal.bubbleText.style.fontSize = size;
	},
	setAgent: function (agent)
	{
		this.internal.agent = agent;
		this.draw();
	},
	
	//Event Handlers
	onClick: function ()
	{
		this.hush();
	},
	onMouseIn: function ()
	{
		return;
	},
	onMouseOut: function ()
	{
		return;
	},
	
	//Desstructor
	destroy: function ()
	{
		var i, prop;
		//We can't destroy our methods, since they are prototyped.  However, we can destroy all our objects;
		for (i in this.internal)
		{
			//delete our html elements
			if (this.internal[i].parentNode)
			{
				this.internal[i].onclick = null;
				this.internal[i].onmousein = null;
				this.internal[i].onmouseout = null;
				this.internal[i].parentNode.removeChild(this.internal[i]);
				delete this.internal[i];
			}
			//delete everything else in internal
			else
			{
				delete this.internal[i];
			}
		}
		//delete everything else;
		for (prop in this)
		{
			if (true)
			{
				this[prop] = null;
				delete this[prop];
			}
		}
		this.onClick = null;
		this.onMouseIn = null;
		this.onMouseOut =  null;
	}
};