var signArray, promoArray;

var currScopeObj, saveScopeObj;
var nullSignObj, nullTypeObj, nullScopeObj;
var lastFeedDate;

var isCollapsed = false;

var PROMO_THRESHOLD = 100000;


var ID_INITIAL = -2, ID_NULL = -10;
var ID_PREVSCOPE = 99, ID_THISSCOPE = 100, ID_NEXTSCOPE = 101;

var URL_SERVERDATE      = "http://astrology.com/wdg/server_date.txt";
var URL_ASTROFEED       = "http://www.astrology.com/wdg/horoscopes.xml";
var URL_ASTROFEED_TEST  = "http://www.daylateanddollarshort.com/misc/iscopes/horoscopes.xml";

var URL_CALL_PREFIX = "tel:"; // or "callto://"

function createNullObjects()
{
	if ( nullSignObj )
		zapSignObj( nullSignObj );
	
	//horoscopeObject( aId, aIndexInArray, aSortOrder, aName, aDate, aText, aParentObj )
	nullScopeObj = new horoscopeObject ( ID_NULL, -1, -1, "Null Scope",  0, "No Data", null );
	//horotypeObject( aId, aIndexInArray, aSortOrder, aName, aInterval, aHoroscopeArray, aParentObj )
	nullTypeObj  = new horotypeObject  ( ID_NULL, -1, -1, "Null Type" ,  0, null, null );
	//signObject( aId, aIndexInArray, aSortOrder, aName, aSymbol, aStartDate, aEndDate, aHorotypeArray, aPromotionsArray )
	nullSignObj  = new signObject      ( ID_NULL, -1, -1, "Null Sign" , "", 0, 0, null, null );
	
	nullScopeObj.parent = nullTypeObj;
	nullScopeObj.next   = nullScopeObj;
	nullScopeObj.prev   = nullScopeObj;
	
	nullTypeObj.horoscopeArray.push( nullScopeObj );
	nullTypeObj.parent = nullSignObj;
	nullTypeObj.next   = nullTypeObj;
	nullTypeObj.prev   = nullTypeObj;
	
	nullSignObj.horotypeArray.push( nullTypeObj );
	nullSignObj.next = nullSignObj;
	nullSignObj.prev = nullSignObj;
}

//
// RETRIEVING HOROSCOPE XML DATA
//

var scopeXMLRequest;

function zapScopeXMLRequest( aRequest )
{
	if ( aRequest )
	{
		aRequest.onreadystatechange = null;
		aRequest.responseXML        = null;
		aRequest.responseText       = null;
		aRequest.readyState         = null;
		aRequest.status             = null;
		
		aRequest = null;
	}
}

function getScopesForSignId( aSignId )
{
	//startSpinAnim( "signs" );
	startSignProgressAnim();
	
	var theURL = URL_ASTROFEED;
	
	if (( document.domain != "" ) && ( document.domain.indexOf("astrology.com") == -1 ))
		theURL = URL_ASTROFEED_TEST;
	
	if (( aSignId != -1 ) && zodiacSignAtIndex( 1*aSignId ))
		theURL = replaceAll( theURL, "/horoscopes.xml", "/horoscopes_"+zodiacSignAtIndex( 1*aSignId ) + ".xml" );
	
	zapScopeXMLRequest( scopeXMLRequest );
	
	scopeXMLRequest = null;
	scopeXMLRequest = new XMLHttpRequest();
	scopeXMLRequest.onreadystatechange = receiveScopesXMLRequest;
	scopeXMLRequest.signId = aSignId;
	
	scopeXMLRequest.open( "GET", theURL, true );
	scopeXMLRequest.send( null );
}


function zodiacSignAtIndex( aIdx )
{
	var theResult = ( new Array( 
		"aries", "taurus", "gemini", 
		"cancer", "leo", "virgo", 
		"libra", "scorpio", "sagittarius", 
		"capricorn", "aquarius", "pisces" ))[aIdx];
	
	return theResult;
}

function startSpinAnim( aSpin ) { domGlobals.busys[aSpin].style.display = "block"; }
function stopSpinAnim ( aSpin ) { domGlobals.busys[aSpin].style.display = "none";  }

function receiveScopesXMLRequest()
{
	if ( scopeXMLRequest.readyState == 4 ) // data request shows "loaded"
	{
		if (( scopeXMLRequest.status == 200 ) && ( scopeXMLRequest.responseXML ))
		// data request status is "OK"
			xmlReceiptSuccess();
		else
			xmlReceiptFailure();
	}
}

