/*
cardstd.js

variables and functions used in most card reading .php files

copyright (c) 2007-2008 Red and Orange/Paul Stuart
*/

/* globals */
var BCt="<center><b><i>A Blue Candle for Protection</i></b></center>";
var bcT="<center>Always burn a blue candle in the center of the card reading spread for spiritual protection during a reading</center>";
var week = "<center>It is no a coincidence that there are fifty-two cards in the deck and fifty-two weeks in the year.<br><br>For every week of the year there is a card, hinting at underlying influences that may be affecting you.<br><br>Click card to view Card of the Week.</center>";
var moment = "<center>A card picked at random from the deck, hinting at underlying influences that may be affecting you.<br><br>Click card to view Card of the Moment.</center>";
var Cid=['1','5','9','13','17','21','25','29','33','37','41','45','49','2','6','10','14','18','22','26','30','34','38','42','46','50','3','7','11','15','19','23','27','31','35','39','43','47','51','4','8','12','16','20','24','28','32','36','40','44','48','52','53','54'];

var oldCommentsHTML, oldRadioHTML, oldPushHTML;
var prizeDivId = ["prize1","prize2"];

var prizeDiv = ["", ""];

/* naughty global flags for tooltip use */
var gettingComment = false;
var prizeClaimed = [false,false];

var cardFlags = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];


function setTtIframeHeight(ctrlId, actualHeight, maxHeight)
{
//	alert("setTtIframeHeight()! ctrlId = " + ctrlId + ", actualHeight = " + actualHeight + ", maxHeight = " + maxHeight);
//	setTtPopUpHeight(ctrlId, maxHeight);
	
// we know the id is "ifrm" + x where x is a number
//	alert("setTtIframHeight: ctrlId = " + ctrlId + ", actualHeight = " + actualHeight + ", maxHeight = " + maxHeight);
	var hite = document.getElementById(ctrlId).contentWindow.document.body.scrollHeight;
	var wydth = document.getElementById(ctrlId).contentWindow.document.body.scrollWidth;
//	alert("setTtIframeHeight: hite = " + hite + ", wydth = " + wydth);
	
	document.getElementById(ctrlId).height = actualHeight;
		
	if (setScrollIfExceeds(maxHeight, ctrlId))
	{
//		alert("There is no God but Allah and Mohammed is His prophet!");
		document.getElementById(ctrlId).height = maxHeight;
	}
//	document.getElementById(ctrlId).width = wydth; 
//	document.getElementById(idivId).height = hite;
//	document.getElementById(idivId).width = wydth; 	
}




function setTtPopUpHeight(ctrlId, maxHeight)
{
	var texthite = document.getElementById(ctrlId).contentWindow.document.body.scrollHeight;
	var textwydth = document.getElementById(ctrlId).contentWindow.document.body.scrollWidth;
	
//	alert("setTtPopUpHeight: ctrlID = " + ctrlId + ", texthite = " + texthite + ", maxHeight = " + maxHeight);
	
	if (texthite > maxHeight)
	{
		size = '' + maxHeight + 'px';
		document.getElementById(ctrlId).style.overflow='auto';
		document.getElementById(ctrlId).style.height=size;
	}
	else
		document.getElementById(ctrlId).height = texthite;

	document.getElementById(ctrlId).width = textwydth; 
}





/* 
	on entry str = location.href, the current fully-qualified URL
	The actual page name should follow the last '/' in the URL.
	
	strArray = str.split(delim) splits str into an array of strings delimited by delim.
	
	So 	strArray[0] = everything up to the first delim,
		strArray[1] = everything between the first and second delim,
		strArray[n] = everything from the n-1th delim and the end of the string
		
		strArray.length is the number of elements in the array.
		strArray[strArray.length - 1] is the last element of the array
*/
function getLoc(str)
{	
/*	alert('getLoc: entry');*/
	var retstr;
	var strArray = str.split('/');
	retstr = strArray[strArray.length - 1];
	
	if (retstr.length == 0)
		retstr = 'index.php';
		
	return(retstr)
}

function getPrizeDiv(dis)
{
	var id=['pRiZe1','pRiZe2'];
	var nm=['cLaIm1','cLaIm2'];
	var testtitle = "This is a test";
	var testmsg = "This is a test message";
	
	var pdv = [
		" method='post'><input type='hidden' id='" + id[dis.houseNum] + "' value=''><input type='image' name='" + nm[dis.houseNum] + "' id='" + nm[dis.houseNum] + "1' value='Claim Prize' src=", 
		" method='post'><input type='hidden' id='pRiZe2' value='" + this.cName + "'><input type='image' name='cLaiM2' id='cLaIm2' value='Claim Prize' src="
	];
	var retstr = "<form name='cLaImPrIzE' action='" + getLoc(location.href) + "' method='post'><p align='center'><input type='hidden' id='" + id[dis.houseNum] + "' name='" + id[dis.houseNum] + "' value='" + dis.cName + "'><a onMouseOut='UnTip()' onMouseOver='Tip(cardlettes[" + dis.houseNum + "].getDs(),SHADOW,false,WIDTH,400,ABOVE,true,TITLE,cardlettes[" + dis.houseNum + "].getTitle())'><input type='image' name='" + nm[dis.houseNum] + "' id='" + nm[dis.houseNum] + "' onClick='document.cLaImPrIzE.submit()' value='Claim Prize' src='" + dis.faceUpImg + "'></a></p></form><p align='center'>Click card to claim your prize</p>";

	return(retstr);
}	 




