///////////////////////////////////////////////////////////////////////////////
//
//  xamlObjects.js   			version 1.0
//	2007 Julia Yu, Lenny Burdette
//
//  These objects  have a 1 on 1 relation with a XAML file
//	And they inherit from xamlObjects
//
//  FUNCTIONS:
//			Loc.clearable
//			Loc.xamlObject
//			Loc.textArea
//			Loc.panel
//			Loc.graphic
//			Loc.worldMap
//			Loc.button
//			Loc.rotator
//			
//	DEPENDENCIES:
//			Utils.js
//			StageObjects.js
//
///////////////////////////////////////////////////////////////////////////////

if ( !window.Loc ) { window.Loc = {}; }

/**
 * Clearable is a parent class objects may extend this
 * if they contain child objects that need to be removed
 */
Loc.clearable = function() {
	this.children = {}; 						// keep track of children elements
}

Loc.clearable.prototype.addChild = function(oType, oParams) {
	
	if (!this.children) {
		Loc.debug(this.name + " I have no children");
		return;	
	}

	if (!this.children[oType]) {
		this.children[oType] = [];				
	}
	if (!oParams.parent && this.selfContent) {
			oParams.parent = this.selfContent;						// no parent host specified, use self if it exists
	}
	if (!oParams.name) {
		oParams.name = oType + "_" + this.children[oType].length;	// make a name if no name
	}
	
	this.children[oType].push(oParams.name); 	// put child name in memory
	return Loc.make(oType, oParams); 			// make the child
}

Loc.clearable.prototype.clearChildren = function(){
	if (!this.selfContent) {
		Loc.debug("existental crises for : " + this.name); 	// no content area 
		return false;	
	}
	
	this.selfContent.children.clear(); 						// all xml nodes removed
	
	for (var childType in this.children) {
		var child = this.children[childType]; 				
		for (var z in child) {
			var childName = child[z];
			
			if (Loc.tracker[childType][childName].unload) {
				Loc.tracker[childType][childName].unload();
			}
			Loc.tracker[childType][childName] = null;
			//Loc.debug("removing: " + childType + " " + childName + " from parent: " + this.name);	
			
		}
	}
	
	this.children = {}; // set children object to nothing
}

Loc.clearable.prototype.makeNewChildren = function(parentContent, parentType, additionalParams){
	this.clearChildren();
	
	for (var contentType in parentContent) {
		var contentTypeParamsArray = parentContent[contentType]; // its an array of this contenttype
		
		for (var i in contentTypeParamsArray) {
			var contentTypeParams=contentTypeParamsArray[i];
			
			// additional parameters passed in are assigned and passed on
			if (additionalParams){
				for (var param in additionalParams) {
					contentTypeParams[param] = additionalParams[param];
				}
			}
			
			contentTypeParams.parent = this.selfContent;
			if (!contentTypeParams.name) {
				contentTypeParams.name = parentType + "_" + i + "_" + contentType; // should use name if it exists
			}
			
			this.addChild(contentType, contentTypeParams);
		}
	}
}

/**
 * Parent of stage object with their own xaml piece
 */
Loc.xamlObject = function() {
	this.test2 = "i am xamlobj";
	this.host =  Loc.root; 		// the parent element where self resides
	this.self = null; 			// self is the canvas that is created
	this.selfContent = null;	// self content contains possible children
	this.top = 0;				// positions the self
	this.left = 0;
	this.stop = false;			// stop init if this is true
	this.children = {};
}

Loc.extend(Loc.xamlObject, Loc.clearable);

Loc.xamlObject.prototype.init = function(){} 

Loc.xamlObject.prototype.preload = function(){}

Loc.xamlObject.prototype.unload = function() {
	this.stop = true;
}

Loc.xamlObject.prototype.loaded = function(xamlString, mySelf) {
	if (this.stop) { return; }
	
	this.addToHost(xamlString);
	if (mySelf) {
		this.self = this.fragment.findName(mySelf);
	}
	this.position(this.top, this.left);
	this.init();
}
	
Loc.xamlObject.prototype.addToHost = function(xamlString) {
	this.fragment = Loc.plugin.content.createFromXaml(xamlString, true);
	this.host.children.add(this.fragment);
}
	
Loc.xamlObject.prototype.position = function(top, left) {
	if (top) {
		this.self['Canvas.Top'] = top;
	}
	if (left) {
		this.self['Canvas.Left'] = left;
	}
}
	
Loc.xamlObject.prototype.setSource = function(newSource) {
	if (newSource && this.selfContent) {
		this.selfContent.Source = newSource;
	}
}
	
