/*
systym: the NIH-syndrome javascript library
copyright (c) 2009 Chris Rose-Mathew
*/

//====================================================
// Type: Scene
//====================================================
function Scene(sceneDivID)
{
	//-----====== attributes ======---------
	
	// General scene attributes
	this.noCurtains = false; // for debugging
	this.useHeightOffsets = true;
	this.useWideScreen = true;
	this.loadingTimeSeconds = 12; // 11
	this.loadingScreenFadeSpeed = 0.15; //0.04;
	this.lowCPU = false;
	
	// Important scene state
	this.ready = false; // The scene is classified as ready this.loadingTimeSeconds seconds after loading
	this.started = false; // The user starts the scene by clicking on the curtains
	this.curtainsCompleted = false; // DOM elements should only change while this is false
	this.frameMilliseconds = 64; // 90
	
	// The viewport into the scene
	// This object tracks the browser window size
	this.viewport = new Viewport();
	this.container = document.getElementById(sceneDivID);
	if (!this.container)
	{
		alert("ERROR - Cannot find scene div element with id " + sceneDivID);
	}

	// An adjustment value for reacting to small browser viewports
	this.generalHeightOffset = 0;
	
	// The Scene object provides some internal support for lightbox-style
	// image galleries and popups
	
	// Gallery management
	this.galleryCount = 0;
	this.currentGallery = null;
	this.currentPopupImage = null;
	
	// The following code segments set up the main scene elements and
	// effect sprites, many of the initial positions and sizes specified here
	// are defaults that are overriden in scene.resize()
	
	// The stage
	this.stageBackgroundElement = null; // the stage background curtain
	this.stageWidth = 980;
	this.stageHeight = 850;
	this.halfStageWidth = this.stageWidth / 2;
	// stageLeftX is "world-coordinates" of stage left (not viewport coordinates), 
	// will likely become negative in thin browser windows
	this.stageLeftX = 0; 
	this.stageRightX = this.stageWidth;
	this.initialCurtainWidth = this.halfStageWidth;

	// frame overlay curtains
	// The actual image for these is specified by CSS, in order to
	// enable IE6 PNG transparency
	this.frameCurtainWidth = this.stageWidth;
	this.frameCurtainSprite = new Sprite(getBodyElement());
	this.frameCurtainSprite.element.setAttribute("id", "staticCurtainFrame");
	this.frameCurtainSprite.absolute();
	this.frameCurtainSprite.position(this.stageLeftX, 0, 5);
	this.frameCurtainSprite.size(this.frameCurtainWidth, 850);

	// Moving curtains
	this.curtainZ = 4;
	
	// Left Curtain
	if (this.noCurtains == true)
		this.initialCurtainWidth = 5;
	this.leftCurtain = new Sprite(getBodyElement());
	this.leftCurtain.deferGeometryChanges = true;
	this.leftCurtain.size(this.initialCurtainWidth, this.stageHeight);
	this.leftCurtain.position(0,0,this.curtainZ);
	this.leftCurtain.useImage("images/2009_09_27/StageCurtainsLeft.jpg");

	// Right Curtain
	this.rightCurtain = new Sprite(getBodyElement());
	this.rightCurtain.deferGeometryChanges = true;
	this.rightCurtain.size(this.initialCurtainWidth, this.stageHeight);
	if (this.noCurtains == true)
		this.rightCurtain.position(this.stageLeftX + this.stageWidth,0,this.curtainZ);
	else
		this.rightCurtain.position(this.halfStageWidth,0,this.curtainZ);
	this.rightCurtain.useImage("images/2009_09_27/StageCurtainsRight.jpg");

	// Curtain opening motion
	this.initialCurtainSpeed = 0.0;
	this.initialCurtainAccel = 0.5;
	this.curtainSpeed = this.initialCurtainSpeed;
	this.curtainAccel = this.initialCurtainAccel;
	
	// Blackout (for loading screens and image popup background)
	this.blackoutZ = 20;
	this.blackout = new Sprite(getBodyElement());
	this.blackout.deferGeometryChanges = false;
	this.blackout.size(this.stageWidth, this.stageHeight);
	this.blackout.position(0,0,this.blackoutZ);
	this.blackout.fixed();
	this.blackout.color("white");
	this.blackout.backgroundColor("#000000");
	this.blackout.element.className = "loadingScreen";
	var p = document.createElement("p");
	//var t = document.createTextNode(" ");
	var loadingGif = document.createElement("img");
	loadingGif.src = "images/2009_09_28/Loading2.gif";
	//p.appendChild(t);
	p.appendChild(loadingGif);
	this.blackout.element.appendChild(p);
	
	// Frame Curtain
	this.frameCurtainWidth = this.stageWidth;

	// Frame-Side Borders (Left-hand side)
	this.frameBorderZ = 19;
	this.leftBorderSprite = new Sprite(getBodyElement());
	this.leftBorderSprite.useBackgroundImage("images/2009_09_27/BorderTileLeft.jpg");
	this.leftBorderSprite.size(120, this.stageHeight);
	this.leftBorderSprite.position(0,0,this.frameBorderZ);
	
	this.leftBorderSkirtSpriteZ = 18;
	this.leftBorderSkirtSprite = new Sprite(getBodyElement());
	this.leftBorderSkirtSprite.absolute();
	this.leftBorderSkirtSprite.backgroundColor("#000000");
	this.leftBorderSkirtSprite.size(500, this.stageHeight * 2)
	this.leftBorderSkirtSprite.position(-500, 0, this.leftBorderSkirtSpriteZ);

	// Frame-Side Borders (Right-hand side)
	this.rightBorderSprite = new Sprite(getBodyElement());
	this.rightBorderSprite.useBackgroundImage("images/2009_09_27/BorderTileRight.jpg");
	this.rightBorderSprite.size(120, this.stageHeight);
	this.rightBorderSprite.position(0,0,this.frameBorderZ);
	
	this.rightBorderSkirtSpriteZ = 18;
	this.rightBorderSkirtSprite = new Sprite(getBodyElement());
	this.rightBorderSkirtSprite.absolute();
	this.rightBorderSkirtSprite.backgroundColor("#000000");
	this.rightBorderSkirtSprite.size(500, this.stageHeight * 2)
	this.rightBorderSkirtSprite.position(this.stageLeftX + this.stageWidth, 0, this.rightBorderSkirtSpriteZ);
	
	// Bottom skirt
	this.bottomSkirtSpriteZ = 18;
	this.bottomSkirtSprite = new Sprite(getBodyElement());
	this.bottomSkirtSprite.size(this.stageWidth, 500);
	this.bottomSkirtSprite.position(0, this.stageHeight, this.bottomSkirtSpriteZ);
	this.bottomSkirtSprite.backgroundColor("#000000");
	
	// Stage lightning:
	// This element darkens the stage background and
	// fades as the curtains open
	this.stageDarknessElement = null;
	this.stageDarknessAlpha = 1.0;
	this.initialStageDarknessAlpha = 1.0;

	// Banner / Logo
	// The banner and logo resize depending on page size (3 different sizes)
	this.bannerWidths = [842, 642, 442];
	this.bannerHeights = [80, 61, 42];
	this.bannerCurrentSizeIndex = 0;
	this.bannerWidth = this.bannerWidths[this.bannerCurrentSizeIndex];
	this.bannerHeight = this.bannerHeights[this.bannerCurrentSizeIndex];
	
	// The bannerSprite uses an existing document element for it's element,
	// rather than for it's container
	this.bannerZ = 11;
	this.bannerSprite = new Sprite(document.getElementById("mainBanner"), true);
	this.bannerSprite.show();
	this.bannerSprite.absolute();
	this.bannerSprite.size(this.bannerWidth, this.bannerHeight);
	this.bannerSprite.position(0,0,this.bannerZ);
	this.bannerSprite.useFilterAlpha = true;
	this.bannerSprite.useImage("images/2009_09_28/Banner.png");
	this.bannerSprite.element.onmouseover = bannerMouseOver;
	this.bannerSprite.element.onmouseout = bannerMouseOut;
	this.bannerSprite.element.onclick = function() { toggleTab('tabPage0'); }

	// Main Logo (Orchid)
	this.logoWidths = [160, 97, 58];
	this.logoHeights = [130, 78, 47];
	this.logoCurrentSizeIndex = 0;
	this.logoWidth = this.logoWidths[this.logoCurrentSizeIndex];
	this.logoHeight = this.logoHeights[this.logoCurrentSizeIndex];

	// The logoSprite uses an existing document element for it's
	// actual Sprite.element, rather than as it's container, as is usual
	this.logoZ = 11;
	this.logoSprite = new Sprite(document.getElementById("mainLogo"), true);
	this.logoSprite.show();
	this.logoSprite.absolute();
	this.logoSprite.size(this.logoWidth, this.logoHeight);
	this.logoSprite.position(0,0,this.logoZ);
	this.logoSprite.useFilterAlpha = true;
	this.logoSprite.useImage("images/2009_09_28/Orchid.png");
	this.logoSprite.element.onmouseover = logoMouseOver;
	this.logoSprite.element.onmouseout = logoMouseOut;
	this.logoSprite.element.onclick = function() { toggleTab('tabPage7'); }
	
	// Fans
	this.mouseOverFans = false;
	this.fansOriginY = 260;
	this.fansTopY = 260;
	this.fansLeftX = this.stageLeftX - 140;
	this.fansElement = document.getElementById("fans");
	if (!this.fansElement)
	{
		alert("ERROR - Failed to find #fans.");
	}
	this.fansElement.onmouseover = fansMouseOver;
	this.fansElement.onmouseout = fansMouseOut;
	this.fansElement.onclick = function() { toggleTab("tabPage2"); };

	// Tickets
	this.mouseOverTickets = false;
	this.ticketsTargetY = 180;
	this.ticketsTopY = 180;
	this.frontTicketsLeftX = -450;
	this.ticketsRearElement = document.getElementById("ticketsRear");
	this.ticketsFrontElement = document.getElementById("ticketsFront");
	if (!this.ticketsRearElement)
		alert("ERROR - Failed to find ticketsRear");
	if (!this.ticketsFrontElement)
		alert("ERROR - Failed to find ticketsFront");
	this.ticketsFrontElement.onmouseover = ticketsMouseOver;
	this.ticketsFrontElement.onmouseout = ticketsMouseOut;
	this.ticketsFrontElement.onclick = function() { toggleTab("tabPage1"); };
	
	// Stars (avatars)
	// These animated stars both move around and provide
	// mouse-over feedback using UV-mapping-like cropped image sliding tecniques.
	// To provide support for IE6, this is done with a sliding image element within
	// a container div, instead of using the simpler background-repeat CSS property,
	// which is not supported when using AlphaImageLoader
	// The movement is achieved using the Sprite object's ability to move
	// it's container element, rather than it's own (ie starSprite.positionContainer = true)
	this.stars = new Array();
	this.starsZ = 15;
	this.starWidth = 196;
	this.starHeight = 97;
	this.starsOffsetX = 735; //relative to scene.stageLeftX
	this.starDistanceX = 40;
	this.starsLeftX = this.stageLeftX + this.starsOffsetX;
	// Initial Y positions, not important for final positions, see moveWidgets()
	this.starOrigins = new Array(-250, -180, -100);   
	this.starY = new Array(0, 0, 0);
	
	this.star01 = new Sprite(document.getElementById("star01"));
	this.star01.relative();
	this.star01.positionContainer = true;
	this.star01.position(this.starsLeftX, this.starOrigins[0], this.starsZ);
	this.star01.size(this.starWidth, this.starHeight);
	this.star01.element.setAttribute("id", "star01Inner");
	this.star01.element.className = "starInner";
	this.star01.element.onmouseover = starMouseOver;
	this.star01.element.onmouseout = starMouseOut;
	this.star01.element.onclick = function() {toggleTab("tabPage4"); toggleArtisteProfiles(0); };
	this.stars.push(this.star01);
	
	this.star02 = new Sprite(document.getElementById("star02"));
	this.star02.relative();
	this.star02.positionContainer = true;
	this.star02.position(this.starsLeftX + this.starDistanceX + 10, this.starOrigins[1], this.starsZ);
	this.star02.size(this.starWidth, this.starHeight);
	this.star02.element.setAttribute("id", "star02Inner");
	this.star02.element.className = "starInner";
	this.star02.element.onmouseover = starMouseOver;
	this.star02.element.onmouseout = starMouseOut;
	this.star02.element.onclick = function() {toggleTab("tabPage4"); toggleArtisteProfiles(1); };
	this.stars.push(this.star02);

	
	// Top hat
	this.topHatOriginX = 110;
	this.topHatOriginY = 2000; // where it starts. This value adjusts to destination
	this.topHatZ = 13;
	this.topHatDestinationY = 701; // where it should end up
	this.topHatSprite = new Sprite(document.getElementById("topHat"));
	this.topHatSprite.relative();
	this.topHatSprite.positionContainer = true;
	this.topHatSprite.position(300, 500, this.topHatZ);
	this.topHatSprite.size(338, 146);
	this.topHatSprite.element.setAttribute("id", "theTopHatInner");
	this.topHatSprite.element.className = "topHatInner";
	this.topHatSprite.element.onmouseover = topHatMouseOver;
	this.topHatSprite.element.onmouseout = topHatMouseOut;
	this.topHatSprite.element.onclick = function() {toggleTab("tabPage5"); };
	this.topHatTargetOffset = 0;
	this.topHatOffset = 0;
	this.mouseOverTopHat = false;
	
	// Beasties Logo
	this.beastiesLogoX = -300;
	this.beastiesLogoY = 1660;
	this.beastiesLogoDestinationX = -10;
	this.beastiesLogoDestinationY = 660;
	this.beastiesLogoZ = 15;
	this.beastiesLogoSprite = new Sprite(document.getElementById("beastiesLogo"), true);
	this.beastiesLogoSprite.absolute();
	this.beastiesLogoSprite.size(170, 228);
	this.beastiesLogoSprite.position(this.beastiesLogoX, this.beastiesLogoY, this.beastiesLogoZ);
	this.beastiesLogoSprite.useFilterAlpha = true;
	this.beastiesLogoSprite.useImage("images/2009_09_28/Beasties.png");
	this.beastiesLogoSprite.element.style.display = "block";
	this.beastiesLogoSprite.element.onmouseover = beastiesMouseOver;
	this.beastiesLogoSprite.element.onmouseout = beastiesMouseOut;
	this.beastiesTargetOffset = 0;
	this.beastiesOffset = 0;
	this.mouseOverBeasties = false;

	// Gallery Logo
	this.galleryLogoZ = 15;
	this.galleryLogoDestinationX = 810;
	this.galleryLogoDestinationY = 340;
	this.galleryLogoX = 1420;
	this.galleryLogoY = 1450;
	this.galleryLogoSprite = new Sprite(document.getElementById("galleryLogo"), true);
	this.galleryLogoSprite.absolute();
	this.galleryLogoSprite.size(172, 224);
	this.galleryLogoSprite.position(this.galleryLogoX, this.galleryLogoY, this.galleryLogoZ);
	this.galleryLogoSprite.useFilterAlpha = true;
	this.galleryLogoSprite.useImage("images/2009_09_28/Gallery.png");
	this.galleryLogoSprite.element.style.display = "block";
	this.galleryLogoSprite.element.onmouseover = galleryMouseOver;
	this.galleryLogoSprite.element.onmouseout = galleryMouseOut;
	this.galleryLogoSprite.element.onclick = function() {toggleTab("tabPage3"); };
	this.galleryLogoTargetOffset = 0;
	this.galleryLogoOffset = 0;
	this.mouseOverGalleryLogo = false;

	// Nipple cap
	this.nippleCapDestinationX = 836;
	this.nippleCapDestinationY = 580;
	this.nippleCapTargetX = this.nippleCapDestinationX;
	this.nippleCapTargetY = this.nippleCapDestinationY;
	this.nippleCapX = 2650;
	this.nippleCapY = this.nippleCapTargetY;
	
	this.nippleCapZ = 14;
	this.nippleCapRadius = 44;
	this.nippleCapSprite = new Sprite(document.getElementById("nippleCap"));
	this.nippleCapSprite.relative();
	this.nippleCapSprite.positionContainer = true;
	this.nippleCapSprite.position(this.nippleCapX, this.nippleCapY, this.nippleCapZ);
	this.nippleCapSprite.size(180, 131);
	this.nippleCapSprite.show();
	this.nippleCapSprite.container.style.display = "block";
	this.nippleCapSprite.element.onmouseover = nippleCapMouseOver;
	this.nippleCapSprite.element.onmouseout = nippleCapMouseOut;
	this.nippleCapSprite.element.onclick = function() {toggleTab("tabPage8"); };
	this.mouseOverNippleCap = false;
	
	this.nippleCapTassleSprite = new Sprite(document.getElementById("nippleCapTassle"));
	this.nippleCapTassleSprite.relative();
	this.nippleCapTassleSprite.positionContainer = true;
	this.nippleCapTassleSprite.position(this.nippleCapX, this.nippleCapY, this.nippleCapZ);
	this.nippleCapTassleSprite.size(42, 183);
	this.nippleCapTassleSprite.show();
	this.nippleCapTassleSprite.container.style.display = "block";
	this.nippleCapTassleSprite.element.onmouseover = nippleCapMouseOver;
	this.nippleCapTassleSprite.element.onmouseout = nippleCapMouseOut;
	this.nippleCapTassleSprite.element.onclick = function() {toggleTab("tabPage8"); };
	
	// Cards
	this.cardsOriginX = 730;
	this.cardsOriginY = 2000; // where it starts. This value adjusts to destination
	this.cardsZ = 13;
	this.cardsDestinationY = 723; // where it should end up
	this.cardsSprite = new Sprite(document.getElementById("cards"));
	this.cardsSprite.relative();
	this.cardsSprite.positionContainer = true;
	this.cardsSprite.position(this.cardsOriginX, this.cardsOriginY, this.cardsZ);
	this.cardsSprite.size(180, 131);
	this.cardsSprite.show();
	this.cardsSprite.container.style.display = "block";
	this.cardsOffset = 0;
	this.mouseOverCards = false;

	// Top card
	this.topCardOriginX = 780;
	this.topCardOriginY = 2000; // where it starts. This value adjusts to destination
	this.topCardZ = 14;
	this.topCardDestinationY = 713; // where it should end up
	this.topCardSprite = new Sprite(document.getElementById("topCard"));
	this.topCardSprite.relative();
	this.topCardSprite.positionContainer = true;
	this.topCardSprite.position(this.topCardOriginX, this.topCardOriginY, this.topCardZ);
	this.topCardSprite.size(256, 173);
	this.topCardSprite.element.setAttribute("id", "theTopCardInner");
	this.topCardSprite.element.className = "topCardInner";
	this.topCardSprite.element.onmouseover = cardsMouseOver;
	this.topCardSprite.element.onmouseout = cardsMouseOut;
	this.topCardSprite.element.onclick = function() {toggleTab("tabPage6"); };
	this.topCardSprite.show();
	this.topCardTargetOffset = 0;
	this.topCardOffset = 0;
	
	// Pointing Hand Buttons
	this.pointingHandZ = 19;
	this.leftPointingHandSprite = new Sprite(getBodyElement());
	this.leftPointingHandSprite.absolute();
	this.leftPointingHandSprite.size(116, 56);
	this.leftPointingHandSprite.position(220, 250, this.pointingHandZ);
	this.leftPointingHandSprite.element.setAttribute("id", "leftHandButton");
	
	this.rightPointingHandSprite = new Sprite(getBodyElement());
	this.rightPointingHandSprite.absolute();
	this.rightPointingHandSprite.size(116, 56);
	this.rightPointingHandSprite.position(650, 250, this.pointingHandZ);
	this.rightPointingHandSprite.element.setAttribute("id", "rightHandButton");
	
	// Front page splash image (after curtains open)
	this.splashSpriteZ = 3;
	this.splashSprite = new Sprite(document.getElementById("splashImage"));
	this.splashSprite.positionContainer = true;
	this.splashSprite.absolute();
	this.splashSprite.position(-1000, 280, this.splashSpriteZ);
	this.splashSprite.size(278,327);
	this.splashSprite.setOpacity(0.0);
	//this.splashSpriteTargetOpacity = 0.45;
	this.splashSpriteTargetOpacity = 0.0;
	
	// Artiste Profiles (sliding pano)
	this.artisteProfileCount = 0; // to be calculated later
	this.currentArtisteProfile = 0;
	this.profileOffset = 0;
	this.profileTargetOffset = 0;
	
	// Event Profiles (sliding pano)
	this.eventProfileCount = 0; // to be calculated later
	this.currentEventProfile = 0;
	this.eventProfileTargetOffset = 0;
	this.eventProfileOffset = 0;
	
	// Contact blurb
	this.contactBlurbZ = 19;
	this.contactBlurbSprite = new Sprite(document.getElementById("contactBlurb"), true);
	this.contactBlurbSprite.absolute();
	this.contactBlurbSprite.size(420, 50);
	this.contactBlurbSprite.position(0, 650 + this.generalHeightOffset, this.contactBlurbZ);
	this.contactBlurbSprite.hide();
	
	// Primary readable content
	this.mainContentElement = document.getElementById("mainContent");
	if (!this.mainContentElement)
	{
		alert("ERROR - Failed to find #mainContent.");
	}
	
	this.pageContentVisible = false;

	this.initialTextAlpha = 0.0;
	this.textAlpha = this.initialTextAlpha;
	
	this.initialTextAlphaDelta = 0.045; // 0.05
	this.textAlphaDelta = this.initialTextAlphaDelta;
	
	//-----====== functions ======---------

	//====================================================
	// Scene::prepare()
	//====================================================
	this.prepare = function()
	{
		// Basic setup
		log.addItem("Preparing Scene...");
		
		this.curtainsCompleted = false;
		
		this.stageLeftX = 0; // will be reset on resize()
		
		// Cache references to curtain DOM elements
		this.stageDarknessElement = document.getElementById("theStageDarkness");
		this.stageBackgroundElement = document.getElementById("theStage");
		
		// Hide elements used to preload/cache big images - no need for them anymore
		var toHide1 = document.getElementById("preLoadStageFrame");
		if (toHide1)
			toHide1.style.display = "none";
		var toHide2 = document.getElementById("preLoadFans");
		if (toHide2)
			toHide2.style.display = "none";
			
		// General moving curtain attributes
		this.curtainSpeed = this.initialCurtainSpeed;
		this.curtainAccel = this.initialCurtainAccel;
		
		// Load event profile posters dynamically and apply positional offsets
		var eventCount = 0;
		while (true)
		{
			// Get the next event profile container
			var eventsElement = document.getElementById("eventProfile" + eventCount);
			if (!eventsElement)
				break;
			
			// Apply positional offsets (so no need for CSS enumeration of all events)
			eventsElement.style.left = (eventCount * 600) + "px";
			
			// Get all images in the container (should only be one)
			var eventImages = eventsElement.getElementsByTagName("img");
			if (eventImages)
			{
				var eventImageElement = eventImages[0];
				if (eventImageElement)
				{
					// Apply the appropriate image url
					eventImageElement.src = eventPosterImages[eventCount] + ".jpg";
				}
			}
		
			eventCount++;
			// Break out of loop if problem
			if (eventCount > 100)
			{
				alert("Too many event profiles");
				break;
			}
		}
		this.eventProfileCount = eventCount;

		// Load Artiste profile images dynamically and apply positional offsets
		var artisteCount = 0;
		while (true)
		{
			// Get the next artiste profile container
			var artistesElement = document.getElementById("artisteProfile" + artisteCount);
			if (!artistesElement)
				break;
			
			// Apply positional offsets (so no need for CSS enumeration of all profiles)
			artistesElement.style.left = (artisteCount * 600) + "px";
			
			// Get all images in the container (should only be one)
			var artisteImages = artistesElement.getElementsByTagName("img");
			if (artisteImages)
			{
				var artisteImageElement = artisteImages[0];
				if (artisteImageElement)
				{
					// Apply the appropriate image url
					artisteImageElement.src = artisteProfileImages[artisteCount] + ".jpg";
				}
			}
		
			artisteCount++;
			// Break out of loop if problem
			if (artisteCount > 100)
			{
				alert("Too many artiste profiles");
				break;
			}
		}
		this.artisteProfileCount = artisteCount;
		
		
		// Load gallery collection thumbnail  images dynamically
		this.galleryCount = 0;
		while (true)
		{
			// Get the next gallery thumbnail container
			var galleryThumbnailElement = document.getElementById("galleryCollection" + this.galleryCount);
			if (!galleryThumbnailElement)
			{
				break;
			}
			
			// Get all images in the container (should only be one)
			var galleryThumbnailImageElements = galleryThumbnailElement.getElementsByTagName("img");
			if (galleryThumbnailImageElements)
			{
				var galleryThumbnailImageElement = galleryThumbnailImageElements[0];
				if (galleryThumbnailImageElement)
				{
					// Apply the appropriate image url
					galleryThumbnailImageElement.src = galleryCollectionImages[this.galleryCount] + "_thumb.jpg";
				}
			}
	
			this.galleryCount++;
			// Break out of loop if problem
			if (this.galleryCount > 100)
			{
				alert("Too many galleries");
				break;
			}
		}
		
		// Force resize code to run, to initialize everything
		this.resize();
		this.restart();
	}

	//====================================================
	// Scene::resize()
	//====================================================
	this.resize = function()
	{
		// update the stored viewport metrics for
		// other calculations to use
		this.viewport.resize();
		
		// resize the main scene container element
		//this.container.style.width = this.viewport.width + "px";

		this.stageLeftX = (this.viewport.width / 2) - this.halfStageWidth;
		this.stageRightX = this.stageLeftX + this.stageWidth;
		// True centering?
		// if (this.stageLeftX < 0)
		//	this.stageLeftX = 0;
		
		// implement widescreen if enabled
		if (this.useWideScreen)
		{
			var bodyElement = getBodyElement();
			if (this.viewport.height > 880)
			{
				bodyElement.style.marginTop = ((this.viewport.height / 2) - (this.stageHeight / 2)) + "px";
			}
			else
			{
				bodyElement.style.marginTop = "0px";
			}
		}
		
		// Surrounds (keeps scrolling to minimum, and crops things going out of bounds)
		var surrounds = getBodyElement();
		surrounds.style.left = 0 + "px";
		if (this.viewport.width > 900)
			surrounds.style.width = this.viewport.width  + "px";
		else
			surrounds.style.width = 900  + "px";
			
		if (this.viewport.height > 850)
			surrounds.style.height = this.viewport.height  + "px";
		else
			surrounds.style.height = 850  + "px";

		// Main container
		this.container.style.left = this.stageLeftX + "px";
		
		// Frame curtain overlay
		this.frameCurtainSprite.position(this.stageLeftX, 0, 5);
		this.frameCurtainSprite.size(this.frameCurtainWidth, 850);

		// Resize and re-position Banner , Logo and content pane to match page proportions
		this.generalHeightOffset = 0;
		this.bannerCurrentSizeIndex = 0;
		this.logoCurrentSizeIndex = 0;
		if (this.viewport.width < this.bannerWidths[1])
		{
			// Smallest banner
			this.bannerCurrentSizeIndex = 2;
			this.bannerWidth = this.bannerWidths[this.bannerCurrentSizeIndex];
			this.bannerHeight = this.bannerHeights[this.bannerCurrentSizeIndex];
			this.bannerSprite.useImage("images/2009_09_28/BannerSmallest.png");
			
			// Smallest logo
			this.logoCurrentSizeIndex = 1; //NOTE: not following banner state
			this.logoWidth = this.logoWidths[this.logoCurrentSizeIndex];
			this.logoHeight = this.logoHeights[this.logoCurrentSizeIndex];
			this.logoSprite.useImage("images/2009_09_28/OrchidSmaller.png");

			if (this.useHeightOffsets && this.viewport.height < 600)
				this.generalHeightOffset -= 120;  // -20
		}
		else if (this.viewport.width < this.bannerWidths[0])
		{
			// Medium-size banner
			this.bannerCurrentSizeIndex = 1;
			this.bannerWidth = this.bannerWidths[this.bannerCurrentSizeIndex];
			this.bannerHeight = this.bannerHeights[this.bannerCurrentSizeIndex];
			this.bannerSprite.useImage("images/2009_09_28/BannerSmaller.png");

			// Medium-size logo
			this.logoCurrentSizeIndex = 0;  // NOTE: not following banner scale
			this.logoWidth = this.logoWidths[this.logoCurrentSizeIndex];
			this.logoHeight = this.logoHeights[this.logoCurrentSizeIndex];
			this.logoSprite.useImage("images/2009_09_28/Orchid.png"); // NOTE, not following banner scale
			
			if (this.useHeightOffsets  && this.viewport.height < 600)
				this.generalHeightOffset -= 60; // -10
		}
		else
		{
			// Largest banner
			this.bannerWidth = this.bannerWidths[this.bannerCurrentSizeIndex];
			this.bannerHeight = this.bannerHeights[this.bannerCurrentSizeIndex];
			this.bannerSprite.useImage("images/2009_09_28/Banner.png");

			// Largest logo
			this.logoWidth = this.logoWidths[this.logoCurrentSizeIndex];
			this.logoHeight = this.logoHeights[this.logoCurrentSizeIndex];
			this.logoSprite.useImage("images/2009_09_28/Orchid.png");
			
			if (this.useHeightOffsets)
				this.generalHeightOffset -= 0;
		}
		
		// Browser window getting short
		if (this.viewport.height < 500)
		{
			this.bannerWidth = this.bannerWidths[2];
			this.bannerHeight = this.bannerHeights[2];
			this.bannerSprite.useImage("images/2009_09_28/BannerSmallest.png");

			if (this.viewport.width > this.bannerWidths[1])
			{
				this.logoCurrentSizeIndex = 1;
				this.logoWidth = this.logoWidths[this.logoCurrentSizeIndex];
				this.logoHeight = this.logoHeights[this.logoCurrentSizeIndex];
				this.logoSprite.useImage("images/2009_09_28/OrchidSmaller.png");
			}
			else
			{
				this.logoCurrentSizeIndex = 2;
				this.logoWidth = this.logoWidths[this.logoCurrentSizeIndex];
				this.logoHeight = this.logoHeights[this.logoCurrentSizeIndex];
				this.logoSprite.useImage("images/2009_09_28/OrchidSmallest.png");
			}
			
			if (this.useHeightOffsets)
				this.generalHeightOffset -= 100; // -10
		}
		
		// Stage background
		this.stageBackgroundElement.style.top = this.generalHeightOffset + "px";
		
		// Main stage frame curtains
		this.frameCurtainSprite.position(this.stageLeftX, this.generalHeightOffset);
		
		// Main page contents
		var mainContentLeft = (this.viewport.width / 2) - 290;  //(580 / 2) = 290
		this.mainContentElement.style.left = mainContentLeft + "px";
		this.mainContentElement.style.top = 320 + this.generalHeightOffset + "px";
		
		// Banner centering and re-sizing
		// Banner height position change depending on size
		if (this.bannerCurrentSizeIndex == 0)
			this.bannerSprite.position((this.viewport.width / 2) - (this.bannerWidth / 2), 20, this.bannerZ);
		else if (this.bannerCurrentSizeIndex == 1)
			this.bannerSprite.position((this.viewport.width / 2) - (this.bannerWidth / 2), 10, this.bannerZ);
		else
			this.bannerSprite.position((this.viewport.width / 2) - (this.bannerWidth / 2), 5, this.bannerZ);
		this.bannerSprite.size(this.bannerWidth, this.bannerHeight);
		
		// Logo centering and re-sizing
		// NOTE: Logo height position change depending on BANNER size
		if (this.bannerCurrentSizeIndex == 0)
			this.logoSprite.position((this.viewport.width / 2) - (this.logoWidth / 2), 110, this.logoZ);
		else if (this.bannerCurrentSizeIndex == 1)
			this.logoSprite.position((this.viewport.width / 2) - (this.logoWidth / 2), 75, this.logoZ);
		else
			this.logoSprite.position((this.viewport.width / 2) - (this.logoWidth / 2), 55, this.logoZ);
		this.logoSprite.size(this.logoWidth, this.logoHeight);
		
		// Left curtain
		this.leftCurtain.position((this.viewport.width / 2) - this.halfStageWidth, this.generalHeightOffset);
		this.leftCurtain.applyGeometryChanges();

		// Right curtain
		if (this.noCurtains == true)
			this.rightCurtain.position(this.stageLeftX + this.stageWidth, this.generalHeightOffset);
		else
			this.rightCurtain.position(this.viewport.width / 2, this.generalHeightOffset);
		this.rightCurtain.applyGeometryChanges();

		// Left Border
		this.leftBorderSprite.size(120, 850 /*this.viewport.height*/);
		this.leftBorderSprite.position(this.stageLeftX - 120, 0, this.frameBorderZ);
		if (this.stageLeftX > 0)
		{
			// Window is wide enough to leave a gap to the left of stage - cover it up
			this.leftBorderSkirtSprite.element.style.display = "block";
			this.leftBorderSkirtSprite.position(0, 0, this.leftBorderSkirtSpriteZ);
			this.leftBorderSkirtSprite.size(this.stageLeftX, this.viewport.height);
		}
		else
		{
			this.leftBorderSkirtSprite.element.style.display = "none";
		}
		
		// Right Border
		this.rightBorderSprite.size(120, 850 /*this.viewport.height*/);
		this.rightBorderSprite.position(this.stageRightX, 0, this.frameBorderZ);
		if (this.stageLeftX + this.stageWidth < this.viewport.width)
		{
			// Window is wide enough to leave a gap to the right of stage - cover it up
			this.rightBorderSkirtSprite.element.style.display = "block";
			this.rightBorderSkirtSprite.position(this.stageRightX, 0, this.rightBorderSkirtSpriteZ);
			this.rightBorderSkirtSprite.size(this.viewport.width - this.stageRightX, this.viewport.height);
		}
		else
		{
			this.rightBorderSkirtSprite.element.style.display = "none";
		}
		
		// Bottom border skirt
		this.bottomSkirtSprite.size(this.viewport.width, 1000);
		this.bottomSkirtSprite.position(0, this.stageHeight + this.generalHeightOffset, this.bottomSkirtSpriteZ);
		
		// Stars
		this.starsLeftX = this.stageLeftX + this.starsOffsetX;

		this.star01.position(this.starsLeftX, 
						this.starOrigins[0] + this.generalHeightOffset + this.starY[0], 
						this.starsZ);
		this.star02.position(this.starsLeftX + this.starDistanceX + 10,
						this.starOrigins[1] + this.generalHeightOffset + this.starY[1],
						this.starsZ);
		
		// Top-hat
		this.topHatOriginY = 1000;
		this.topHatSprite.position(this.stageLeftX + this.topHatOriginX, 
							this.topHatOriginY + this.generalHeightOffset,
							this.topHatZ);
		
		// Beasties Logo
		this.beastiesLogoX = this.stageLeftX - 300;
		this.beastiesLogoY = 1000;
		this.beastiesLogoSprite.position(this.stageLeftX + this.beastiesLogoX, 
								this.beastiesLogoY + this.generalHeightOffset,
								this.beastiesLogoZ);

		// Gallery Logo
		this.galleryLogoX = 1120;
		this.galleryLogoY = 1150;
		this.galleryLogoSprite.position(this.stageLeftX + this.galleryLogoX, 
								this.galleryLogoY + this.generalHeightOffset,
								this.galleryLogoZ);

		// Cards
		this.cardsSprite.position(this.stageLeftX + this.cardsOriginX, 
							this.cardsOriginY + this.generalHeightOffset,
							this.cardsZ);
				
		// Top Card
		this.topCardSprite.position(this.stageLeftX + this.topCardOriginX, 
							this.topCardOriginY + this.generalHeightOffset,
							this.topCardZ);
		// Fan
		this.fansLeftX = this.stageLeftX - 120; //-300;
		/*if (this.fansLeftX < 0)
			this.fansLeftX = this.fansLeftX / 4;*/
		this.fansElement.style.left = this.fansLeftX + "px";
		this.fansElement.style.top = (this.fansTopY + this.generalHeightOffset) + "px";

		// Tickets
		this.frontTicketsLeftX = this.stageLeftX - 450; // must NOT be equal to targetX or will not reposition on resize properly
		this.ticketsRearElement.style.left = this.frontTicketsLeftX + "px";
		this.ticketsRearElement.style.top = (this.ticketsTopY + this.generalHeightOffset) + "px";
		
		// Pointing Hands
		this.leftPointingHandSprite.position(this.stageLeftX + this.halfStageWidth - 216,
									250 + this.generalHeightOffset,
									this.pointingHandZ);
		this.rightPointingHandSprite.position(this.stageLeftX + this.halfStageWidth + 100,
									250 + this.generalHeightOffset,
									this.pointingHandZ);

		// Nipple cap
		this.nippleCapSprite.position(this.stageLeftX + this.nippleCapX,
								this.nippleCapY + this.generalHeightOffset,
								this.nippleCapZ);
		this.nippleCapTassleSprite.position(this.stageLeftX + this.nippleCapX + this.nippleCapRadius,
								this.nippleCapY + this.nippleCapRadius + 19 + this.generalHeightOffset,
								this.nippleCapZ);
		this.nippleCapSprite.visible();
		this.nippleCapTassleSprite.visible();
								
		// Splash Image
		this.splashSprite.position((this.viewport.width / 2) - (this.splashSprite.width / 2), 280 + this.generalHeightOffset);
		this.splashSprite.setOpacity(0.0);
			
		// Contact Blurb
		this.contactBlurbSprite.position(this.stageLeftX + 280, 700 + this.generalHeightOffset, 19);
		
		// Blackout
		this.blackout.position(0,0,this.blackoutZ);
		this.blackout.size(this.viewport.width, this.viewport.height);

	}

	//====================================================
	// Scene::startPresentation()
	//====================================================
	// The main scene presentation can begin after some time has been left for
	// the loading of resources such as images.
	// This function gets called 5 seconds or after the document has loaded, in
	// order to trigger the fading out of the loading screen.
	// This function also attaches the mouseclick handler for opening the
	// curtains. This is not done earlier so that the user does not click and 
	// thereby miss the curtain effect.
	//====================================================
	this.startPresentation = function()
	{
		//this.blackout.color("11", "11", "11", 0);
		//this.blackout.container.removeChild(this.blackout.element);
		this.ready = true;

		// The main trigger to open the curtains
		// TODO check which code is best
		// var bodyElement = document.body;
		var bodyElement = getBodyElement();
		bodyElement.onclick = function() { /*scene.triggerCurtains();*/ document.body.onclick = null; }
	}

	//====================================================
	// Scene::restart()
	//====================================================
	this.restart = function()
	{
		// Reclose the curtains so they can be opened again,
		// and all that entails
		this.curtainsCompleted = false;
		this.curtainSpeed = this.initialCurtainSpeed;
		this.curtainAccel = this.initialCurtainAccel;
		
		this.textAlpha = this.initialTextAlpha;
		this.textAlphaDelta = this.initialTextAlphaDelta;
		
		this.restartStageLighting();
		this.restartTextFadeIn();
		
		// sizes for left moving curtain to fit
		this.leftCurtain.size(this.initialCurtainWidth, this.stageHeight);
		this.leftCurtain.position((this.viewport.width / 2) - this.halfStageWidth, this.generalHeightOffset);
	
		// sizes for right moving curtain to fit
		this.rightCurtain.size(this.initialCurtainWidth, this.stageHeight);
		if (this.noCurtains == true)
			this.rightCurtain.position(this.stageLeftX + this.stageWidth, this.generalHeightOffset);
		else
			this.rightCurtain.position((this.viewport.width / 2), this.generalHeightOffset);
	}
	
	//====================================================
	// Scene::tick()
	//====================================================
	this.tick = function()
	{
		//log.addItem("Tick");
		this.applyLoadingScreen();
		this.moveCurtains();
		this.moveWidgets();
		this.applyStageLighting();
		this.applyTextEffects();
	}


	//----======= Custom Functions ====-------
	
	//====================================================
	// Scene::triggerCurtains()
	//====================================================
	this.triggerCurtains = function()
	{
		this.started = true;
	}

	//====================================================
	// Scene::applyLoadingScreen()
	//====================================================
	this.applyLoadingScreen = function()
	{
		if (this.ready && this.blackout.element && this.blackout.opacity > 0)
		{
			if (!this.curtainsCompleted)
			{
				// only fade out blackout when curtains completed opening
				// because we will use it later for popups
				this.blackout.backgroundColor("#000000");
				if (this.lowCPU)
					this.blackout.setOpacity(this.blackout.opacity - (this.loadingScreenFadeSpeed * 4));
				else
					this.blackout.setOpacity(this.blackout.opacity - this.loadingScreenFadeSpeed);
			}
			if (this.blackout.opacity <= 0)
			{
				// Permantly remove blackout - commented out because using for
				// lightbox effect
				   //this.blackout.container.removeChild(this.blackout.element);
				   //delete this.blackout.element;
				this.blackout.element.style.display = "none";
				setTimeout("scene.triggerCurtains();", 1000);
			}
		}
	}

	//====================================================
	// Scene::moveCurtains()
	//====================================================
	this.moveCurtains = function()
	{	
		var movedCurtains = false;
		var halfWidth = this.halfStageWidth;
		
		// Change curtain speed due to acceleration (if triggered)
		if (this.started == true)
		{
			if (this.lowCPU)
				this.curtainSpeed += (this.curtainAccel * 4);
			else
				this.curtainSpeed += this.curtainAccel;

			// Move the left curtain to the left
			if (this.leftCurtain.width > 0)
			{
				this.leftCurtain.size(this.leftCurtain.width - this.curtainSpeed, this.stageHeight);
				if (this.leftCurtain.width < 0)
					this.leftCurtain.size(0, this.stageHeight);
				this.movedCurtains = true;
			}
		
			// Move the right curtain to the right and shrink it
			// in order to not make a horiz scrollbar
			if (this.rightCurtain.width > 0)
			{
				this.rightCurtain.size(this.rightCurtain.width - this.curtainSpeed, this.stageHeight);
				movedCurtains = true;
			}
		
			var rightEdgeX = (this.viewport.width / 2) + (this.halfStageWidth);
			if (this.rightCurtain.x < rightEdgeX)
			{
				this.rightCurtain.position(this.rightCurtain.x + this.curtainSpeed, this.generalHeightOffset);
				if (this.rightCurtain.x >= rightEdgeX)
					this.rightCurtain.hide();
				movedCurtains = true;
			}

			// Find out if scene is completed
			if (movedCurtains == false)
			{
				// No movement happened this frame - 
				// must have reached destination positions.
				this.curtainsCompleted = true;
				
				// Reveal misc. things after curtains opened
				this.contactBlurbSprite.show();
			}
			else
			{
				// Change DOM only if scene not yet completed.
				this.leftCurtain.applyGeometryChanges();
				this.rightCurtain.applyGeometryChanges();
			}
		}

		/*	opacity: 0.00;
			filter: alpha(opacity=00);
			-moz-opacity: 0.00;
		*/
		
	}
	
	this.moveWidgets = function()
	{
		// -------- Move surrounding bits/effects in once curtains open ------
		if (this.curtainsCompleted)
		{
			// ================ Splash image  =====================
			var splashOpacityDiff = this.splashSpriteTargetOpacity - this.splashSprite.opacity;
			if (Math.abs(splashOpacityDiff) > 0.02)
			{
				if (this.splashSprite.opacity < 0.01)
					this.splashSprite.opacity = 0.0;
				else if (this.splashSprite.opacity > 0.445)
					this.splashSprite.opacity = 0.45;

				this.splashSprite.setOpacity(this.splashSprite.opacity + (splashOpacityDiff * 0.03));
			}
			
			// ================ Fans =====================
			var movedFans = false;
			var fansTargetX = this.stageLeftX - 40;
			var fansTargetY = 340;
			// fudge to bias offscreen as screen shrinks
			if (fansTargetX < 0)
				fansTargetX = fansTargetX / 2.5;
			
			// Wobble fans target positions
			if (this.mouseOverFans == true)
			{
				fansTargetX += (15 + (15 * Math.random()));
				fansTargetY += (6 * Math.random());
			}
			
			// Move fans to X target position
			if (this.fansLeftX != fansTargetX)
			{
				var diff = fansTargetX - this.fansLeftX;
				if (diff < 0.1 && diff > -0.1)
				{
					diff = 0;
				}
				else
				{
					movedFans = true;
				}
				this.fansLeftX += (diff * 0.23);
			}
			
			// Move fans to Y target position
			if (this.fansTopY != fansTargetY)
			{
				var diffY = fansTargetY - this.fansTopY;
				if (diffY < 0.1 && diffY > -0.1)
				{
					diffY = 0;
				}
				else
				{
					movedFans = true;
				}
				this.fansTopY += (diffY * 0.2);
			}

			if (movedFans)
			{
				this.fansElement.style.display = "block";
				this.fansElement.style.left = this.fansLeftX.toFixed(0) + "px";
				this.fansElement.style.top = (this.fansTopY + this.generalHeightOffset) + "px";
			}

			// ================ Tickets =====================
			
			var movedTicket = false;
			
			var ticketsTargetX = scene.stageLeftX;
			if (ticketsTargetX < 0)
				ticketsTargetX = 0;

			var frontTicketTargetXOffset = 95; // how much it should shift on mouseover
			var frontTicketTargetX = this.stageLeftX - 118; // NOTE: must not be equal to value in resize() or movedTicket will not be set on resize
			if (frontTicketTargetX < -115)
				frontTicketTargetX = -115;

			// Shift ticket target position when mouseover
			if (this.mouseOverTickets == true)
			{
				frontTicketTargetX += frontTicketTargetXOffset;
			}
			
			// Move tickets to X target position
			if (this.frontTicketsLeftX != frontTicketTargetX)
			{
				var diffTicketsX = frontTicketTargetX - this.frontTicketsLeftX;
				if (Math.abs(diffTicketsX) < 0.1)
					diffTicketsX = 0;
				else
					movedTicket = true;
				this.frontTicketsLeftX += (diffTicketsX * 0.2);
			}
			
			// Move tickets to Y target position
			this.ticketsTopY = this.ticketsTargetY;
			
			if (movedTicket)
			{
				this.ticketsRearElement.style.left = ticketsTargetX + "px";
				this.ticketsRearElement.style.top = this.ticketsTopY + this.generalHeightOffset + "px";
				
				this.ticketsFrontElement.style.left = (this.frontTicketsLeftX).toFixed(0) + "px";
				this.ticketsFrontElement.style.top = this.ticketsTopY + 35 + this.generalHeightOffset + "px";
			}
			
			// ================ Tophat =====================
			
			var movedTopHat = false;
			// Large scale fly-in
			if (this.topHatOriginY > this.topHatDestinationY)
			{
				// move tophat into general destination
				var topHatOriginDiff = this.topHatOriginY - this.topHatDestinationY;
				if (Math.abs(topHatOriginDiff) > 2.0)
				{
					this.topHatOriginY -= (topHatOriginDiff * 0.1);
					movedTopHat = true;
				}
			}
			
			this.topHatTargetOffset = 0;
			if (this.mouseOverTopHat)
			{
				this.topHatTargetOffset = 7;
			}
			var topHatDiff = (this.topHatTargetOffset - this.topHatOffset);
			var shiftAmount = (topHatDiff * 0.1);
			if (Math.abs(shiftAmount) > 0.03)
			{
				this.topHatOffset += shiftAmount;
				movedTopHat = true;
			}
			if (movedTopHat)
				this.topHatSprite.position(Math.round(this.stageLeftX + this.topHatOriginX + (this.topHatOffset / 2)),
								Math.round(this.topHatOriginY - this.topHatOffset + this.generalHeightOffset),
									this.topHatZ);

			// ================ Cards =====================
			
			var movedCards = false;
			// Large scale fly-in
			if (this.cardsOriginY > this.cardsDestinationY)
			{
				// move cards into general destination
				var cardsOriginDiff = this.cardsOriginY - this.cardsDestinationY;
				if (Math.abs(cardsOriginDiff) > 2.0)
				{
					this.cardsOriginY -= (cardsOriginDiff * 0.1);
					movedCards = true;
				}
			}
			
			this.cardsTargetOffset = 0;
			if (this.mouseOverCards)
			{
				this.cardsTargetOffset = 0; // TODO: 2 to move bottom cards slightly
			}
			var cardsDiff = (this.cardsTargetOffset - this.cardsOffset);
			var cardShiftAmount = (cardsDiff * 0.1);
			if (Math.abs(cardShiftAmount) > 0.03)
			{
				this.cardsOffset += cardShiftAmount;
				movedCards = true;
			}
			if (movedCards)
				this.cardsSprite.position(Math.round(this.stageLeftX + this.cardsOriginX - (this.cardsOffset)),
								Math.round(this.cardsOriginY - this.cardsOffset + this.generalHeightOffset),
									this.cardsZ);

			// ================ Top Card =====================
			
			var movedTopCard = false;
			// Large scale fly-in
			if (this.topCardOriginY > this.topCardDestinationY)
			{
				// move cards into general destination
				var topCardOriginDiff = this.topCardOriginY - this.topCardDestinationY;
				if (Math.abs(topCardOriginDiff) > 2.0)
				{
					this.topCardOriginY -= (topCardOriginDiff * 0.1);
					movedTopCard = true;
				}
			}
			
			this.topCardTargetOffset = 0;
			if (this.mouseOverCards)
			{
				this.topCardTargetOffset = 37;
			}
			var topCardDiff = (this.topCardTargetOffset - this.topCardOffset);
			var topCardShiftAmount = (topCardDiff * 0.1);
			if (Math.abs(topCardShiftAmount) > 0.03)
			{
				this.topCardOffset += topCardShiftAmount;
				movedTopCard = true;
			}
			if (movedTopCard)
				this.topCardSprite.position(Math.round(this.stageLeftX + this.topCardOriginX - (this.topCardOffset / 3)),
								Math.round(this.topCardOriginY - (this.topCardOffset) + this.generalHeightOffset),
									this.topCardZ);

			// ================ Nipplecap =====================
			
			var movedNippleCap = false;
			
			// Large scale fly-in
			if (this.nippleCapX > this.nippleCapTargetX)
			{
				// move nippleCap into general destination
				if (Math.abs(this.nippleCapX - this.nippleCapTargetX) > 2.0)
				{
					this.nippleCapX -= ((this.nippleCapX - this.nippleCapTargetX) * 0.1);
					movedNippleCap = true;
				}
			}
			
			if (this.mouseOverNippleCap)
			{
				this.nippleCapTargetX = this.nippleCapDestinationX + (-10 + (Math.random() * 20));
				this.nippleCapTargetY = this.nippleCapDestinationY + (-10 + (Math.random() * 20));
			}
			var nippleCapOffsetDiffX = (this.nippleCapTargetX - this.nippleCapX);
			var nippleCapOffsetDiffY = (this.nippleCapTargetY - this.nippleCapY);
			var nippleCapShiftAmountX = (nippleCapOffsetDiffX * 0.093);
			var nippleCapShiftAmountY = (nippleCapOffsetDiffY * 0.093);
			if (Math.abs(nippleCapShiftAmountX) > 0.03)
			{
				this.nippleCapX += nippleCapShiftAmountX;
				movedNippleCap = true;
			}
			if (Math.abs(nippleCapShiftAmountY) > 0.03)
			{
				this.nippleCapY += nippleCapShiftAmountY;
				movedNippleCap = true;
			}
			
			if (movedNippleCap)
			{
				this.nippleCapSprite.position(Math.round(this.stageLeftX + this.nippleCapX),
								Math.round(this.nippleCapY + this.generalHeightOffset),
									this.nippleCapZ);
				this.nippleCapTassleSprite.position(Math.round(this.stageLeftX + nippleCapShiftAmountX + this.nippleCapX + this.nippleCapRadius - 5),
								Math.round(this.nippleCapY + this.nippleCapRadius + 19 + nippleCapShiftAmountY + this.generalHeightOffset),
									this.nippleCapZ);
			}
									
			// ================ Beasties Logo =====================
			
			var movedBeasties = false;
			
			// Zoom Fly-in
			var beastiesDiffX = (this.beastiesLogoDestinationX - this.beastiesLogoX);
			var beastiesDiffY = (this.beastiesLogoDestinationY - this.beastiesLogoY);
			var beastiesShiftX = beastiesDiffX * 0.08;
			var beastiesShiftY = beastiesDiffY * 0.08;
			if (Math.abs(beastiesDiffX) > 2 || Math.abs(beastiesDiffY) > 2)
			{
				this.beastiesLogoX += beastiesShiftX;
				this.beastiesLogoY += beastiesShiftY;
				movedBeasties = true;
			}
			
			// Mouse over movement
			this.beastiesTargetOffset = 0;
			if (this.mouseOverBeasties)
			{
				this.beastiesTargetOffset = 10;
			}
			var beastiesDiff = (this.beastiesTargetOffset - this.beastiesOffset);
			var beastiesShiftAmount = (beastiesDiff * 0.1);
			if (Math.abs(beastiesShiftAmount) > 0.03)
			{
				this.beastiesOffset += beastiesShiftAmount;
				movedBeasties = true;
			}
			
			// Move actual DOM elements
			if (movedBeasties)
				this.beastiesLogoSprite.position(Math.round(this.stageLeftX + this.beastiesLogoX + this.beastiesOffset),
								Math.round(this.beastiesLogoY - this.beastiesOffset + this.generalHeightOffset),
									this.beastiesLogoZ);

			// ================ Gallery =====================
			
			var movedGalleryLogo = false;
			
			// Zoom Fly-in
			var galleryLogoDiffX = (this.galleryLogoDestinationX - this.galleryLogoX);
			var galleryLogoDiffY = (this.galleryLogoDestinationY - this.galleryLogoY);
			var galleryLogoShiftX = galleryLogoDiffX * 0.09;
			var galleryLogoShiftY = galleryLogoDiffY * 0.09;
			if (Math.abs(galleryLogoDiffX) > 2 || Math.abs(galleryLogoDiffY) > 2)
			{
				this.galleryLogoX += galleryLogoShiftX;
				this.galleryLogoY += galleryLogoShiftY;
				movedGalleryLogo = true;
			}
			
			// Mouse over movement
			this.galleryLogoTargetOffset = 0;
			if (this.mouseOverGalleryLogo)
			{
				this.galleryLogoTargetOffset = 10;
			}
			var galleryDiff = (this.galleryLogoTargetOffset - this.galleryLogoOffset);
			var galleryShiftAmount = (galleryDiff * 0.33);
			if (Math.abs(galleryShiftAmount) > 0.06)
			{
				this.galleryLogoOffset += galleryShiftAmount;
				movedGalleryLogo = true;
			}
			if (movedGalleryLogo)
				this.galleryLogoSprite.position(Math.round(this.stageLeftX + this.galleryLogoX - this.galleryLogoOffset),
								Math.round(this.galleryLogoY - (this.galleryLogoOffset / 3 )+ this.generalHeightOffset),
									this.galleryLogoZ);
									
			// ================ Stars =====================
			
			var currentStarOrigin = 0;
			for (var i = 0; i < this.stars.length; i++)
			{	
				var theStar = this.stars[i];
				currentStarOrigin = this.starOrigins[i] + this.generalHeightOffset;
				var starX = theStar.x;
				
				// Get stars to final positions (the term after the < is the most important for
				// post-animation station-keeping during resize
				if (currentStarOrigin + this.starY[i] < (this.generalHeightOffset + 140 + (i * 100)))
				{
					this.starY[i] += (this.curtainSpeed / 3.0);
					theStar.position(starX, currentStarOrigin + this.starY[i]);
				}
			}
		}
	}

	this.applyStageLighting = function()
	{
		if (this.stageDarknessAlpha > 0.0 && this.leftCurtain.width < (this.halfStageWidth - 20))
		{
			this.stageDarknessAlpha -= (this.textAlphaDelta / 2);
			if (this.stageDarknessAlpha < 0.0)
				this.stageDarknessAlpha = -0.001;
				
			this.applyStageLightingStyle();
		}
	}

	this.applyTextEffects = function()
	{
		// Fade in text if appropriate
		if (this.textAlpha < 1.0 && this.leftCurtain.width < 200)
		{
			this.textAlpha += this.textAlphaDelta;
			if (this.textAlpha > 1.0)
				this.textAlpha = 1.0;
				
			this.applyTextStyle();
		}
		
		if (!this.pageContentVisible && this.textAlpha > 0.03)
		{
			// Retrieve the featured tabs table, make it visible, but only after text has been 
			// fading in for a while and the curtains are open wide enough
			var mainTabComponent = document.getElementById("tabComponent");
			if (mainTabComponent)
			{
				mainTabComponent.style.display = "block";
			}
			// Must perform same logic on pageContent div, otherwise Mozilla draws big black
			// block before fading in (over curtains, yuch)
			var pageContentDiv = document.getElementById("pageContent");
			if (pageContentDiv)
			{
				pageContentDiv.style.display = "block";
			}
			// Don't run this code again.
			this.pageContentVisible = true;
		}
	}

	this.restartTextFadeIn = function()
	{
		this.textAlpha = this.initialTextAlpha;
		this.textAlphaDelta = this.initialTextAlphaDelta;
		this.applyTextStyle();
	}
	
	this.applyTextStyle = function()
	{
		this.mainContentElement.style.opacity = this.textAlpha;
		this.mainContentElement.style.filter = "alpha(opacity=" + (this.textAlpha * 100) + ")";
	}
	
	this.restartStageLighting = function()
	{
		this.stageDarknessAlpha = this.initialStageDarknessAlpha;
		this.applyStageLightingStyle();
	}
	
	this.applyStageLightingStyle = function()
	{
		this.stageDarknessElement.style.left = ((this.viewport.width / 2) - 490) + "px";
		this.stageDarknessElement.style.opacity = this.stageDarknessAlpha;
		this.stageDarknessElement.style.filter = "alpha(opacity=" + (this.stageDarknessAlpha * 100) + ")";
	}

	this.showPointingHands = function()
	{
		this.leftPointingHandSprite.visible();
		this.rightPointingHandSprite.visible();
	}

	this.hidePointingHands = function()
	{
		this.leftPointingHandSprite.invisible();
		this.rightPointingHandSprite.invisible();
	}

	//----======= Basic construction ====----

	this.prepare();
}

