
Shop = new Class({
	Implements: [Options, Events],
	options: {
		sections:	{ },
		currentStep:	null,
		hide_duration: 200,
		show_duration: 400
	},

	initialize: function(container, options) {
		this.container = container;
		this.setOptions(options);

		this.sections = {};
		this.section_count = 0;
		for(var k in this.options.sections) {
			this.sections[k] = new Shop.Section(this, k, this.options.sections[k]);
			++this.section_count;
		}

		// create shop elements
		this.frame = new Shop.Frame(this);
		this.session = new Shop.Session(this);
		this.cart = new Shop.Cart(this);
		this.forms = new Shop.Forms(this);

		// load order for shop elements
		this._load_order = ['frame', 'session', 'cart'];


		// preload images used by the shop
		var preloadImageList = [
			'shop-button-continue.png',
			'shop-button-continue-over.png',
			'shop-button-checkout.png',
			'shop-button-checkout-over.png',
			'shop-button-back.png',
			'shop-button-back-over.png',
			'shop-button-edit.png',
			'shop-button-edit-over.png',
			'shop-icon-add-to-cart.png',
			'shop-icon-checkbox.png',
			'shop-icon-checkbox-checked.png',
			'shop-icon-rem-from-cart.png',
			'shop-loading.gif',
			'shop-icon-update-cart.png',
			'shop-error-exclamation'
		];

		var img = new Image();
		for(var i=0; i<preloadImageList.length; ++i) img.src = 'assets/images/' + preloadImageList[i];

		
		window.addEvent('domready', function() {
			this.container = $(this.container);
			if(!this.container) alert('Error: element not found, unable to create shop.');
			this._beginLoading();
		}.bind(this));
	},

	_beginLoading: function() {
		//if(this.options.addProductId) {
		//	new Request({
		//		method: 'post',
		//		url: '/site/shop/ajax_add_product_to_cart?productid='+this.options.addProductId+'&'+this.session_name+'='+this.session_id,
		//		onSuccess: function(response) {
		//			this._continueLoading();
		//		}
		//	}).send();
		//}
		//else this._continueLoading();
		this._continueLoading();
	},

	_continueLoading: function() {
		if(this._load_order.length > 0) {
			var curstep = this._load_order.shift();
			this[curstep].addEvent('loaded', function() {
				this._continueLoading();
			}.bind(this));
			this[curstep].load();
		}
		else this._doneLoading();
	},


	_doneLoading: function() {

		// show the default step, or the first if not defined
		if(!this.options.currentStep || !this.sections[this.options.currentStep]) {
			for(var n in this.sections) {
				this.options.currentStep  = n;
				break;
			}
		}
		this.updateSections();


		this.frame.showSection(this.options.currentStep);
		this.cart.refresh();
	},

	updateSections: function() {

		var c = new Chain();
		c.chain(function() {
			this.session.refresh(c);
		}.bind(this)).chain(function() {

			for(var k in this.sections) {
				this.sections[k].refresh();
			}

		}.bind(this)).callChain();


	}



});




