// ===========================================================================================
// Copyright 2010
// by Asset Generation Elite Services, Inc.
// ===========================================================================================
function shuffleObj(callerProvidedPosFunk, namebase, frameloc, numvisi, display_options)
{
	this.lox      = new Array();		// This holds info about the "target" cardz locations
	this.cardz    = new Array();		// Array of "cardz" (HTML div Elements that can be dynamically moved)
	this.scenez   = new Array();		// Array of Scenes specs (HTML content) (to be displayed on cardz)
	this.disp_opt = display_options;	// Passed to scene whenever generating inner HTML

	this.scene0th = 0;					// scene index that will be loaded if we "slide up"
	this.sceneNth = 0;					// scene index that will be loaded if we "slide down"

	callerProvidedPosFunk(this, namebase, frameloc, numvisi);	// Create all the Lox & Cardz
}

shuffleObj.dispOptSet  = function(opt)
{
	this.disp_opt = opt;
}

shuffleObj.prototype.sceneAlign  = function(index)
{
	if (this.scenez.length > 0)
	{
		this.scene0th = index;
		while (this.scene0th >= this.scenez.length) this.scene0th -= this.scenez.length;

		this.sceneNth = this.scene0th + this.cardz.length + 1;
		while (this.sceneNth >= this.scenez.length) this.sceneNth -= this.scenez.length;
	}
}

shuffleObj.prototype.posAdd  = function(name, loc)
{
	if (loc == null)
		return;

	this.lox.push(loc.clone());
	this.cardz.push(new cardzObj(name, loc));
	this.sceneAlign(this.scene0th);
}

shuffleObj.prototype.posDraw = function(i, eclass)		// Add HTML element to document
{
	this.cardz[i].Open(eclass);
	this.cardz[i].Close();
}

shuffleObj.prototype.posDrawAll = function(eclass)		// Add All HTML elements to document
{
	for( var i = 0; i < this.cardz.length; i++)
	{
		this.posDraw(i, eclass);
	}
}

shuffleObj.prototype.sceneAdd  = function(scene)
{
	if (scene == null)
		return;

	this.scenez.push(scene);
	this.sceneAlign(this.scene0th);
}

shuffleObj.prototype.sceneLystApply  = function(lyst)
{
	var oldLyst = this.scenez;
	this.scenez   = new Array();		// re-init Array of Scenes
	for(var i = 0; i < lyst.length; i++)
		this.scenez.push(lyst[i]);
	this.sceneAlign(0);
	
	return(oldLyst);					// return olde lyste ... in case someone wants it for later
}

shuffleObj.prototype.InvisiOne = function(i, deltaT)
{
	var fadeaway = this.cardz[i].curr.clone();
	fadeaway.opacitySet(0);
	this.cardz[i].xlateTarget(fadeaway, deltaT);
}

shuffleObj.prototype.InvisiAll = function(deltaT)
{
	// Make all cardz invisible
	for(var i = 0; i < this.cardz.length; i++)
		this.InvisiOne(i, deltaT);
}

shuffleObj.prototype.RestoreOne = function(i, deltaT)
{
	this.cardz[i].xlateTarget(this.cardz[i].prev, deltaT);
}

shuffleObj.prototype.RestoreAll = function(deltaT)
{
	// Restore all cardz to "previous" position (and opacity)
	for(var i = 0; i < this.cardz.length; i++)
		this.RestoreOne(i, deltaT);
}

shuffleObj.prototype.FillOne = function(i, pos)
{
	// Fill cardz at index "i" from scene at index "pos"ition
	this.cardz[i].elemSceneSet(pos, this.scenez[pos], this.disp_opt);
}

shuffleObj.prototype.FillAll = function()
{
	// Fill All cardz from scenes at indices (0th,Nth) ... "non-inclusive"
	var pos = this.scene0th + 1;
	for(var i = 0; i < this.cardz.length; i++, pos++)
	{
		if (pos >= this.scenez.length) pos = 0;
		this.FillOne(i, pos);
	}
}

