require('Ojay', 'Ojay.HTTP', function() {
	Gallery = new JS.Class('Gallery', {
		include: [Ojay.Observable, JS.State],
	
		initialize: function(root, imageContainers) {
			this._root = Ojay(root).addClass('show-captions');
		
			this._images = Ojay(imageContainers).map(function(container) {
				var caption = container.children('.caption'),
					link    = container.children('a'),
					img     = link.children('img'),
					wrapper;
				
					wrapper = 	Ojay(Ojay.HTML.div(function(H) {
									// If the file is a video
									if (/^.*\.(flv|mp4|ogg)$/.test(link.node.href.toLowerCase())) {
									H.a({id: 'player', href: link.node.href});
									}
									// If it is a youtube video in you_tube.html
									else if (/^.*\.(html)/.test(link.node.href.toLowerCase())) {
										youtubeWrapper = Ojay(H.div({className: 'youtube_vid'}));
										Ojay(link).on("click", function(){
											Ojay.HTTP.GET(link.node.href)
											.insertInto(youtubeWrapper)
											.evalScripts()
										});
									}
									else {
									// It should be an image
										H.img({alt: img.node.alt, src: link.node.href});
										};
								})).insert(caption);
			

				wrapper.setStyle({
					position: 'absolute',
					top:      0,
					left:     0,
					zIndex:   1,
					opacity:  0
				}).hide();
			
				return wrapper;
			});
		
			this._current = 0;
			this._captionsVisible = true;
		
			this.setState('CREATED');
		},
	
		states: {
			CREATED: {
				setup: function() {
					this._container = Ojay(Ojay.HTML.div({id: 'viewport'})).setStyle({
						position: 'relative',
						overflow: 'hidden',
						width:    '585px',
						height:   '240px'
					});

					this._images.forEach(function(image) {
						this._container.insert(image, 'bottom');
					}, this);

					this._images[this._current].setStyle({
						opacity: 1,
						zIndex:  3
					}).show();

					this._root.insert(this._container, 'top');
				
					this.on('imagechange', function() {
						if (this._action && typeof this[this._action] === 'function') {
							this[this._action]();
							delete this._action;
						}
					}, this);
				
					this.setState('READY');
				}
			},
		
			READY: {
				setImage: function(index, controller) {
					if (index === this._current) return;

					var current = this._images[this._current],
						next    = this._images[index];
				
					// if (controller !== this) {
					// 	this.pause();
					// }
				
					this.setState('ANIMATING');
				
					current.setStyle({zIndex: 1})
					._(next).show().setStyle({zIndex: 3}).animate({
						opacity: {
							from: 0,
							to:   1
						}
					}, 1.0)
					._(current).setStyle({opacity: 0}).hide()
					._(function(self) {
						self._current = index;
						self.setState('READY');
						self.notifyObservers('imagechange', next, index);
					}, this);
				},
			
				next: function() {
					var nextImage = this._current + 1;
				
					if (nextImage >= this._images.length) nextImage = 0;
				
					this.setImage(nextImage);
				},
			
				previous: function() {
					var previousImage = this._current - 1;
				
					if (previousImage < 0) previousImage = this._images.length - 1;
				
					this.setImage(previousImage);
				},
			
				play: function() {
					this._playing = setInterval(function() {
						this.next();
					}.bind(this), 3000);

					this.next();
				},
			
				pause: function() {
					clearInterval(this._playing);
					this._playing = null;
				}
			},
		
			ANIMATING: {
				play: function() {
					this._action = 'play';
				},
			
				pause: function() {
					this._action = 'pause';
				}
			}
		},
	
		getCurrentIndex: function() {
			return this._current;
		},
	
		isPlaying: function() {
			return typeof this._playing === 'number';
		},
	
		hideCaptions: function() {
			if (this._captionsVisible) {
				this._root.replaceClass('show-captions', 'hide-captions');
				this._captionsVisible = false;
			}
		},
	
		showCaptions: function() {
			if (!this._captionsVisible) {
				this._root.replaceClass('hide-captions', 'show-captions');
				this._captionsVisible = true;
			}
		},
	
		captionsVisible: function() {
			return this._captionsVisible;
		},
	
		getImages: function() {
			return this._images;
		}
	});

	Gallery.Controls = {};

	Gallery.Controls.Next = new JS.Class('Gallery.Controls.Next', {
		initialize: function(gallery) {
			this._gallery = gallery;
		
			this._html 		 = Ojay(Ojay.HTML.div({className: 'next-previous-controls'}));
			this._prevButton = Ojay(Ojay.HTML.div({className: 'previous'}, 'Previous'));
			this._nextButton = Ojay(Ojay.HTML.div({className: 'next'}, 'Next'));
		
			this._html.insert(this._prevButton).insert(this._nextButton, 'bottom');
		
			this._prevButton.on('click')._(this._gallery).previous();
			this._nextButton.on('click')._(this._gallery).next();
		},
	
		getHTML: function() {
			return this._html;
		}
	});

	Gallery.Controls.Captions = new JS.Class('Gallery.Controls.Captions', {
		initialize: function(gallery) {
			this._gallery = gallery;
			this._html    = Ojay(Ojay.HTML.div({className: 'control'}, 'Hide captions'));
		
			this._html.on('click')._(this).toggleCaptions();
		},
	
		toggleCaptions: function() {
			var method, text;
		
			if (this._gallery.captionsVisible()) {
				method = 'hideCaptions';
				text   = 'Show captions';
			} else {
				method = 'showCaptions';
				text   = 'Hide captions';
			}
		
			this._gallery[method]();
			this._html.setContent(text);
		},
	
		getHTML: function() {
			return this._html;
		}
	});

	Gallery.Controls.Slideshow = new JS.Class('Gallery.Controls.Slideshow', {
		initialize: function(gallery) {
			this._gallery = gallery;
			this._html    = Ojay(Ojay.HTML.div({className: 'control slideshow'}, 'Start Slideshow'));
		
			this._html.on('click')._(this).toggleSlideshow();
		},
	
		toggleSlideshow: function() {
			var method, text;
		
			if (this._gallery.isPlaying()) {
				method = 'pause';
				text   = 'Play slideshow';
			} else {
				method = 'play';
				text   = 'Pause slideshow';
			}
		
			this._gallery[method]();
			this._html.setContent(text);
		},
	
		getHTML: function() {
			return this._html;
		}
	});

	Gallery.Controls.Thumbnails = new JS.Class('Gallery.Controls.Thumbnails', {
		initialize: function(gallery, container, options) {
			this._gallery   = gallery;
			this._container = Ojay(container);
			this._links     = this._container.descendants('a');
			this._options   = options || {};
		},
	
		setup: function() {
			var self = this;
			this._links.forEach(function(link, i) {
				link.on('click', function(elem, evnt) {
					evnt.stopDefault();
					self._gallery.setImage(i);
				});
			});
		
			this._paginator = new Ojay.Paginator(this._container, this._options);
			this._paginator.setup();
			this._paginator.addControls('after');
		},
	
		getHTML: function() {
			return this._paginator.getHTML();
		}
	});

	Gallery.Notifier = new JS.Class('Gallery.Notifier', {
		initialize: function(gallery, container) {
			this._gallery   = gallery;
			this._container = Ojay(container);
			this._html      = Ojay(Ojay.HTML.p({className: 'gallery-notifier'}));
		
			this._gallery.on('imagechange', function(g, image, index) {
				this.update(index, g.getImages().length);
			}, this);
		
			this._container.insert(this._html);
			this.update(this._gallery.getCurrentIndex(), this._gallery.getImages().length);
		},
	
		getHTML: function() {
			return this._html;
		},
	
		update: function(index, count) {
			this._html.setContent('Slide ' + (index + 1) + ' of ' + count);
		}
	});
});