function xmlReceiptSuccess()
{
	//stopSpinAnim( "signs" );
	stopSignProgressAnim();
	
	appState = "normal";
	
	var theSignId = scopeXMLRequest.signId;
	var theXML    = scopeXMLRequest.responseXML;
	var theText   = scopeXMLRequest.responseText;
	zapScopeXMLRequest( scopeXMLRequest );
	lastFeedDate  = feedDate( theXML );
	
	processScopes( scopeXMLRequest.responseXML );
	
	currScopeObj = scopeObjectFromIds( ( theSignId == ID_NULL ? 0 : theSignId ) , 100, 100 );
	
	buildTypePopup();
	
//	if ( currPanel == 0 )
//		startSlide(1);
		
		
	updatePanesAndSlide( 
		theSignId,
		ID_NULL,
		ID_NULL,
		1 );

}

function xmlReceiptFailure()
{
	//stopSpinAnim( "signs" );
	stopSignProgressAnim();
	
	appState = "error:loading";
	
	//alert( "Failed to retrieve astrofeed." );
	var theSignId = scopeXMLRequest.signId;
	
	zapScopeXMLRequest( scopeXMLRequest );
	processNoScopes();
	currScopeObj = scopeObjectFromIds( ( theSignId == ID_NULL ? 0 : theSignId ) , 100, 100 );
	
	document.getElementById("splash-error").style.display = "block";
}

function buildDefaultScopeObject()
{
	processNoScopes();
	
	currScopeObj = scopeObjectFromIds( ID_INITIAL, ID_INITIAL, ID_INITIAL );
}

function feedDate( aXML )
{
	var theResult = -1;
	
	aXML = aXML.getElementsByTagName("astrofeed");
	if ( aXML && ( aXML.length > 0 ))
		theResult = aXML[0].getAttribute("date");
	
	return theResult;
}

function zapSignObject( aSignObj )
{
	aSignObj.id           = null;
	aSignObj.indexInArray = null;
	aSignObj.sortOrder    = null;
	aSignObj.name         = null;
	aSignObj.symbol       = null;
	aSignObj.startDate    = null;
	aSignObj.endDate      = null;
	
	if ( aSignObj.horotypeArray )
	{
		for ( var aIdx = 0; aIdx < aSignObj.horotypeArray.length; aIdx++ )
			zapHorotypeObject( aSignObj.horotypeArray[aIdx] );
		aSignObj.horotypeArray.length = 0;
	}
	aSignObj.horotypeArray = null;
}

function zapHorotypeObject( aTypeObj )
{
	if ( aTypeObj.id > PROMO_THRESHOLD )
	{
		aTypeObj.date         = null;
		aTypeObj.head         = null;
		aTypeObj.text         = null;
	}
	
	aTypeObj.id           = null;
	aTypeObj.indexInArray = null;
	aTypeObj.sortOrder    = null;
	aTypeObj.name         = null;
	aTypeObj.interval     = null;
	
	if ( aTypeObj.horoscopeArray )
	{
		for ( var aIdx = 0; aIdx < aTypeObj.horoscopeArray.length; aIdx++ )
			zapHoroscopeObject( aTypeObj.horoscopeArray[aIdx] );
		aTypeObj.horoscopeArray.length = 0;
	}
	aTypeObj.horoscopeArray = null;
}

function zapHoroscopeObject( aScopeObj )
{
	aScopeObj.id           = null;
	aScopeObj.indexInArray = null;
	aScopeObj.sortOrder    = null;
	aScopeObj.name         = null;
	aScopeObj.date         = null;
	aScopeObj.text         = null;
}

function zapArrays()
{
	if ( signArray )
	{
		for ( var aIdx = 0; aIdx < signArray.length; aIdx++ )
			zapSignObject( signArray[aIdx] );
		signArray.length = 0;
	}
	
	signArray = null;
}