/* The cardlette object corresponds to the card-of-the-day and card-of-the-week items. These get displayed face-down and the user must
click on them to turn 'em over and see what they are. Usually this will just be an ordinary card with an ordinary description, but - 
a black or red joker can be randomly inserted into the display stream for any page. The joker is a wild card corresponding to a prize,
such as a free saved reading for the current session, or a free saved reading in this or any future session. Turning the card
over to display the joker isn't enough, the user must click the card several times - they have to earn their free prize. First click 
reveals the joker, with a message that a special prize or gift has been won. The user must click to reveal what the prize is. For now 
the prize is always a free saved reading. Black joker is a free saved reading during the current session, red joker is a free saved 
reading in this or some future session for registered members, or during the current session for nonregistered useres. Who should have
registered already so they would have two free saved readings but they didn't so too bad for them. Once the prize is revealed the user 
needs to click again to claim the prize.

How it works. Clicking the joker the first time updates the card description to show the prize that has been won. This is basically just
like showing the next card interpretation except the display string is a randomly selected prize description string (or at least it will
be someday, right now it's a fixed prize string but oh well.) 

Clicking again dynamically updates the card div innerHTML and changes the card from just a display object to a submit button with hidden
input fields describing the prize that will be won if the user clicks the card again. Which the user must do to claim the prize.

The server processes the prize request, updates the appropriate session and (if appropriate) database entries, and reloads the page.

If the user is not currently registered (just a visitor or guest) they will need to make user of their prize (like a free saved reading)
DURING THE CURRENT SESSION or it is forfeited. Which looks like a word that violates the spelling rule of i before e except after c. */
function cardlette (cName, cType, cDs, titles)
{
	/* cardlette properties */
	this.faceUp 		= 0;					/* face-up flag: 1 if card is face-up */
	this.faceUpImg 		= "";					/* pathname of image file for card when face-up */
	this.faceDownImg	= "images/b1fv.png";	/* default face-down card image file */
	this.cName 			= cName;				/* card name (queen of clubs, for example */
	this.cType 			= cType;				/* interpretation type: 0 = modern, 1 = classical, 2 = traditional */
	this.houseNum 		= 0;					/* card house number 0 - 12 (for now, maybe more later for romany spreads */	
	this.houseName 		= "housename";			/* card house name - 1st house, 2nd house, etc */
	this.houseDesc 		= "housedesc";			/* house description - meaning of the house card spread position */
	this.prizeClaimed 	= false;				/* set if user has claimed prize associated with this card (if any) */
	
	this.cDs 			= cDs;					/* card descriptions arrays */
	this.ctitle			= titles;				/* card titles array */
		
//	alert("cType = " + this.cType);
//	for(i = 0; i < this.cDs.length; i++)
//		alert("cDs[" + i + "] = " + this.cDs[i]);
//
//	alert("title = " + this.ctitle);

	/* cardlette methods */
	
	/* getImage() returns the current card image file based on the face-up flag for this card */
	this.getImage = function() 
	{
		if (this.faceUp)
			return(this.faceUpImg);
		else
			return(this.faceDownImg);	
	}
	
	/* setType() sets the default interpretation type value for this card */
	this.setType = function(type)
	{
		this.cType = type;
	}
	
	/* nexType() steps thru the interpretation types for this card unless a prize has been claimed, wrapping around to type 0 */
	this.nexType = function()
	{
/*		alert('this.cType = ' + this.cType);*/
		if (!this.prizeClaimed)
		{
			this.cType++;
			if (this.cType == this.ctitle.length)
				this.cType = 0;
		}
		else
		{
			this.cType++;
		}
	}

	/* getName() returns the name for this card */		
	this.getName = function()
	{
		return(this.cName);
	}
	
	/* setName(name) sets the name for this card */
	this.setName = function(name)
	{
		this.cName = name;
	}
	
	/* setHouseName() sets the house name for this card */
	this.setHouseName = function(name)
	{
		this.houseName = name;
	}
	
	/* setHouseDesc() sets the house description for this card */
	this.setHouseDesc = function(desc)
	{
		this.houseDesc = desc;
	}
	
	/* getTitle() returns an HTML formatted title string for this card */
	this.getTitle = function()
	{
		return('<center>' + this.houseName + '</center>');
	}
	
	/* getDs() returns the current HTML formatted description string for the card; if the card is face-down only the house description 
	is returned. If the card is face-up, it returns an HTML formatted string with the card title, current interpretation type, and
	current card description for that type. 
	
	If the card is a red or black joker it's a wild card corresponding to a special prize for the user and needs special processing. */
	this.getDs = function()
	{
		if (this.faceUp == 0)
		{
			return(this.houseDesc);
		}
		else
		{
			if ( (this.cName == "Red Joker" || this.cName == "Black Joker") && this.cType == 1 && !this.prizeClaimed )
			{
				UnTip();
				/* set up for prize thing */
				prizeFlag[this.houseNum] = true;
				this.prizeClaimed = true;
				
				document.getElementById(prizeDivId[this.houseNum]).innerHTML = getPrizeDiv(this);
				prizeDiv[this.houseNum] = getPrizeDiv(this);
			}
			if(this.cName != "Red Joker" && this.cName != "Black Joker")
			{
				retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Card Oracle</center><br>" + this.cDs[this.cType];
				retstr = retstr + "<br><center><br>Click card to view alternate Card Oracle interpretations</center>";
			}
			else
			{
				retstr = "<center>" + this.cName + "</center><br>" + this.cDs[this.cType];
			}
			return(retstr);
		}
	} 
	
	/* setDs() sets the current card description string for this card */	
	this.setDs = function(j, ds)
	{
		this.cDs[j] = ds;
	}

	/* setTitle() sets the current card oracle title string */
	this.setTitle = function(j, cardTitle)
	{
		this.ctitle[j] = cardTitle;
	}	
	
	/* turnOver turns over the card if it hasn't been turned over already, otherwise it increments the card interpretation type */
	this.turnOver = function(id, hstr)
	{
		if (this.faceUp == 1)
		{
			/* switch to next type and update title and description to display */
			this.nexType();
		}
		else
		{
			/* update face-up flag, display face-up card image, update title and description to display */
			this.faceUp = 1;
			document.getElementById(id).src=this.faceUpImg; /*"images/"+hstr+".png";*/
		}
	}
};