Loc.xamlObject.prototype.show = function() {
	if (this.hideAnimation) {
		this.hideAnimation.Stop();
	}
	if (this.showAnimation) {
		this.showAnimation.Begin();
	}
}
	
Loc.xamlObject.prototype.hide = function() {
	if (this.showAnimation) {
		try {
			this.showAnimation.Stop();
		} catch(e) {}
	}
	if (this.hideAnimation) {
		try {
			this.hideAnimation.Begin();
		} catch(e) {}
	}
}

/**
 * The text area which paginates
 */
Loc.textArea = function(params) {
	this.name = params.name;
	this.host = params.parent || Loc.root;
	this.top = params.top || 20;
	this.left = params.left || 50;
	this.height = params.height || 185;
	this.textContent = params.content || "";
	
	this.loaded(Loc.interfaceXaml.getResponseText('textArea.xaml'), "text_box");
}

Loc.extend(Loc.textArea, Loc.xamlObject);

Loc.textArea.prototype.init = function() {
	this.content = this.fragment.findName("text_content");
	this.showAnimation = this.fragment.findName("text_appear");
	this.hideAnimation = this.fragment.findName("text_disappear");		
	
	this.formatText(this.content, this.textContent);
	this.fixHeight();
	this.initEvents();
	this.setupPagination();
	this.show();
}

Loc.textArea.prototype.fixHeight = function() {
	this.fragment.findName('text_box_bg').height = this.height;
	this.fragment.findName('text_box_clip').clip = 'M0,0 240,0 240,' + this.height + ' 0,' + this.height;
	this.fragment.findName('pagingButtons')['Canvas.Top'] = this.height + 5;
}

Loc.textArea.prototype.initEvents = function() {
	this.pageDownIcon = this.fragment.findName('pageDown');
	this.pageUpIcon = this.fragment.findName('pageUp');
	this.pageUpIcon.opacity = 0.6;
	this.pageDownIcon.opacity = 0.6;
	
	this.pageDownBtn = this.fragment.findName('pageDown_hit');
	this.pageDownBtn.addEventListener('MouseLeftButtonDown', this.pageDown.bind(this));
	this.pageUpBtn = this.fragment.findName('pageUp_hit');
	this.pageUpBtn.addEventListener('MouseLeftButtonDown', this.pageUp.bind(this));
	
	this.pageDownBtn.addEventListener('MouseEnter', function() {
		this.pageDownIcon.opacity = 1;
	}.bind(this));
	this.pageDownBtn.addEventListener('MouseLeave', function() {
		this.pageDownIcon.opacity = .6;
	}.bind(this));
	this.pageUpBtn.addEventListener('MouseEnter', function() {
		this.pageUpIcon.opacity = 1;
	}.bind(this));
	this.pageUpBtn.addEventListener('MouseLeave', function() {
		this.pageUpIcon.opacity = .6;
	}.bind(this));
}

Loc.textArea.prototype.setupPagination = function() {	
	this.pageSize = this.fragment.findName('text_box_bg').height;
	this.numPages = Math.ceil(this.content.actualHeight / this.pageSize * 2);
	if (this.numPages > 3) { this.numPages = this.numPages-1; }
	this.numPages = this.numPages == 2 ? 1 : this.numPages;
	this.currentPage = 1;
	this.content['Canvas.Top'] = 0;
	this.toggleButtons();
}

Loc.textArea.prototype.pageDown = function() {
	if (this.currentPage < this.numPages) {
		this.currentPage++;
		var newTop = (this.currentPage - 1) * (-this.pageSize / 2);
		if (this.moveTween) {
			this.moveTween.stop();
		}
		this.moveTween = new Loc.Tween({ obj: this.content, prop: 'canvas.top', end: newTop, func: Loc.Tween.easeOutCubic }, 1.2).startFromHere();
		// this.content['Canvas.Top'] = (this.currentPage - 1) * (-this.pageSize / 2);
	}
	this.toggleButtons();
}

Loc.textArea.prototype.pageUp = function() {
	if (this.currentPage > 1) {
		this.currentPage--;
		var newTop = (this.currentPage - 1) * (-this.pageSize / 2);
		if (this.moveTween) {
			this.moveTween.stop();
		}
		this.moveTween = new Loc.Tween({ obj: this.content, prop: 'canvas.top', end: newTop, func: Loc.Tween.easeOutCubic }, 1.2).startFromHere();
		// this.content['Canvas.Top'] = (this.currentPage - 1) * (-this.pageSize / 2);
	}
	this.toggleButtons();
}

