//
// Displays an interactive collection
// Tim Mowrer
// May 30, 2009
//

// TODO: startUi elements after all graphels are loaded, but don't need to wait for products to load
// TODO: add wait-for-product-image support

var collectionStatic = {

	currentProductWindow: null,
	currentProductInfo: null

};

var ProductInfo = Class.create({

	isReady: false,
	imgBackground: null,
	modalWindow: null,
	shouldForceRender: false,
	content: null,
	productId: 0,	// currently selected product (takes variant into account)
	divPrice: null,
	divAddToCartResult: null,
	//src: '',

	initialize: function( handle, data ) {
	
		var that = this;
		
		this.imgBackground = $(Builder.node('img'));
		this.content = $(document.createElement('div'));
		this.content.appendChild(this.imgBackground);
		this.divAddToCartResult = $(document.createElement('div'));
		
		// create "Add to cart" function
		var imgAddToBasket = $(document.createElement('img'));
		imgAddToBasket.setStyle({
			width: '118px',
			height: '27px',
			position: 'absolute',
			right: '24px',
			bottom: '27px'
		});
		
		this.productId = data.id;

		if (data.info.instock == true) {
			imgAddToBasket.src = '../images/collections/add-to-basket.gif';
			imgAddToBasket.observe('click',function() {
				add_to_basket( that.productId );
			});
			imgAddToBasket.setStyle({cursor:'pointer'});
		} else {
			imgAddToBasket.src = '../images/collections/out-of-stock.gif';
		}
		this.content.appendChild(imgAddToBasket);
		
		this.divPrice = $(document.createElement('div'));
		this.divPrice.innerHTML = '&pound;'+ data.info.price + '.00';
		this.divPrice.setStyle({
			position: 'absolute',
			right: '24px',
			bottom: '64px',
			opacity: .99,
			color: '#565656',
			fontSize: '14pt'
		});
		this.content.appendChild( this.divPrice );
		
		this.divAddToCartResult.addClassName( 'addToCartResult' );
		this.divAddToCartResult.setStyle({
			position: 'absolute'
		});
		this.divAddToCartResult.hide();
		this.content.appendChild( this.divAddToCartResult );
		
		// Alternate styles
		if (data.info.children.length > 0) {
			
			var options = [];
			option = $(Builder.node('option', {value: 0}, data.info.short_desc + ' (Shown)' ));
			options.push( option );
			for (i=0;i<data.info.children.length;++i) {
				child = data.info.children[i];
				option = Builder.node('option', {value: i+1}, child.short_desc );
				options.push( option );
			}
		
			// Add a drop down box
			select = $(Builder.node('select', options ));
			select.selectedIndex = 0;
			select.setStyle({
				width: '100px'
			});
			select.observe( 'change', function() {
				that.productId = (this.value == 0) ? data.id : data.info.children[this.value-1].id;
				that.divPrice.innerHTML = '&pound;'+ ((this.value == 0) ? data.info.price : data.info.children[this.value-1].price) + '.00';
			});
			form = $(Builder.node( 'form', select ));
			
			form.setStyle({
				position: 'absolute',
				left: '149px',
				top:  '369px'
			});
			
			this.content.appendChild( form );
			
			// Add "available options text
			div = $(Builder.node('div'));
			div.innerHTML = 'Available options:';
			div.setStyle({
				position: 'absolute',
				left: '150px',
				top:  '350px',
				opacity: .99,
				fontSize: '10pt',
				color: '#565656'
			});
			this.content.appendChild(div);
		
		}
		
		Event.observe( this.imgBackground, 'load', function(e) {
		
			that.isReady = true;			
			if (that.shouldForceRender)
			{
				that.modalWindow.render();
			}
			
		});
		
		Event.observe( this.imgBackground, 'error', function(e) {
			that.isReady = true;
			if (that.shouldForceRender)
			{
				that.modalWindow.render();
			}
		});
		
		this.imgBackground.src = data.info.backgroundImage;
		//this.src = data.backgroundImage;
		
		// set up modal window
		this.onPrerenderEvent = this.onPrerender.bindAsEventListener(this);
		
		this.modalWindow = new modalWindow( handle, {
			onPrerender: that.onPrerenderEvent,
			width:       data.info.width,
			height:      data.info.height
		});
	},
	
	setState: function( state, msg ) {

		var d = this.divAddToCartResult;
		var w = this.modalWindow.width;
		var h = this.modalWindow.height;
		var fadeOut = true;
		var msgTime = 0;
	
		switch (state) {
			case 'adding':
				d.innerHTML = "Adding...";
				fadeOut = false;
				break;
			case 'success':
				d.innerHTML = "Added to cart";
				msgTime = 200
				break;
			case 'failure':
				d.innerHTML = "ERROR:<br/ >" + msg;
				msgTime = 2000;
				break;
		}
		
		d.setStyle({
			left: (414 - d.getWidth())*.5 + 'px',
			top:  (414 - d.getHeight())*.5 + 'px'
		});
		d.show();
		d.setOpacity(.99);
		
		if (fadeOut) {
			setTimeout( function() {
				Csem.disappear( d, { duration: 1, afterFinish: function() {
					if (collectionStatic.currentProductWindow) {
						collectionStatic.currentProductWindow.hide();
					}
				}});
			}, msgTime );
		}
	},
		
	onPrerender: function( divContent ) {
	
		collectionStatic.currentProductWindow = this.modalWindow;
		collectionStatic.currentProductInfo   = this;
		
		this.shouldForceRender = !this.isReady;
				
		// Fill the content div
		// divContent.innerHTML = '';
		if (this.content.parentNode != this.modalWindow.divContent)
		{
			this.modalWindow.divContent.appendChild( this.content );
		}
				
		return this.isReady;
	}
	
});