//----======= Event handling helpers ====----

getEventElement = function(e, cancelDefault)
{
	var isIE = false;
	if (!e)
	{
		e = window.event;   // for IE compatibility
		isIE = true;
	}
	
	// Find the event target element depending on browser
	var eventElement = null;
	if (e.srcElement)
	{
		// IE event model
		eventElement = e.srcElement;
		if (cancelDefault)
			e.returnValue = false;
	}
	if (e.target)
	{
		// Simple event model
		eventElement = e.target;
	}
	
	return eventElement;
}


//----======= Further special effects ====----


//==========================================
// Banner mouse effects
//==========================================
bannerMouseOver = function()
{
	//scene.banner.style.width = (scene.bannerWidths[scene.bannerCurrentSizeIndex] + 3) + "px";
}

bannerMouseOut = function()
{
	//scene.banner.style.width = (scene.bannerWidths[scene.bannerCurrentSizeIndex] - 3 ) + "px";
}

//==========================================
// Logo mouse effects
//==========================================
logoMouseOver = function()
{
	//scene.banner.style.width = (scene.bannerWidths[scene.bannerCurrentSizeIndex] + 3) + "px";
}

logoMouseOut = function()
{
	//scene.banner.style.width = (scene.bannerWidths[scene.bannerCurrentSizeIndex] - 3 ) + "px";
}