function processScopes( aXML, aText )
{
	var aIdx;
	var theSignArray  = aXML.getElementsByTagName("sign");
	var thePromoArray = aXML.getElementsByTagName("promotions");
	
	zapArrays();
	
	signArray = new Array();
	
	for ( aIdx = 0; aIdx < theSignArray.length; aIdx++ )
	{
		signArray[aIdx] = new signObject(
			theSignArray[aIdx].getAttribute("id"),
			aIdx,
			theSignArray[aIdx].getAttribute("sortOrder"),
			theSignArray[aIdx].getAttribute("name"),
			theSignArray[aIdx].getAttribute("symbol"),
			theSignArray[aIdx].getAttribute("date").split("/")[0],  // start date
			theSignArray[aIdx].getAttribute("date").split("/")[1],  //   end date
			
			theSignArray[aIdx].getElementsByTagName("horotype"),
			thePromoArray  // Attach "Special Offers" to each type array
		);
	}
	
//	signArray.sort( compareObjectIds );
	signArray.sort( compareObjectSortOrders );
	
	for ( aIdx = 0; aIdx < signArray.length; aIdx++ )
	{
		signArray[aIdx].next = signArray[(aIdx+1                 ) % signArray.length];
		signArray[aIdx].prev = signArray[(aIdx-1+signArray.length) % signArray.length];
	}
}

function processNoScopes()
{
	zapArrays();
	
	signArray = new Array();
	
//	function signObject( aId, aIndexInArray, aSortOrder, aName, aSymbol, aStartDate, aEndDate, aHorotypeArray, aPromotionsArray )
	
	signArray[ 0] = new signObject(  0,  0,  0,       "Aries",          "Ram", 20000321, 20000419, "No Data", null );
	signArray[ 1] = new signObject(  1,  1,  1,      "Taurus",         "Bull", 20000420, 20000520, "No Data", null );
	signArray[ 2] = new signObject(  2,  2,  2,      "Gemini",        "Twins", 20000521, 20000621, "No Data", null );
	signArray[ 3] = new signObject(  3,  3,  3,      "Cancer",         "Crab", 20000622, 20000722, "No Data", null );
	signArray[ 4] = new signObject(  4,  4,  4,         "Leo",         "Lion", 20000723, 20000822, "No Data", null );
	signArray[ 5] = new signObject(  5,  5,  5,       "Virgo",       "Virgin", 20000823, 20000922, "No Data", null );
	signArray[ 6] = new signObject(  6,  6,  6,       "Libra",       "Scales", 20000923, 20001022, "No Data", null );
	signArray[ 7] = new signObject(  7,  7,  7,     "Scorpio",     "Scorpion", 20001023, 20001121, "No Data", null );
	signArray[ 8] = new signObject(  8,  8,  8, "Sagittarius",       "Archer", 20001122, 20001221, "No Data", null );
	signArray[ 9] = new signObject(  9,  9,  9,   "Capricorn",     "Sea-Goat", 20001222, 20000119, "No Data", null );
	signArray[10] = new signObject( 10, 10, 10,    "Aquarius", "Water-Bearer", 20000120, 20000218, "No Data", null );
	signArray[11] = new signObject( 11, 11, 11,      "Pisces",         "Fish", 20000521, 20000621, "No Data", null );
}



function signObject( aId, aIndexInArray, aSortOrder, aName, aSymbol, aStartDate, aEndDate, aHorotypeArray, aPromotionsArray )
{
	var aIdx, bIdx, aPromoArray, promoHead, promoText;
	
	this.id           = aId;
	this.indexInArray = aIndexInArray;
	this.sortOrder    = aSortOrder;
	this.name         = aName;
	this.symbol       = aSymbol;
	this.startDate    = aStartDate;
	this.endDate      = aEndDate;
	
	this.horotypeArray = new Array();
	if ( aHorotypeArray == "No Data" )
	{
		//function horotypeObject( aId, aIndexInArray, aSortOrder, aName, aInterval, aHoroscopeArray, aParentObj )
		this.horotypeArray[0] = new horotypeObject( 0, 0, 0, "No Data", 0, "No Data", null );
	}
	else if ( aHorotypeArray )
	{
		for ( aIdx = 0; aIdx < aHorotypeArray.length; aIdx++ )
		{
			this.horotypeArray[aIdx] = new horotypeObject(
				aHorotypeArray[aIdx].getAttribute("id"), // = id
				this.horotypeArray.length, // = indexInArray
				aHorotypeArray[aIdx].getAttribute("sortOrder"), // = sortOrder
				aHorotypeArray[aIdx].getAttribute("name"), // = name
				aHorotypeArray[aIdx].getAttribute("interval"), // = interval
				
				aHorotypeArray[aIdx].getElementsByTagName("horoscope"), // = horoscopeArray
				this // parent
			);
		}
	}
	
	if ( aPromotionsArray )
	{
		for ( bIdx = 0; bIdx < aPromotionsArray.length; bIdx++ )
		{
			aPromoArray = aPromotionsArray[bIdx].getElementsByTagName("promo");
			
			for ( aIdx = 0; aIdx < aPromoArray.length; aIdx++ )
			{
				if ( useThisPromoItem( aPromoArray[aIdx] ) )
				{
					this.horotypeArray.push( new promoObject(
						PROMO_THRESHOLD + 1*aPromoArray[aIdx].getAttribute("id"), // = id
						this.horotypeArray.length, // = indexInArray
						0, // = sortOrder
						aPromoArray[aIdx].getAttribute("shortName"), // = name
						aPromoArray[aIdx].getAttribute("interval"), // = interval
						aPromoArray[aIdx].getAttribute("date"), // = date
						headFromPromoElement( aPromoArray[aIdx] ), // = head
						textFromPromoElement( aPromoArray[aIdx] ), // = text
						urlFromPromoElement ( aPromoArray[aIdx] ), // = url
						this // = parent
					) );
				}
			}
		}
	}
	
//	this.horotypeArray.sort( compareObjectSortOrders );
	this.horotypeArray.sort( compareObjectIds );	// DEBUG: Should sort by sortOrder, but current XML doesn't give sortOrders. 
													// Be sure to adjust "promo" sortOrders to come last.
	
	for ( aIdx = 0; aIdx < this.horotypeArray.length; aIdx++ )
	{
		this.horotypeArray[aIdx].next = this.horotypeArray[(aIdx+1                          ) % this.horotypeArray.length];
		this.horotypeArray[aIdx].prev = this.horotypeArray[(aIdx-1+this.horotypeArray.length) % this.horotypeArray.length];
	}
}

