var tomcode = tomcode || {};

tomcode.error = {
	
	check:function(e, emmetter) {
		
		if(emmetter in this) {
			
			this[emmetter].count++;
			
			// console.log(this[emmetter].count, this[emmetter].max, 'error.check');

			if(this[emmetter].count >= this[emmetter].max) {
				
				this[emmetter].callback(e, emmetter);

				this.unregister(emmetter);
				
			}
		}
	},
	
	unregister:function(emmetter) {

		if(emmetter in this) {
			
			delete this[emmetter];
		}
	},
	
	register:function(count, emmetter, callback) {
		
		this[emmetter] = {

			count:0,
			max:count,
			callback:callback
		};
	}
};

tomcode.events = {
	
	eventLists:[
		{
			ident:'videoEl',
			lists:[
				{
					events:['abort', 'error', 'canplay', 'canplaythrough', 'error', 'loadeddata'],
					suffix:'Handler'
				},
				{
					events:['error'],
					suffix:'SrcHandler'
				}
			]
		}
	],
	
	addList:function(ident, list) {
		
		var i;
		
		for(i = 0; i < this.eventLists.length; i++) {
			
			if(this.eventLists[i].ident === ident) {
				
				this.eventLists[i].lists.push(list);
			}
		}
		// console.log(this.eventLists, 'events addList this.eventLists[i]');
	},
	
	remove:function(el, ident) {
		
		// console.log(ident, 'events remove');

		this._set(el, ident, 'removeEventListener');
	},
	
	add:function(el, ident) {

		// console.log(ident, 'events add');

		this._set(el, ident, 'addEventListener');
	},

	_set:function (el, ident, method){

		var i, j, k,
			lists = this.eventLists,
			list, eve, elEvents;
		
		for(i = 0; i < lists.length; i++) {
			
			list = lists[i];
				
			if(list.ident !== ident) {
				
				continue;
				
			}
			
			for(j = 0; j < list.lists.length; j++) {
				
				elEvents = list.lists[j];
				
				for(k = 0; k < elEvents.events.length; k++) {
				
					eve = elEvents.events[k];
				
					switch(method) {
						
						case 'addEventListener' :
						el.addEventListener(eve, tomcode.events[eve +elEvents.suffix], false);
						break;
						
						default :
						el.removeEventListener(eve, tomcode.events[eve +elEvents.suffix], false);
						break;
					}
				}
			}
		}
		
	},
	
	
	loadeddataHandler:function(e) {
		
		// console.log('listener loadeddata');
		
		this.setAttribute('class', 'loadeddata');
	},

	canplayHandler:function(e) {

		// if('console' in window) console.log('listener canplay',  e.srcElement.currentSrc);
		// console.log('listener canplay e.target.networkState', e.target.networkState);
		// console.log('listener canplay e.target.networkState', e.target);

		this.play();

		// this.setAttribute('class', 'canplay');
	},
	abortHandler:function(e) {

		// if('console' in window) console.log('listener abort', e.srcElement.currentSrc);
		// console.log('listener abort e.target.networkState', e.target.networkState);
		// console.log('listener abort', e);

		// var videoHash = tomcode.player.hashPart(1),
		// 	sourcesStr = tomcode.player.movie(videoHash, 'sources'),
		// 	sources = tomcode.player.extractSources(sourcesStr, videoHash +'.sources');
		// 
		// console.log('listener abort sources', sources);

		if(e.target.networkState != HTMLMediaElement.NETWORK_LOADING) {

			tomcode.player.tryFlash(e);

		} else {
			
			this.play();

			this.setAttribute('class', 'canplay');
		}
	},
	
	errorHandler:function(e) {

		/*
		Ready States
		------------
		0 HAVE_NOTHING (numeric value 0)
			No information regarding the media resource is available.
			No data for the current playback position is available.
			Media elements whose networkState attribute are set to NETWORK_EMPTY 
			are always in the HAVE_NOTHING state.
		1 HAVE_METADATA (numeric value 1)
			Enough of the resource has been obtained that the duration of 
			the resource is available. In the case of a video element, the 
			dimensions of the video are also available. The API will no longer 
			raise an exception when seeking. No media data is available for the 
			immediate current playback position. The text tracks are ready.
		2 HAVE_CURRENT_DATA (numeric value 2)
			Data for the immediate current playback position is available, but either 
			not enough data is available that the user agent could successfully advance 
			the current playback position in the direction of playback at all without 
			immediately reverting to the HAVE_METADATA state, or there is no more data t
			o obtain in the direction of playback. For example, in video this corresponds 
			to the user agent having data from the current frame, but not the next frame; 
			and to when playback has ended.
		3 HAVE_FUTURE_DATA (numeric value 3)
			Data for the immediate current playback position is available, as well 
			as enough data for the user agent to advance the current playback position 
			in the direction of playback at least a little without immediately reverting 
			to the HAVE_METADATA state. For example, in video this corresponds to the 
			user agent having data for at least the current frame and the next frame. 
			The user agent cannot be in this state if playback has ended, as the current 
			playback position can never advance in this case.
		4 HAVE_ENOUGH_DATA (numeric value 4)
			All the conditions described for the HAVE_FUTURE_DATA state are met, 
			and, in addition, the user agent estimates that data is being fetched 
			at a rate where the current playback position, if it were to advance 
			at the effective playback rate, would not overtake the available data 
			before playback reaches the end of the media resource.
			
		Network states
		--------------
		0 NETWORK_EMPTY (numeric value 0)
			The element has not yet been initialized. All attributes are 
			in their initial states.
		1 NETWORK_IDLE (numeric value 1)
			The element's resource selection algorithm is active and has 
			selected a resource, but it is not actually using the network at this time.
		2 NETWORK_LOADING (numeric value 2)
			The user agent is actively trying to download data.
		3 NETWORK_NO_SOURCE (numeric value 3)
			The element's resource selection algorithm is active, but it 
			has not yet found a resource to use.
		*/
		
		// console.log('listener error', 'network ' +e.target.networkState, 'ready ' +e.target.readyState);

		e.target.setAttribute('class', 'error');
		
		switch(true) {
			
			case e.target.networkState === HTMLMediaElement.NETWORK_EMPTY :
			tomcode.player.tryFlash(e);
			break;
			
			default :
			break;
		}
	},

	errorSrcHandler:function(e) {

		// console.log(e, 'listener errorSrcHandler e');

		tomcode.error.check(e, 'errorSrcHandler');
	}
};
		
