///////////////////////////////////////////////////////////////////////////////
//
//  Zoom.js   			version 1.0
//  2007 Lenny Burdette
//
///////////////////////////////////////////////////////////////////////////////

if ( !window.Loc) { window.Loc = {}; }

/****************************
*		Zoom Component		*
****************************/

Loc.Zoomer = function(params) {
	this.page = params.page;
	this.parent = params.parent || Loc.root;
	this.params = params;
	this.initialized = false;
	this.getData();
	this.getPresentation();
}

Loc.Zoomer.prototype = {
	
	getData : function() {
		/*
		this.asset = Loc.content.asset[this.assetId];
		this.textContent = Loc.assetContent[this.assetId];
		this.imagePath = 'cmn/img/asset/' + this.assetId + 'R.png';
		this.largeImagePath = 'cmn/img/asset/' + this.assetId + 'R-large.jpg';
		*/
		this.pageData = Loc.content[this.page];
		this.textContent = this.pageData;
		this.imagePath = 'cmn/img/' + this.page + '.png';
		this.largeImagePath = 'cmn/img/' + this.page + '-large.jpg';
	},

	getPresentation : function() {
		this.downloader = new Silverlight.Downloader({
		    resource : "cmn/xaml/zoom/zoom.zip",
		    plugin: Loc.plugin,
		    onComplete : function(downloader) {
				this.initXaml(downloader);
			}.bind(this)
		});
	},

	initXaml : function(dl) {
		this.componentXaml = Loc.plugin.content.createFromXaml(dl.getResponseText('zoom.xaml'), true);
		this.labelMaker = function() { 
			return Loc.plugin.content.createFromXaml(dl.getResponseText('label.xaml'), true); 
		};
		this.buttonMaker = function() { 
			return Loc.plugin.content.createFromXaml(dl.getResponseText('button.xaml'), true) 
		};
		
		this.labelHolder = this.componentXaml.findName('labelHolder');
		this.imageHolder = this.componentXaml.findName('imageHolder');
		this.largeImage = this.componentXaml.findName('largeImage');

		this.zoomPreloader = Loc.make('Preloader', {name: 'zoomLoader', top: 150, left: 60});
		
		// wait to load the images so the nav can load
		// setTimeout(this.createImage.bind(this), 250);
		this.createImage();
			    
		// position and attach
		this.componentXaml['Canvas.Left'] = this.params.left || 0;
		this.componentXaml['Canvas.Top'] = this.params.top || 0;
		this.parent.children.add(this.componentXaml);
	},
	
	createImage : function() {
		// main image
		this.image = new Loc.ZoomImage(this.componentXaml.findName('image'), this.imagePath, this.textContent);
		this.imageReady = false;
		var imageToken = this.image.xaml.addEventListener('DownloadProgressChanged', function() {
			if (this.image.xaml.downloadProgress >= 1) {
				this.imageLoaded(1);
				this.image.xaml.removeEventListener('DownloadProgressChanged', imageToken);
			}
		}.bind(this));
		
		// position labels above image
		this.labelHolder['Canvas.Left'] = this.image.xaml['Canvas.Left'];
		this.labelHolder['Canvas.Top'] = this.image.xaml['Canvas.Top'];
		this.labelHolder.width = this.textContent.width;
		this.labelHolder.height = this.textContent.height;
		
		// zoomed-in image
		this.largeImage.source = this.largeImagePath;
		this.largeImageFrame = this.componentXaml.findName('largeImageFrame');
		this.largeImageReady = false;
		var largeImageToken = this.largeImage.addEventListener('DownloadProgressChanged', function() {
			if (this.largeImage.downloadProgress >= 1) {
				this.imageLoaded(2);
				this.largeImage.removeEventListener('DownloadProgressChanged', largeImageToken);
			}
		}.bind(this));
	},
	
	imageLoaded : function(index) {
		if (index == 1) {
			this.imageReady = true;
		} else {
			this.largeImageReady = true;
		}
		if (this.imageReady && this.largeImageReady && ! this.initialized) {
			this.initialize();
		}
	},
	
	initialize : function() {
		if (this.initialized) {
			return;
		}
		this.initialized = true;
		this.zoomPreloader.stop();
		this.labelHolder.visibility = 'visible';
		this.createHotspots();
		this.createButtons();
	},

	createHotspots : function() {
		this.hotspots = [];
		var hotspot;
		for (var i = 0, data = null; data = this.textContent.hotspots[i]; i++) {
			hotspot = new Loc.Hotspot(data, this.labelMaker(), this.onClick.bind(this, i));
			hotspot.attach(this.labelHolder);
			this.hotspots.push(hotspot);
		}
	},
	
	onClick : function(index, zoomIn) {
		if (zoomIn) {
			this.zoomIn(index);
			this.hotspotButtons[index].select();
		} else {
			this.zoomOut();
			this.hotspotButtons[index].deselect();
		}
	},
	
	// TODO: don't hard code button heights
	createButtons : function() {
		this.buttonHolder = this.componentXaml.findName('buttonHolder');
		
		this.componentXaml.findName('toggleButton').visibility = 'visible';
		this.toggleButton = new Loc.ZoomButton(['Hide Highlights', 'Show Highlights'], this.componentXaml.findName('toggleButton'), this.toggleHotspots.bind(this));
		
		this.resetButton = new Loc.ZoomButton('Full View', this.buttonMaker(), this.reset.bind(this)).attach(this.buttonHolder, 0).disable().select();
		
		this.hotspotButtons = [];
		var button;
		for (var i = 0, hotspot = null; hotspot = this.hotspots[i]; i++) {
			button = new Loc.ZoomButton(hotspot.data.title, this.buttonMaker(), this.buttonPress.bind(this, i));
			button.attach(this.buttonHolder, (20 * (i + 1)));
			this.hotspotButtons.push(button);
		}
	},
	
	buttonPress : function(index) {
		this.zoomIn(index);
		this.resetButton.enable();
		for (var i = 0, button = null; button = this.hotspotButtons[i]; i++) {
			button[(i == index) ? 'select' : 'deselect']();
		}
	},
	
	reset : function() {
		this.zoomOut();
		for (var i = 0, button = null; button = this.hotspotButtons[i]; i++) {
			button.deselect();
		}
	},
	
	/****************************
	*		Zooooooom!			*
	****************************/
	
	zoomIn : function(index) {
		this.resetButton.deselect();
		this.stopTweens();
		this.largeImageFrame.visibility = 'visible';
		var position = this.calcPosition(this.hotspots[index].data),
			tweens = [
				{ obj: this.image.scaler, prop: 'ScaleX', end: 2, func: Loc.Tween.easeOutExpo },
				{ prop: 'ScaleY' },
				{ obj: this.image.xaml, prop: 'Opacity', end: 0 },
				{ obj: this.largeImageFrame, end: 1 },
				{ obj: this.largeImage, prop: 'Canvas.Left', end: position.x },
				{ prop: 'Canvas.Top', end: position.y }
				];
		for (var i = 0, hotspot = null; hotspot = this.hotspots[i]; i++) {
			if (i != index) {
				hotspot.deselect();
				hotspot.disable();
				if (hotspot.xaml.opacity > 0) {
					tweens.push({ obj: hotspot.xaml, prop: 'opacity', end: 0 });
				}
			} else {
				hotspot.select();
				hotspot.enable();
				if (hotspot.xaml.opacity < 1) {
					tweens.push({ obj: hotspot.xaml, prop: 'opacity', end: 1 });
				}
				tweens.push({ obj: hotspot.xaml, prop: 'Canvas.Left', end: this.labelHolder.width / 2 });
				tweens.push({ obj: hotspot.xaml, prop: 'Canvas.Top', end: this.labelHolder.height / 2 });
			}
		}
		this.zoomInTween = new Loc.Tween(tweens, .5).startFromHere();
	},
	
	zoomOut : function(index) {
		this.resetButton.select();
		this.stopTweens();
		var tweens = [
			{ obj: this.image.scaler, prop: 'ScaleX', end: 1, func: Loc.Tween.easeOutExpo },
			{ prop: 'ScaleY' },
			{ obj: this.image.xaml, prop: 'Opacity', end: 1 },
			{ obj: this.largeImageFrame, end: 0 },
			{ obj: this.largeImage, prop: 'Canvas.Left', end: this.textContent.largeWidth / 2 },
			{ prop: 'Canvas.Top', end: this.textContent.largeHeight / 2 }
			];
		for (var i = 0, hotspot = null; hotspot = this.hotspots[i]; i++) {
			hotspot.deselect();
			hotspot.enable();
			if (hotspot.xaml.opacity < 1) {
				tweens.push({ obj: hotspot.xaml, prop: 'opacity', end: 1 });
			}
			tweens.push({ obj: hotspot.xaml, prop: 'Canvas.Left', end: hotspot.data.left });
			tweens.push({ obj: hotspot.xaml, prop: 'Canvas.Top', end: hotspot.data.top });
		}
		this.zoomOutTween = new Loc.Tween(tweens, .5).startFromHere();
	},
	
	toggleHotspots : function() {
		this.labelHolder.visibility = this.labelHolder.visibility.toLowerCase() == 'collapsed' ? 'visible' : 'collapsed';
	},
	
	stopTweens : function() {
		if (this.zoomInTween) {
			this.zoomInTween.stop();
		}
		if (this.zoomOutTween) {
			this.zoomOutTween.stop();
		}
	},
	
	calcPosition : function(data) {
		var centerX = this.imageHolder.width / 2,
			centerY = this.imageHolder.height / 2;
		return { x: centerX - data.x, y: centerY - data.y };
	}
}