/* the card object is used to manage the display of the cards in a reading. */
function card (cName, cNum, cType, cDs, cTitle)
{
	/* card properties */
	this.faceUp 	= 0;                                /* face-up flag: 1 if card is face-up */                                    
	this.cName 		= cName;                            /* card name (queen of clubs, for example */
	this.cNum		= cNum;								/* card number */
	this.cType 		= cType;                            /* interpretation type: 0 = modern, 1 = classical, 2 = traditional */
	this.tmpComment = "";                               /* temporary incarnation of current card comment (for preview) */
	this.newComment = "";                               /* new card comment */
	this.houseNum 	= 0;                                /* card house number 0 - 12 (for now, maybe more later for romany spreads */
	this.houseName 	= "housename";                      /* card house name - 1st house, 2nd house, etc */
	this.houseDesc	= "housedesc";                      /* house description - meaning of the house card spread position */

	this.ctitle		= cTitle;	
	this.cDs		= cDs;			                                          
	this.userComments 		= "";         				/* card comments */
	this.commentOwnerInfo	= "";						/* display name of comment owner */

//	alert("cTitle = " + cTitle + ", ctitle = " + this.ctitle);
	/* card methods */
	
	/* setType() sets the default interpretation type value for this card */
	this.setType = function(type)
	{
		this.cType = type;
	}
	
	/* nexType() steps thru the interpretation types, wrapping around to the beginning when it reaches the end */
	this.nexType = function()
	{
		this.cType++;
		if (this.cType == this.ctitle.length)
			this.cType = 0;
	}
	
	/* getName() returns the name of this card */
	this.getName = function()
	{
		return(this.cName);
	}
	
	/* setName() sets the name of this card */
	this.setName = function(name)
	{
		this.cName = name;
	}
	
	
	this.chkSticky = function()
	{
		if(this.faceUp)
			tt_aV[STICKY] = true;
	}
	/* setHouseName sets the house name for this card */
	this.setHouseName = function(name)
	{
//		alert("houseName = " + name);
		this.houseName = name;
	}
	
	/* setHouseDesc() sets the house description for this card */
	this.setHouseDesc = function(desc)
	{
//		alert("houseDesc = " + desc);
		this.houseDesc = desc;
	}
	
	/* getRdgTitle() returns the house name if the card is face down, and the more complicated HTML formatted
	house name/house description if the card if face up */
	this.getRdgTitle = function()
	{
		if (this.faceUp == 0)
		{
			return(this.houseName);
		}
		else
		{
			return(this.houseName + "<br>" + this.houseDesc);
		}
	}
	
	/* getTitle() returns an HTML formatted string with the card name and interpretation type */
	this.getTitle = function()
	{
		return(this.cName + "<center>" + this.ctitle[this.cType] + " Card Oracle</center>");
	}
	
	/* getTmpComments() returns the current value of the tmpComment property. Not sure if I'm still even using this */
	this.getTmpComments = function()
	{
		return(this.tmpComment);
	}	
	
	/* endPreview() ends the card comment preview display and restores the card comment edit display by restoring the innerHTML
	divs for the edit display */
	this.endPreview = function()
	{
		document.getElementById('cOMMENTS').innerHTML=oldCommentsHTML;
		document.getElementById('Comments').value = this.tmpComment;
		document.getElementById('pUshBtns').innerHTML=oldPushHTML;
	}
	
	/* preview() displays a preview of the card reading description with the added user comment. First is saves off the innerHTML for
	the card edit divs, then it makes sure there are now double quotes " in the comment (converting them to ' if there are), displays the
	user comments in the comments div and an 'end preview' pushbutton in the button div. If the comment height exceeds 163px it creates
	a scroll control for the comment div to ensure the card tooltip stays a reasonable size no matter how long the comment. */
	this.preview = function(comments)
	{
		var newCommentsHTML, newRadioHTML, newPushHTML, hite;
		this.tmpComment = comments;
		oldCommentsHTML = document.getElementById('cOMMENTS').innerHTML;
		oldPushHTML = document.getElementById('pUshBtns').innerHTML;
		document.getElementById("cOMMENTS").style.height='';
		
		newPushHTML = "<p align='center'><input type='button' name='edit' value='End Preview' onClick='cards[" + this.houseNum + "].endPreview()'></p>";
		
		if (comments != "")
		{
		newCommentsHTML = "<p align='center'>" + dblQuoteToSingle(comments) + "<br>- " + updateName + ", " + updateDate + "</p>";
		}
		else
		{
			newCommentsHTML = " ";
		}
		document.getElementById('cOMMENTS').innerHTML=newCommentsHTML;
		
		setScrollIfExceeds(163, "cOMMENTS");
		
		document.getElementById('pUshBtns').innerHTML = "</p><hr size=1 width=50%>" + newPushHTML;
	}
	
	
	/* getRdgDs() is called only from reading.php and returns the house description if the card is face down, and an HTML-formatted 
	string with the card name and card description if the card is face up.  */
	this.getRdgDs = function()
	{
		if (this.faceUp == 0)
		{
			return(this.houseDesc);
		}
		else
		{
			retstr = "<div name=\'rdg" + this.houseNum + "\'><iframe src=\'" + getPageName() + "?House=" + this.houseNum + "&Oracle=" + this.ctitle[this.cType] + "&cNum=" + this.cNum + "&fUp=" + this.faceUp + "\' scrolling=\'no\' height=\'100%\' width=\'500\' frameborder=\'no\' name=\'rdg" + this.houseNum + "\' id=\'rdg" + this.houseNum + "\'></iframe></div>";
//			alert(retstr);
//			retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Interpretation</center><br>" + this.cDs[this.cType];
			return(retstr);
		}
	} 
	/* getShareRdgDs() is called only from viewsaved.php when a reading is to be shared and returns the house description if the card is face down, and an HTML-formatted 
	string with the card name and card description and card comments if the card is face up.  */
	this.getShareRdgDs = function()
	{
		if (this.faceUp == 0)
		{
			return(this.houseDesc);
		}
		else
		{
			retstr = "<div name=\'savrdg" + this.houseNum + "\'><iframe src=\'" + getPageName() + "?House=" + this.houseNum + "&Oracle=" + this.ctitle[this.cType] + "&cNum=" + this.cNum + "&fUp=1" + "\' scrolling=\'no\' height=\'100%\' width=\'500\' frameborder=\'no\' name=\'savrdg" + this.houseNum + "\' id=\'savrdg" + this.houseNum + "\'></iframe></div>";
			return(retstr);
			
			retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Oracle</center><br>" + this.cDs[this.cType];
			if (this.userComments != "")
				retstr = retstr + "<hr size=1 width=50%><div style='overflow:auto;' id='cOMMENTS'>" + this.getComments(false) + "</div>";
			return(retstr);
		}
	} 
	
	/* getSaveRdgDs() is called only from saverdg.php, therefore only by the owner of a saved reading, and returns the house/card 
	description info as per getRdgDs(), and it also manages entering/editing card comment and flags data. To do this it does some
	relatively fancy dynamic HTML stuff which I should probably describe in more detail to make sure I know what I'm actually doing.
	Maybe later. */
	this.getSaveRdgDs = function(getComment)
	{

		retstr = "<div name=\'savrdg" + this.houseNum + "\'><iframe src=\'" + getPageName() + "?House=" + this.houseNum + "&Oracle=" + this.ctitle[this.cType] + "&cNum=" + this.cNum + "&fUp=1" + "\' scrolling=\'no\' height=\'100%\' width=\'500\' frameborder=\'no\' name=\'savrdg" + this.houseNum + "\' id=\'savrdg" + this.houseNum + "\'></iframe></div>";
		return(retstr);
		
		gettingComment = getComment;	/* naughty global flag for tooltip use */
		if(!getComment)
		{
			retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Oracle</center><br>" + this.cDs[this.cType];
			if (this.userComments != "")
			{
				retstr = retstr + "<hr size=1 width=50%><div style='overflow:auto;' id='cOMMENTS'>" + this.getComments(true) + "</div>";
				retstr = retstr + "<hr size=1 width=50%><p align='center'>Click card to edit comments</p>";
				return(retstr);
			}
			else
			{
				retstr = retstr + "<hr size=1 width=50%><p align='center'>Click card to add comments</p>";
				return(retstr);
			}
		}
		else
		{
			retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Oracle</center><br>" + this.cDs[this.cType] + "<hr size=1 width=50%>";
			if (this.getComments(false) == "")
			{
				/* no comment is present yet, so we only need the "add comment" and "preview comment" buttons */
				commentDiv = "<div style='overflow:auto;' id='cOMMENTS'><p align='center'>Enter comments for this card and oracle (optional).</p><form name='test'><p align='center'><textarea rows=5 cols=37 ID='Comments' name='Comments'></textarea></p></form></div>";
				pushDiv = "<div id='pUshBtns'><table align='center'><tr><td><input type='button' name='asdf' value='Submit Comments' onClick='cards[" + this.houseNum + "].setComments(document.test.Comments.value)'></td><td><input type='button' name='bsdf' value='Preview Comments' onClick='cards[" + this.houseNum + "].preview(document.test.Comments.value)'></td></tr></table></div>";
				retstr = retstr + commentDiv /*+ radioDiv*/ + pushDiv;
			}
			else
			{
				/* show current comment in the textarea of the get-comment form so it can be edited, include "edit comment" and "delete comment" buttons */
				commentDiv = "<div style='overflow:auto;' id='cOMMENTS'><p align='center'>Enter comments for this card and oracle (optional).</p><form name='test'><p align='center'><textarea rows=5 cols=37 ID='Comments' name='Comments'>" + this.getComments(false) + "</textarea></p></form></div>";
				pushDiv = "<div id='pUshBtns'><table align='center'><tr><td><input type='button' name='asdf' value='Update Comments' onClick='cards[" + this.houseNum + "].setComments(document.test.Comments.value)'></td><td><input type='button' name='bsdf' value='Preview Comments' onClick='cards[" + this.houseNum + "].preview(document.test.Comments.value)'></td></tr></table></div>";
				retstr = retstr + commentDiv /*+ radioDiv*/ + pushDiv
			}
			return(retstr);
		}
	}
	
	/* getViewRdgDs() is called only from viewsaved.php and returns an HTML-formatted house/card description string like getRdgDs(), 
	but also manages card comment/flag viewing/editing/adding/updating functions. This function is currently only called by the owner 
	of a saved reading since only the owner of a saved reading can access it from viewsaved.php at this time. */
	this.getViewRdgDs = function(getComment)
	{
		if(!this.faceUp)
			return(this.houseDesc + "<hr size=1 width=50%><p align='center'>Click card to reveal its meaning</p>");

		retstr = "<div name=\'savrdg" + this.houseNum + "\'><iframe src=\'" + getPageName() + "?House=" + this.houseNum + "&Oracle=" + this.ctitle[this.cType] + "&cNum=" + this.cNum + "&fUp=1" + "\' scrolling=\'no\' height=\'100%\' width=\'500\' frameborder=\'no\' name=\'savrdg" + this.houseNum + "\' id=\'savrdg" + this.houseNum + "\'></iframe></div>";
		return(retstr);
		
		gettingComment = getComment;	/* naughty global flag for tooltip use */
		if(!getComment)
		{
			retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Oracle</center><br>" + this.cDs[this.cType];
			if (this.userComments != "")
			{
				retstr = retstr + "<hr size=1 width=50%><div style='overflow:auto;' id='cOMMENTS'>" + this.getComments(false) + "</div>";
				retstr = retstr + "<hr size=1 width=50%><p align='center'>Click card to add comments</p>";
				return(retstr);
			}
			else
			{
				retstr = retstr + "<hr size=1 width=50%><p align='center'>Click card to add comments</p>";
				return(retstr);
			}
		}
		else
		{
			retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Oracle</center><br>" + this.cDs[this.cType];
			
			retstr = retstr + "<hr size=1 width=50%>";
				
			if (this.getComments(false) == "")
			{
				/* no comment is present yet, so we only need the "add comment" and "preview comment" buttons */
				commentDiv = "<div style='overflow:auto;' id='cOMMENTS'><p align='center'>Enter comments for this card and oracle (optional).</p><form name='test'><p align='center'><textarea rows=5 cols=37 ID='Comments' name='Comments'></textarea></p></form></div>";
				pushDiv = "<div id='pUshBtns'><table align='center'><tr><td><input type='button' name='asdf' value='Submit Comments' onClick='cards[" + this.houseNum + "].setComments(document.test.Comments.value)'></td><td><input type='button' name='bsdf' value='Preview Comments' onClick='cards[" + this.houseNum + "].preview(document.test.Comments.value)'></td></tr></table></div>";
				retstr = retstr + commentDiv /*+ radioDiv*/ + pushDiv;
			}
			else
			{
				/* show current comment in the textarea of the get-comment form so it can be edited, include "edit comment" and "delete comment" buttons */
				commentDiv = "<div style='overflow:auto;' id='cOMMENTS'><p align='center'>Enter comments for this card and oracle (optional).</p><form name='test'><p align='center'><textarea rows=5 cols=37 ID='Comments' name='Comments'>" + this.getTmpComments() + "</textarea></p></form></div>";
				pushDiv = "<div id='pUshBtns'><table align='center'><tr><td><input type='button' name='asdf' value='Update Comments' onClick='cards[" + this.houseNum + "].updateComments(document.test.Comments.value)'></td><td><input type='button' name='bsdf' value='Preview Comments' onClick='cards[" + this.houseNum + "].preview(document.test.Comments.value)'></td></tr></table></div>";
				retstr = retstr + commentDiv /*+ radioDiv*/ + pushDiv
			}
			return(retstr);
		}
	}
	
	/* getAuthViewDs() is called only from authview.php, which could be either an authorized viewer (but NOT the owner) of a saved reading, 
	or a reading owner who is not a registered member of The Card Reading. It returns the HTML-formatted house/card description string 
	like getRdgDs(), but for authview.php also manages card comment/flag viewing/editing/adding/updating functions. Since this function
	could be called by either a reading owner who is not a registered member or by an authorized viewer of a reading who is NOT the owner,
	extra steps are needed when displaying, editing, and saving card comments. */
	this.getAuthViewDs = function(getComment)
	{
		if(!this.faceUp)
			return(this.houseDesc + "<hr size=1 width=50%><p align='center'>Click card to reveal its meaning</p>");

		retstr = "<div name=\'savrdg" + this.houseNum + "\'><iframe src=\'" + getPageName() + "?House=" + this.houseNum + "&Oracle=" + this.ctitle[this.cType] + "&cNum=" + this.cNum + "&fUp=1" + "\' scrolling=\'no\' height=\'100%\' width=\'500\' frameborder=\'no\' name=\'savrdg" + this.houseNum + "\' id=\'savrdg" + this.houseNum + "\'></iframe></div>";
		return(retstr);
		
		gettingComment = getComment;	/* naughty global flag for tooltip use */
		if(!getComment)
		{
			retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Oracle</center><br>" + this.cDs[this.cType];
			if (this.userComments != "")
			{
				retstr = retstr + "<hr size=1 width=50%><div style='overflow:auto;' id='cOMMENTS'>" + this.getComments(false) + "</div>";
				retstr = retstr + "<hr size=1 width=50%><p align='center'>Click card to add comments</p>";
				return(retstr);
			}
			else
			{
				retstr = retstr + "<hr size=1 width=50%><p align='center'>Click card to add comments</p>";
				return(retstr);
			}
		}
		else
		{
			retstr = "<center>" + this.cName + " - " + this.ctitle[this.cType] + " Oracle</center><br>" + this.cDs[this.cType];
			
			retstr = retstr + "<hr size=1 width=50%>";
				
			if (this.getComments(false) == "")
			{
				/* no comment is present yet, so we only need the "add comment" and "preview comment" buttons */
				commentDiv = "<div style='overflow:auto;' id='cOMMENTS'><p align='center'>Enter comments for this card and oracle (optional).</p><form name='test'><p align='center'><textarea rows=5 cols=37 ID='Comments' name='Comments'></textarea></p></form></div>";
				pushDiv = "<div id='pUshBtns'><table align='center'><tr><td><input type='button' name='asdf' value='Submit Comments' onClick='cards[" + this.houseNum + "].setComments(document.test.Comments.value)'></td><td><input type='button' name='bsdf' value='Preview Comments' onClick='cards[" + this.houseNum + "].preview(document.test.Comments.value)'></td></tr></table></div>";
				retstr = retstr + commentDiv /*+ radioDiv*/ + pushDiv;
			}
			else
			{
				/* show current comment in the textarea of the get-comment form so it can be edited, include "edit comment" and "delete comment" buttons */
				commentDiv = "<div style='overflow:auto;' id='cOMMENTS'><p align='center'>Enter comments for this card and oracle (optional).</p><form name='test'><p align='center'><textarea rows=5 cols=37 ID='Comments' name='Comments'>" + this.getTmpComments() + "</textarea></p></form></div>";
				pushDiv = "<div id='pUshBtns'><table align='center'><tr><td><input type='button' name='asdf' value='Update Comments' onClick='cards[" + this.houseNum + "].updateComments(document.test.Comments.value)'></td><td><input type='button' name='bsdf' value='Preview Comments' onClick='cards[" + this.houseNum + "].preview(document.test.Comments.value)'></td></tr></table></div>";
				retstr = retstr + commentDiv /*+ radioDiv*/ + pushDiv
			}
			return(retstr);
		}
	}
	
	/* getDs() returns the card description for the current card interpretation type. */
	this.getDs = function()
	{
		return(this.cDs[this.cType]);
	}
	
	/* setDs() sets the card description for the specified interpretation type */
	this.setDs = function(j, ds)
	{
		this.cDs[j] = ds;
	}
	
	/* getComments() returns the current user comment for the specified interpretation type. If format is TRUE, it returns an HTML-
	formatted comment display string; if format is FALSE it just returns the raw comment data string. I think. */
	this.getComments = function(format)
	{
		var retstr;
		if(this.userComments == "")
			return("");
		else
		{	
			return(getDisplayComment(this.userComments, format));
		}
	}
	
	/* initComments() sets the comment and comment flag values for the specified card interpretation type. This function is called
	at page load time and is used to initialize the card comments */
	this.initComments = function(comments)
	{
		this.userComments = comments;
	}
	
	/* setComments() sets the comment and comment flag values for the specified card interpretation type and updates the
	corresponding input fields in case the user chooses to save the comments. This function is called by the 'update' button
	in the card description button div */
	this.setComments = function(comments)
	{
		this.userComments = formatComment(comments);
		updateCardCommentPostValues(this.houseNum, this.userComments);	
	}
	
	/* updateComments() looks a lot like setComments, the difference being in the formatting of the comments. There is a reason 
	why	I did this, and now I remember what it is - to convert double quotes into single quotes otherwise there's trouble.	*/
	this.updateComments = function(comments)
	{
		/* append new comment to displayed comments */
		this.userComments = this.userComments + formatDisplayComment(comments);
		updateCardCommentPostValues(this.houseNum, formatComment(comments));	
	}
	
	/* setTitle() sets the current card oracle title string */
	this.setTitle = function(j, cardTitle)
	{
		this.ctitle[j] = cardTitle;
	}	
	
	/* turnOver() turns the card over and displays it face up if it's currently face-down, or increments the interpretation type if it's
	already face-up */
	this.turnOver = function(id, hstr)
	{
		if (this.faceUp == 1)
		{
			/* switch to next type and update title and description to display */
			this.nexType();
		}
		else
		{
			/* update face-up flag, display face-up card image, update title and description to display */
			this.faceUp = 1;
			document.getElementById(id).src="images/"+hstr+".png";
		}
	}
};