tomcode.videoPlayer = {

	// values may contain the codec
	// the video tag's type attribute
	mimeTypes: {
		mp4:'video/mp4',
		m4v:'video/mp4',
		ogg:'video/ogg',
		webm:'video/webm'
	},
	htmlTitle:'',
	
	sourceType:function(fileName) {

		var type,
			mimeTypes = this.mimeTypes;

		if(fileName) {
			
			type = fileName.split('.').pop();

			if(type && type in mimeTypes) {
			
				return mimeTypes[type]; 
			}
		}
		
		return '';
	},
	
	detectPlayable:function(sources, el) {
	
		el = el || document.createElement('video');
		
		// console.log(sources, 'detectPlayable sources');

		if(! el || ! ('canPlayType' in el)) { 
			
			return false;
		}
	
		if(! sources || ! tomcode.utils.isArray(sources)) { 
			
			return false;
		}
		
		var type,
			i, 
			strNoOrBoolean;
			
			for(i = 0; i < sources.length; i++) {
			
				type = this.sourceType(sources[i]);
				
				// console.log('detectPlayable type', type);
				
				if( ! type) {
					
					continue;
				}
				
				strNoOrBoolean = el.canPlayType(type);
		
				// console.log('videoPlayer detectPlayable ' +type +' "' +strNoOrBoolean +'"');

				if(! (strNoOrBoolean === 'no' || ! strNoOrBoolean) ) {

					// console.log('videoPlayer detectPlayable BINGO', type);
					
					return true;
				}
			}

		return false;
	}
};

tomcode.transitions = {
	
	eventTypeName:null,

	support:function() {
		
		return this._support();
	},
	
	_support:function() {
		
		var r,
			eventTypeName = this.eventTypeName || false;

		switch(true) {
		
			case eventTypeName :
			break;
			
			// webkit future ?
			case window.transitionend !== undefined:
			// webkit now
			case window.onwebkittransitionend !== undefined:
			eventTypeName = 'webkitTransitionEnd';
			break;
			
			// Firefox 4
			case 'TransitionEvent' in window:
			eventTypeName = 'transitionend';
			break;
							
			default:
			// Opera 11.11
			try { r = document.createEvent('OTransitionEvent') ;} catch(e) {}
			if(r) {
				eventTypeName = 'otransitionend';
				r  = null;
			}
			break;
		}
		
		this.eventTypeName = eventTypeName;
		
		return eventTypeName;
	}
};

