/**
 * utility classes.
 */
var Util = new Class(
{
	/*
	 * RemoveEvents function modified from mootools v1.11 
	 * Element.Methods.Events.removeEvents because
	 *  effects do not have this method.
	 */
	removeEvents : function (elem, type) 
	{
		if (elem.$events[type]){
			elem.$events[type].each(function(fn){
				elem.removeEvent(type, fn);
			}, elem);
			elem.$events[type] = null;
		}
	}
});

var util = new Util();

/**
 * The data required to represent a video.
 */
var Video = new Class({
	ident : false,
	title : false,
	flashURL : false,
	image : false,
	
	initialize : function (id, title, flashURL, image)
	{
		this.ident = id;
		this.title = title;
		this.flashURL = flashURL;
		this.image = image;
	}
});

/**
 * The visual representation of a video.
 */
var VisualVideo = Video.extend({
	initialize : function (id, title, flashURL, imageSRC)
	{
		this.parent(id, title, flashURL, imageSRC);
		var container = new Element("div");
		$extend(container, this);
		container.addClass("vid");
//		container.id = 'thumb_'+id;
		var image = new Element('img');
		image.injectInside(container);
		image.setProperty('alt', title);
		image.setProperty('src', imageSRC);
		var caption = new Element('span');
		caption.addClass("vidCaption");
		caption.setHTML(title);
		caption.injectInside(container);
		
		image.addEvent('click', function (){
				var vid = this.getParent();
				susutv.playFile(vid);
				vid.getParent().getChildren().each(function (elem){
					if(elem != vid)
					{
						var style = new Fx.Style(elem, "opacity", {duration : 300});
						style.start(0.5);
					}
				});
				var style = new Fx.Style(vid, "opacity", {duration : 300});
				style.start(1);
			});
		
		return container;
	},
	
	remove : function ()
	{
		this.parentNode.removeChild(this);
		this.setStyle("opacity", 1);
	}
	
	
});

var VideoHolder = new Class({
	initialize : function ()
	{
		var container = new Element("div");
		container.addClass("videoPlaceHolder");
		$extend(container, this);
		return container;
	}
});

var InitialVisualVideo = Video.extend({
	initialize : function (vid, index)
	{
		this.parent(videoInfo[index].ID, videoInfo[index].title, videoInfo[index].file, videoInfo[index].previewImage);
		$extend(vid, this);
		vid.getChildren(1).addEvent('click', function (){
				
				var vid = this.getParent();
				susutv.playFile(vid);
				vid.getParent().getChildren().each(function (elem){
					if(elem != vid)
					{
						var style = new Fx.Style(elem, "opacity", {duration : 300});
						style.start(0.5);
					}
				});
				var style = new Fx.Style(vid, "opacity", {duration : 300});
				style.start(1);
			});
		
		return vid;
	},
	
	remove : function ()
	{
		if(this.parentNode)
			this.parentNode.removeChild(this);
		this.setStyle("opacity", 1);
	}
});

/**
 * observerable functions for use in the observer pattern
 */
var Observable = new Class({
	observers : false,
	initialize : function ()
	{
		this.observers = new Array();
	},
	
	registerObserver  : function(observer)
	{
		this.observers.push(observer);
	},
	
	notfiyObservers : function()
	{
		this.observers.each(function(elem){
			elem.notify(this);
		}, this);
	}
});

/**
 * Sets and controls the effects when changing page.
 */