/* My first foray into the CSS realm, this is whacked out but still kinda cool for dynamic HTML display.
setScroll IfExceeds() sets a scroll bar control for the specified control if its current height in px exceeds Height.
We use it in order to make sure the comment div stays a reasonable size, both for card comments and for reading comments. */
function setScrollIfExceeds(Height, ctrlId)
{
	var hite;
	var size;
	var retval = false;
//	alert("setScrollIfExceeds, Height = " + Height + ", ctrlId = " + ctrlId);
	if (document.getElementById(ctrlId) != null)
	{
//		alert("ssie: not null!");
		hite = document.getElementById(ctrlId).clientHeight;
		if (hite == 0)
			hite = document.getElementById(ctrlId).offsetHeight;
//		alert("ssie: hite = " + hite + ", Height = " + Height);
		if( hite >= Height )
		{
			size = '' + Height + 'px';
			document.getElementById(ctrlId).style.overflow='auto';
			document.getElementById(ctrlId).style.height=size;
			retval = true;
		}
	}
	return(retval);
}

function setHite(ctrlId, size)
{
	document.getElementById(ctrlId).style.height=size;
}

function setWidth(ctrlId, size)
{
	document.getElementById(ctrlId).style.width=size;
}


/* getHite() returns the height of the specified control in px in a relatively browser-independent way. Seems to work in:
Internet Exploder, Firefox, Opera, Safari, Flock. Is that new Google browser out yet? */
function getHite(ctrlId)
{
	var hite = 0;
	if (document.getElementById(ctrlId) != null)
	{
		hite = document.getElementById(ctrlId).clientHeight;
		if (hite == 0)
			hite = document.getElementById(ctrlId).offsetHeight;
	}
	return(hite);
}

