/*\
|*|  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
|*|
|*|
|*|  
|*|   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)
|*| 	¥ alt			- alt tag for image
|*|		¥ disabled      - to disable the button on creation (no argument)
|*|
|*|
|*|  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
|*|
\*/

var pb_DISABLE_CLICK = false;

function PushButton (i_Doc, i_szBasePath)
{
	// load all the images
	PushButton.prototype.loadImages = function (i_szPath)
	{
		if (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++)
			{
				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].onload = new Function ("alert ('image " + i + ": ' + document.images[" + this.m_nImgIndex + "]);");
				this.m_aImages[i].src = szName;
				this.m_aImages[i].m_bComplete = true;
			}
		}
		else
		{
			this.delayLoad (i_szPath, 0);
		}
	};

	PushButton.prototype.delayLoad = function (i_szPath, i_nIndex)
	{
		//if the i_nIndex is greater than zero then delayLoad is called from onLoad
		if(i_nIndex > 0)
		{
				var nOldIndex = i_nIndex - 1;
				if(this.m_aImages[nOldIndex] != null)
					this.m_aImages[nOldIndex].m_bComplete = true;
		}	

		if (i_nIndex >= this.m_aXtn.length)
		{
			this.updateImage ();
			return;
		}

		var szName = this.buildName (i_szPath, this.m_aXtn[i_nIndex]); 
	
		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) + ");";
	
		this.m_aImages[i_nIndex] = new Image;
		this.m_aImages[i_nIndex].m_bComplete = false;
		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.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]);
		}
	};
	
	// called when the button is clicked
	PushButton.prototype.click = function ()
	{
//		alert ("Click");
		if(!pb_DISABLE_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 ()
	{
		//Note: Netscape 6 does not seem to mark the complete property correctly for cached images
		//so as an alternative a dynamic property m_bComplete is being set to true in onLoad
		var pNewImage = this.m_Image;

		if (this.m_aImages[this.IMG_UP] != null && this.m_aImages[this.IMG_UP].m_bComplete)
			pNewImage = this.m_aImages[this.IMG_UP];

		if (this.m_bEnable)
		{
			if (this.m_bPress)
			{
				if (this.m_aImages[this.IMG_PRESS] != null && this.m_aImages[this.IMG_PRESS].m_bComplete)
					pNewImage = this.m_aImages[this.IMG_PRESS];
			}
			else if (this.m_bInside)
			{
				if (this.m_aImages[this.IMG_OVER] != null && this.m_aImages[this.IMG_OVER].m_bComplete)
					pNewImage = this.m_aImages[this.IMG_OVER];
			}				
		}
		else
		{
			if (this.m_aImages[this.IMG_DISABLE] != null && this.m_aImages[this.IMG_DISABLE].m_bComplete)
				pNewImage = this.m_aImages[this.IMG_DISABLE];
		}

		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 "invisible":
						this.m_bVisible = false;
						break;
	
					case "visible":
						this.m_bVisible = true;
						break;
				}
			}
		}
	};

	// 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;

		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");
	
		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 + "' ");
	
		if(this.m_bVisible)
		{
		// output the href stuff
		this.m_document.write ("<a " + szHref + szName +
				"onMouseOver='document.images[" + this.m_nImgIndex + "].m_Button.over (true); return (true);' " +
				"onMouseOut='document.images[" + this.m_nImgIndex + "].m_Button.over (false);' " +
				"onMouseDown='document.images[" + this.m_nImgIndex + "].m_Button.press (true);' " +
				"onMouseUp='document.images[" + this.m_nImgIndex + "].m_Button.press (false);' " +
				"onClick='return (document.images[" + this.m_nImgIndex + "].m_Button.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 + ">");
		this.m_document.write ("</a>");

		// link the button back to this object
		this.m_Image = this.m_document.images[this.m_nImgIndex];
		this.m_Image.m_Button = this;

		// load the rest of the images
		this.loadImages (this.m_szBasePath);
		}
		this.updateImage ();
	};

	PushButton.prototype.set_img_up = function (i_sImagePath)
	{
		this.m_aImages[this.IMG_UP].src = i_sImagePath;
	};
	
	PushButton.prototype.set_img_press = function (i_sImagePath)
	{
		var tmpImg = this.m_aImages[this.IMG_PRESS];
		if(tmpImg != null)
			tmpImg.src = i_sImagePath;
	};

	PushButton.prototype.set_img_disabled = function (i_sImagePath)
	{
		var tmpImg = this.m_aImages[this.IMG_DISABLE];
		if(tmpImg != null)
			tmpImg.src = i_sImagePath;
	};

	PushButton.prototype.set_img_over = function (i_sImagePath)
	{
		var tmpImg = this.m_aImages[this.IMG_OVER];
		if(tmpImg != null)
			tmpImg.src = i_sImagePath;
	};

	
	//constructor
  this.m_aXtn = ["u", "d", "x", "r"];
//	this.m_aXtn = ["x", "d", "r", "u"];

	// 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";

	//store the various state indexes
	this.IMG_UP = 0;
	this.IMG_PRESS = 1;
	this.IMG_DISABLE = 2;
	this.IMG_OVER = 3;
	
	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_bPress = false;
	this.m_bInside = false;
	this.m_bVisible = true;

	// 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 ();
	}
};