var PageChanger = Observable.extend({
	
	channelStore : false,
	effect : false,
	vidsContainer : false,
	indicator : false,
	disabled : false,
	
	initialize : function (channelStore, indicator)
	{
		this.parent();
		this.indicator = indicator;
		this.channelStore = channelStore;
		this.vidsContainer = $('videoContainerMov');
		this.vidsContainer.setStyle("left", 0);
		if(this.channelStore.getCurrentChannel().noOfPages == 1)
		{
			this.disabled = true;
			return;
		}
	},
	
	start : function (direction)
	{
		if((this.channelStore.getCurrentChannel().totalPages == 1) || this.disabled)
			return;
		//refresh vidsContainer - incase we changed channel.
		this.vidsContainer = $('videoContainerMov');
		this.disabled = true;
		this.effect = new Fx.Style(this.vidsContainer, 'margin-left', {duration : 750, transition: Fx.Transitions.Expo.easeOut});
		
		var currentPos = this.vidsContainer.getStyle("margin-left").toInt();
		var nextPos = false;
		var moveDist = 138 * config.vidsPerPage;
		
		var currentChannel = this.channelStore.getCurrentChannel();
		var currentPage = currentChannel.getCurrentPage();
		var nextPage = false;
		if($type(direction) == "number")
		{
			var curInd = currentChannel.currentPageIndex;
			nextPage = currentChannel.getPage(direction);
			if(curInd > direction)
				direction = "left";
			else
				direction = "right";
		}
		else
			nextPage = currentChannel.getNextPage(direction);
			
		var videos = this.vidsContainer.getChildren();
		
		if(direction == "left")
		{
			var node = $(videos[0]);
			this.vidsContainer.setStyle("margin-left", currentPos - moveDist);

			nextPage.getVids().each(function (vid) {
				vid.injectBefore(node);
			});
			
			nextPos = 0;
		}else if(direction == "right")
		{
			var node = $(videos[5]);
			nextPage.getVids().each(function (vid) {
				vid.injectAfter(node);
				node = vid;
			});
			nextPos = -moveDist;
		}
		
		//remove the videos after the new ones are added. and notify any observers
		var boundFunc = function () {
			this.vidsContainer.setStyle("margin-left", 0);
			this.notfiyObservers();
			this.disabled = false;
			}.bind(this);
		this.effect.addEvent("onComplete", function () {
				currentPage.getVids().each(function (elem){elem.remove();});
			boundFunc();
		});
		this.effect.start(nextPos);
		this.indicator.start(currentChannel.currentPageIndex);
	}
});

var PageIndicatorChanger = new Class({
	indicatorImages : false,
	replaced : false,
	selected : false,
	
	initialize : function (index) {
		this.indicator = $("pageIndicator");
		this.indicatorImages = this.indicator.getChildren();
		this.selected = this.makeSelectedImage();
		
		this.indicatorImages.each(function (elem, index) {
			elem.addEvent("click", function () {susutv.pageChanger.start(index);});
		}, this);

		this.replaced = this.indicatorImages[index];
		this.selected.injectBefore(this.indicatorImages[index]);
		this.indicatorImages[index].remove();
	},
	
	makeSelectedImage : function () {
		var im = new Element("img");
		im.setProperty("src", config.pageSelImgSRC);
		im.setProperty("alt", config.pageSelImgALT);
		return im;
	},
	
	start : function (index) {
		//put all unselected
		this.replaced.injectBefore(this.selected);
		this.selected.remove();
		var toBeReplaced = this.indicator.getChildren()[index];
		//alert(toBeReplaced +" " +toBeReplaced.getParent()+" " + index);
		//put the selected image in.
		this.selected.injectBefore(toBeReplaced);
		toBeReplaced.remove();
		this.replaced = toBeReplaced;

	},

	setTotalPages : function (total, startPage)
	{
		var diff = total - this.indicator.getChildren().length;
		//alert(total + " " + diff + " " + this.indicator.getChildren().length);
		//get rid of the this page active button
		this.replaced.injectBefore(this.selected);
		this.selected.remove();
		
		if(diff > 0)
		{
			len  = this.indicator.getChildren().length;
			//add
			for (var i = 0; i < diff ; i++)
			{
				var img = new Element("img");
				img.setProperty("src", this.replaced.getProperty("src"));
				//alert(this.indicatorImages[0].parentNode);
				img.injectInside(this.indicator);
			}
			
			this.indicator.getChildren().each(function (elem, index) {
				elem.removeEvents("click");
				elem.addEvent("click", function () {susutv.pageChanger.start(index);});
				elem.setProperty("alt", "Page "+index);
			}, this);
			
		}else if (diff < 0)
			//remove
		{
			var change = this.indicator.getChildren().length + diff - 1;
			for (var i = this.indicator.getChildren().length-1; i > change ; i--)
				this.indicator.getChildren()[i].remove();
		}
		var toBeReplaced = this.indicator.getChildren()[startPage];
		//alert(toBeReplaced +" " +toBeReplaced.getParent()+" " + index);
		//put the selected image in.
		this.selected.injectBefore(toBeReplaced);
		toBeReplaced.remove();
		this.replaced = toBeReplaced;
	}
});