/* getWidth() returns the width of the specified control in px in a relatively browser-independent way. Seems to work in:
Internet Exploder, Firefox, Opera, Safari, Flock. Is that new Google browser out yet? */
function getWidth(ctrlId)
{
	var wydth = 0;
	if (document.getElementById(ctrlId) != null)
	{
		wydth = document.getElementById(ctrlId).clientWidth;
		if (wydth == 0)
			wydth = document.getElementById(ctrlId).offsetWidth;
	}
	return(wydth);
}

/* claimPrize() sets the appropriate prize claimed flag (for the unlikely situation where the user got both a red and a black joker
as card of the week and card of the moment, a situation that will probably never happen in real life but we need to be able to handle,
and which happens 100 percent of the time during intial testing of the prize stuff */
function claimPrize(which)
{
	if (!prizeClaimed[which])
	{
		prizeClaimed[which] = true;
	}
}

/* updateDivs() updates some divs for dynamic HTML */
function updateDivs()
{
	var sizeStr, ttbw, ttbh, ttcw, ttch, ovrflow, hite;
	scrollBarInComment = false;
	updateIframeSize = false;
	
//	ttbw = document.getElementById("WzBoDy").clientWidth;
//	ttbh = document.getElementById("WzBoDy").clientHeight;
	
	if(document.getElementById("cOMMENTS") != null)
	{
		/* I think this was for testing, development, and debugging */
		ttcw = document.getElementById("cOMMENTS").clientWidth;
		ttch = document.getElementById("cOMMENTS").clientHeight;

		/* OK, so obviously we're setting a scroll bar if the comment size exceeds 163 or 127. Why the two different values?
		I don't remember and did not see fit to say why at the time, so now I have to go back and figure it out. What the
		hell was I thinking and why did I do it this way ? */
		if (gettingComment)	
			scrollBarInComment = setScrollIfExceeds(163, "cOMMENTS");
		else
			scrollBarInComment = setScrollIfExceeds(127, "cOMMENTS");

		if (scrollBarInComment)			
			tt_aV[STICKY] = true;	/* make tooltip sticky for safari, opera, etc */
	}
	else 
	{
		for( i = 0; i < 52; i++)
		{
/*			var idivId = "idiv" + i;*/
			ctrlId = "ifrm" + i;
			idivId = "idiv" + i;
			
			if(document.getElementById(ctrlId) != null)
			{
				
//				alert("this is a test, i = " + i);
//				alert("ttbw = " + ttbw + ", ttbh = " + ttbh + ", ifrm hite = " + getHite(ctrlId) + ", ifrm width = " + getWidth(ctrlId) + ", idiv hite = " + getHite(idivId) + ", idiv width = " + getWidth(idivId));
//				alert("hite = " + document.getElementById(ctrlId).contentWindow.document.body.scrollHeight);
//				alert("width = " + document.getElementById(ctrlId).contentWindow.document.body.scrollWidth);
//				alert("does this still happen");
				updateIframeSize = true;

//				setHite(ctrlId, getHite(ctrlId));
//				setWidth(ctrlId, getHite(ctrlId));
				
//				alert(getHite(idivId);
//				alert(getWidth(idivId);
				break;
			}

			ciTitle = "ifrmTtl" + i;
			ciTxt = "ifrmTxt" + i;
			
			if(document.getElementById(ciTxt) != null)
			{
//				alert("asdf asdf asdf");
//				var txthite = document.getElementById(ciTxt).contentWindow.document.body.scrollHeight;
//				var txtwydth = document.getElementById(ciTxt).contentWindow.document.body.scrollWidth;
	
//				alert("texthite = " + texthite + ", textwidth = " + textwydth + "old hite = " + document.getElementById(ciTxt).height + ", old width = " + document.getElementById(ciTxt).width);
				updateCustInterpsPopUp = true;
				break;
			}
		}
	}
}