var Product = Class.create({

	img: null,
	isReady:  false,
	hasError: false,
	collection: null,
	graphel: null,

	initialize: function( data, collection, graphel )
	{
		var that = this;
		this.img = Builder.node('img');
		
		// apply defaults
		data = Object.extend( {
			anchorx: 'middle',
			anchory: 'middle',
			src:     ''
		}, data );
	
		this.collection  = collection;
		this.graphel     = graphel;
				
		Event.observe( this.img, 'load', function(e)  {			
			var divContainer = collection.divProductImage;
			
			var size = divContainer.getDimensions();
			
			// Added for IE support.  IE cannot report the dimensions
			// of an image unless it is actually in the page, e.g. added to the body
			$('ie-image-area').appendChild( this );
			
			switch (data.anchorx)
			{
				case 'left':   this.setStyle({left:0}); break;
				case 'right':  this.setStyle({right:0}); break;
				case 'middle': this.setStyle({left: (size.width - this.width) * 0.5 + 'px' });
			}
			
			switch (data.anchory)
			{
				case 'top':    this.setStyle({top:0}); break;
				case 'bottom': this.setStyle({bottom:0}); break;
				case 'middle': this.setStyle({top: (size.height - this.height) * 0.5 + 'px' });
			}
			
			// Remove the image (IE hack)
			$('ie-image-area').removeChild( this );
			
			that.isReady = true;
			collection.imageReady( this, true );
		} );
		
		// Trap errors
		Event.observe( this.img, 'error', function(e) {
			that.hasError = true;
			collection.imageReady( this, false );
		});
		
		// Begin loading the image
		this.img.src = data.src;
	},
	
	show: function()
	{
		this.collection.changeProductImage( this.img, this.graphel.img.getStyle('zIndex') );
	},
	
	hide: function()
	{
		this.collection.hideProductImage( );
	}

});

var g_graphel_initMsg = null;

