/*\
|*|  PushButton
|*|
|*|  Copyright (c) 1999 Dolphin Inc.  All rights reserved.
|*|  Dave Sugar 12/2/99
|*|
|*|  Use: 
|*|		The use of this PushButton object is to handle buttons in HTML
|*|		easily.  Instead of having to manage the images manually now you
|*|		just need to create a 'PushButton' object passing the doucment 
|*|		you wish to draw to and the relative path of the image(s) to use
|*|		as the button.  It will automatically handing loading the images
|*|		and processing the rollOver/click messages for you.  
|*|
|*|
|*|   Example 1:
|*|		var x = new PushButton (document, 'images/blah.gif', ['disabled',]
|*|					['href=help/helpframe.html',] ['onClick=alert ("haha");']);
|*|
|*|		For the above example the images must be named as follows:
|*|			blah_u.gif - for the up image
|*|			blah_r.gif - for the roll over image
|*|			blah_d.gif - for the depressed image
|*|			blah_x.gif - for the disabled image
|*|			blah_h.gif - for the hidden image
|*|
|*|
|*|  
|*|   Example 2:
|*|  	In addition you can use the button to submit a form, like a regular
|*|  	submit button, but it is much better looking.  The submit line looks
|*|  	a follows:
|*|  
|*|     var btn = new PushButton (document, 'images/blah.gif',
|*|                   'onClick=document.forms[n].submit ()');
|*|  
|*|     In this example you substitute the 'n' in forms[n] to be the form you
|*|     want to submit (zero based!).  I think it can also be the name of the 
|*|     form, but I havn't actually tried that yet.
|*|
|*|
|*|  Required Arguments:
|*|		The first argument is the constructor is the document to draw the
|*|		button on.
|*|		The second argument is the relative path of the image to be drawn.
|*|
|*|  Optional Arguments:
|*|		Optional you can include the following things after the image, in
|*|		any order.
|*|		¥ href			- href of a URL to link to upon clicking on the button
|*|		¥ onClick		- handler which will be called when the click occrurs
|*|		¥ onMouseOver	- hander which will be called when the mouse rolls over the item
|*|		¥ onMouseOut	- hander which will be called when the mouse rolls out of the item
|*|		¥ onMouseDown	- hander which will be called when the mouse is pressed on the item
|*|		¥ onMouseUp		- hander which will be called when the mouse is released over the item
|*|		¥ target		- the target property for the anchor tag
|*|		¥ name			- name assigned to the anchor AND image tags
|*|		¥ img_up		- relative path for image to use for default up state (overrides the default)
|*|		¥ img_over		- relative path for image to use for rollover state (overrides the default)
|*|		¥ img_press		- relative path for image to use for depressed state (overrides the default)
|*|		¥ img_disable	- relative path for image to use for disabled state (overrides the default)
|*|		¥ img_hidden	- relative path for image to use for hidden state (overrides the default)
|*| 	¥ alt			- alt tag for image
|*|		¥ disabled      - to disable the button on creation (no argument)
|*|		¥ states		- states to load (comma separated string of r, u, d, x, h)
|*|		  style	--added by meb - the style for the img tag
|*|
|*|
|*|  Requirements:
|*|		The names of the images MUST follow a certain naming convention.
|*|		Currently the images must be either a .gif or .jpg image with the
|*|		correct extension.  And the file name can not contain .gif or .jpg
|*|		anywhere except for the extension.  
|*|		All the images for a particular button must be of the same type
|*|		(all jpeg or all gif can't mix/match for the same button).  
|*|		The various states must have the following naming conventions.
|*|		The up state must have '_u' before the extention
|*|		The down state must have '_d' before the extention
|*|		The disabled state must have '_x' before the extention
|*|		The roll over state must have '_r' before the extention
|*|		When you pass the relative path of the image to the constructor of
|*|		the PushButton don't include the '_?' part of the name, that will be
|*|		filled in automaticlly.  
|*|		If a particular image was unable to be loaded it will just be
|*|		ignored silently (which may be good or bad but that is how it works!)
|*|
|*|   Known Issues:
|*|		1) It seems that when using Netscape (4.6 & 4.7 at least!) there is a
|*|		problem when putting buttons inside of a style sheet.  In the function
|*|     loadImages it has a problem with the 'onerror' function.  If that is
|*|		called becuase the image can not be loaded it is unable to correctly
|*|		reference the 'document'.  If it is NOT included in a style sheet it
|*|		works ok. If you find a solution, please let me know, I havn't looked
|*|		into it throughly, just enough to figure out what the problem is.
|*|		2) There is also an issue when the button is within a <div> tag that
|*|		contains a style attribute (it is ok if the <div> tag contains an align
|*|		though).  This only seems to be a problem on the Macintosh.
|*|
|*|
|*|  Internals:
|*|		m_aImage[0] = Disabled State
|*|		m_aImage[1] = Down State
|*|		m_aImage[2] = Roll Over State
|*|		m_aImage[3] = Up State
|*|		m_aImage[4] = Hidden State
\*/