//==========================================
// Fans mouse effects
//==========================================
fansMouseOver = function()
{
	scene.mouseOverFans = true;
}

fansMouseOut = function()
{
	scene.mouseOverFans = false;
}

//==========================================
// Tickets mouse effects
//==========================================
ticketsMouseOver = function()
{
	scene.mouseOverTickets = true;
}

ticketsMouseOut = function()
{
	scene.mouseOverTickets = false;
}

//==========================================
// Stars mouse effects
//==========================================
starMouseOver = function(e)
{
	var eventElement = getEventElement(e);
	eventElement.style.left = -97 + "px";
}

starMouseOut = function(e)
{
	var eventElement = getEventElement(e);
	eventElement.style.left = 0 + "px";
}

//==========================================
// Top Hat mouse effects
//==========================================
topHatMouseOver = function(e)
{
	var eventElement = getEventElement(e);
	eventElement.style.left = -169 + "px";
	
	scene.mouseOverTopHat = true;
}

topHatMouseOut = function(e)
{
	var eventElement = getEventElement(e);
	eventElement.style.left = 0 + "px";
	
	scene.mouseOverTopHat = false;
}

//==========================================
// Cards mouse effects
//==========================================
cardsMouseOver = function(e)
{
	var eventElement = getEventElement(e);
	eventElement.style.left = -128 + "px";
	
	scene.mouseOverCards = true;
}