shuffleObj.prototype.cardzMoveOne = function(i, loc, rate)
{
	this.cardz[i].xlateTarget(loc, rate);
}

shuffleObj.prototype.cardzMoveAllPerLox = function(rate)
{
	for(var i = 0; i < this.cardz.length; i++)
	{
		this.cardzMoveOne(i, this.lox[i], rate);
	}
}

shuffleObj.prototype.Start = function(deltaT)
{
	this.InvisiAll(1);
	this.FillAll();
	this.cardzMoveAllPerLox(deltaT);	// fade in while moving to required places.
}

shuffleObj.prototype.updateVisualOne = function(i, pos, deltaT)
{
	this.InvisiOne(i, deltaT);			// fade out
	this.FillOne(i, pos);				// update content of all cardz
	this.RestoreOne(i, deltaT);			// fade in
}

shuffleObj.prototype.updateVisualAll = function(i, pos, deltaT)
{
	// Fill All cardz from scenes at indices (0th,Nth) ... "non-inclusive"
	var pos = this.scene0th + 1;
	for(var i = 0; i < this.cardz.length; i++, pos++)
	{
		if (pos >= this.scenez.length) pos = 0;
		this.updateVisualOne(i, pos, deltaT);
	}
}

shuffleObj.prototype.updateVisualAllAtOnce = function(deltaT)
{
	this.InvisiAll(deltaT);				// fade out
	this.FillAll();						// update content of all cardz
	this.RestoreAll(deltaT);			// fade in
}

shuffleObj.prototype.slideUp   = function(num, animate, rate)	// Move cardz toward head of lox lyst
{
	while (num-- > 0)
	{
		this.FillOne(0, this.sceneNth);
		this.cardz.push(this.cardz.shift());		// Remove from head, add to tail

		if (++(this.scene0th) >= this.scenez.length) this.scene0th = 0;
		if (++(this.sceneNth) >= this.scenez.length) this.sceneNth = 0;

		if (animate)
			this.cardzMoveAllPerLox(rate);
	}
}

shuffleObj.prototype.slideDown = function(num, animate, rate)	// Move cardz toward tail of lox lyst
{
	while (num++ < 0)
	{
		this.cardz.unshift(this.cardz.pop());		// Remove from tail, add to head
		this.FillOne(0, this.scene0th);

		if (--(this.scene0th) < 0) this.scene0th = this.scenez.length - 1;
		if (--(this.sceneNth) < 0) this.sceneNth = this.scenez.length - 1;
		
		if (animate)
			this.cardzMoveAllPerLox(rate);
	}
}

shuffleObj.prototype.slide     = function(dir, animate, rate)	// +/- dir allows "slide up" & "slide down"
{
	if (dir == 0) return;

	if (dir > 0)
		this.slideUp(dir, animate, rate);
	else
		this.slideDown(dir, animate, rate);
}

shuffleObj.prototype.moveFancyAnimated = function(n, rate)				// +/-   n allows "move left N" & "move right N"
{
	if (n == 0) return;
	
	var i = Math.abs(n);
	n = parseInt(n/i);			// Now n is only +/- 1
	
	while(i-- >= 0)
	{
		this.slide(n, true, parseInt(rate / (i+1)));		// spin fast for longer movement, slower as we approach goal
	}
}

// ===========================================================================================
function curvilinearObj()
{
	this.posi   = null;
	this.clSpec = new Array();
}

curvilinearObj.prototype.addTerm = function(loc)
{
	this.clSpec.push(loc);
	if (this.posi == null)
		this.posi = loc;		// Reference to 1st Term
}

curvilinearObj.prototype.pos = function()
{
	return(this.posi);
}