/* getDisplayComment() returns commentSpec as an HTML-formatted display string with username and date if format is TRUE, or
just as the same raw commentSpec string if format is FALSE. */
function getDisplayComment(commentSpec, format)
{
	var retStr = "";
	
	if (commentSpec != "")
	{
		if (format)
			retStr = "<p align='center'>" + commentSpec + "<br>- " + updateName + ", " + updateDate + "</p>";
		else
			retStr = commentSpec;	
	}
	return(retStr);
}

/* formatComment() is an artifact of a previous comment handling attempt, which now is used to convert double quotes " into	
single quotes ' in a comment string because of the horrible, terrible, tragic things that happen if that isn't done */
function formatComment(comment)
{
	var retstr;
	retstr = dblQuoteToSingle(comment);
	return(retstr);
}

/* formatDisplayComment() converts double quotes " to single quotes ' in the specified comment string, then returns an HTML-formatted
display string version of that comment with the user name and date. */
function formatDisplayComment(comment)
{
	var retstr;
	var cmnt;
	cmnt = dblQuoteToSingle(comment);
	retstr = "<p align='center'>" + cmnt + "<br>- " + updateName + ", " + updateDate + "</p>";
	return(retstr);
}

/* dblQuoteToSingle() finds all instances of " and turns them to ' to make them form-safe otherwise bad things can happen. */
function dblQuoteToSingle(string)
{
	var retstr = "";
	var fixit;
	fixit = string.split('"');
	if(fixit.length > 1)
	{
		/* there are fixit.length-1 embedded quotes in the string */
		for (i = 0; i < fixit.length; i++)
		{
			retstr = retstr + fixit[i]
			if (i < fixit.length-1)
				retstr = retstr + "'";
		}
	}
	else retstr = string;
	return(retstr);
}