function PushButton (i_Doc, i_szBasePath)
{
	// load all the images
	PushButton.prototype.loadImages = function (i_szPath, i_bIgnoreDelay)
	{
		if (this.m_Image == null)
		{
			this.m_szBasePath = i_szPath;	// in case we change the image src before it has drawn for the first time
			return;
		}		
		
		if (typeof (this.m_Image) == "undefined")
			return;

		if (i_bIgnoreDelay || typeof (this.m_Image.onerror) == "undefined" || typeof (this.m_Image.onload) == "undefined")
		{
				// for browsers that don't support the onerror AND onload functions (Opera!)
			for (var i = 0; i < this.m_aXtn.length; i++)
			{
				if (!this.stateAvailable (this.m_aXtn[i]))
					continue;
					
				var szName = this.buildName (i_szPath, this.m_aXtn[i]); 
	
				this.m_aImages[i] = new Image;
				
	//			this.m_aImages[i].onerror = new Function ("alert ('name: ' + window.name + ' images: ' + document.images.length);");
	//			this.m_aImages[i].onerror = new Function ("alert ('name: ' + window.name);");
	//			this.m_aImages[i].onerror = new Function ("alert ('image " + i + ": ' + document.images[" + this.m_nImgIndex + "]);");
//				this.m_aImages[i].onerror = new Function ("document.images[" + this.m_nImgIndex + "].m_Button.m_aImages[" + i + "] = null;");
				this.m_aImages[i].onerror = new Function ("document.m_aPushBtns[" + this.m_nBtnIndex + "].m_aImages[" + i + "] = null;");
	//			this.m_aImages[i].onload = new Function ("alert ('image " + i + ": ' + document.images[" + this.m_nImgIndex + "]);");
				this.m_aImages[i].src = szName;
			}
		}
		else
		{
			this.delayLoad (i_szPath, 0);
		}
	};

	PushButton.prototype.delayLoad = function (i_szPath, i_nIndex)
	{
		if (i_nIndex >= this.m_aXtn.length)
		{
			this.updateImage ();
			return;
		}

		if (!this.stateAvailable (this.m_aXtn[i_nIndex]))
		{
			this.delayLoad (i_szPath, i_nIndex + 1);
			return;
		}

		var szName = this.buildName (i_szPath, this.m_aXtn[i_nIndex]); 
//alert ("Load Image: " + szName);
	
//		var szFailFunc = "document.images[" + this.m_nImgIndex + "].m_Button.m_aImages[" + i_nIndex + "] = null;";
//		var szNextCall = "document.images[" + this.m_nImgIndex + "].m_Button.delayLoad ('" + i_szPath + "', " + (i_nIndex + 1) + ");";
		var szFailFunc = "document.m_aPushBtns[" + this.m_nBtnIndex + "].m_aImages[" + i_nIndex + "] = null;";
		var szNextCall = "document.m_aPushBtns[" + this.m_nBtnIndex + "].delayLoad ('" + i_szPath + "', " + (i_nIndex + 1) + ");";

		this.m_aImages[i_nIndex] = new Image;
		this.m_aImages[i_nIndex].onerror = new Function (szFailFunc + ";" + szNextCall);
		this.m_aImages[i_nIndex].onload	= new Function (szNextCall);
		this.m_aImages[i_nIndex].src = szName;
	};

	PushButton.prototype.stateAvailable = function (i_szXtn)
	{
		var nItems = this.m_aAvail.length;
		for (var i = 0; i < nItems; i++)
		{
			if (this.m_aAvail[i] == i_szXtn)
				return (true);
		}

		return (false);
	};

	PushButton.prototype.buildName = function (i_szPath, i_szXtn)
	{
		// check to see if the user has overriden the default naming
		var szLookup = this.m_aLookup[i_szXtn];
		if (szLookup != null)
		{
			szLookup = this.getParam (szLookup);
			if (szLookup != "")
				return (szLookup);
		}

		return (i_szPath.replace (/(\.gif|\.jpg|\.png)/, ("_" + i_szXtn + "$1")));
	};

	// show the rollover if the button is enabled AND the image exists
	PushButton.prototype.over = function (i_bMouseOver)
	{
		var a_szFuncName = ["onmouseout", "onmouseover"];
//		alert ("Mouse over: " + i_bMouseOver);
		if (this.m_bEnable && this.m_bInside != i_bMouseOver)
		{
			if (!i_bMouseOver)		// can't be pressed if not over!
				this.m_bPress = false;		
			this.m_bInside = i_bMouseOver;
			this.updateImage ();
			this.execParam (a_szFuncName[i_bMouseOver ? 1 : 0]);
		}
	};

	// called when the button is pressed or released
	PushButton.prototype.press = function (i_bPressed)
	{
		var a_szFuncName = ["onmouseup", "onmousedown"];
//		alert ("Mouse press: " + i_bPressed);
		if (this.m_bEnable && this.m_bInside && this.m_bPress != i_bPressed)
		{
			this.m_bPress = i_bPressed;
			this.updateImage ();
			this.execParam (a_szFuncName[i_bPressed ? 1 : 0]);
		}
	};
	
	PushButton.prototype.keyPress = function (event)
	{
		bReturn = false;
		
		if (this.m_bEnable)
		{
			if (event.keyCode == 13)
			{
				bReturn = this.click();
			}
		}
		
		return bReturn;
	};
	
	// called when the button is clicked
	PushButton.prototype.click = function ()
	{
//		alert ("Click");
		if (this.m_bEnable)
		{
			this.m_bPress = true;
			this.updateImage ();
			this.execParam ("onclick");
			this.m_bPress = false;
			this.updateImage ();
		}
		
		var szHref = this.getParam ("href");
		return (this.m_bEnable && szHref != "");
	};
	
	// enable/disable the button action and show the enabled image if it exists
	PushButton.prototype.enable = function (i_bEnable)
	{
		if (this.m_bEnable != i_bEnable)
		{
			this.m_bEnable = i_bEnable;
			this.updateImage ();
		}
	};		

	// update the visual representation of the button in the browser
	PushButton.prototype.updateImage = function ()
	{
		var pNewImage = this.m_Image;

		if (typeof (this.m_aImages[0]) != "undefined" && this.m_aImages[0] != null) // && this.m_aImages[0].complete)
			pNewImage = this.m_aImages[0];

		if (this.m_bVisible == false)
		{
			pNewImage = this.m_aImages[4];	// hidden state
		}
		else if (this.m_bEnable)
		{
			if (this.m_bPress)
			{
				if (typeof (this.m_aImages[1]) != "undefined" && this.m_aImages[1] != null) // && this.m_aImages[1].complete)
					pNewImage = this.m_aImages[1];
			}
			else if (this.m_bInside)
			{
				if (typeof (this.m_aImages[3]) != "undefined" && this.m_aImages[3] != null) // && this.m_aImages[3].complete)
					pNewImage = this.m_aImages[3];
			}				
		}
		else
		{
			if (typeof (this.m_aImages[2]) != "undefined" && this.m_aImages[2] != null) // && this.m_aImages[2].complete)
			{
				pNewImage = this.m_aImages[2];
			}
		}

		if (pNewImage != null)
		{
//	alert ("Display Img: " + pNewImage.src);
			this.m_Image.src = pNewImage.src;
		}
	};

	// get paremeter passed at creation of the item by name
	PushButton.prototype.getParam = function (i_szParamName)
	{
		var szVal = this.m_aParams[i_szParamName];
		if (szVal == null)
			szVal = new String ("");
			
		return (szVal);
	};

	// execute the script associated with the named parameter
	PushButton.prototype.execParam = function (i_szParamName)
	{
		var bResult = true;
		var szCmd = this.getParam (i_szParamName);
		if (szCmd != "")
		{
//			alert ("exec: " + szCmd);
		
			var pFunc = new Function (szCmd);
			bResult = pFunc ();
		}
		
		return (bResult);
	};

	// function to set the value of a parameter for the button
	PushButton.prototype.setParam = function (i_szParamName, i_szFunc)
	{
		this.m_aParams[i_szParamName] = i_szFunc;
	};

	// parse the parameters bassed to the constructor.  Used by passing
	// the 'arguments' from the constructor and the first parameter to
	// start looking at.  
	PushButton.prototype.parseParams = function (i_aParams, i_nFirstIndex)
	{
		if (i_aParams == null || typeof (i_aParams) != "object")
			return;
	
		if (i_nFirstIndex == null || i_nFirstIndex < 0)
			i_nFirstIndex = 2;
	
		// store all optional params.  We will use them if they are named
		// what we expect!
		for (var i = i_nFirstIndex; i < i_aParams.length; i++)
		{
			var szTemp = i_aParams[i];
			var nIndex;
			if ((nIndex = szTemp.indexOf ("=")) >= 0)
			{
				var szVarName = szTemp.substr (0, nIndex).toLowerCase ();
				var szParam = szTemp.substr (nIndex +1);
			
				// remove any quotes from both ends of the param string
				if (szParam.charAt (0) == szParam.charAt (szParam.length -1))
				{
					if (szParam.charAt (0) == "'" || szParam.charAt (0) == "\"")
						szParam = szParam.substr (1, szParam.length -2);
				}
				this.setParam (szVarName, szParam);
			}
			else
			{
				switch (szTemp.toLowerCase ())
				{
					case "disabled":
						this.m_bEnable = false;
						break;
						
					case "enabled":
						this.m_bEnable = true;
						break;

					case "hidden":
						this.m_bVisible = false;
						break;
				}
			}
		}
	};


	PushButton.prototype.beginImageLoad = function ()
	{
		if (this.m_bLoaded)
			return;

		var szStates = this.getParam ("states");
		if (szStates != "")
		{
			this.m_aAvail = szStates.split (",");
		}
//	alert ("States: " + this.m_aAvail.toString ());
		this.m_bLoaded = true;
		this.loadImages (this.m_szBasePath, false);
		this.updateImage ();
	};

	// build the anchor tag and display the image for the button.  This
	// is called by the sub-class contrustor once stuff is setup correctly.
	// This does the meat of the work!
	PushButton.prototype.buildAnchor = function ()
	{
		// index of the image in the document
//		this.m_nImgIndex = this.m_document.images.length;

		if (typeof (this.m_document.m_aPushBtns) == "undefined")
			this.m_document.m_aPushBtns = new Array ();
//		alert (this.m_document.m_aPushBtns.length);
		this.m_nBtnIndex = this.m_document.m_aPushBtns.length;
		this.m_document.m_aPushBtns[this.m_nBtnIndex] = this;
		
	//alert ("Images.length: " + this.m_nImgIndex);

		var szHref = this.getParam ("href");
		var szTarget = this.getParam ("target");
		var szName = this.getParam ("name");
		var szWidth = this.getParam ("width");
		var szHeight = this.getParam ("height");
		var szAlt = this.getParam ("alt");
		var szStyle = this.getParam ("style");
	
		szTarget = (szTarget == "" ? "" : "target='" + szTarget + "'");
//		var szClickRet = "return (" + (szHref == "" ? "false" : "true") + ");"
	
		szHref = (szHref == "" ? "href='#'" : "href='" + szHref + "' ");
		szName = (szName == "" ? "" : "name='" + szName + "' ");
		szWidth = (szWidth == "" ? "" : "width='" + szWidth + "' ");
		szHeight = (szHeight == "" ? "" : "height='" + szHeight + "' ");
		szAlt = (szAlt = "" ? "" : "alt='" + szAlt + "' ");
		szStyle = (szStyle = "" ? "" : "style='" + szStyle + "' ");
	
		// output the href stuff
		this.m_document.write ("<a " + szHref + szName +
				"onMouseOver='document.m_aPushBtns[" + this.m_nBtnIndex + "].over (true); return (true);' " +
				"onMouseOut='document.m_aPushBtns[" + this.m_nBtnIndex + "].over (false);' " +
				"onMouseDown='document.m_aPushBtns[" + this.m_nBtnIndex + "].press (true);' " +
				"onMouseUp='document.m_aPushBtns[" + this.m_nBtnIndex + "].press (false);' " +
				"onKeyPress='document.m_aPushBtns[" + this.m_nBtnIndex + "].keyPress (event);' " +
				"onClick='return (document.m_aPushBtns[" + this.m_nBtnIndex + "].click ());' " + szTarget + ">");
		
		// build the path for the default 'up' image
		var szUpName = this.buildName (this.m_szBasePath, this.m_bEnable ? "u" : "x"); 
	
		// output the image tag for the default up state
		this.m_document.write ("<img src='" + szUpName + "' border='0' " + szName  + szWidth + szHeight + szAlt + szStyle +
			" onLoad='this.m_Button=document.m_aPushBtns[" + this.m_nBtnIndex + "]; document.m_aPushBtns[" + this.m_nBtnIndex + "].m_Image = this; document.m_aPushBtns[" + this.m_nBtnIndex + "].beginImageLoad ();'"
			 + ">");
		this.m_document.write ("</a>");


		// link the button back to this object
//		this.m_Image = this.m_document.images[this.m_nImgIndex];
	//alert (this.m_nImgIndex);
	///alert (this.m_document.images);
	//	alert (typeof (this.m_Image))
//		if (typeof (this.m_Image) != "undefined")
//			this.m_Image.m_Button = this;

		// load the rest of the images
//		this.loadImages (this.m_szBasePath, false);
//		this.updateImage ();
	};

	this.m_aXtn = ["u", "d", "x", "r", "h"];
//	this.m_aXtn = ["x", "d", "r", "u"];
	this.m_aAvail = ["u", "d"];

	// store the various states
	this.m_aLookup = new Array (this.m_aXtn.length);
	this.m_aLookup["u"] = "img_up";
	this.m_aLookup["r"] = "img_over";
	this.m_aLookup["d"] = "img_press";
	this.m_aLookup["x"] = "img_disable";
	this.m_aLookup["h"] = "img_hidden";

//	this.m_nImgIndex = -1;
	this.m_Image = null;

	// stuff that any sub-classes NEED to set correctly before calling parseParams or buildAnchor
	// store the document
	this.m_document = null;
	this.m_szBasePath = "";

	// current state
	this.m_bEnable = true;
	this.m_bVisible = true;
	this.m_bPress = false;
	this.m_bInside = false;

	this.m_bLoaded = false;

	// any sub-classes need to do this stuff to see anything!
	// call if there is an image path given!
	if (i_szBasePath != "")
	{
		this.m_aImages = new Array (this.m_aXtn.length);
		this.m_aParams = new Object ();

		this.m_document = i_Doc;
		this.m_szBasePath = i_szBasePath;
		this.parseParams (arguments, 2);
		this.buildAnchor ();
	}
};