Loc.textArea.prototype.toggleButtons = function() {
	if (!this.name) {return;}

	if (this.numPages == 1) {
		this.pageDownIcon.visibility = 'collapsed';
		this.pageUpIcon.visibility = 'collapsed';
	} 
	if (this.currentPage >= this.numPages) {
		this.pageDownBtn.visibility = 'collapsed';
		this.pageDownIcon.opacity = .6;
	} else {
		this.pageDownBtn.visibility = 'visible';
	}
	
	if (this.currentPage <= 1) {
		 this.pageUpBtn.visibility = 'collapsed';
		this.pageUpIcon.opacity = .6;
	} else {
		this.pageUpBtn.visibility = 'visible';
	}
}

/* OMG ITS SO UGLY */
Loc.textArea.prototype.formatText = function(block, text) {
	if (text == null) {
		Loc.debug("zOMG i have no text!!! " + this.name);
		return;
	}
	
	// no line breaks YAY
	if (text.search(/\<P\>/i) == -1) {
		block.Text = text;
		return;
	}
	
	block.text = '';
	
	try {
		while (block.inlines[0]) {
			block.inlines.removeAt(0);
		}	
	} catch(e) {}
	
	var	textPieces = text.split(/\<P\>/i),
		run = null,
		linebreak = null,
		linebreak2 = null,
		pieces;
		
	for (var i = 0, piece = null; piece = textPieces[i]; i++) {
		if (piece.search(/\<BR\>/gi) != -1) {
			console.log("br found?");
			pieces = piece.split(/\<BR\>/i);
			for (var j = 0, newpiece = null; newpiece = pieces[j]; j++) {
				run = Loc.plugin.content.createFromXaml('<Run/>', true);
				linebreak = Loc.plugin.content.createFromXaml('<LineBreak/>', true);
				run.text = newpiece;
				block.inlines.add(run);
				block.inlines.add(linebreak);
			}
		} else {
			
			linebreak = Loc.plugin.content.createFromXaml('<LineBreak/>', true);
			linebreak2 = Loc.plugin.content.createFromXaml('<LineBreak/>', true);
			
			//Loc.parseItalics(block, piece);
			
			run = Loc.plugin.content.createFromXaml('<Run/>', true);
			run.text = piece;
			block.inlines.add(run);
			
			block.inlines.add(linebreak);
			block.inlines.add(linebreak2);	
		}
	}
}

/**
 * The content panel generic object
 */
Loc.panel = function(params) {
	this.name = params.name; 	
	this.host = params.parent || Loc.root; 		
	this.top = params.top || 140;
	this.left = params.left || 20;
	
	this.loaded(Loc.interfaceXaml.getResponseText('panel.xaml'), "panel");
}

Loc.extend(Loc.panel, Loc.xamlObject);

Loc.panel.prototype.init = function(params) {
	this.showAnimation = this.fragment.findName("panel_slide_out");
	this.hideAnimation = this.fragment.findName("panel_slide_in");
	this.selfContent = this.fragment.findName("panel_content");
	
	this.show();
	
	Loc.dispatch.subscribe("assetClick", this.name, this.listenAssetClick.bind(this));
	Loc.dispatch.subscribe("pageLoad", this.name, this.listenPageLoad.bind(this));
	Loc.dispatch.subscribe("subPageLoad", this.name, this.listenSubPageLoad.bind(this));
	Loc.dispatch.broadcast("pageLoad", "home"); // should be when panel, subtitle, and stage has been made
}

Loc.panel.prototype.listenPageLoad = function(pageName) {
	this.show();
	var myPage = Loc.page[pageName];
	if (myPage.panelContent) {
		this.makeNewChildren(myPage.panelContent, "panel");
	}
}
	
Loc.panel.prototype.listenAssetClick = function(assetName) {
	var myAsset = Loc.assetContent[assetName];
	var myVideo = "cmn/video/location_" + myAsset.location + ".wmv";
	
	this.clearChildren();

	this.addChild('textArea', {top: 20, left: 30, height: 195, content: myAsset.description});
	this.addChild('worldMap', {top: 260, left: 58, source: myVideo });
	this.show();
}

Loc.panel.prototype.listenSubPageLoad = function(){
	this.listenAssetClick(Loc.tracker.currentAsset);
}

/**
 * Generic image
 */
Loc.graphic = function(params) {
	this.name = params.name; 	
	this.host = params.parent || Loc.root; 	
	this.width = params.width || 371;
	this.height = params.height || 326;
	this.top = params.top || 0;
	this.left = params.left || 0;
	this.source = params.source || ""; 
	this.notLoaded = true;
	this.children = {};
	
	this.loaded(Loc.interfaceXaml.getResponseText('graphic.xaml'), "graphic");
}