/****************************
*		Hotspots			*
****************************/
Loc.Hotspot = function(data, xaml, callback) {
	this.data = data;
	this.xaml = xaml;
	this.id = this.data.id;
	this.callback = callback;
	this.selected = false;
	this.init();
	this.initEvents();
}

Loc.Hotspot.prototype = {
	init : function() {
		this.label = this.xaml.findName('label');
		this.overlay = this.xaml.findName('overlay');
		
		this.labelText = this.xaml.findName('labelText');
		this.labelText.text = this.data.title;
		
		this.labelDescription = this.xaml.findName('labelDescription');
		this.labelDescription.text = this.data.text;
		
		this.xaml['Canvas.Left'] = this.data.left;
		this.xaml['Canvas.Top'] = this.data.top;
		
		this.plus = this.xaml.findName('plusButton');
		this.minus = this.xaml.findName('minusButton');
	},
	
	initEvents : function() {
		this.hit = this.xaml.findName('hit');
		this.hit.cursor = 'Hand';
		this.hit.addEventListener('MouseEnter', this.onOver.bind(this));
		this.hit.addEventListener('MouseLeave', this.onOut.bind(this));
		this.hit.addEventListener('MouseLeftButtonDown', this.onClick.bind(this));
	},
	
	reposition : function() {
		this.bg1 = this.xaml.findName('bg1');
		this.bg2 = this.xaml.findName('bg2');
		this.bg3 = this.xaml.findName('bg3');
		this.bg4 = this.xaml.findName('bg4');
		
		if (this.labelText.actualWidth > 100) {
			this.bg4.width = this.labelText.actualWidth + 4
			this.bg3.width = this.bg4.width + 6;
			this.bg2.width = this.bg4.width;
			this.bg1.width = this.bg4.width + 6;
			this.labelDescription.width = this.labelText.actualWidth;
			this.hit.width = this.labelText.actualWidth + 22;
		}
		
		if (this.labelDescription.actualHeight > 200) {
			this.bg2.width = 254;
			this.bg1.width = 260;
			this.labelDescription.width = 250;
			this.labelDescription.text = this.data.text;
		}
		
		// TODO: don't hardcode width data into label
		if (this.data.left + this.bg1.width > this.container.width) {
			this.label['Canvas.Left'] = -this.bg3.width + 12;
			this.overlay['Canvas.Left'] = -this.bg1.width + 12;
			this.hit['Canvas.Left'] = -this.bg3.width + 12;
		}
		
		this.bg2.height = this.labelDescription.actualHeight + 4;
		this.bg1.height = this.bg2.height + 6;
		
		if (this.bg2.height + this.data.top > this.container.height) {
			this.overlay['Canvas.Top'] = -1 * (this.bg2.height + this.data.top - this.container.height)
		}
	},
	
	attach : function(container) {
		this.container = container;
		this.container.children.add(this.xaml);
		this.reposition();
	},
	
	// mouse events 
	onOver : function() {
		this.label.visibility = 'collapsed';
		this.xaml['Canvas.ZIndex'] = 10;
		this.overlay.visibility = 'visible';
	},
	
	onOut : function() {
		this.label.visibility = 'visible';
		this.xaml['Canvas.ZIndex'] = 4;
		this.overlay.visibility = 'collapsed';
	},
	
	onClick : function() {
		this.selected = ! this.selected;
		this.plus.visibility = this.selected ? 'collapsed' : 'visible';
		this.minus.visibility = this.selected ? 'visible' : 'collapsed';
		this.callback(this.selected);
	},
	
	select : function() {
		this.selected = true;
		this.plus.visibility = 'collapsed';
		this.minus.visibility = 'visible';
	},
	
	deselect : function() {
		this.selected = false;
		this.plus.visibility = 'visible';
		this.minus.visibility = 'collapsed';
	},
	
	disable : function() {
		this.disabled = true;
		this.hit.visibility = 'collapsed';
		this.xaml['Canvas.ZIndex'] = 1;
	},
	
	enable : function() {
		this.disabled = false;
		this.hit.visibility = 'visible';
		this.hit.isHitTestVisible = true;
		this.xaml['Canvas.ZIndex'] = 5;
	}
}