function useThisPromoItem( aPromoItem )
{
	// Not all promotional items are to be displayed in this widget.
	// In particular, items that require "POST" actions.
	//
	// The primary "POST"-using promos have "format" attribute "birthdayform".
	
	var theResult = false;
	var theType   = aPromoItem.getAttribute("type"  );
	var theFormat = aPromoItem.getAttribute("format");
	
	theResult = theResult || ( ( theType == "psychiclove" ) && ( theFormat == "plaintext"      ) );
	theResult = theResult || ( ( theType == "general"     ) && ( theFormat == "linkedtexticon" ) );
	theResult = theResult || ( ( theType == "special"     ) && ( theFormat == "linkedtext"     ) );
	
	return theResult;
}


function headFromPromoElement( aPromoElement )
{
	var theResult = "";
	var theScratch = aPromoElement.getElementsByTagName("head");
	
	if ( theScratch.length > 0 )
		theResult = theScratch[0].nodeValue;
	
	return theResult;
}

function textFromPromoElement( aPromoElement )
{
	var theResult = "";
	var theScratch;
	
	// Get the contents of the <text> element.
	theScratch = aPromoElement.getElementsByTagName("text");
	if ( theScratch.length > 0 )
		theResult = xmlObjectToString( theScratch[0] );
	
	// Nullify any links. (We should probably regExp them away, but this works.)
	theResult = replaceAll( replaceAll( theResult, "<a ", "<blah "), "</a>", "</blah>" );
	
	return theResult;
}
function urlFromPromoElement( aPromoElement )
{
	var theResult = "";
	var theScratch;
	
	switch ( aPromoElement.getAttribute("format") )
	{
		
		case "birthdayform":
			theScratch = getElementsByClassName( aPromoElement, "form", "promoForm" );
			if ( theScratch.length > 0 )
				theResult = theScratch[0].getAttribute("action");
			break;
		
		// case "linkedtext":
		// case "linkedtexticon":
		// case "plaintext": // should have no promoURL
		default:
			theScratch = getElementsByClassName( aPromoElement, "*", "promoURL" );
			
			if ( theScratch.length > 0 )
				theResult = theScratch[0].getAttribute("href");
			break;
	}
	
	
	theResult = theResult.replace( new RegExp( "WDGMACHORO", "g" ), "IPHONEISCOPES" );  // Current XML feed uses referral "WDGMACHORO", which flags the Dashboard widget
	theResult = theResult.replace( new RegExp(     "tel://", "g" ), "tel:"          );  // Current XML feed includes unnecessary "//"
	
	return theResult;
}