curvilinearObj.prototype.next = function()
{
	for(var i = 1; i < this.clSpec.length; i++)
		this.clSpec[i-1].add(this.clSpec[i]);
}

// ===========================================================================================
// Highly Generalized Function .. from which to build various interesting PosFunk :-)
function PosFunk_Linear_Bevel_Ends(shuff, namebase, foreloc, numfore, forecurve, numvisi, visicurve, numaft, aftcurve, aftloc)
{
	var i = 0;

	shuff.posAdd(namebase + "_fore_cap", foreloc);				// Front Terminus
	i = 0;
	while (i++ < numfore)										// Front Bevel
	{
		shuff.posAdd(namebase + "_fore" + i, forecurve.pos());
		forecurve.next();
	}
	i = 0;
	while (i++ < numvisi)										// Main Array
	{
		shuff.posAdd(namebase + "_visi" + i, visicurve.pos());
		visicurve.next();
	}
	i = 0;
	while (i++ < numaft)										// End Bevel
	{
		shuff.posAdd(namebase + "_aft" + i, aftcurve.pos());
		aftcurve.next();
	}
	shuff.posAdd(namebase + "_aft_cap", aftloc);					// End Terminus
}

// ===========================================================================================
// Many Varieties of Pos Creation Functions!!  All Usable with the Shuffle Object :-)
function PosFunk_Example(shuff, namebase, frameloc, numvisi)
{
	// DO NOT ACTUALLY USE OR CALL THIS FUNCTION AT RUNTIME :-)  IT'S A REMINDER OF THE CALLING SPEC
	// PosFunk Functions will be attached to Prototype of a shuffleObj before being called
	// Therefore "this" refers to the shuffleObj
}

function PosFunk_SlideShow_Simple(shuff, namebase, frameloc, numvisi)	// Ignoring numvisi ... pretend that it's "1"
{
	var invisilok = frameloc.clone();
	invisilok.opacitySet(0);

	var visiSpek  = new curvilinearObj();
	visiSpek.addTerm(frameloc());
	
	PosFunk_Linear_Bevel_Ends(shuff, namebase, invisilok, 0, null, 1, visiSpek, 0, null, invisilok);
}

function PosFunk_BoxStep_Horizontal(shuff, namebase, frameloc, numvisi)
//   "SIDE VIEW":
//
//   ======= ======= ======= ... ======= ======= =======  Visi
//   =======                                     =======  Fore/Aft
//   - - - -                                     - - - -  Invisible Fore/Aft
//
{
	if (numvisi < 1) numvisi = 1;
	var dubya      = parseInt(frameloc.w / numvisi);
	var zstep      = 10;

	var invisiFore = frameloc.clone();
	invisiFore.w   = dubya;
	invisiFore.x   = 0;
	invisiFore.y   = 0;

	var forelok    = invisiFore.clone();
	forelok.z     += zstep;
	var foreSpek   = new curvilinearObj();
	foreSpek.addTerm(forelok);

	var visilok    = forelok.clone();
	visilok.z     += zstep;
	var visistep   = new locObj(dubya, 0, 0, 0, 0, 0);		// Line of Visibles steps horizontally by dubya
	var visiSpek   = new curvilinearObj();
	visiSpek.addTerm(visilok);
	visiSpek.addTerm(visistep);

	var aftlok     = forelok.clone();
	aftlok.x      += dubya * (numvisi - 1);
	var aftSpek    = new curvilinearObj();
	aftSpek.addTerm(aftlok);

	invisiFore.opacitySet(0);
	var invisiAft  = invisiFore.clone();
	invisiAft.x   += dubya * (numvisi - 1);

	PosFunk_Linear_Bevel_Ends(shuff, namebase, invisiFore, 1, foreSpek, numvisi, visiSpek, 1, aftSpek, invisiAft);
}