/* usingProfile() is planning ahead for faceBook application, and for the day when our card reading user settings page includes
a user profile with stuff like the user's display thumbnail photo and other frufru personalization crap that 60%s love so much. 
Sinc we don't have profiles now we always return false, and I'm not even sure this function ever gets called right now. */
function usingProfile()
{
	return false;
}

/* nextInterp() calls HC for something somewhere and was written to make my life easier but I'm not even sure if it's being used */
function nextInterp(num)
{
	houses = ["1stHouse", "2ndHouse", "3rdHouse", "4thHouse", "5thHouse", "6thHouse", "7thHouse", "8thHouse", "9thHouse", "10thHouse", "11thHouse", "12thHouse"];
	HC(houses[num], num+1, 0);
}

/* updateCardCommentPostValues() updates the input fields associated with the specified card in case the user decides to save a reading */
function updateCardCommentPostValues(cardnum, comments)
{
	cmntId  = "Card" + cardnum + "Cmnts";
	document.getElementById(cmntId).value = comments;
	enableSave();
	setTimeout('tt_Hide()', 50);
}

/* isCheckedIf() returns the string " checked " if the specified value and flag are equal, otherwise it returns " ". */
function isCheckedif(value, flag)
{
	if (value == flag)
		return(" checked ");
	else
		return(" ");
}



/* initHouseNames() initializes the card object house names and descriptions for each of the specified card objects */
function initHouseNames(num, Hn, hDs)
{
	for (i = 0; i < num; i++)
	{
		cards[i].setHouseName(Hn[i]);
		cards[i].setHouseDesc(hDs[i]);
	}
}