function getElementsByClassName(oElm, strTagName, strClassName)
{
/*
    Written by Jonathan Snook, http://www.snook.ca/jonathan
    Add-ons by Robert Nyman, http://www.robertnyman.com
*/
	var arrElements = (strTagName == "*" && oElm.all) ? oElm.all : oElm.getElementsByTagName(strTagName);
	var arrReturnElements = new Array();
	
	strClassName = strClassName.replace(/\-/g, "\\-");
	
	
	var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	
	for( var i = 0; i < arrElements.length; i++ )
	{
		oElement = arrElements[i];
		
		if ( oRegExp.test( oElement.getAttribute("class") )
			|| oRegExp.test( oElement.className ) )			 // DLDS Edit: changed 'oElement.className' to 
															 // 'oElement.getAttribute("class")', since original
															 // inexplicably failed for 'div's of class 'promoText'.
			arrReturnElements.push(oElement);
	}
	return (arrReturnElements)
}


function horotypeObject( aId, aIndexInArray, aSortOrder, aName, aInterval, aHoroscopeArray, aParentObj )
{
	this.id           = aId;
	this.indexInArray = aIndexInArray;
	this.sortOrder    = aSortOrder;
	this.name         = aName;
	this.interval     = aInterval;
	this.parent       = aParentObj;
	
	this.horoscopeArray = new Array();
	if ( aHoroscopeArray == "No Data" )
	{
		//function horoscopeObject( aId, aIndexInArray, aSortOrder, aName, aDate, aText, aParentObj )
		this.horoscopeArray[0] = new horoscopeObject( 0, 0, 0, "No Data", "0", "No Data", null );
	}
	else if ( aHoroscopeArray )
	{
		for ( var aIdx = 0; aIdx < aHoroscopeArray.length; aIdx++ )
		{
			this.horoscopeArray[aIdx] = "";
			this.horoscopeArray[aIdx] = new horoscopeObject(
				aHoroscopeArray[aIdx].getAttribute("id"),
				aIdx,
				aHoroscopeArray[aIdx].getAttribute("sortOrder"),
				aHoroscopeArray[aIdx].getAttribute("name"),
				aHoroscopeArray[aIdx].getAttribute("date"),
				
				xmlObjectToString( aHoroscopeArray[aIdx].childNodes[0] ),
				this
			);
		}
	}
	
	this.horoscopeArray.sort( compareObjectSortOrders );
	
	for ( aIdx = 0; aIdx < this.horoscopeArray.length; aIdx++ )
	{
		this.horoscopeArray[aIdx].next = this.horoscopeArray[(aIdx+1                           ) % this.horoscopeArray.length];
		this.horoscopeArray[aIdx].prev = this.horoscopeArray[(aIdx-1+this.horoscopeArray.length) % this.horoscopeArray.length];
	}
}

function promoObject( aId, aIndexInArray, aSortOrder, aName, aInterval, aDate, aHead, aText, aURL, aParentObj )
{
	this.id           = aId;
	this.indexInArray = aIndexInArray;
	this.sortOrder    = aSortOrder;
	this.name         = aName;
	this.interval     = aInterval;
	this.date         = aDate;
	this.head         = aHead;
	this.text         = "<p class='promoText'>" + aText +"</p>";
	this.parent       = aParentObj;
	
	if ( aURL && ( aURL != "" ) )
	{
		if ( aURL.indexOf("800-") != -1 )
		{
			if ( aURL.indexOf("1-") != 0 )
				aURL = "1-" + aURL;
			
			aURL = URL_CALL_PREFIX + replaceAll( aURL, "-", "" );
		}
		this.text += "<a "
		this.text += " id='promo-btn-"+aId+"-PROMOSCOPEID'"; // PROMOSCOPEID will be replaced with a tab id to distinguish copies of the button.
		this.text += " class='btn go-btn word-btn word-btn-off promo-btn'";
		this.text += " href='"+aURL+"'";
		this.text += " target=_TOP";
		this.text += " xonmousedown = 'highlightElement( this, true  )'";
		this.text += " xonmouseup   = 'highlightElement( this, false )'";
		this.text += " >"
		this.text += ( aURL.indexOf(URL_CALL_PREFIX) == -1 ? "Go" : "Call" );
		this.text += "</a>";
		this.text += "<p class='promo-footnote'>";
		this.text += ( aURL.indexOf(URL_CALL_PREFIX) == -1 ? "Opens new browser window." : "Triggers phone call." );
		this.text += "</p>";
	}
	
	this.horoscopeArray = "";
	this.horoscopeArray = new Array();
	this.horoscopeArray.push( new horoscopeObject(
		ID_THISSCOPE, // = id
		0, // = indexInArray
		0, // = sortOrder
		aHead, // = name
		aDate, // = date
		this.text, // = text
		this // = parent
	) );
	
	// Load up redundant copies for "next" and "prev" scopes
	this.horoscopeArray.push( new horoscopeObject(
		ID_NEXTSCOPE, // = id
		0, // = indexInArray
		0, // = sortOrder
		aHead, // = name
		aDate, // = date
		this.text, // = text
		this // = parent
	) );
	this.horoscopeArray.push( new horoscopeObject(
		ID_PREVSCOPE, // = id
		0, // = indexInArray
		0, // = sortOrder
		aHead, // = name
		aDate, // = date
		this.text, // = text
		this // = parent
	) );
	
	for ( aIdx = 0; aIdx < this.horoscopeArray.length; aIdx++ )
	{
		this.horoscopeArray[aIdx].next = this.horoscopeArray[(aIdx+1                           ) % this.horoscopeArray.length];
		this.horoscopeArray[aIdx].prev = this.horoscopeArray[(aIdx-1+this.horoscopeArray.length) % this.horoscopeArray.length];
	}
}