/**********************************************************/
// Class Shop.Section 
Shop.Section = new Class({
	initialize: function(parent, key, title) {
		this.parent = parent;
		this.key = key;
		this.title = title;


	},

	/********** Shop.Section.checkStatus() **********/
	// simply checks whether the section is sufficiently completed
	// returns bool true/false
	checkStatus: function() {
		return ( this.parent.session['section_ok_'+this.key] ) ? true : false;
	},

	/********** Shop.Section.checkAccess() **********/
	// checks whether the section is editable, ie all previous sections are completed
	// returns bool true/false
	checkAccess: function() {
		var ok = true;
		var sec = this.key;
		while(sec = this.parent.sections[sec].getPrev()) {
			if(!this.parent.sections[sec].checkStatus()) {
				ok = false;
				break;
			}
		}
		return ok;
	},

	refresh: function() {
		var chk = $('shop-image-check-' + this.key);
		var btn_edit = $('shop-button-edit-' + this.key);
		var btn_continue = $('shop-button-continue-' + this.key);
		var btn_back = $('shop-button-back-' + this.key);


		// we'll always show the back button if there are previous steps
		var prev = this.getPrev();
		if(prev) btn_back.setStyle('display', 'block');
		else btn_back.setStyle('display', 'none');

		if(this.checkAccess()) {
			btn_edit.setStyle('display', 'block');
		} else {
			btn_edit.setStyle('display', 'none');
		}

		if( this.checkStatus() ) {
			chk.src = 'assets/images/shop-icon-checkbox-checked.png';

			// show / hide the continue button
			var next = this.getNext();
			if(next && this.parent.sections[next].checkAccess()) btn_continue.setStyle('display', 'block');
			else btn_continue.setStyle('display', 'none');
		} else {

			if(this.key == 'summary') {
				btn_continue.src = 'assets/images/shop-button-checkout.png';
				btn_continue.setStyle('display', 'block');
				btn_continue.onclick = function() {
					window.shop.forms.submitOrder();
				};
			}
			else {
				chk.src = 'assets/images/shop-icon-checkbox.png';
			
				btn_continue.setStyle('display', 'none');
			}
		}

	},

	getNext: function() {

		var match = false;
		for( var k in this.parent.sections ) {
			if(match) return k;
			if( this.key == k ) match = true;
		}
		return false;
	},

	getPrev: function() {
		var prev = false;
		for( var k in this.parent.sections ) {
			if( this.key == k ) break;
			prev = k;
		}
		return prev;
	}


});


/**********************************************************/
// Class Shop.Session 
Shop.Session = new Class({
	Implements: [Events],

	initialize: function(shop) {
		this.parent = parent;
	},
	load: function() {
		var c = new Chain();
		c.chain(function() {
			window.shop.session.refresh(c);
		}).chain(function() {
			this.fireEvent('loaded');
		}.bind(this)).callChain();
	},


	refresh: function(chain) {



		new Request({
			method: 'post',
			url: '/site/shop/ajax_get_session',
			onSuccess: function(response) {
				response = JSON.decode(response);
				this.callChain(response);
			}
		}).send().chain(function(response) {
			if(response) {
				for(var k in response) this.set(k, response[k]);

				if(window.shop.frame.div['controls']) {
					window.shop.frame.div['controls'].innerHTML = response.controls_html;
				}

			}


			if(chain) chain.callChain();
		}.bind(this));


	},

	set: function(k, v) {
		this[k] = v;
	}




});

/**********************************************************/
// Class Shop.Cart 
// 
Shop.Cart = new Class({
	Implements: [Events],

	initialize: function(parent) {
		this.parent = parent;
	},

	load: function() {
		this.fireEvent('loaded');
	},

	refresh: function(k, chain) {

		if(!k) {
			this.refresh('cart-items');
			this.refresh('cart-totals');
		}
		else {
			var c = new Chain();
	
			c.chain(function() {
	
				// load the cart content
				var q = { 'key': k };
	
				new Request.JSON({
					method: 'post',
					url: '/site/shop/ajax_get_content',
					data: q,
					onSuccess: function(response) {
						if(response) c.callChain(response.content);
					}
				}).send();
	
			}.bind(this)).chain(function(content) {
				this.parent.frame.div[k].empty();
	
				var d = new Element('div');
				d.setStyle('opacity', 0);
				d.innerHTML = content;
				d.inject(this.parent.frame.div[k]);
	
				new Fx.Tween(d, {
					duration: 250,
					onComplete: function() {
						c.callChain();
					}
				}).start('opacity', 1);

			}.bind(this)).chain(function(content) {
				this.parent.frame.refresh();

				if(chain) chain.callChain();
			}.bind(this)).callChain();
		}

	},

	addProduct: function(product_id, qty) {
		if(!qty) qty = 1;

		var q = {
			'product_id': product_id,
			'qty': qty
		};
		new Request({
			method: 'post',
			url: '/site/shop/ajax_add_product_to_cart',
			data: q,
			onSuccess: function(response) {
				this.refresh();
				this.parent.updateSections();
			}.bind(this)
		}).send();
	},

	removeProduct: function(product_id) {
		var q = {
			'product_id': product_id
		};
		new Request({
			method: 'post',
			url: '/site/shop/ajax_remove_product_from_cart',
			data: q,
			onSuccess: function(response) {
				this.refresh();
				this.parent.updateSections();
			}.bind(this)
		}).send();
	},

	updateQuantity: function(product_id, qty, delZero) {
		qty = parseInt( qty.replace(/[^0-9]/, '') );

		if( !qty && delZero) return this.removeProduct(product_id);
		else {
			var q = {
				'product_id': product_id,
				'qty': qty
			};

			new Request({
				method: 'post',
				url: '/site/shop/ajax_update_product_cart_quantity',
				data: q,
				onSuccess: function(response) {
					this.refresh();
				}.bind(this)
			}).send();
		}
	}

});