var Graphel = Class.create({

	// Data
	fadeDelay: 0,
	zIndex:    0,
		
	// Runtime objects
	img: null,
	isReady:  false,
	isLoaded: false,
	hasError: false,
	product:  null,
	collection: null,
	enabled:  false,
	midX: 0,
	midY: 0,
	fadeOut: -1,
	isInitMsg: false,
	aMoreInfo: null,

	initialize: function( data, collection )
	{
		var that = this;
		this.img = Builder.node('img');
		
		// Apply data to fill in this object
		
		data = Object.extend( {
			src:'',
			fadeDelay: 0,
			fadeOut: -1,	// fade out after some time
			zIndex: 5,
			product: null,
			isInitMsg: false
		}, data );
		
		// Save these for later
		this.isInitMsg = data.isInitMsg;
		if (this.isInitMsg)
			g_graphel_initMsg = this;
			
		this.zIndex    = data.zIndex;
		if (this.zIndex == 0)
		{
			if (data.product != null)
				this.zIndex = 5;
			else
				this.zIndex = 1;
		}
			
		this.fadeDelay = data.fadeDelay;
		this.fadeOut   = data.fadeOut;
		
		this.collection = collection;
		
		// Initialize objects
		// Set error and load detection
		Event.observe( this.img, 'load', function(e){
			that.isLoaded = true;
			that.midX += this.width / 2;
			that.midY += this.height / 2;
			if (that.product != null) {
				if (data.more_info_left != undefined) {
					l = data.more_info_left + (data.left ? data.left : 0) + 'px';
					t = data.more_info_top  + (data.top  ? data.top  : 0) + 'px';
					that.aMoreInfo.setStyle({
						left: l,
						top:  t
					});
				} else {
					that.aMoreInfo.setStyle({
						left: (that.midX - 50  / 2) + 'px',
						top:  Math.min(data.top + this.height + 16, 440) + 'px'
					});
				}
			}
			collection.imageReady( this, true );
		});
		Event.observe( this.img, 'error', function(e){
			that.hasError = true;
			collection.imageReady( this, false );
		});
				
		this.img.setPosition( data );
			
		this.img.setStyle({
			position: 'absolute'
		});
		
		this.midX = data.left ? data.left : 0;
		this.midY = data.top ? data.top : 0;
		
		// Interactive?
		if (data.product != null)
		{
			
			// This is a product, so indicate it is clickable
			this.img.setStyle({cursor:'pointer'});
			
			// Load in the rollover image
			this.product = new Product( data.product, collection, this );
			
			// Add rollover events
			this.eventMouseOver = this.showProduct.bindAsEventListener(this);
			this.eventMouseOut  = this.hideProduct.bindAsEventListener(this);

			Event.observe( this.img, 'mouseover', this.eventMouseOver );
			Event.observe( this.img, 'mouseout',  this.eventMouseOut  );
			
			// Add the 'more info' text (image)
			this.aMoreInfo = $(Builder.node('img'));
			this.aMoreInfo.src = '../images/collections/more-info.gif';
			this.aMoreInfo.alt = 'more info';
			this.aMoreInfo.setStyle({
				position: 'absolute',
				left:     (data.left ? data.left : 0) + 'px',
				top:      (data.top  ? data.top  : 0) + 'px',
				color:    'white',
				zIndex:   this.zIndex - 1,
				fontSize: '10pt'
			});
			this.aMoreInfo.hide();
			
			
			// This is the pop-up box that displays additional info
			// and allows user to add to basket
			new ProductInfo( this.img, data.product );
		}
				
		// Begin hidden
		this.img.hide();
		
		// begin loading in the image
		this.img.src = data.src;
	},
	
	startUi: function()
	{
		var that = this;
		this.img.setOpacity(0);
		this.show();
		
		this.collection.divContainer.appendChild( this.img );
		if (this.product != null) {
			this.collection.divContainer.appendChild( this.aMoreInfo );
		}
		
		if (this.zIndex != 0)
		{
			this.img.setStyle({zIndex: this.zIndex});
		}
		
		this.collection.graphelsRemaining++;

		Csem.appear( this.img, {delay: this.fadeDelay, afterFinish: function(){
			that.isReady = true;
			that.collection.graphelReady();
			
			if (that.fadeOut > 0)
			{
				Csem.disappear( that.img, {delay: that.fadeOut} );
			}
		}});
	},
	
	enable: function()
	{
		this.enabled = true;
	},
	
	showProduct: function(e)
	{
		if (this.enabled == false)
			return;
	
		this.product.show();
		
		// Show the 'more info' box
		Csem.appear( this.aMoreInfo, {to: .85} );
	},
	
	hideProduct: function(e)
	{
		// Hide the 'more info' box
		Csem.disappear( this.aMoreInfo );

		if (this.enabled == false)
			return;
		
		this.product.hide();		
	},
	
	// Visualization control
	hide: function()
	{
		this.img.hide();
	},
	
	show: function()
	{
		this.img.show();
	}

});