function PosFunk_BoxStep_Vertical(shuff, namebase, frameloc, numvisi)
//   "SIDE VIEW" (but only if you turn the picture 90 degrees):
//
//   ======= ======= ======= ... ======= ======= =======  Visi
//   =======                                     =======  Fore/Aft
//   - - - -                                     - - - -  Invisible Fore/Aft
//
{
	if (numvisi < 1) numvisi = 1;
	var hstep      = parseInt(frameloc.h / numvisi);
	var zstep      = 10;

	var invisiFore = frameloc.clone();
	invisiFore.h   = hstep;
	invisiFore.x   = 0;
	invisiFore.y   = 0;

	var forelok    = invisiFore.clone();
	forelok.z     += zstep;
	var foreSpek   = new curvilinearObj();
	foreSpek.addTerm(forelok);

	var visilok    = forelok.clone();
	visilok.z     += zstep;
	var visistep   = new locObj(0, hstep, 0, 0, 0, 0);		// Line of Visibles steps vertically by hstep
	var visiSpek   = new curvilinearObj();
	visiSpek.addTerm(visilok);
	visiSpek.addTerm(visistep);

	var aftlok     = forelok.clone();
	aftlok.y      += hstep * (numvisi - 1);
	var aftSpek    = new curvilinearObj();
	aftSpek.addTerm(aftlok);

	invisiFore.opacitySet(0);
	var invisiAft  = invisiFore.clone();
	invisiAft.y   += hstep * (numvisi - 1);

	PosFunk_Linear_Bevel_Ends(shuff, namebase, invisiFore, 1, foreSpek, numvisi, visiSpek, 1, aftSpek, invisiAft);
}

function PosFunk_Rotunda_Horizontal(shuff, namebase, frameloc, numvisi)
//   "SIDE VIEW":
//
//             ======= ======= ======= ... ======= ======= =======           Visi
//        ======                                                 ======      Fore/Aft (Smaller)
//     =====                                                         =====   Fore/Aft (2nd Layer, Smaller Still)
//    ====                                                             ====  Fore/Aft (3rd Layer, Even Smaller Still)
//    -  -                                                             -  -  Invisible Fore/Aft
//
{
	if (numvisi < 1) numvisi = 1;
	var aych       = frameloc.h;
	var dubya      = parseInt(frameloc.w / (numvisi + (1/2)));
	var zstep      = 10;
	var bevelcount = 2;								// This code currently only supports bevelcount == 2

	var invisiFore = frameloc.clone();
	invisiFore.x   = 0;
	invisiFore.y   = 0;
	invisiFore.w   = dubya;
	invisiFore.h   = aych;

	var forelok    = invisiFore.clone();
	forelok.z     += zstep;
	var forestep   = forelok.clone();
	forestep.x     = parseInt(    dubya /16);
	forestep.y     = 0;
	forestep.w     = 0;
	forestep.h     = 0;
	forestep.z     = zstep;
	var foreSpek   = new curvilinearObj();
	foreSpek.addTerm(forelok);
	foreSpek.addTerm(forestep);

	var visilok    = frameloc.clone();
	visilok.x      = parseInt(dubya / 4);
	visilok.y      = 0;
	visilok.w      = dubya;
	visilok.z     += (bevelcount + 1) * zstep;
	var visistep   = new locObj(dubya, 0, 0, 0, 0, 0);		// Line of Visibles steps horizontally by dubya
	var visiSpek   = new curvilinearObj();
	visiSpek.addTerm(visilok);
	visiSpek.addTerm(visistep);

	var aftlok     = visilok.clone();
	aftlok.x       = parseInt(dubya * (numvisi - (9 /16)));		// Yes, I'm sure
	aftlok.z      -= zstep;
	var aftstep    = aftlok.clone();
	aftstep.x      = parseInt(    dubya / 16);
	aftstep.z      = -zstep;
	aftstep.w      = 0;
	aftstep.h      = 0;
	var aftSpek    = new curvilinearObj();
	aftSpek.addTerm(aftlok);
	aftSpek.addTerm(aftstep);

	invisiFore.opacitySet(0);
	var invisiAft  = invisiFore.clone();
	invisiAft.x    = parseInt(dubya * (numvisi - (1 / 2)));		// Yes...I'm sure of this one, too

	PosFunk_Linear_Bevel_Ends(shuff, namebase, invisiFore, bevelcount, foreSpek, numvisi, visiSpek, bevelcount, aftSpek, invisiAft);
}