var ChannelStore = new Class({
	channels : false,
	currentChannel : false,

	initialize : function (firstChannel, chanNo)
	{
		this.channels = new Array();
		this.channels[chanNo] = firstChannel;
		this.currentChannel =  chanNo;
	},
	
	getCurrentChannel : function()
	{
		return this.channels[this.currentChannel];
	},
	
	getChannel : function(channel)
	{
		if($defined(this.channels[channel]))
		{
			this.currentChannel = channel;
			this.channels[channel] = new PageStore(0,false,channel, true);

			return this.channels[channel]
		}
		this.currentChannel = channel;
		this.channels[channel] = new PageStore(0,false,channel, true);
		return this.channels[channel];
	}
});

var ChannelChanger = new Class({
	channelStore : false,
	pageChanger : false,
	disabled : false,
	curIndex : false,
		
	initialize : function (channelStore, pageChanger, curIndex)
	{
		
		this.channelStore = channelStore;
		this.pageChanger = pageChanger;
		this.curIndex = curIndex;
		
	},
	
	start : function (channel, nextIndex)
	{
		
		if(this.disabled || (this.channelStore.currentChannel == channel))
			return;
		this.disabled = true;
		var newContainer = new Element("div");
		newContainer.setProperty("id", 'videoContainerMov');
		var nextChannel = this.channelStore.getChannel(channel);
		var curIndex = this.curIndex;
		this.curIndex = nextIndex;
		var pageChanger = this.pageChanger;
		var boundFunc = function () {this.disabled=false;}.bind(this);
		(function (){
			//may have to wait if the channel is not cached.
			if($defined(nextChannel.getCurrentPage()))
			{
				nextChannel.getCurrentPage().getVids().each(function (vid){
					vid.injectInside(newContainer);
				});
				var oldContainer = $('videoContainerMov');
					if(curIndex < nextIndex)
				{
					newContainer.injectAfter(oldContainer);
					var par = newContainer.getParent();
					var slide = new Fx.Style(par, "margin-top", {duration : 750, transition: Fx.Transitions.Expo.easeOut})
					slide.start("-120px");
				}else
				{
					newContainer.injectBefore(oldContainer);
					var par = newContainer.getParent();
					par.setStyle("margin-top", "-120px");
					var slide = new Fx.Style(par, "margin-top", {duration : 750, transition: Fx.Transitions.Expo.easeOut})
					slide.start("0px");
				}
				slide.addEvent("onComplete", function () {
					oldContainer.remove();
					//set opacity to 1 incase we were playing a video
					oldContainer.getChildren().each(function (elem){elem.setStyle("opacity", 1);});
					par.setStyle("margin-top", "0px");
					boundFunc();
				});
				
				pageChanger.indicator.setTotalPages(nextChannel.totalPages,nextChannel.currentPageIndex);
			}else
				this.delay(150);			
		}).delay(10);		
	}
});
/**
 * Responsible for caching the next and previous pages, and fetching new ones.
 */