cardsMouseOut = function(e)
{
	var eventElement = getEventElement(e);
	eventElement.style.left = 0 + "px";
	
	scene.mouseOverCards = false;
}

//==========================================
// Beasties mouse effects
//==========================================
beastiesMouseOver = function(e)
{
	scene.mouseOverBeasties = true;
}

beastiesMouseOut = function(e)
{
	scene.mouseOverBeasties = false;
}

//==========================================
// Gallery mouse effects
//==========================================
galleryMouseOver = function(e)
{
	scene.mouseOverGalleryLogo = true;
}

galleryMouseOut = function(e)
{
	scene.mouseOverGalleryLogo = false;
}

//==========================================
// Nipple cap mouse effects
//==========================================
nippleCapMouseOver = function(e)
{
	scene.mouseOverNippleCap = true;
}

nippleCapMouseOut = function(e)
{
	scene.mouseOverNippleCap = false;
}

//=================================
//                                 Helpers
//=================================

//=================================
// Artist Profile Sliding
//=================================

function toggleArtisteProfiles(artisteNumber, direction)
{	
	if (direction == null)
	{
		// Go straight to specified artiste (shortcut)
		scene.currentArtisteProfile = artisteNumber;
		scene.profileTargetOffset = artisteNumber * (-600);
	}
	else
	{
		// Move incrementally through each profile
		scene.currentArtisteProfile += direction;
		if (scene.currentArtisteProfile >= scene.artisteProfileCount - 1)
			scene.currentArtisteProfile = scene.artisteProfileCount - 1;
		if (scene.currentArtisteProfile <= 0)
			scene.currentArtisteProfile = 0;
		scene.profileTargetOffset = scene.currentArtisteProfile * (-600);
	}
	
	// Set up the timer to slide to destination artiste
	if (scene.artisteSlideTimer)
	{
		clearInterval(scene.artisteSlideTimer);
	}
	if (scene.lowCPU)
		scene.artisteSlideTimer = setInterval(slideArtistes, 70);
	else
		scene.artisteSlideTimer = setInterval(slideArtistes, 50);
}