Loc.extend(Loc.graphic, Loc.xamlObject);

Loc.graphic.prototype.imageLoaded = function() {
	this.preloader.stop();
	this.preloader = null;
	this.setSource(this.source); 
	this.position(this.top, this.left);
}

Loc.graphic.prototype.init = function(params) {
	this.selfContent = this.fragment.findName('myImage');
	
	var pTop = this.height/2;
	var pLeft = this.width/2-10;

	this.preloader = Loc.make('Preloader', {name: this.name+'_preloader', top: pTop, left: pLeft, parent: this.fragment });
	
	if (this.source) {
		this.downloadImage = new Silverlight.Downloader({
		    resource: this.source,
		    plugin: Loc.plugin,
		    onComplete: this.imageLoaded.bind(this),
		    name: this.name
		});
	}
}

/**
 * World Map
 */
Loc.worldMap = function(params) {
	this.name = params.name; 	
	this.host = params.parent || Loc.root; 		
	this.top = params.top || 0;
	this.left = params.left || 0;
	this.source = params.source || ""; 
	
	this.loaded(Loc.interfaceXaml.getResponseText('worldMap.xaml'), "worldMap");
}

Loc.extend(Loc.worldMap, Loc.xamlObject);

Loc.worldMap.prototype.mapLoaded = function(params) {
	this.setSource(this.source);
	this.show();
	this.position(this.top, this.left);
}

Loc.worldMap.prototype.init = function(params) {
	this.selfContent = this.fragment.findName('mapVideo');
	this.showAnimation = this.fragment.findName("where_appear");
	this.hideAnimation = this.fragment.findName("where_disappear");		
	
	if (this.source) {
		// show the map after the video has finished downloading
		this.downloadImage = new Silverlight.Downloader({
		    resource: this.source,
		    plugin: Loc.plugin,
		    onComplete: this.mapLoaded.bind(this),
		    name: this.name
		}); 
	}
	
}

/**
 * Generic button
 */
Loc.button = function(params) {
	this.name = params.name; 	
	this.host = params.parent || Loc.root; 		
	this.top = params.top || 0;
	this.left = params.left || 0;
	this.type = params.type || "text"; 				// can be text type or graphic type
	this.width = params.w || 100;					// hit area def
	this.height = params.h || 15;					
	this.imageSource = params.imageSource || "";
	this.margin = params.margin || 3;
	this.marginV = params.marginV || this.margin;				
	this.marginH = params.marginH || this.margin;			
	this.goToPage = params.page || "home";			// default action is to go to page
	this.buttonText = params.text || "";	
	this.click = params.click;						// click handler
	this.bgFill = params.bgFill || "gray";
	
	this.loaded(Loc.interfaceXaml.getResponseText('button.xaml'), "button");
}

Loc.extend(Loc.button, Loc.xamlObject);

Loc.button.prototype.init = function(params) {
	
	this.hitArea = this.fragment.findName('button_hit');
	this.textArea = this.fragment.findName('button_text');
	this.background = this.fragment.findName('button_background');
	this.image = this.fragment.findName('button_image');
	
	this.textArea['Canvas.Top'] = this.marginV;
	this.textArea['Canvas.Left'] = this.marginH;
	
	if ((this.type == "text") && this.buttonText){
		this.textArea.Text = this.buttonText;
		this.background.fill = this.bgFill;
		this.background.visibility = "Collapsed";
		this.resizeButtonBackground();
	}
	
	if ((this.type == "image") && this.imageSource) {
		this.image.opacity = '0.8'
		this.image.source = this.imageSource;
		this.hitArea.width = this.width;
		this.hitArea.height = this.height;
	}

	this.hitArea.addEventListener('MouseLeftButtonDown', this.buttonClick.bind(this));
	this.hitArea.addEventListener('MouseEnter', this.buttonEnter.bind(this));
	this.hitArea.addEventListener('MouseLeave', this.buttonLeave.bind(this));
}

Loc.button.prototype.changeText = function(newText) {
	if (newText) {
		this.textArea.Text = newText;
		this.resizeButtonBackground();
	}
}

Loc.button.prototype.resizeButtonBackground = function(newText) {
	this.width = this.textArea.actualWidth;
	this.height = this.textArea.actualHeight;

	this.background.width = this.width + this.marginH*2;
	this.background.height = this.height + this.marginV*2;
	
	this.hitArea.width = this.width + this.marginH*2;
	this.hitArea.height = this.height + this.marginV*2;
}

Loc.button.prototype.changeClick = function(newHandler) {
	if (typeof newHandler == "function" ){
		this.click = newHandler;
	}
}