function PosFunk_Rotunda_Vertical(shuff, namebase, frameloc, numvisi)
//   "SIDE VIEW" (but only if you turn the picture 90 degrees):
//
//             ======= ======= ======= ... ======= ======= =======           Visi
//        ======                                                 ======      Fore/Aft (Smaller)
//     =====                                                         =====   Fore/Aft (2nd Layer, Smaller Still)
//    ====                                                             ====  Fore/Aft (3rd Layer, Even Smaller Still)
//    -  -                                                             -  -  Invisible Fore/Aft
//
{
	if (numvisi < 1) numvisi = 1;
	var aych       = parseInt(frameloc.h / (numvisi + 2));
	var dubya      = frameloc.w;
	var zstep      = 10;
	var bevelcount = 3;								// This code currently only supports bevelcount == 3

	var invisiFore = frameloc.clone();
	invisiFore.w   = parseInt(    dubya /  4);
	invisiFore.h   = parseInt(    aych  /  4);
	invisiFore.x   = parseInt(3 * dubya /  8);
	invisiFore.y   = parseInt(    aych  / 16);

	var forelok    = invisiFore.clone();
	forelok.z     += zstep;
	var forestep   = forelok.clone();
	forestep.x     = -parseInt(   dubya  / 8);
	forestep.z     = zstep;
	var forecurve  = new locObj(0, parseInt(3 * aych  / 16), 0, 0, 0, 0);
	var foreSpek   = new curvilinearObj();
	foreSpek.addTerm(forelok);
	foreSpek.addTerm(forestep);
	foreSpek.addTerm(forecurve);

	var visilok    = frameloc.clone();
	visilok.h      = aych;
	visilok.y      = aych;
	visilok.x      = 0;
	visilok.z     += (bevelcount + 1) * zstep;
	var visistep   = new locObj(0, aych, 0, 0, 0, 0);		// Line of Visibles steps vertically by aych
	var visiSpek   = new curvilinearObj();
	visiSpek.addTerm(visilok);
	visiSpek.addTerm(visistep);

	var aftlok     = visilok.clone();
	aftlok.y       = parseInt(aych * (numvisi + (7 / 8)));	// Yes...really!  I triple-checked this
	aftlok.x       = parseInt(   dubya  / 8);
	aftlok.z      -= zstep;
	aftlok.w       = parseInt(3 * dubya / 4);
	aftlok.h       = parseInt(3 * aych  / 4);
	var aftstep    = aftlok.clone();
	aftstep.y      = parseInt(aych / 2);
	aftstep.z      = -zstep;
	aftstep.w      = -parseInt(    dubya / 4);
	aftstep.h      = -parseInt(    aych  / 4);
	var aftcurve   = new locObj(0, -parseInt(3 * aych  / 16), 0, 0, 0, 0);
	var aftSpek    = new curvilinearObj();
	aftSpek.addTerm(aftlok);
	aftSpek.addTerm(aftstep);
	aftSpek.addTerm(aftcurve);

	invisiFore.opacitySet(0);
	var invisiAft  = invisiFore.clone();
	invisiAft.y    = parseInt(aych * (numvisi + (27 / 16)));	// Yes...I'm sure of this one, too

	PosFunk_Linear_Bevel_Ends(shuff, namebase, invisiFore, bevelcount, foreSpek, numvisi, visiSpek, bevelcount, aftSpek, invisiAft);
}

// ===========================================================================================
