var Ct_Slider = Class.create(Ct_Component_Abstract, {

	NEXT_PAGE: 'next_page',
	PREV_PAGE: 'prev_page',

	_isDone: true,

	_setNamespace: function() {
		this._namespace = 'ctSlider';
	},

	__construct: function() {

		Ct_Page.domLoaded(this._assemble.bind(this));

		//
		// EVENT OBSERVING
		//

		// page refresh
		this.element.on('Ct_Page:refresh', null, this._assemble.bindAsEventListener(this));

		this.element.on('click', '.' + this._namespace + '-pagerButton', this.onPagerButtonClick.bindAsEventListener(this));

		this.element.on('click', '.' + this._namespace + '-nextButton', this.onNextButtonClick.bindAsEventListener(this));
		this.element.on('click', '.' + this._namespace + '-prevButton', this.onPrevButtonClick.bindAsEventListener(this));

	},

	_assemble: function() {
		$$('.' + this._namespace).each(function(element) {
			var config, contentContainer;

			if (this.isAssembled(element)) {
				return;
			}

			this._markAsAssembled(element);

			config = this._makeConfig(element);
			element.store('config', config);

			contentContainer = element.down('.' + this._namespace + '-contentContainer');
			element.store('contentContainer', contentContainer);

			// Process pager
			//
			var pagerContainer,pagerButtonList;

			pagerContainer = element.down('.' + this._namespace + '-pagerContainer');
			if (Object.isElement(pagerContainer)) {
				element.store('isHasPager', true);

				element.store('pagerContainer', pagerContainer);

				// process pager button
				pagerButtonList = new Hash();
				element.select('.' + this._namespace + '-pagerButton').each(function(pagerButton) {
					var config;

					if (pagerButton.retrieve('config', false) !== false) {
						return;
					}

					config = this._makeConfig(pagerButton);

					if (!('pageNum' in config)) {
						throw this._namespace + ': _assemble - field "pageNum" is required in PagerButton config';
					}

					pagerButton.store('config', config);
					pagerButton.store('pageNum', config.pageNum);
					pagerButtonList.set(config.pageNum, pagerButton);
					pagerButton.store('element', element);

				}.bind(this));
				element.store('pagerButtonList', pagerButtonList);
			} else {
				element.store('isHasPager', false);
			}

			element.store('pageCount',  element.select('.' + this._namespace + '-page').length);

			// Process content storage
			//

			var contentStorage, currentPage;
			contentStorage = element.down('.' + this._namespace + '-contentStorage');
			element.store('contentStorage', contentStorage);

			if (!Object.isElement(contentStorage)) {
				throw this._namespace + ': _assemble invalid DOM element "contentStorage"';
			}

			contentStorage.select('.' + this._namespace + '-page').each(function(page) {
				var config = this._makeConfig(page);

				if (!('pageNum' in config)) {
					throw this._namespace + ': _assemble - field "pageNum" is required in Page config';
				}
				this._storePage(element, config.pageNum, page);
			}.bind(this));

			if (element.retrieve('config') && 'currentPage' in element.retrieve('config')) {
				currentPage = element.retrieve('config').currentPage;
			} else {
				currentPage = 0;
			}

			// Show first page
			//

			var newContainer;
			contentContainer = element.retrieve('contentContainer');
			newContainer = new Element('div', {className: this._namespace + '-content'});
			newContainer.update(this._retrievePage(element, currentPage));
			contentContainer.insert(newContainer);
			element.store('currentPage', currentPage);

		}.bind(this));
	},

	onPagerButtonClick: function(event) {
		var button, element;
		Event.stop(event);

		button = Event.findElement(event, '.' + this._namespace + '-pagerButton');
		element = button.retrieve('element');

		this.gotoPage(element, button.retrieve('pageNum'));
	},

	onNextButtonClick: function(event) {
		var button, element;
		Event.stop(event);
		button = Event.findElement(event, '.' + this._namespace + '-nextButton');
		element = button.up('.' + this._namespace);
		this.gotoPage(element, element.retrieve('currentPage', 0) + 1);
	},

	onPrevButtonClick: function(event) {
		var button, element;
		Event.stop(event);
		button = Event.findElement(event, '.' + this._namespace + '-prevButton');
		element = button.up('.' + this._namespace);
		this.gotoPage(element, element.retrieve('currentPage', 0) - 1);
	},

	gotoPage: function(element, pageNum) {
		var currentPage, pageCount, direction;

		if (!this._isDone) {
			return;
		}
		this._isDone = false;

		currentPage = element.retrieve('currentPage', 0);

		// Determine navigation direction in pager context
		//

		pageCount = element.retrieve('pageCount');
		direction = pageNum > currentPage ? this.NEXT_PAGE : this.PREV_PAGE;

		if (pageNum >= pageCount) {
			pageNum = 0;
		} else if (pageNum < 0) {
			pageNum = pageCount - 1;
		}

		if (pageNum == currentPage) {
			this._isDone = true;
			return;
		}

		// Mark active page
		//

		if (element.retrieve('isHasPager') === true) {
			var pagerButtonList, pagerButton;
			pagerButtonList = element.retrieve('pagerButtonList');
			pagerButton = pagerButtonList.get(pageNum);
			pagerButtonList.values().invoke('removeClassName', 'active');
			pagerButton.addClassName('active');
		}
		element.store('currentPage', pageNum);

		this._flipPage(element, this._retrievePage(element, pageNum), direction);
	},

	_flipPage: function(element, page, direction) {
 		var contentContainer, oldContainer, newContainer, content;

		if (!page) {
			this._isDone = true;
			return;
		}

		if (Object.isElement(page)) {
			content = page.innerHTML;
		} else {
			content = new Element('div').update(page).innerHTML;
		}

		contentContainer = element.retrieve('contentContainer');
		oldContainer = contentContainer.down('.' + this._namespace + '-content');
		newContainer = new Element('div', {className: this._namespace + '-content new'});
		newContainer.hide();
		newContainer.update(content);
 		contentContainer.insert(newContainer);

		if (Object.isElement(oldContainer)) {
			this._toggleContent(contentContainer, oldContainer, newContainer, direction);
		} else {
			throw this._namespace + ': _flipPage - oldContainer undefined (look insertPage)';
		}
	},

	_toggleContent: function(container, prev, next, direction) {
		var d, nd;
		d = direction == this.PREV_PAGE ? '' : '-';
		nd = direction == this.PREV_PAGE ? '-' : '';

		// Hide old
		new Effect.Parallel([
			new Effect.Opacity(prev, {sync: true, from: 1, to: 0.3}),
			new Effect.Morph(prev, {
				sync: true,
				style: 'left: ' + d + prev.getWidth() + 'px'
			})
		], {
			duration: 0.8,
			beforeSetup: function() {
				container.makePositioned();
				prev.absolutize();
			},
			afterFinish: function() {
				prev.remove();
			}
		});

		// Show new
		new Effect.Parallel([
			new Effect.Opacity(next, {sync: true, from: 0.3, to: 1}),
			new Effect.Morph(next, {
				sync: true,
				style: 'left: 0px'
			})
		], {
			duration: 0.8,
			delay: 0.2,
			beforeSetup: function() {
				container.setStyle({
					width: container.getWidth() + 'px',
					overflow: 'hidden',
					position: 'relative'
				});

				next.absolutize(); // width, height
				next.setStyle({left: nd + container.getWidth() + 'px', top: 0});
				next.show();
			}.bind(this),
			afterFinish: function() {
				container.setStyle({
					width: '100%',
					overflow: 'hidden',
					position: 'static'
				});
				next.setStyle({position: 'static', width: '100%'});
				this._isDone = true;
			}.bind(this)
		});
	},

	_storePage: function(element, pageNum, pageContent) {
		var cache = element.retrieve('cache', new Hash());
		cache.set(pageNum, pageContent);
		element.store(cache);
	},

	_retrievePage: function(element, pageNum) {
		var cache = element.retrieve('cache', new Hash());
		return cache.get(pageNum);
	},

	refresh: function(ident, response) {
		var element = $(ident);
		if (!Object.isElement(element)) {
			return;
		}
		if (response.html && response.html.length) {
			element.update(response.html);
		}
	},

	x: null
});

Ct_Page.registerScript("Ct_Slider");