function horoscopeObject( aId, aIndexInArray, aSortOrder, aName, aDate, aText, aParentObj )
{
	aSortOrder = aId;
	
	this.id           = aId;
	this.indexInArray = aIndexInArray;
	this.sortOrder    = aSortOrder;
	this.name         = aName;
	this.date         = aDate;
	this.text         = aText;
	this.parent       = aParentObj;
}

function scopeObjectFromIds( aSignId, aTypeId, aScopeId )
{
	// ID_INITIAL for a parameter indicates "take first element from array"
	var theResult = nullScopeObj;
	var aIdx, bIdx, cIdx;
	
	//alert( "scopeObjectFromIds:"+aSignId+":"+aTypeId+":"+aScopeId );
	if ( signArray )
	{
		//alert("signArray.length:"+signArray.length);
		for ( aIdx = 0; aIdx < signArray.length; aIdx++ )
		{
			//alert( aIdx );
			if ( (( aSignId == signArray[aIdx].id ) || (( aIdx == 0 ) && ( aSignId == ID_INITIAL ))) && ( signArray[aIdx].horotypeArray ) )
			{
				//alert( "typeArray.length:"+signArray[aIdx].horotypeArray.length );
				for ( bIdx = 0; bIdx < signArray[aIdx].horotypeArray.length; bIdx++ )
				{
					//alert( bIdx );
					if ( (( aTypeId == signArray[aIdx].horotypeArray[bIdx].id ) || (( bIdx == 0 ) && ( aTypeId == ID_INITIAL ))) && ( signArray[aIdx].horotypeArray[bIdx].horoscopeArray ))
					{
						//alert( "scopeArray.length:"+signArray[aIdx].horotypeArray[bIdx].horoscopeArray.length );
						for ( cIdx = 0; cIdx < signArray[aIdx].horotypeArray[bIdx].horoscopeArray.length; cIdx++ )
						{
							//alert( "a:"+aIdx+" b:"+bIdx+" c:"+cIdx +" ?:"+(( cIdx == 0 ) && (aScopeId == ID_INITIAL )));
							if ( ( aScopeId == signArray[aIdx].horotypeArray[bIdx].horoscopeArray[cIdx].id ) || (( cIdx == 0 ) && ( aScopeId == ID_INITIAL )) )
							{
								//alert( "result - sign:"+aIdx+" type:"+bIdx+" scope:"+cIdx );
								theResult = signArray[aIdx].horotypeArray[bIdx].horoscopeArray[cIdx];
							}
						}
					}
				}
			}
		}
	}
	
	return theResult;
}



//
// MISC UTILITIES
//

function compareObjectIds       ( aObj, bObj ) { return 1*aObj.id        - 1*bObj.id;        }
function compareObjectSortOrders( aObj, bObj ) { return 1*aObj.sortOrder - 1*bObj.sortOrder; }



//
// XML UTILITIES
//

function xmlObjectToString( aXML ) { return (new XMLSerializer()).serializeToString(aXML); }
function stringToXMLObject( aStr )
{
	var theParser = new DOMParser();
	
//	if ( theParser )
//		theParser.setPreserveWhitespace(false); // Errors out. Why?
//	else
//		alert( "stringToXMLObject: no parser?" );
	
	return theParser.parseFromString( aStr, "text/xml" );
}