var PageStore = new Class({
	currentPageIndex : false,
	pages : false,
	imagesPerPage : false,
	maxIndex : false,
	channel : false,
	totalPages : false,
	/**
	 * @param channel Integer the channel that we will fetch pages for (null=allvids).
	 * @param newPage Boolean Whether there are already videos from this channel on the page
	 */
	initialize : function(start, noOfImages, channel, newPage, totalPages)
	{
		this.pages = new Array();
		this.currentPageIndex = start;
		if(!$defined(channel))
			channel = null;
		this.channel = channel;
		var vidsOnscreen = $$(".vid");
		//alert(totalPages);
		this.imagesPerPage = noOfImages || vidsOnscreen.length;
		this.maxIndex =  totalPages -1;
		this.totalPages  = totalPages;
		if(newPage == true)
		{
			this.cache(start);
		}else
		{
			this.pages[start] = new Page(false);
			// get the current page
			vidsOnscreen.each(function (element){
				this.pages[start].addVideo(new InitialVisualVideo(element, $E("span.videoID", element).innerHTML));
			},this);
			$$(".videoPlaceHolder").each(function (element){
				this.pages[start].addVideo(element);
			},this);
		}
//		console.log(this.totalPages);
		for(var i = 0; i<=this.totalPages; i++)
			this.cache(i);
	},
	
	getCurrentPage : function()
	{
		//return the current page
		return this.pages[this.currentPageIndex];
	},
	
	getNextPage : function(direction)
	{		
		
		//get the next page in the direction given
		if(direction == "left")
		{
			if(this.currentPageIndex == 0)
				this.currentPageIndex = this.maxIndex;
			else
				this.currentPageIndex -= 1;
		}
		else
		{
			if(this.currentPageIndex == this.maxIndex)
				this.currentPageIndex = 0;
			else
				this.currentPageIndex += 1;
		}
		//alert(this.currentPageIndex+" "+ this.totalPages+" "+ this.maxIndex);
		return this.pages[this.currentPageIndex];
	},
	
	getPage : function (index)
	{
		this.currentPageIndex = index;
		return this.pages[index];
	},
	
	cacheTheRest : function()
	{
		for(var i = 0; i<=this.totalPages; i++)
			this.cache(i);
		
		
	},

	/**
	 * cache the pages to avoid slowdown on image load.
	 */
	cache : function (index)
	{
		//console.log(this.channel);
//		for(var i = 0; i<=this.totalPages; i++)
//			this.cache(i);
		
		if($defined(this.pages[index]))
			return;
		func = function(el){this.cacheOnComplete(el, index);};
		boundFunc = func.bind(this);
		var ajax = new Ajax("AjaxHandler.php", {onComplete : boundFunc, data : "page="+index+"&channel="+this.channel });
		ajax.request();
	},
	
	cacheOnComplete : function (json, index)
	{
		json = Json.evaluate(json);
		var vidsArr = new Array();
		json.videos.each(function (obj) {
			if(obj.ID != "holder")
				vidsArr.push(new VisualVideo(obj.ID, obj.title, obj.file, obj.previewImage));
			else
				vidsArr.push(new VideoHolder());
		});
		if(!this.totalPages){
			this.totalPages = json.totalPages;
			this.cacheTheRest();
		} else {
			this.totalPages = json.totalPages;
		}
		this.maxIndex =  this.totalPages -1;
		this.pages[index] = new Page(vidsArr);
//		for(var i = 0; i<this.totalPages; i++)
//			this.cache(i);
	}
});

/**
 * Stores all of the VisualVideo objects for a given page.
 */
var Page = new Class({
	visualVideos : false,
	
	initialize : function(videos)
	{
		this.visualVideos = videos || new Array();
	},
	
	addVideo : function(vid)
	{
		this.visualVideos.push(vid);
	},
	
	getVids : function()
	{
		return this.visualVideos;
	}
});

var SusuTVObserver = new Class({
	pageChangeIndicator : false,
	channelChanger : false,
	channelStore : false,
	pageChanger : false,
	pageStore : false,
	controller : false,
	
	
	initialize : function ()
	{
		this.pageStore = new PageStore(config.currentPage, false, config.currentChannel, false, config.noOfPages);
		this.channelStore = new ChannelStore(this.pageStore, config.currentChannel);
		this.pageChangeIndicator = new PageIndicatorChanger(this.pageStore.currentPageIndex)
		this.pageChanger = new PageChanger(this.channelStore, this.pageChangeIndicator);
		this.pageChanger.registerObserver(this);
		
		this.channelChanger = new ChannelChanger(this.channelStore, this.pageChanger, config.currentIndex);
		this.controller = new FlashController();
		this.notify();
		
		var currentVids = this.channelStore.getCurrentChannel().getCurrentPage().getVids();
		currentVids.each(function (elem){
			if(elem.ident != config.defaultVid)
			{
				var style = new Fx.Style(elem, "opacity", {duration : 300});
				style.start(0.5);
			}
		});
	},
	
	notify : function ()
	{
	},
	
	playFile : function (video)
	{
		this.controller.loadFile({ file : video.flashURL, title: video.title, previewImage : video.image});
		$("linkID").innerHTML = video.ident;
		this.controller.togglePlay();
	},
	
	changeChannel : function (channel, buttonPressed, index)
	{
		buttonPressed.blur();
		this.channelChanger.start(channel, index);
		var id  = $(buttonPressed).getProperty("id");
		$("current").setProperty("id", "");
		buttonPressed.setProperty("id", "current");
		return false;
	}
});

var susutv = false;

function domReady ()
{
	susutv = new SusuTVObserver();
}
window.addEvent('load', domReady);
/**
 * The functionality to load a file and toggle the play on a flash video.
 */
var FlashController = new Class ({
	player : false,
	initialize : function () {
		this.player = $('playerID');
	},
	
	loadFile : function (obj)
	{
		this.player.loadFile(obj);
	},
	
	togglePlay : function () {
		this.player.sendEvent('playpause');
	}
});