tomcode.uri = {
	
	hashPart:function(segment, hash) {
		
		var parts = tomcode.uri.hashParts(hash);
		
		return parts[segment] || false;
	},
	
	hashParts:function(hash) {

		hash = hash ? hash : location.hash;
		
		hash =hash.split('#/').join('#').split('#').join('');
		
		return hash.split('.');
	},
	
	hash:function(hashString) {
		
		return '#' +hashString;
	}
};
tomcode.player = {
	
	mediaPath:'files/test/',
	
	categories:['cat1', 'cat2', 'cat3'],
	
	watchInterval:false,
	
	strings:{
		'en':{
			'error.title.404':"Sorry",
			'error.message.404':"There are no videos to show",
			'error.title.errorSrcHandler':"Movie Error",
			'error.message.errorSrcHandler':"Did not find a suitable movie format."
		},
		'fr':{
			'error.title.404':"Oups",
			'error.message.404':"Il n'y a pas de videos à montrer",
			'error.title.errorSrcHandler':"Erreur video",
			'error.message.errorSrcHandler':"Impossible de trouver un format video adapté."
		}
	},
	
	idents:{},
	
	oldHash:'',
	hasMessage:false,
	hashPart:false,
	
	movies:{},
	
	tryFlash:function(e) {
		
		// if('console' in window) console.log('tryFlash');
		// if(e) {
		// 	// console.log('tryFlash', e.target.networkState, 'readyState ' +e.target.readyState);
		// }
		
		var videoHash = tomcode.player.hashPart(1),
			sourcesStr = tomcode.player.movie(videoHash, 'sources'),
			sources,
			mediaPath = tomcode.player.mediaPath,
			sourceStr = videoHash +'-desktop.mp4',
			data = {},
			description = this.movie(videoHash, 'description');
		
		sources = tomcode.player.extractSources(sourcesStr, videoHash +'.sources');
		
		// console.log('tryFlash sources', sources);
		// console.log('tryFlash sourceStr', sourceStr);
		
		// if(tomcode.utils.inArray(sourceStr, sources)) {
		if(e && (e.target.networkState === HTMLMediaElement.NETWORK_NO_SOURCE)) {
			
			// if('console' in window) console.log('tryFlash', 'if e');
			
			tomcode.player.removeVideo();
		
		}
		
		data.sourceStr = tomcode.utils.baseUrl() +mediaPath +videoHash +'/' +sourceStr;
		
		tomcode.view('embedFlash', data);

		this.movie(videoHash, 'description')
		
		if(description === videoHash +'.description') {
			
			description = '';
		}

		tomcode.view('description', {
			videoHash:videoHash,
			description:description
		});
	},
	
	setPath:function(path) {
		
		if('mediaPath' in window) {
			
			this.mediaPath = window.mediaPath;
			
			delete window.mediaPath;
		}
	},
	
	setIdentsAndMovies:function() {
		
		// console.log('setIdentsAndMovies');

		var i, j,
			categoryEls = document.querySelectorAll('#subHeader li a'),
			categoryId,
			articleEls = document.querySelectorAll('#playList article'),
			sectionMovies = [],
			idents = {},
			idParts = [],
			description,
			movie = {},
			categoryHash,
			videoHash, 
			descriptionEl,
			titleEl,
			linkEl,
			sources;
		
		for(i = 0; i < categoryEls.length; i++ ) {
			
			categoryId = categoryEls[i].getAttribute('id').split('Link').join('');
			
			if( ! idents[categoryId]) {
				
				idents[categoryId] = [];
			}
		}
		
		// console.log(idents, 'setIdentsAndMovies idents');
		
		for(i = 0; i < articleEls.length; i++) {
		
			idParts = articleEls[i].id.split('.');
		
			if( idParts[0].length < 2) {
			
				continue;
			}
		
			categoryHash = idParts[0];
			videoHash = idParts[1];
		
			idents[categoryHash].push(videoHash);

			titleEl = articleEls[i].querySelector('h3');
			title = titleEl ? titleEl.innerHTML : '';
		
			descriptionEl = articleEls[i].querySelector('p');
			description = descriptionEl ? descriptionEl.innerHTML : '';
		
			linkEl = articleEls[i].querySelector('a');
			sources = linkEl ? linkEl.getAttribute('data-videos') : '';
		
			if( ! sources) {

				continue;
			}
		
			movie = {
				title:title,
				description:description,
				sources:sources
			};

			tomcode.player.movies[videoHash] = movie;
		}
		
		tomcode.player.idents = idents;
	},
	
	theFirstMovie:function(cat) {
		
		return cat +'.' +this.idents[cat][0] || '1';
	},
	
	pauseVideo:function() {

		// console.log('pauseVideo');

		var knoten = document.getElementById("videoEl");

		if(knoten) {
			
			// console.log('pauseVideo knoten.pause' +knoten.nodeName);
			
			if(knoten.nodeName === 'VIDEO') {

				knoten.pause();
			}
		}
	},
	
	removeVideo:function() {

		tomcode.player.pauseVideo();
		
		var knoten = document.getElementById("videoEl");

		if(knoten) {

			if(knoten.nodeName === 'VIDEO') {

				tomcode.events.remove(knoten, 'videoEl');
			}
			
			knoten.parentNode.removeChild(knoten);
		}
	},
	
	removeMessage:function() {

		// console.log('removeMessage');

		var knoten = document.getElementById("messageBox");
		
		if(knoten) {
		
			knoten.parentNode.removeChild(knoten);
			
		}

		this.hasMessage = false;
	},
	
	showError:function(e, errorCode) {
		
		tomcode.player.hasMessage = true;
		
		tomcode.player.removeVideo();

		tomcode.view('message', {errorCode:errorCode});
	},
	
	watchLocationHash:function() {
		
		var that = tomcode.player;
		
		// console.log(location.hash, 'location.hash watchLocationHash	 that.oldHash ' +that.oldHash);

		if(that.oldHash !== location.hash) {
			
			that.onLocationChange();
			
		}
	},
	
	onLocationChange:function() {

		// console.log('onLocationChange');

		var categoryHash = this.hashPart(0);
		
		if(this.hasMessage) {
			
			this.removeMessage();
		}
		
		if( ! this.idents[categoryHash]) {
			
			this.oldHash = location.hash;

			this.setNavigation(categoryHash);
			
			this.showError(false, 404);

		} else {

			var videoHash = this.hashPart(1);
		
			// console.log(videoHash, 'onLocationChange new videoHash');
		
			this.oldHash = location.hash;
			
			if(videoHash) {
		
				this.showVideo(videoHash);
			}
			else {
		
				this.showPlayList(categoryHash);
			}
			
			this.setNavigation(categoryHash);
		}
	},
	
	setEvents:function() {
		
		// console.log('setEvents');

		var links = document.getElementById('playList').querySelectorAll('a[href]');
		
		function setHash(href) {
			
			var parts = href.split('/'),
				hash = tomcode.uri.hash(parts.slice(parts.length - 2).join('.'));
				
			return location.protocol +'//' + location.host + location.pathname +hash;	
		}
		
		for(i = 0; i < links.length; i++) {
			
			links[i].href = setHash(links[i].href);
		}
		
		
		if('onhashchange' in window) {
			
			// console.log('BINGO has onhashchange');
			
			window.addEventListener('hashchange', this.watchLocationHash, false);
			
			this.watchLocationHash();
			
		} else {

			tomcode.player.watchInterval = setInterval(this.watchLocationHash, 100);
		}
		
		// console.log('setEvents');
	},
	
	setNavigation:function(categoryHash) {
		
		// console.log(categoryHash, 'setNavigation');

		var i,
			links = document.getElementById('subHeader').querySelectorAll('a');
		
		for(i = 0; i < links.length; i++) {
			
			links[i].setAttribute('class', '');
		}
		document.getElementById(categoryHash +'Link').setAttribute('class', 'current');
	},
	
	extractSources:function(sourcesStr, check){
		
		if(sourcesStr === check) {

			return [];
		}
		
		var i,
			srcs = sourcesStr.split(' ');
			sourceFiles = [];
		
		for(i = 0; i < srcs.length; i++) {
			
			if( ! srcs[i]) {
				
				continue;
			}
			
			sourceFiles.push(srcs[i]);
		}
		
		return sourceFiles;
	},
	
	showVideo:function(videoHash) {
		
		// if('console' in window) console.log('showVideo');

		var sourcesStr = this.movie(videoHash, 'sources'),
			data = {
				videoHash:videoHash,
				categoryHash:tomcode.player.hashPart(0)
			},
			containerEl;
		
		data.sources = tomcode.player.extractSources(sourcesStr, videoHash +'.sources');
		
		if( ! data.sources.length || ! tomcode.videoPlayer.detectPlayable(data.sources)) {
			
			tomcode.player.tryFlash();

		} else {
			
			tomcode.player.removeVideo();
		
			document.getElementById('playList').setAttribute('class', 'player');
		
			setTimeout(function() { tomcode.view('video', data); }, 10);
			
			tomcode.view('description', {
			
				videoHash:videoHash,
				description:this.movie(videoHash, 'description')
			});
		
		}

		this.setHtmlTitle();
	},
	
	showPlayList:function(category) {

		// console.log('showPlayList');

		var videoEl = document.getElementById('videoEl'),
			descriptionEl = document.querySelector('footer'),
			removeDelay = tomcode.transitions.support() ? 1000 : 10;
	
		descriptionEl.innerHTML = '<p></p>';

		tomcode.player.setCurrentContent();

		if(videoEl) {
			
			videoEl.setAttribute('class', 'hidden');
		}

		tomcode.player.pauseVideo();

		setTimeout(function() {

			document.getElementById('playList').setAttribute('class', 'playList');

			tomcode.player.removeVideo();

		}, removeDelay);

	},
	
	lang:function(ident) {
		
		var lang = tomcode.lang || 'fr';
		
		return this.strings[lang][ident] || ident;
	},
	
	movie:function(ident, type) {
		
		if(this.movies && this.movies[ident] && this.movies[ident][type]) {

			return this.movies[ident][type];
		
		} else {
			
			return [ident,type].join('.');
		}
	},

	fetchHtmlTitle:function() {
		
		this.htmlTitle = document.title;
	},
	
	setHtmlTitle:function() {
		
		var titles = [],
		video = this.movie(this.hashPart(1), 'title');
		
		if(video !== 'false.title') {

			titles.push(video);
		}
		
		titles.push(this.htmlTitle);
		
		document.title = titles.join(' - ');
	},
	
	setLanguageToggleLinkHash:function() {
		
		var el = document.getElementById('toggleLanguageLink'),
			cat = this.hashPart(0);
			
		if(el && 'hash' in el) {
			
			cat = cat ? tomcode.uri.hash(cat) : '';

			el.hash = cat;
		}
	},
	
	setCurrentContent:function(hideAll) {
		
		// console.log('setCurrentContent');

		var i,
			categories = this.categories,
			curHash = this.hashPart(0),
			categoryEl;
		
		for(i = 0; i < categories.length; i++) {
			
			categoryEl = document.getElementById(categories[i]);
			
			if ( ! categoryEl) {
			
				continue;
			}
			
			if(categories[i] === curHash && ! hideAll) {
				
				document.getElementById(categories[i]).setAttribute('class', 'current');
		
				continue;
			}
			
			document.getElementById(categories[i]).setAttribute('class', 'hidden');
		}
		
		this.setHtmlTitle();
		
		this.setLanguageToggleLinkHash();
	},
	
	init:function() {
		
		tomcode.player.hashPart = tomcode.uri.hashPart;
		
		tomcode.utils.setLang();
		
		tomcode.player.setPath();
		
		tomcode.player.setIdentsAndMovies();
		
		tomcode.player.fetchHtmlTitle();

		tomcode.player.setCurrentContent(true);

		setTimeout(function() {
			
			tomcode.player.setEvents();
		
			// show first video if freshly arriving
			// location.hash = location.hash || tomcode.uri.hash(tomcode.player.theFirstMovie('cat1'));
			
			// show first category
			location.hash = location.hash || tomcode.uri.hash('cat1');
			

		}, 10);
		
		if(navigator.userAgent.match(/iPhone/i)) {
		
			setTimeout(function() { window.scrollTo(0, 1); }, 100);
		}
	},
	
	run:function(){
		
		function canRun() {
			
			switch(false) {
				case 'addEventListener' in window :
				case 'querySelector' in document :
				case 'querySelectorAll' in document :
				case 'styleSheets' in document :
				return false;
				
				default: return true;
			}
		}
		
		if(canRun()) {
			
			if(document.styleSheets[0]) {
		
				tomcode.utils.addRule('.index #playList section', 'position: absolute; opacity: 0;');
			}
	
			window.addEventListener('load', function() {
	
				setTimeout(function() {
	
					tomcode.player.init();
		
				}, 10);
	
			}, false);
		}
	}
};
tomcode.player.run();