function slideArtistes()
{
	var reachedTarget = false;
	var threshold = 0.01;
	var distance = scene.profileTargetOffset - scene.profileOffset;
	if (Math.abs(distance) < threshold)
		reachedTarget = true; // close enough, stop animating
	scene.profileOffset += (distance * 0.1);
	
	for (var i = 0; i < scene.artisteProfileCount; i++)
	{
		var artisteProfile = document.getElementById("artisteProfile" + i);
		if (artisteProfile)
			artisteProfile.style.left = scene.profileOffset + (i * 600) + "px";
	}
		
	if (reachedTarget)
		clearInterval(scene.artisteSlideTimer);
}

//=================================
// Event Profile Sliding
//=================================

function toggleEventsProfiles(direction)
{
	scene.currentEventProfile += direction;
		
	if (scene.currentEventProfile >= scene.eventProfileCount - 1)
		scene.currentEventProfile = scene.eventProfileCount - 1;
	if (scene.currentEventProfile < 0)
		scene.currentEventProfile = 0;
		
	scene.eventProfileTargetOffset = scene.currentEventProfile * (-600);
	
	if (scene.eventProfileSlideTimer)
	{
		clearInterval(scene.eventProfileSlideTimer);
	}
	if (scene.lowCPU)
		scene.eventProfileSlideTimer = setInterval(slideNextEvent, 70);
	else
		scene.eventProfileSlideTimer = setInterval(slideNextEvent, 50);
}

function slideNextEvent()
{
	var reachedTarget = false;
	var threshold = 0.01;
	var distance = scene.eventProfileTargetOffset - scene.eventProfileOffset;
	if (Math.abs(distance) < threshold)
		reachedTarget = true; // close enough, stop animating
	scene.eventProfileOffset += (distance * 0.1);

	for (var i = 0; i < scene.eventProfileCount; i++)
	{
		var eventProfile = document.getElementById("eventProfile" + i);
		if (eventProfile)
			eventProfile.style.left = scene.eventProfileOffset + (i * 600) + "px";
	}
	
	if (reachedTarget)
		clearInterval(scene.eventProfileSlideTimer);
}