Loc.button.prototype.buttonEnter = function() {
	if (this.type == "text"){
		this.background.visibility = "Visible";
	}
	if (this.type == "image"){
		this.image.Opacity="1";
	}
}

Loc.button.prototype.buttonLeave = function() {
	if (this.type == "text"){
		this.background.visibility = "Collapsed";
	}
	if (this.type == "image"){
		this.image.Opacity="0.8";
	}
}

Loc.button.prototype.buttonClick = function() {
	if (this.click) {
		this.click();
	} else {
		Loc.tracker.currentPage = this.goToPage;
		Loc.dispatch.broadcast("pageLoad", this.goToPage); 
	}
}

/**
 * Rotator starting routine loads the rotation sequence
 */
 
Loc.rotatorSequence = function(params) {
	this.name = params.name; 	
	this.host = params.parent || Loc.root; 		
	this.top = params.top || 60;
	this.left = params.left || 500;
	this.parentName = params.parentName;
	
	var zip = "cmn/img/rotate/"+ Loc.tracker.currentAsset + ".zip";
	
	this.images = new Silverlight.Downloader({
		resource : zip,
		plugin: Loc.plugin,
		onComplete : this.loaded.bind(this),
		name : this.name,
		self : this
	});
}

Loc.rotatorSequence.prototype.loaded = function(downloader) {
	var myRotator = Loc.tracker.rotator[this.parentName];
	if (myRotator) {
		myRotator.initEvents(downloader);
		myRotator.setSequence();
	}
}

/**
 * Rotator loads clickables when rotate sequence is done
 */
 
Loc.rotator = function(params) {
	this.name = params.name; 	
	this.host = params.parent || Loc.root; 		
	this.top = params.top || 0;
	this.left = params.left || 0;
	this.images = params.images;
	this.notLoaded = true;
	this.children = {}; 						// loosing children from clearable, why?
	
	this.loaded(Loc.interfaceXaml.getResponseText('rotator.xaml'), "rotator");
}

Loc.extend(Loc.rotator, Loc.xamlObject);

Loc.rotator.prototype.preload = function() {}

Loc.rotator.prototype.init = function(params) {

	this.left = this.fragment.findName('rotate_left');
	this.leftHit = this.fragment.findName('rotate_left_hit');
	this.right = this.fragment.findName('rotate_right');
	this.rightHit = this.fragment.findName('rotate_right_hit');
	this.currentFrame = 1;
	this.imageFrame = this.fragment.findName('rotate_image');
	this.controls = this.fragment.findName('rotate_controls');
	this.assetID = Loc.tracker.currentAsset;
	
	Loc.make('rotatorSequence', { name: "rotateSequence", parentName: this.name });
}

Loc.rotator.prototype.initEvents = function(sequence) {
	this.sequence = sequence;
	
	this.leftHit.addEventListener('MouseEnter', this.onLeftHover.bind(this));
	this.leftHit.addEventListener('MouseLeave', this.onLeftLeave.bind(this));
	this.rightHit.addEventListener('MouseEnter', this.onRightHover.bind(this));
	this.rightHit.addEventListener('MouseLeave', this.onRightLeave.bind(this));
	
	// show the buttons
	this.controls.Visibility = "Visible";
}

Loc.rotator.prototype.setSequence = function() {
	var frame = this.assetID + "_" + this.currentFrame + ".jpg";
	try {
		this.imageFrame.setSource(this.sequence, frame);
	} catch(e) {}

}

Loc.rotator.prototype.goLeft = function() {
	if (this.currentFrame < 29) {
		this.currentFrame++;
		this.setSequence();
	} else {
		this.currentFrame = 1;	
	}
}

Loc.rotator.prototype.goRight = function() {
	if (this.currentFrame > 1) {
		this.currentFrame--;
		this.setSequence();
	} else {
		this.currentFrame = 30;	
	}
}

Loc.rotator.prototype.onLeftHover = function(sender, args) {
	this.leftFrameInterval = setInterval(this.goLeft.bind(this), 100);
	this.left.Opacity = "1";
}

Loc.rotator.prototype.onLeftLeave = function(sender, args) {
	clearInterval(this.leftFrameInterval);
	this.left.Opacity = "0.7";
}

Loc.rotator.prototype.onRightHover = function(sender, args) {
	this.rightFrameInterval = setInterval(this.goRight.bind(this), 100);
	this.right.Opacity = "1";
}

Loc.rotator.prototype.onRightLeave = function(sender, args) {
	clearInterval(this.rightFrameInterval);
	this.right.Opacity = "0.7";
}