/* init() initializes the default values for the array of card objects */
//function init(j, type, cards, Cn, cvw, cvtI, cvtII, cva)
function init(j, cType, cards, Cn, descriptions, titles, CR)
{
	var i;
//	alert(titles);
	for (i = 0; i < j; i++)
	{
//		cards[i] = new card("card", 0, ["mod","trad1","trad2","arcana"],["Modern","Classical","Traditional","Arcana Arcanorum"]);
//		alert("i = " + i + ", " + descriptions[i]);
		cards[i] = new card(Cn[i], CR[i], cType, descriptions[i], titles);
//		cards[i].cType = cType;
//		cards[i].setName(Cn[i]);
/*		
		cards[i].setDs(0,cvw[i]);
		cards[i].setDs(1,cvtI[i]);
		cards[i].setDs(2,cvtII[i]);
		cards[i].setDs(3,cva[i]);
*/
		cards[i].houseNum = i;
		cards[i].initComments("");
		
	}
}

/* initHouses() looks like it does the same thing as initHouseNames(). I wonder why there are two of them */ 
function initHouses(j, hNames, hDesc)
{
	for (i = 0; i < j; i++)
	{
		cards[i].setHouseName(hNames[i]);
		cards[i].setHouseDesc(hDesc[i]);
	}
}

/* init52() initialzes descriptions for a deck of card objects, with the default display interpretation specified by the parm.
I think this is only used in cards.php */
//function init52(cards, r, cvw, cvtI, cvtII, cva, Cn)

function init52(cards, cType, Cn, descriptions, titles)
{
	var i;
//	alert(titles);
	for (i = 0; i < 52; i++)
	{
//		alert("i = " + i + ", " + descriptions[i]);
//		cards[i] = new card("card", r, ["trad2","mod","trad1","arcana"],["Traditional","Modern","Classical","Arcana Arcanorum"]);
		cards[i] = new card(Cn[i], i, cType, descriptions[i], titles);
		cards[i].faceUp = 1;
/* 
	the order of descriptions/titles is set by php, which i suppose can be done by always listing the default first  - 
	then there is no need for the hoop-jumping below
*/
/*
		switch(r)
		{
			case 0:
			default:
				cards[i].setDs(0,cvw[i]);
				cards[i].setDs(1,cvtI[i]);
				cards[i].setDs(2,cvtII[i]);
				cards[i].setDs(3,cva[i]);
			break;
			case 1:
				cards[i].setDs(0,cvw[i]);
				cards[i].setDs(1,cvtI[i]);
				cards[i].setDs(2,cvtII[i]);
				cards[i].setDs(3,cva[i]);
			break;
			case 2:
				cards[i].setDs(0,cvw[i]);
				cards[i].setDs(1,cvtI[i]);
				cards[i].setDs(2,cvtII[i]);
				cards[i].setDs(3,cva[i]);
			break;
			case 3:
				cards[i].setDs(0,cvw[i]);
				cards[i].setDs(1,cvtI[i]);
				cards[i].setDs(2,cvtII[i]);
				cards[i].setDs(3,cva[i]);
			break;
		}
*/
//		cards[i].setName("<center>" + Cn[i] + "</center>");
	}
}

/* handleClick() handles a generic click event for a card */
function handleClick(i)
{
	UnTip();
	cards[i].nexType();
	Tip(cards[i].getDs(),SHADOW,false,WIDTH,400,ABOVE,true,TITLE,cards[i].getTitle());
}

/* initCardlettes() initializes the cardlettes array with all the stuff they need to display correctly and have a prize */
//function initCardlettes(cardlettes, j, cType, cimgs, Cn, cvw, cvtI, cvtII, cva)
function initCardlettes(cardlettes, j, cType, cimgs, Cn, descriptions, titles)
{
	var i;
	var name = ["Card of the Week", "Card of the Moment"];
	var desc = [week, moment];
	
	for (i = 0; i < j; i++)
	{
		cardlettes[i] = new cardlette(Cn[i], 0, descriptions[i], titles);
/*
		cardlettes[i] = new cardlette(	"card", 		// name of card
										j, 				// number of cardlette array elements to initialize
										descriptions, 	// array of oracle descriptions zb ["trad", "classical", "modern", "arcana"]
										titles			// arry of oracle names zb ["Modern","Classical","Traditional","Arcana Arcanorum"]
										);
										
		sanity check - descriptions.length == names.length or error
		
		The descriptions and names arrays can be built dynamically by php from database information
*/		
//		cardlettes[i].cType = type;
		/* if we don't have a joker select a random interpretation for each cardlette to start with */
		if (Cn[i] != "Black Joker" && Cn[i] != "Red Joker")
			cardlettes[i].cType = (Math.ceil(titles.length * Math.random()) - 1);

//		cardlettes[i].setName(Cn[i]);

		/* replace this */		
//		cardlettes[i].setDs(0,cvw[i]);
//		cardlettes[i].setDs(1,cvtI[i]);
//		cardlettes[i].setDs(2,cvtII[i]);
//		cardlettes[i].setDs(3,cva[i]);
/*		
		with this
		for(k = 0; k < names.length; k++)
		{
			cardlettes[i].setDs(k, descriptions[k]);
			cardlettes[i].setTitle(k, titles[k]);
			
		}
		after setting up construction of the appropriate javascript arrays in php in the calling module
*/		
		
		cardlettes[i].houseNum = i;
		cardlettes[i].faceUpImg = cimgs[i];
		cardlettes[i].setHouseName(name[i]);
		cardlettes[i].setHouseDesc(desc[i]);
		cardlettes[i].houseNum = i;
	}
}

/* cardlette handle click */
function ClHC(id, i)
{
	var j,hstr;
	j=ClR[i];
	hstr=Cid[i];
	UnTip();
	cardlettes[i].turnOver(id, hstr);
	Tip(cardlettes[i].getDs(),SHADOW,false,WIDTH,400,ABOVE,true,TITLE,cardlettes[i].getTitle());
}