/****************************
*			Image			*
****************************/

Loc.ZoomImage = function(xaml, source, data) {
	this.xaml = xaml;
	this.xaml.source = source;
	this.scaler = this.xaml.findName('imageScaler');
	this.container = this.xaml.getParent();
	this.data = data;
	this.position();
}
Loc.ZoomImage.prototype = {
	position : function() {
		this.xaml.width = this.data.width;
		this.xaml.height = this.data.height;
		this.xaml['Canvas.Left'] = this.container.width / 2 - this.data.width / 2;
		this.xaml['Canvas.Top'] = this.container.height / 2 - this.data.height / 2;
	}
}

/****************************
*		Zoom Buttons		*
****************************/
Loc.ZoomButton = function(label, xaml, callback) {
	if (typeof label == 'string') {
		this.label = label;
	} else {
		this.label = label[0];
		this.selectedLabel = label[1];
	}
	this.xaml = xaml;
	this.callback = callback;
	this.init();
	return this;
}
Loc.ZoomButton.prototype = {
	init : function() {
		this.labelXaml = this.xaml.findName('label');
		this.labelXaml.text = this.label;
		
		this.overState = this.xaml.findName('over');
		this.selectedState = this.xaml.findName('selected');
		
		this.hit = this.xaml.findName('hit');
		this.hit.cursor = 'Hand';
		this.hit.addEventListener('MouseEnter', this.onOver.bind(this));
		this.hit.addEventListener('MouseLeave', this.onOut.bind(this));
		this.hit.addEventListener('MouseLeftButtonDown', this.onClick.bind(this));
		
		this.labelXaml['Canvas.Left'] = this.hit.width / 2 - this.labelXaml.actualWidth / 2;
	},
	
	attach : function(container, y) {
		this.xaml['Canvas.Top'] = y;
		this.container = container;
		this.container.children.add(this.xaml);
		return this;
	},
	
	onOver : function() {
		this.overState.visibility = 'visible';
	},
	
	onOut : function() {
		this.overState.visibility = 'collapsed';
	},
	
	onClick : function() {
		if (this.selectedState) {
			this.toggle();
		}
		this.callback();		
	},
	
	enable : function() {
		this.disabled = false;
		this.hit.visibility = 'visible';
		return this;
	},
	
	disable : function() {
		this.disabled = true;
		this.hit.visibility = 'collapsed';
		return this;
	},
	
	select : function() {
		this.selected = true;
		if (this.selectedLabel) {
			this.labelXaml.text = this.selectedLabel;
		}	
		this.selectedState.visibility = 'visible';
		return this;
	},
	
	deselect : function() {
		this.selected = false;
		this.labelXaml.text = this.label;
		this.selectedState.visibility = 'collapsed';
		return this;
	},
	
	toggle : function() {
		if (this.selected) {
			this.deselect();
		} else {
			this.select();
		}
		return this;
	}
}