/**********************************************************/
// Class Shop.Frame 
// shop frame provides creates the layout of the shop 
Shop.Frame = new Class({
	Implements: [Events],

	initialize: function(parent) {
		this.parent = parent;
		this._in_transition = false;
		this.div = {};
		this.contentdiv_height = 0;
	},

	/********** Shop.Frame.load() **********/
	load: function() {
		this.draw();
		this.refresh();
		//this.showSection(this.parent.options.currentStep);
		this.fireEvent('loaded');
	},

	/********** Shop.Frame.draw() **********/
	// creates the shop layout
	draw: function() {
		this.parent.container.addClass('shop');

		/****************** right frame **********************/
		with( this.div['frameRight'] = new Element('div') ) {
			addClass('frameRight');
			setStyle('float', 'right');
			inject(this.parent.container);
		};

		with( this.div['cart-items'] = new Element('div') ) {
			addClass('cart-items');
			setStyle('overflow', 'auto');
			inject( this.div['frameRight'] );
		};

		with( this.div['cart-totals'] = new Element('div') ) {
			addClass('cart-totals');
			setStyle('overflow', 'hidden');
			inject( this.div['frameRight'] );
		};


		/****************** left frame **********************/
		with( this.div['frameLeft'] = new Element('div') ) {
			addClass('frameLeft');
		};
		this.div['frameLeft'].inject(this.parent.container);

		// create each section in left frame

		for(var k in this.parent.sections) {
			var tmp;

			with(this.div[k] = new Element('div') ) {
				addClass('section');
			};

			// create the titlebar
			with( this.div[k+'_titlebar'] = new Element('div') ) {
				addClass('titlebar');
				//innerHTML =  '<img src="assets/images/shop-icon-checkbox.png" class="shop-image-check">'+this.parent.sections[k].title;
				store('key', k);
				inject( this.div[k] );
			};

			with( tmp = new Element('img', { src: 'assets/images/shop-icon-checkbox.png' } ) ) {
				id = 'shop-image-check-'+k;
				addClass('shop-image-check');
				store('key', k);
				addEvent('click', function(e) { this.showSection( $(e.target).retrieve('key') ) }.bind(this));
				inject( this.div[k+'_titlebar'] );
			};


			// edit button
			with( tmp = new Element('img', { src: 'assets/images/shop-button-edit.png' } ) ) {
				id = 'shop-button-edit-'+k;
				store('key', k);
				setStyles({
					float: 'right',
					padding: '2px 4px 0px 0px',
					display: 'none',
					cursor: 'pointer'
				});
				
				addEvent('click', function(e) { this.showSection( $(e.target).retrieve('key') ) }.bind(this));
				addEvent('mouseover', function() { this.src = this.src.replace(/(\.[^\.]+)$/, '-over$1') });
				addEvent('mouseout', function() { this.src = this.src.replace(/-over/, '') });
				inject( this.div[k+'_titlebar'] );
			};

			with( tmp = new Element('span') ) {
				innerHTML = this.parent.sections[k].title;
				inject( this.div[k+'_titlebar'] );
			};


			// create the content area
			with(this.div[k+'_content'] = new Element('div') ) {
				addClass('content');
				setStyle('overflow', 'auto');
				setStyle('height', 0);
				setStyle('display', 'none');
				inject( this.div[k] );
			};

			// create the navbar
			with(this.div[k+'_navbar'] = new Element('div') ) {
				addClass('navbar');
				setStyle('display', 'none');
				inject( this.div[k] );
			};

			// back button
			with( tmp = new Element('img', { src: 'assets/images/shop-button-back.png' } ) ) {
				id = 'shop-button-back-'+k;
				store('key', k);
				setStyles({
					'float': 'left',
					'padding': '2px 4px 0px 0px',
					'display': 'none',
					'cursor': 'pointer'
				});
				
				addEvent('click', function(e) { this.sectionNavPrev( $(e.target).retrieve('key') ) }.bind(this));
				addEvent('mouseover', function() { this.src = this.src.replace(/(\.[^\.]+)$/, '-over$1') });
				addEvent('mouseout', function() { this.src = this.src.replace(/-over/, '') });

				inject( this.div[k+'_navbar'] );
			};
			// continue button
			with( tmp = new Element('img', { src: 'assets/images/shop-button-continue.png' } ) ) {
				id = 'shop-button-continue-'+k;
				store('key', k);
				setStyles({
					'float': 'right',
					'padding': '2px 4px 0px 0px',
					'display': 'none',
					'cursor': 'pointer'
				});
				
				addEvent('click', function(e) { this.sectionNavNext( $(e.target).retrieve('key') ) }.bind(this));
				addEvent('mouseover', function() { this.src = this.src.replace(/(\.[^\.]+)$/, '-over$1') });
				addEvent('mouseout', function() { this.src = this.src.replace(/-over/, '') });

				inject( this.div[k+'_navbar'] );
			};


			// add this section to the left frame
			this.div[k].inject( this.div['frameLeft'] );

		};



		/****************** controls **********************/
		this.div['controls'] = $(this.parent.container.id + 'Controls');
		if(this.div['controls']) {
			this.div['controls'].addClass('shop-controls');
		};


	},

	/********** Shop.Frame.refresh() **********/
	// sizes the frame elements, should be called if the shop container size changes
	refresh: function() {
		var containerSize = this.parent.container.getSize();

		this.div['frameRight'].setStyle('height', containerSize.y);

		// determine the height of the titlebar and navbars
		for(var k in this.parent.sections) {
			this.titlebar_height = this.div[k+'_titlebar'].getHeight();

			if( this.div[k+'_navbar'].getStyle('display') == 'none' ) {
				this.div[k+'_navbar'].setStyles({
					position: 'absolute',
					opacity: 0,
					display: 'block'
				});
				this.navbar_height = this.div[k+'_navbar'].getHeight();
				this.div[k+'_navbar'].setStyles({
					position: 'static',
					display: 'none'
				});
			}
			else this.navbar_height = this.div[k+'_navbar'].getHeight();

			break;
		}

		// now calculate the available height for the content sections
		this.contentdiv_height = containerSize.y - ( this.navbar_height + (this.titlebar_height * this.parent.section_count) );
		this.contentdiv_width = containerSize.x - ( this.div['frameRight'].getWidth() );

		// now resize any visible content sections
		for(var k in this.parent.sections) {
			if( this.div[k+'_content'].getStyle('display') != 'none') {
				this.div[k+'_content'].setStyle('height', this.contentdiv_height);
			}
		}

		// size the cart frames
		this.div['cart-totals'].setStyle('height', 1);
		this.div['cart-totals'].setStyle('height', this.div['cart-totals'].scrollHeight);
		this.div['cart-items'].setStyle('height', containerSize.y - this.div['cart-totals'].getHeight());


	},

	/********** Shop.Frame.sectionNavNext() **********/
	// show a specific section
	sectionNavNext: function(key) {
		if(!key) key = this.parent.options.currentStep;
		var next = this.parent.sections[key].getNext();
		if(next) this.showSection(next);

	},
	/********** Shop.Frame.sectionNavPrev() **********/
	// show a specific section
	sectionNavPrev: function(key) {
		if(!key) key = this.parent.options.currentStep;
		var prev = this.parent.sections[key].getPrev();
		if(prev) this.showSection(prev);
	},

	/********** Shop.Frame.showSection() **********/
	// show a specific section
	showSection: function(key, querydata) {
		// don't start a new transition if we're currently in the middle of one
		if(this._in_transition) return;
		if(!this.div[key]) return;

		// make sure we can show the requested section
		if(!this.parent.sections[key].checkAccess()) return;

		var c = new Chain();

		c.chain(function() {
			// check for and hide opened sections
			var found = null;
			for( var k in this.parent.sections ) {
				if( this.div[k+'_content'].getStyle('display') != 'none' ) {
					found = k;
					break;
				}
			}

			if(found) {
				if( found == key) this.refreshSection(querydata);
				else this.hideSection( found, c );
			}
			else c.callChain();
		}.bind(this)).chain(function() {
			// show this section
			this._in_transition = true;

			this.div[key+'_content'].empty();
			this.div[key+'_content'].setStyle('display', 'block');

			new Fx.Tween(this.div[key+'_content'], {
				transition: Fx.Transitions.Quad.easeOut,
				duration: this.parent.options.show_duration,
				onComplete: function() {
					c.callChain();
				}
			}).start('height', this.contentdiv_height );

		}.bind(this)).chain(function() {
			// show the navbar
			this.div[key+'_navbar'].setStyle('opacity', 1);
			this.div[key+'_navbar'].setStyle('display', 'block');

			c.callChain();
		}.bind(this)).chain(function() {
			// set the current step
			this.parent.options.currentStep = key;
			this._in_transition = false;

			this.refresh();

			// now load and show section data
			this.refreshSection(querydata);
		}.bind(this)).callChain();
	},

	/********** Shop.Frame.refreshSection() **********/
	// refresh a specific section
	refreshSection: function(querydata) {
		key = this.parent.options.currentStep;
		if(!this.div[key]) return;
		if(!querydata) querydata = {};

		// if we're showing shipping, and the shipping info is not ok, make them fix it
		//if(key == 'shipping' && !this.parent.session.shipping_info_ok) {
		//	querydata.key = 'account-modify-shipping';
		//}

		var c = new Chain();
		c.chain(function() {
			// show the loading graphic
			this.div[key+'_content'].empty();
			this.showLoading(key);

			// load the section content
			if(!querydata.key) querydata.key = key;

			new Request.JSON({
				method: 'post',
				url: '/site/shop/ajax_get_content',
				data: querydata,
				onSuccess: function(response) {
					if(response) c.callChain(response.content);
				}
			}).send();

		}.bind(this)).chain(function(content) {
			// display the section content
			this.hideLoading();
			this.div[key+'_content'].empty();
			this.div[key+'_content'].setStyle('opacity', 0);
			this.div[key+'_content'].innerHTML = '<div>' + content + '</div>';

			new Fx.Tween(this.div[key+'_content'], {
				duration: 250,
				onComplete: function() { c.callChain(); }
			}).start('opacity', 1);

		}.bind(this)).chain(function() {

			// change the #target in the href so refreshing the page will present the user with the correct section
			var href;
			if( document.location.href.indexOf('#') > -1 ) href = document.location.href.substr(0, document.location.href.indexOf('#'));
			else href = document.location.href;
			document.location = href + '#' + key;

		}.bind(this)).callChain();
		
	},


	hideSection: function(key, chain) {
		if(this._in_transition) return;
		if(!this.div[key]) return;


		if( this.div[key+'_content'].getStyle('display') == 'none' ) return; // already collapsed



		var c = new Chain();
		c.chain(function() {
			// hide the navbar
			this.div[key+'_navbar'].setStyle('display', 'none');


			// collapse the section
			new Fx.Morph(this.div[key+'_content'], {
				duration: this.parent.options.hide_duration,
				onStart: function() {
					this.element.setStyle('overflow', 'hidden'); // hide scrollbars during transition
				},
				onComplete: function() {
					this.element.setStyle('display', 'none');
					this.element.setStyle('overflow', 'auto'); // undo hidden scrollbars
					c.callChain();
				}
			}).start({
				opacity: 0,
				height: 0
			});

		}.bind(this)).chain(function() {
			if(chain) chain.callChain();
		}.bind(this)).callChain();
	},



	/********** Shop.Frame.showLoading() **********/
	// show the loading graphic in a specific frame
	showLoading: function(key) {
		this.hideLoading();

		if(!this.div[key+'_content']) return;

		var img = new Element('img', { src: 'assets/images/shop-loading.gif', id: 'shopImgLoading' });
		img.setStyles({
			
			position: 'absolute',
			display: 'block',
			'top': this.div[key+'_content'].getTop() + ( this.div[key+'_content'].getHeight() / 2 - 16 ),
			'margin-left': ( this.div[key+'_content'].getWidth() / 2 ) - 16,
			opacity: 0.5
		});
		img.inject(this.div[key+'_content']);
	},

	/********** Shop.Frame.hideLoading() **********/
	// hide the loading graphic
	hideLoading: function() {
		if($('shopImgLoading')) $('shopImgLoading').dispose();
	},

	/********** Shop.Frame.showErrors() **********/
	// 
	showErrors: function(errors) {
		var key = this.parent.options.currentStep;

		var div = $('shop-div-errors');
		if(!div) {
			with( div = new Element('div', { id: 'shop-div-errors' }) ) {
				setStyles({
					position: 'absolute',
					display: 'none'
				});
				addEvent('click', function() {
					this.hideErrors();
				}.bind(this));
				inject(this.parent.container);
			};
		}

		var buf = '<table width="100%" cellpadding="0" cellspacing="0">';
		buf += '<tr><td colspan="3"><h1 style="display:inline;">The following errors were detected, please correct and try again:</h1></td></tr>';

		buf += '<tr>';
		buf += '<td width="5%" align="center"><img src="assets/images/shop-error-exclamation.png" style="display:block;"></td>';
		buf += '<td><ul>';
		for(var i=0; i<errors.length; ++i) {
			buf += '<li>';
			buf += errors[i];
			buf += '</li>';
		}
		buf += '</ul></td>';
		buf += '<td width="5%" valign="bottom"><input type="button" value=" OK " style=""></td>';
		buf += '</tr></table>';


		div.setStyles({
			display: 'block',
			overflow: 'hidden',
			opacity: 0,
			height: 1,
			width: this.contentdiv_width,
			top: this.div[key].getTop() + this.titlebar_height
		});
		div.innerHTML = '<div>' + buf + '</div>';
		
		div.setStyle('height', div.scrollHeight); // don't know why but this fixes an IE bug

		new Fx.Tween(div, {
			duration: 500,
			onStart: function() {
				this.element.setStyle('height', this.element.scrollHeight);
			}
		}).start('opacity', this.parent.options.errorOpacity);
	},

	hideErrors: function() {
		var div = $('shop-div-errors');
		if(div) {
			new Fx.Tween(div, {
				duration: 250,
				onComplete: function() {
					this.element.setStyle('display', 'none');
				}
			}).start('opacity', 0);
		}
	}


});



