var Collection = Class.create({

	divContainer: null,
	divProductImage: null,
	imgProduct: null,
	graphels: new Array(),
	graphelsRemaining: 0,
	
	setProductImage: function( img, zIndex )
	{
		// Copies image properties into the product image
		img.setOpacity(0);
		this.imgProduct.parentNode.replaceChild( img, this.imgProduct );
		
		// zIndex needs to be at least one minus the product the mouse is over
		this.divProductImage.setStyle({zIndex: zIndex-1});
		this.imgProduct = img;
	},
	
	changeProductImage: function( img, zIndex )
	{
		//alert(img.src + "\n\n" + img.width + ', ' + img.height  );
		var that = this;
		
		// HACK!
		if (g_graphel_initMsg)
		{
			Csem.disappear( g_graphel_initMsg.img );
			g_graphel_initMsg = null;
		}
		
		// Hide current product if applicable
		this.hideProductImage( function(){
			
			// Copy image and style
			that.setProductImage( img, zIndex );
			
			// Reveal
			that.showProductImage();
		});
	},
	
	hideProductImage: function( onFinishFunc )
	{
		var opacity  = this.imgProduct.getOpacity();
		if (opacity > 0)
		{
			// Continue fading out
			Csem.disappear( this.imgProduct, {
				afterFinish: onFinishFunc,
				duration: .3 * opacity
			});
		}
		else
		{
			// Just fire finishing func directly
			if (onFinishFunc)
				onFinishFunc();
		}
	},
	
	showProductImage: function()
	{
		// Fade in
		this.divProductImage.show();
		Csem.appear( this.imgProduct );
	},

	initialize: function( divContainer, data )
	{
		var that = this;
		// Create the collection object,
		// but delay processing until page is loaded
		
		// Default product area
		data.productArea = Object.extend({
			width: 100,
			height: 100,
			left: 0,
			top: 0
		}, data.productArea );
		
		this.divProductImage = Builder.node('div');
		this.imgProduct = Builder.node('img');
		this.divProductImage.setStyle({
			position: 'absolute',
			width:  data.productArea.width + 'px',
			height: data.productArea.height + 'px',
			left:   data.productArea.left + 'px',
			top:    data.productArea.top + 'px',
			zIndex: 999
		});
		this.divProductImage.hide();
		this.divProductImage.appendChild( this.imgProduct );
		
		// Has page loaded?
		DoOrWaitForLoad( function(){
			that.divContainer = $(divContainer);
			that.init( data.graphels );
		});
	},
	
	init: function( graphels )
	{
		this.divContainer.appendChild( this.divProductImage );
		
		// Wait for all graphels to load
		var that = this;
		
		//
		// Compute number of images to load
		//
		{
			this.imagesRemaining = graphels.length;
			graphels.each( function(g) {
				if (g.product)
					that.imagesRemaining++;				
			});
		}
		
		//
		// Load them and wait for completion
		//
		{
			graphels.each( function(g) {
				that.graphels.push( new Graphel( g, that ) );
			});
		}
	},

	imageReady: function( img, success )
	{
		if (success == false)
		{
			alert("An image failed to load:\n\n" + img.src + "\n\nAttempting to continue anyway.");
		}
		
		if (--this.imagesRemaining == 0)
		{
			this.startUi();
		}
	},
	
	shouldSwap: function( g1, g2 )
	{
		if (g1.midX > g2.midX)
			return true;
		return false;
	},
	
	startUi: function()
	{
		// Work out fade in order
		// left to right, top to bottom
		var sorted = false;
		while (!sorted)
		{
			sorted = true;
			for (var i = 0; i < this.graphels.length-1; ++i)
			{
				if ( this.shouldSwap( this.graphels[i], this.graphels[i+1] ) )
				{
					sorted = false;
					var temp = this.graphels[i];
					this.graphels[i] = this.graphels[i+1];
					this.graphels[i+1] = temp;
				}
			}
		}
		
		for (var i = 0; i < this.graphels.length; ++i)
		{
			this.graphels[i].fadeDelay = i * 0.1;
		}
		
		// IE bug: zIndex doesn't work properly so we need to
		// add the graphels in the zIndex sorted order
		/*
		var n = this.graphels.length;
		var zOrder = new Array( n );
		
		// Initialize
		for (var i = 0; i < n; ++i)
			zOrder[i] = i;
		
		// Sort
		sorted = false;
		while (!sorted)
		{
			sorted = true;
			for (var i = 0; i < n-1; ++i)
			{
				if ( this.graphels[zOrder[i]].zIndex > this.graphels[zOrder[i+1]].zIndex )
				{
					sorted = false;
					var temp = zOrder[i];
					zOrder[i] = zOrder[i+1];
					zOrder[i+1] = temp;
				}
			}
		}
		
		// Sorted, now append them to the div in the correct order
		for (var i=0;i<n;++i)
		{
			this.divContainer.appendChild( this.graphels[zOrder[i]].img );
		}
		*/

		this.graphels.each( function(g){
			// Only start the ui if image succeeded
			if (g.isLoaded)
			{
				g.startUi();
			}
		});
		
		//this.divContainer.appendChild( this.divProductImage );
		
		setTimeout( g_OnUiReady, 500 );
	},
	
	graphelReady: function( )
	{
		if (--this.graphelsRemaining == 0)
		{
			// enable interface
			this.graphels.each( function(g){
				g.enable();
			});
		}
	}

});
