/*global NettTv,NettTvAds,drklikk,window*/

/**
 * API-extended.js
 * Script for use with Aptoma & Kroma NettTv, a web-TV solution
 * http://aptoma.no/produkt/tv/
 *
 * This script offers an API for third party developers using JavaScript, an
 * API for a Flash-player and internal methods for fetching information about
 * videos, loading other scripts and internal logistics such as playlist functionality
 * and debug mode.
 *
 * Third party documentation should be available in index.html in the same
 * folder as this script. <- big time @todo on this
 *
 * @author Lars Hetland, lars@aptoma.com
 */
var NETTTV_MESSAGE_FATAL = 1;
var NETTTV_MESSAGE_WARNING = 2;
var NETTTV_MESSAGE_NOTICE = 3;
var NETTTV_MESSAGE_SPAM = 4;
var NETTTV_MESSAGE_VERBOSE = 5;

if ( !( 'NettTv' in window ) ) {
	NettTv = {};
}
NettTv._settings = {
	cookieName : 'NettTV-settings',
	loadSettings : true,
	drKlikkSettings : {
		active : false,
		pageType : 'portal'
	},
	drKlikkLoaded : false,
	drKlikkInitQue : [],
	drKlikkLoadQue : {},
	nettTvLoaded : false,
	playerPaths : []
};
if ( !NettTv._path ) {
	NettTv._path = null;
}
if ( !NettTv._backendPath ) {
	NettTv._backendPath = null;
}
NettTv._player = {
	defaultVideoParentId : 'netttv-video-parent',
	videoParent : null,
	oldVideoParent : null,
	objectWidth : null,
	objectHeight : null,
	playerPath : null,
	videos : {},
	playlist : [],
	playOrder : [],
	history : [],
	active : null,
	activeIndex : null,
	loading : null,
	loadingIndex : null,
	players : {},
	getPlaylist : function( tracelevel ) {
		if ( !(typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_player.getPlaylist()', tracelevel, NETTTV_MESSAGE_NOTICE );
		var playlist = [];
		for ( var i = 0, iMax = NettTv._player.playOrder.length; i < iMax; i++ ) {
			playlist.push( NettTv._player.playlist[NettTv._player.playOrder[i]].videoId );
		}
		return playlist;
	},
	addToPlaylist : function( id, tracelevel ) {
		if ( !(typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}			
		NettTv._message.add( '_player.addToPlaylist()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof id === 'number' && id > 0 ) {
			NettTv._message.add( 'videoId [' + id + '] in correct format and added to playlist', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			var playlistId = NettTv._player.playlist.length;
			NettTv._player.playOrder.push( playlistId );
			NettTv._player.playlist[playlistId] = {'playlistId':playlistId,'videoId':id};
			return playlistId;
		} else {
			NettTv._message.add( 'videoId in incorrect format', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
	},
	removeFromPlaylist : function( id, tracelevel ) {
		if ( !(typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_player.removeFromPlaylist()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof id === 'number' ) {
			NettTv._message.add( 'videoId in valid format, will iterate over playlist for it', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			for ( var i = 0, iMax = NettTv._player.playOrder.length; i < iMax; i++ ) {
				if ( NettTv._player.playOrder[i] === id ) {
					NettTv._message.add( 'Found videoId, removing it from playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
					NettTv._player.playOrder.splice( i, 1 );
					return true;
				}
			}
		} else {
			NettTv._message.add( 'VideoId in invalid format', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
		NettTv._message.add( 'VideoId not found in playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
		return false;
	},
	clearPlaylist : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_player.clearPlaylist()', tracelevel, NETTTV_MESSAGE_NOTICE );
		NettTv._player.playOrder = [];
		return true;
	},
	moveToTopOfPlaylist : function( playlistId, tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_player.moveToTopOfPlaylist()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof playlistId === 'number' ) {
			NettTv._message.add( 'VideoId in valid format, will iterate over playlist for it', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			for ( var i = 0, iMax = NettTv._player.playOrder.length; i < iMax; i++ ) {
				if ( NettTv._player.playOrder[i] === playlistId ) {
					if ( i === 0 || i === 1 ) {
						NettTv._message.add( 'VideoId found, but already at top of playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						return true;
					} else {
						NettTv._message.add( 'VideoId found, moving to top', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						NettTv._player.playOrder.splice( i, 1 );
						NettTv._player.playOrder.splice( 1, 0, playlistId );
						return true;
					}
				}
			}
		} else {
			NettTv._message.add( 'VideoId in invalid format', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
		NettTv._message.add( 'VideoId not found in playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
		return false;
	},
	moveToBottomOfPlaylist : function( playlistId, tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_player.moveToBottomOfPlaylist()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof playlistId === 'number' ) {
			NettTv._message.add( 'VideoId in correct format, will iterate over playlist for it', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			for ( var i = 0, iMax = NettTv._player.playOrder.length; i < iMax; i++ ) {
				if ( NettTv._player.playOrder[i] === playlistId ) {
					if ( i === 0 ) {
						NettTv._message.add( 'VideoId already at bottom of playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						return false;
					} else {
						NettTv._message.add( 'VideoId found, moving to bottom of playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						NettTv._player.playOrder.splice( i, 1 );
						NettTv._player.playOrder.push( playlistId );
						return true;
					}
				}
			}
		} else {
			NettTv._message.add( 'VideoId in incorrect format', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
		NettTv._message.add( 'VideoId not found in playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
		return false;
	},
	moveUpInPlaylist : function( playlistId, tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_player.moveUpInPlaylist()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof playlistId === 'number' ) {
			NettTv._message.add( 'VideoId in correct format, will iterate over playlist for it', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			for ( var i = 0, iMax = NettTv._player.playOrder.length; i < iMax; i++ ) {
				if ( NettTv._player.playOrder[i] === playlistId ) {
					if ( i === 0 || i === 1 ) {
						NettTv._message.add( 'VideoId already at top of playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						return false;
					} else {
						NettTv._message.add( 'VideoId found, moving it up', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						NettTv._player.playOrder.splice( i, 1 );
						NettTv._player.playOrder.splice( i - 1, 0, playlistId );
						return true;
					}
				}
			}
		} else {
			NettTv._message.add( 'VideoId in invalid format', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
		NettTv._message.add( 'VideoId not found in playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
		return false;
	},
	moveDownInPlaylist : function( playlistId, tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_player.moveDownInPlaylist()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof playlistId === 'number' ) {
			NettTv._message.add( 'VideoId in correct format, will iterate over playlist for it', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			for ( var i = 0, iMax = NettTv._player.playOrder.length; i < iMax; i++ ) {
				if ( NettTv._player.playOrder[i] === playlistId ) {
					if ( i === iMax - 1 ) {
						NettTv._message.add( 'VideoId already at bottom of playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						return false;
					} else {
						NettTv._message.add( 'VideoId found, moving it down', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						NettTv._player.playOrder.splice( i, 1 );
						NettTv._player.playOrder.splice( i + 1, 0, playlistId );
						return true;
					}
				}
			}
		} else {
			NettTv._message.add( 'VideoId in invalid format', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
		NettTv._message.add( 'VideoId not found in playlist', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
		return false;
	}
};
NettTv._debug = {
	active : true,
	importance : NETTTV_MESSAGE_NOTICE,
	output : function( object, tracelevel ) {
		if ( window.console && typeof window.console.log === 'function' ) {
			if ( typeof object === 'string' && typeof tracelevel === 'number' && tracelevel > 0 ) {
				for ( var i = 0; i < tracelevel; i++ ) {
					object = '	' + object;
				}
			}
			console.log( object );
		} else if ( window.opera && typeof window.opera.postError === 'function' ) {
			opera.postError( object );
		} else {
	 		//alert( object );
		}
	}
};
if ( !NettTv._tools ) {
	NettTv._tools = {};
}
if ( !NettTv._tools.getPath ) {
	NettTv._tools.getPath = function() {
		if ( !NettTv._path ) {
			var scripts = document.getElementsByTagName( 'script' );
			for ( var i = 0, s, iMax = scripts.length; i < iMax; i++ ) {
				s = scripts[i];
				if ( s.src.match( /API-extended\.js(\?.*)?$/ ) ) {
					if ( s.src.match( /js\/API-extended\.js(\?.*)?$/ ) ) {
						NettTv._path = s.src.replace( /js\/API-extended\.js(\?.*)?$/, '' );
						var backendPath = s.getAttribute( 'rel' );
						if ( typeof backendPath === 'string' ) {
							NettTv._backendPath = backendPath;
						} else {
							NettTv._backendPath = NettTv._path;
						}
						if ( !NettTv.loadVideos ) {
							var matches = s.src.match( /\?.*id=([0-9,]*)/ );
							if ( matches && matches.length ) {
								NettTv.loadVideos = matches[0].replace( /\?id=/,'' );
							}
						}
						return true;
					} else {
						var path = location.href.match(/(.*)js\//)[1];
						if ( typeof path === 'string' && path.length > 0 ) {
							NettTv._path = path;
							NettTv._backendPath = NettTv._path;
							return true;
						}
					}
				}
			}
			NettTv._path = NettTv._backendPath = false;
			return false;
		}
		return true;
	};
}
NettTv._tools.extendedPreloading = function() {
	NettTv._message.add( '_tools.extendedPreloading()', 0, NETTTV_MESSAGE_NOTICE );
	var loadString = '';
	if ( NettTv.loadVideos ) {
		loadString += NettTv.loadVideos;
		delete NettTv.loadVideos;
	}
	if ( typeof NettTv.playId === 'number' ) {
		if ( loadString.length > 0 ) {
			loadString += ',' + NettTv.playId;
		} else {
			loadString = NettTv.playId;
		}
	}
	if ( typeof NettTv.loadId === 'number' ) {
		if ( loadString.length > 0 ) {
			loadString += ',' + NettTv.loadId;
		} else {
			loadString = NettTv.loadId;
		}
		delete NettTv.loadId;
	}
	if ( loadString.length > 0 ) {
		NettTv._tools.require( '?do=js&id=' + loadString, true );
	}
};
NettTv._tools.extendedLoading = function( tracelevel ) {
	if ( typeof tracelevel !== 'number' ) {
		tracelevel = 0;
	}
	NettTv._message.add( '_tools.extendedLoading()', tracelevel, NETTTV_MESSAGE_NOTICE );
	if ( NettTv._settings.loadSettings === true ) {
		NettTv._message.add( 'Settings set for loading, will do so', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		NettTv._tools.require( '?do=apisettings', true, false, tracelevel + 2 );
	} else {
		NettTv._tools.settingsLoaded( tracelevel + 1 );
	}
};
NettTv._tools.extendedLoaded = function( tracelevel ) {
	if ( typeof tracelevel !== 'number' ) {
		tracelevel = 0;
	}
	NettTv._message.add( '_tools.extendedLoaded()', tracelevel, NETTTV_MESSAGE_NOTICE );
	if ( typeof NettTv._settings.refererDomains === 'object' && NettTv._settings.refererDomains !== null && NettTv._settings.refererDomains.constructor === Array && NettTv._settings.refererDomains.length > 0 ) {
		NettTv._message.add( 'System has a limited referer domain policy, checking against current domain', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		try {
			var domain = document.URL;
			var filter = '.*(';
			var domains = NettTv._settings.refererDomains.slice(0);
			for ( var i = 0, iMax = domains.length; i < iMax; i++ ) {
				domains[i] = domains[i].split( '.' );
				for ( var j = 0, jMax = domains[i].length; j < jMax; j++ ) {
					filter += domains[i][j] + '\\.';
				}
				filter = filter.substring( 0, filter.length - 2 ) + '|';
			}
			filter = filter.substring( 0, filter.length - 1 ) + ')$';
			var urlArray = domain.split( '/' );
			if ( !( urlArray[2].match( filter ) ) ) {
				NettTv._message.add( 'System is not running on a valid domain, halting playback process', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				NettTv._loadId = null;
				NettTv._player.videos = [];
				NettTv._tools.require = function( fileName, isBackend, isAbsolute, tracelevel, description, parameters ) {
					NettTv._message.add( '_tools.require(' + description + ') failed, system on invalid domain', tracelevel, NETTTV_MESSAGE_WARNING );
				};
				var drKlikkEvent = {event:'domainblock'};
				NettTv._message.add( 'Registering domain block with DrKlikk', 0, NETTTV_MESSAGE_NOTICE );
				if ( typeof urlArray[2] === 'string' && urlArray[2].length > 0 ) {
					if ( urlArray[2].length > 100 ) {
						urlArray[2] = urlArray[2].substring( 0, 100 );
					}
					drKlikkEvent.text1 = urlArray[2];
				}
				NettTv._tools.drklikkRegister( drKlikkEvent, 1 );
				if ( typeof NettTv._hooks.refererDomain === 'function' ) {
					NettTv._message.add( 'Referer domain hook is function, calling it', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
					NettTv._hooks.refererDomain();
				}
			}
		} catch ( error ) {}
	}
	if ( NettTv._settings.nettTvLoaded === false ) {
		NettTv._settings.nettTvLoaded = true;
		if ( typeof NettTv._loadId === 'number' ) {
			NettTv._message.add( 'A video is set for loading', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			NettTv._player.loading = NettTv._loadId;
			if ( typeof NettTv._loadIndex === 'number' ) {
				NettTv._player.loadingIndex = NettTv._loadIndex;
			} else {
				NettTv._player.loadingIndex = null;
			}
			if ( NettTv._info.isLoaded( NettTv._loadId, tracelevel + 2 ) ) {
				NettTv._message.add( 'The video was loaded, playing', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				NettTv._action.play( tracelevel + 3, NettTv._player.loading, NettTv._player.loadingIndex );
			} else {
				NettTv._message.add( 'Video not loaded, loading it', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				NettTv._tools.require( '?do=js&id=' + NettTv._player.loading, true, false, tracelevel + 3 );
			}	
		}
	}
};
NettTv._tools.videoLoaded = function( videoArray ) {
	NettTv._message.add( '_tools.videoLoaded()', 0, NETTTV_MESSAGE_NOTICE );
	if ( typeof NettTv._player.loading === 'number' && typeof NettTv._player.videos['v' + NettTv._player.loading] === 'object' ) {
		NettTv._message.add( 'A video set for loading has loaded', 1, NETTTV_MESSAGE_NOTICE );
		var temp = NettTv._player.loading;
		var tempIndex = NettTv._player.loadingIndex;
		NettTv._player.loading = null;
		NettTv._player.loadingIndex = null;
		NettTv._action.play( 2, temp, tempIndex );
	}
	if ( typeof videoArray === 'object' && videoArray !== null && videoArray.constructor === Array && videoArray.length > 0 ) {
		NettTv._message.add( 'Loaded videoArray in correct format, will iterate over loaded videoIds and call potential hooks', 1, NETTTV_MESSAGE_NOTICE );
		for ( var i = 0, iMax = videoArray.length; i < iMax; i++ ) {
			if ( typeof videoArray[i] === 'number' ) {
				NettTv._message.add( 'VideoId [' + videoArray[i] + '] loaded', 2, NETTTV_MESSAGE_NOTICE );
				if ( typeof NettTv._hooks.loading['v' + videoArray[i]] === 'function' ) {
					NettTv._message.add( 'VideoId has hook, calling it', 3, NETTTV_MESSAGE_NOTICE );
					NettTv._hooks.loading['v' + videoArray[i]]( videoArray[i] );
				} else {
					NettTv._message.add( 'VideoId has no hook', 3, NETTTV_MESSAGE_NOTICE );
				}
			} else {
				NettTv._message.add( 'Found loaded videoId in invalid format', 2, NETTTV_MESSAGE_WARNING );
			}
		}
		if ( typeof NettTv._hooks.load === 'function' ) {
			NettTv._message.add( 'Hook on event [load] found, calling it', 2, NETTTV_MESSAGE_NOTICE );
			NettTv._hooks.load( videoArray );
		}
	}
};
NettTv._tools.settingsLoaded = function( tracelevel ) {
	if ( typeof tracelevel !== 'number' ) {
		tracelevel = 0;
	}
	NettTv._message.add( '_tools.settingsLoaded()', tracelevel, NETTTV_MESSAGE_NOTICE );
	if ( NettTv._settings.drKlikkSettings.active === true ) {
		NettTv._message.add( 'Settings say that DrKlikk should be used', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		if ( 'drklikk' in window ) {
			NettTv._message.add( 'DrKlikk allready loaded', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
			drklikk.addServer( NettTv._settings.drKlikkSettings.prefix, NettTv._settings.drKlikkSettings.registerPath );
		} else if ( typeof NettTv._settings.drKlikkSettings.javascriptPath === 'string' && NettTv._settings.drKlikkSettings.javascriptPath.length > 0 ) {
			NettTv._message.add( 'Loading DrKlikk', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
			NettTv._tools.require( (NettTv._settings.drKlikkSettings.javascriptPath.substring(0, 4) === 'http' ? '' : NettTv._path) + NettTv._settings.drKlikkSettings.javascriptPath, false, true, tracelevel + 3 );
			setTimeout( function() {
				if ( NettTv._settings.drKlikkLoaded === false ) {
					NettTv._message.add( 'DrKlikk loading timeout', tracelevel + 3, NETTTV_MESSAGE_WARNING );
					NettTv._settings.drKlikkSettings.active = false;
					NettTv._tools.extendedLoaded( tracelevel + 4 ); 
				}
			}, ( typeof NettTv._settings.drKlikkSettings.timeout === 'number' && NettTv._settings.drKlikkSettings.timeout > 0 ) ? NettTv._settings.drKlikkSettings.timeout : 2000 );
			return true;
		} else {
			NettTv._settings.drKlikkSettings.active = false;
			NettTv._message.add( 'Needed DrKlikk info from settings not precent, deactivating it', tracelevel + 2, NETTTV_MESSAGE_WARNING );
		}
	}
	NettTv._tools.extendedLoaded( tracelevel + 1 );
};
NettTv._tools.drKlikkLoaded = function() {
	NettTv._settings.drKlikkLoaded = true;
	drklikk.addServer( NettTv._settings.drKlikkSettings.prefix, NettTv._settings.drKlikkSettings.registerPath );
	NettTv._message.add( '_tools.drKlikkLoaded() - DrKlikk loaded correctly', 0, NETTTV_MESSAGE_NOTICE );
	if ( NettTv._settings.drKlikkInitQue.length > 0 ) {
		NettTv._message.add( 'Events found in DrKlikk que, processing them', 1, NETTTV_MESSAGE_NOTICE );
		for ( var i = 0, iMax = NettTv._settings.drKlikkInitQue.length; i < iMax; i++ ) {
			NettTv._tools.drklikkRegister( NettTv._settings.drKlikkInitQue[i], 2 );
		}
	} else {
		NettTv._message.add( 'No events in DrKlikk que, moving on', 1, NETTTV_MESSAGE_NOTICE );
	}
	NettTv._tools.extendedLoaded();
};
NettTv._tools.playerLoaded = function() {
	NettTv._message.add( '_tools.playerLoaded()', 0, NETTTV_MESSAGE_NOTICE );	
	if ( typeof NettTv._player.loading === 'number' && NettTv._player.loading !== NettTv._player.active && typeof NettTv._player.players[NettTv._player.videos['v' + NettTv._player.loading].player] === 'object' ) {
		var player = NettTv._player.players[NettTv._player.videos['v' + NettTv._player.loading].player];
		NettTv._message.add( 'Currently loading videoId [' + NettTv._player.loading + '] has player [' + NettTv._player.videos['v' + NettTv._player.loading].player + '] loaded correctly', 1, NETTTV_MESSAGE_NOTICE );
		if ( player.checkRequirements( 1 ) === true ) {
			NettTv._message.add( 'Player requirements met, playing', 2, NETTTV_MESSAGE_NOTICE );
			NettTv._action.play( 3, NettTv._player.loading, NettTv._player.loadingIndex );
		} else {
			NettTv._message.add( 'Player requirements are not met, will require list', 2, NETTTV_MESSAGE_NOTICE );
			if ( player.requirements.length > 0 ) {
				NettTv._message.add( 'Requirements found, will iterate and require list', 3, NETTTV_MESSAGE_NOTICE );
				for ( var i = 0, iMax = player.requirements.length; i < iMax; i++ ) {
					NettTv._tools.require( player.requirements[i].src, false, true, 4, null, player.requirements[i].parameters );
				}
				NettTv._message.add( 'All requirements loaded, will start timeout', 3, NETTTV_MESSAGE_NOTICE );
				setTimeout( NettTv._tools.checkingPlayerRequirements, 500 );
			} else {
				NettTv._message.add( 'Player requirements not met, but there are no requirements.. will try to play', 3, NETTTV_MESSAGE_WARNING );
				NettTv._action.play( 4, NettTv._player.loading, NettTv._player.loadingIndex );
			}
		}
	}
};
NettTv._tools.checkingPlayerRequirements = function() {
	if ( typeof NettTv._player.loading === 'number' && NettTv._player.loading !== NettTv._player.active ) {
		var player = NettTv._player.players[NettTv._player.videos['v' + NettTv._player.loading].player];
		if ( player.checkRequirements() === true ) {
			NettTv._message.add( 'Player requirements met, playing', 0, NETTTV_MESSAGE_NOTICE );
			NettTv._action.play( 1, NettTv._player.loading, NettTv._player.loadingIndex );
		} else {
			setTimeout( NettTv._tools.checkingPlayerRequirements, 500 );
		}
	}
};
NettTv._tools.urlencode = function( string, tracelevel ) {
	if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
		tracelevel = 0;
	}
	NettTv._message.add( '_tools.urlencode()', tracelevel, NETTTV_MESSAGE_NOTICE );
	return window.escape( string ).replace( '+', '%2B' ).replace( '%20', '+' ).replace( '*', '%2A' ).replace( '/', '%2F' ).replace( '@', '%40' );
};
NettTv._tools.urldecode = function( string, tracelevel ) {
	if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
		tracelevel = 0;
	}
	NettTv._message.add( '_tools.urldecode()', tracelevel, NETTTV_MESSAGE_NOTICE );
	return window.unescape( string.replace( '+', ' ' ) );
};
NettTv._tools.getDimensions = function( parentElement, width, height ) {
	var newWidth = null;
	var newHeight = null;
	if ( typeof width === 'number' ) {
		width = Math.round( width );
		if ( width > 0 ) {
			newWidth = width;
		}
	}
	if ( typeof height === 'number' ) {
		height = Math.round( height );
		if ( height > 0 ) {
			newHeight = height;
		}
	}
	if ( typeof parentElement === 'object' && parentElement && parentElement.nodeType === 1 ) {	
		if ( newWidth === null ) {
			var parentWidth = parentElement.clientWidth;
			if ( typeof parentWidth === 'number' && parentWidth > 0 ) {
				newWidth = parentWidth;
			}
		}
		if ( newHeight === null ) {
			var parentHeight = parentElement.clientHeight;
			if ( typeof parentHeight === 'number' && parentHeight > 0 ) {
				newHeight = parentHeight;
			}
		}
	}
	return [newWidth, newHeight];
};
NettTv._tools.drklikkRegister = function( event, tracelevel ) {
	if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
		tracelevel = 0;
	}
	NettTv._message.add( 'Trying to register event with DrKlikk', tracelevel, NETTTV_MESSAGE_NOTICE );
	if ( typeof event === 'object' && typeof event.event === 'string' && NettTv._settings.loadSettings === true ) {
		if ( NettTv._settings.drKlikkLoaded === false ) {
			NettTv._message.add( 'DrKlikk not loaded yet, putting event [' + event.event + '] in queue for later registration', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			NettTv._settings.drKlikkInitQue[NettTv._settings.drKlikkInitQue.length] = event;
		} else if ( NettTv._settings.drKlikkLoaded === true && NettTv._settings.drKlikkSettings.active === true && typeof NettTv._settings.drKlikkSettings.events === 'object' && NettTv._settings.drKlikkSettings.events[event.event] === true && typeof drklikk.register === 'function' ) {
			drklikk.register(
				( typeof NettTv._settings.drKlikkSettings.prefix === 'string' ? NettTv._settings.drKlikkSettings.prefix : null ),
				event.event,
				( typeof event.identification === 'string' || typeof event.identification === 'number' ? event.identification : null ),
				( typeof event.text1 === 'string' || typeof event.text1 === 'number' ? event.text1 : null ),
				( typeof event.text2 === 'string' || typeof event.text2 === 'number' ? event.text2 : null ),
				( typeof event.number === 'string' || typeof event.number === 'number' ? event.number : null ),
				null,
				null,
				null,
				null,
				( typeof NettTv._settings.drKlikkSettings.prefix === 'string' ? NettTv._settings.drKlikkSettings.prefix : null )
			);
			NettTv._message.add( 'Registered event [' + event.event + '] with DrKlikk', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		} else {
			NettTv._message.add( 'Event [' + event.event + '] not to be registered', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		}
	} else {
		NettTv._message.add( 'DrKlikk deactivated or event malformed', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
	}
};
NettTv._tools.getUrl = function( name, tracelevel ) {
	if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
		tracelevel = 0;
	}
	NettTv._message.add( '_tools.getUrl()', tracelevel, NETTTV_MESSAGE_NOTICE );
	if ( !( typeof name === 'string' && name.length > 0 ) ) {
		NettTv._message.add( 'Name parameter not valid', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		return null;
	}
	NettTv._message.add( 'Trying to find url for key [' + name + ']', tracelevel, NETTTV_MESSAGE_NOTICE );
	var url = null;
	if ( typeof NettTvAds === 'object' && NettTvAds ) {
		NettTv._message.add( 'Found NettTvAds object', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTvAds.urls === 'object' && NettTvAds.urls ) {
			NettTv._message.add( 'Found urls object', tracelevel, NETTTV_MESSAGE_NOTICE );
			if ( typeof NettTvAds.urls[name] === 'string' && NettTvAds.urls[name].length > 0 ) {
				NettTv._message.add( 'Found url for key [' + name + '], returning it', tracelevel, NETTTV_MESSAGE_NOTICE );
				url = NettTvAds.urls[name];
			} else {
				NettTv._message.add( 'Url for key not found or not valid', tracelevel, NETTTV_MESSAGE_NOTICE );
			}
		} else {
			NettTv._message.add( 'Urls object not found', tracelevel, NETTTV_MESSAGE_NOTICE );
		}
	} else {
		NettTv._message.add( 'NettTvAds object not found', tracelevel, NETTTV_MESSAGE_NOTICE );
	}
	// @todo this is a iframe hack
	if ( url === null && typeof parent === 'object' && typeof parent.NettTvAds === 'object' && parent.NettTvAds ) {
		NettTv._message.add( 'Found NettTvAds object in parent', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof parent.NettTvAds.urls === 'object' && parent.NettTvAds.urls ) {
			NettTv._message.add( 'Found urls object in parent', tracelevel, NETTTV_MESSAGE_NOTICE );
			if ( typeof parent.NettTvAds.urls[name] === 'string' && parent.NettTvAds.urls[name].length > 0 ) {
				NettTv._message.add( 'Found url for key [' + name + '] in parent, returning it', tracelevel, NETTTV_MESSAGE_NOTICE );
				url = parent.NettTvAds.urls[name];
			} else {
				NettTv._message.add( 'Url for key not found or not valid in parent', tracelevel, NETTTV_MESSAGE_NOTICE );
			}
		} else {
			NettTv._message.add( 'Urls object not found in parent', tracelevel, NETTTV_MESSAGE_NOTICE );
		}
	}
	return url;
};
NettTv._tools.getUrls = function( tracelevel ) {
	if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
		tracelevel = 0;
	}
	NettTv._message.add( '_tools.getUrls()', tracelevel, NETTTV_MESSAGE_NOTICE );
	var urls = null;
	if ( typeof NettTvAds === 'object' && NettTvAds ) {
		NettTv._message.add( 'Found NettTvAds object', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTvAds.urls === 'object' && NettTvAds.urls ) {
			NettTv._message.add( 'Found urls object, returning it', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
			urls = NettTvAds.urls;
		} else {
			NettTv._message.add( 'Urls object not found', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
		}
	} else {
		NettTv._message.add( 'NettTvAds object not found', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
	}
	return urls;
};
NettTv._tools.getAds = function( videoId, categoryId, tracelevel ) {
	if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
		tracelevel = 0;
	}
	NettTv._message.add( '_tools.getAds()', tracelevel, NETTTV_MESSAGE_NOTICE );
	var inputAds = [null, null,null];
	var outputAds = [[],[],[]];
	if ( typeof NettTv._player.videos['v' + NettTv._player.active].show_ads === 'boolean' && NettTv._player.videos['v' + NettTv._player.active].show_ads === false ) {
		NettTv._message.add( 'Ads deactivated for this video', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		return outputAds;
	}
	if ( typeof NettTvAds === 'object' ) {
		NettTv._message.add( 'Global object NettTvAds exist', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		var tempAds;
		if ( typeof NettTvAds.adFunction === 'function' ) {
			NettTv._message.add( 'Function NettTvAds.adFunction exist, calling it with videoId [' + videoId + '] of type [' + typeof videoId + '] and categoryId [' + categoryId + '] of type [' + typeof categoryId + ']', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
			var ads = NettTvAds.adFunction( videoId, categoryId );
			if ( typeof ads === 'object' && ads !== null && ads.constructor === Array ) {
				NettTv._message.add( 'Data returned from NettTvAds.adFunction in apparently correct format, trying to read and use values', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
				if ( typeof ads[0] !== 'undefined' ) {
					NettTv._message.add( 'Found pre-ad(s)', tracelevel + 4, NETTTV_MESSAGE_NOTICE );
					inputAds[0] = ads[0];
				} else {
					NettTv._message.add( 'Did not find pre-ad(s)', tracelevel + 4, NETTTV_MESSAGE_NOTICE );
				}
				if ( typeof ads[1] !== 'undefined' ) {
					NettTv._message.add( 'Found post-ad(s)', tracelevel + 4, NETTTV_MESSAGE_NOTICE );
					inputAds[1] = ads[1];
				} else {
					NettTv._message.add( 'Did not find post-ad(s)', tracelevel + 4, NETTTV_MESSAGE_NOTICE );
				}
				if ( typeof ads[2] !== 'undefined' ) {
					NettTv._message.add( 'Found overlay(s)', tracelevel + 4, NETTTV_MESSAGE_NOTICE );
					inputAds[2] = ads[2];
				} else {
					NettTv._message.add( 'Did not find overlay(s)', tracelevel + 4, NETTTV_MESSAGE_NOTICE );
				}
				for ( var i = 0; i < 3; i++ ) {
					if ( inputAds[i] !== null ) {
						tempAds = NettTv._tools.validateAds( inputAds[i], tracelevel + 4 );
						if ( tempAds.length > 0 ) {
							NettTv._message.add( 'Found valid ' + ( i === 0 ? 'pre' : ( i === 1 ? 'post' : 'overlay' ) ) + '-ad(s)', tracelevel + 5, NETTTV_MESSAGE_NOTICE );
							outputAds[i] = tempAds;
						}
					}
				}
			} else {
				NettTv._message.add( 'Data returned from NettTvAds.adFunction in wrong format', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
			}
		} else {
			NettTv._message.add( 'Function NettTvAds.adFunction does not exist, looking for static objects', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			if ( typeof NettTvAds.preAds !== 'undefined' ) {
				NettTv._message.add( 'Found pre-ad(s)', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				inputAds[0] = NettTvAds.preAds;
			} else {
				NettTv._message.add( 'Did not find pre-ad(s)', tracelevel + 2, NETTTV_MESSAGE_NOTICE );	
			}
			if ( typeof NettTvAds.postAds !== 'undefined' ) {
				NettTv._message.add( 'Found post-ad(s)', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				inputAds[1] = NettTvAds.postAds;
			} else {
				NettTv._message.add( 'Did not find post-ad(s)', tracelevel + 2, NETTTV_MESSAGE_NOTICE );	
			}
			if ( typeof NettTvAds.overlayAds !== 'undefined' ) {
				NettTv._message.add( 'Found overlay(s)', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				inputAds[2] = NettTvAds.overlayAds;
			} else {
				NettTv._message.add( 'Did not find overlay(s)', tracelevel + 2, NETTTV_MESSAGE_NOTICE );	
			}
			for ( var j = 0; j < 3; j++ ) {
				if ( typeof inputAds[j] === 'number' && inputAds[j] > 0 ) {
					NettTv._message.add( 'Found valid single ' + ( j === 0 ? 'pre' : ( j === 1 ? 'post' : 'overlay' ) ) + '-ad', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
					outputAds[j].push( [inputAds[j]] );
				} else if ( typeof inputAds[j] === 'object' && inputAds[j] !== null ) {
					if ( inputAds[j].constructor === Array ) {
						var random = Math.floor( Math.random() * inputAds[j].length );
						NettTv._message.add( 'Found array for ' + ( j === 0 ? 'pre' : ( j === 1 ? 'post' : 'overlay' ) ) + '-ad, picking one slot at random and will validate it', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						tempAds = NettTv._tools.validateAds( inputAds[j][random], tracelevel + 3 );
						if ( tempAds.length > 0 ) {
							NettTv._message.add( 'Random ' + ( j === 0 ? 'pre' : ( j === 1 ? 'post' : 'overlay' ) ) + '-ad(s) valid', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
							outputAds[j] = tempAds;
						} else {
							NettTv._message.add( 'Random ' + ( j === 0 ? 'pre' : ( j === 1 ? 'post' : 'overlay' ) ) + '-ad(s) not valid', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						}
					} else if ( typeof inputAds[j].id === 'number' && inputAds[j].id > 0 ) {
						NettTv._message.add( 'Found valid single object for ' + ( j === 0 ? 'pre' : ( j === 1 ? 'post' : 'overlay' ) ) + '-ad', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
						var ad = [inputAds[j].id];
						if ( typeof inputAds[j].url === 'string' && inputAds[j].url.length > 0 ) {
							NettTv._message.add( 'Found valid url for ad', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
							ad.push( NettTv._tools.urlencode( inputAds[j].url ) );
						}
						outputAds[j].push( ad );
					} else {
						NettTv._message.add( 'Found invalid ad', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
					}
				}
			}
		}
	} else {
		NettTv._message.add( 'Global object NettTvAds does not exist', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
	}
	return outputAds;
};
NettTv._tools.outputPlayerVersion = function( player, tracelevel ) {
	if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
		tracelevel = 0;	
	}
	NettTv._message.add( '_tools.outputPlayerVersion()', tracelevel, NETTTV_MESSAGE_NOTICE );
	if ( !( typeof player === 'string' && player.length > 0 ) ) {
		NettTv._message.add( 'Player parameter not set, trying to use active player', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active].player === 'string' ) {
			player = NettTv._player.videos['v' + NettTv._player.active].player;
			NettTv._message.add( 'Found active video and its player [' + player + ']', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
		} else {
			NettTv._message.add( 'No active video, aborting', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
			return;
		}
	} else {
		NettTv._message.add( 'Using player parameter [' + player + ']', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
	}
	if ( typeof NettTv._player.players[player] === 'object' ) {
		NettTv._message.add( 'Found player, outputting version', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
		NettTv._debug.output( NettTv._player.players[player].playerVersion );
	} else {
		NettTv._message.add( 'Player not loaded, aborting', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
	}
};
NettTv._tools.validateAds = function( ad, tracelevel ) {
	if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
		tracelevel = 0;	
	}
	NettTv._message.add( '_tools.validateAds()', tracelevel, NETTTV_MESSAGE_NOTICE );
	var outputAds = [];
	if ( typeof ad === 'number' && ad > 0 ) {
		NettTv._message.add( 'Found valid single ad in integer form', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		outputAds.push( [ad] );
	} else if ( typeof ad === 'object' && ad !== null ) {
		var tempAd;
		if ( ad.constructor === Array ) {
			NettTv._message.add( 'Found array, will iterate over them', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			for ( var i = 0, iMax = ad.length; i < iMax; i++ ) {
				if ( typeof ad[i] === 'number' && ad[i] > 0 ) {
					NettTv._message.add( 'Found valid ad in integer form', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
					outputAds.push( [ad[i]] );
				} else if ( typeof ad[i] === 'object' && ad[i] !== null && typeof ad[i].id === 'number' && ad[i].id > 0 ) {
					NettTv._message.add( 'Found valid ad in object form', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
					tempAd = [ad[i].id];
					if ( typeof ad[i].url === 'string' && ad[i].url.length > 0 ) {
						NettTv._message.add( 'Found url for ad', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
						tempAd.push( NettTv._tools.urlencode( ad[i].url ) );
					}
					outputAds.push( tempAd );
				} else {
					NettTv._message.add( 'Found invalid ad', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				}
			}
		} else if ( typeof ad.id === 'number' && ad.id > 0 ) {
			NettTv._message.add( 'Found valid single ad in object form', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			tempAd = [ad.id];
			if ( typeof ad.url === 'string' && ad.url.length > 0 ) {
				NettTv._message.add( 'Found url for ad', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				tempAd.push( NettTv._tools.urlencode( ad.url ) );
			}
			outputAds.push( tempAd );
		} else {
			NettTv._message.add( 'Found invalid ad', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		}
	} else {
		NettTv._message.add( 'Found invalid ad', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
	}
	return outputAds;
};
if ( !NettTv._tools.requireCache ) {
	NettTv._tools.requireCache = {};
}
if ( !NettTv._tools.require ) {
	NettTv._tools.require = function( fileName, isBackend, isAbsolute, tracelevel, description, parameters ) {
		if ( typeof description !== 'string' ) {
			if ( typeof fileName === 'string' ) {
				description = fileName;
			} else {
				description = '';
			}
		}
		NettTv._message.add( '_tools.require(' + description + ')', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof fileName === 'string' && fileName.length > 0 ) {
 			if ( typeof NettTv._tools.requireCache[fileName] === 'undefined' ) {
				if ( !NettTv._path && typeof NettTv._path !== 'boolean' && !NettTv._tools.getPath() ) {
					return false;
				}
				var script = document.createElement( 'script' );
				script.setAttribute( 'type', 'text/javascript' );
				script.setAttribute( 'charset', 'utf-8' );
				if ( typeof parameters === 'object' && parameters !== null && parameters.constructor === Array && parameters.length > 0 ) {
					for ( var i = 0, iMax = parameters.length; i < iMax; i++ ) {
						if ( typeof parameters[i] === 'object' && parameters[i] !== null && typeof parameters[i][0] === 'string' && typeof parameters[i][1] === 'string' ) {
							script.setAttribute( parameters[i][0], parameters[i][1] );
						}
					}
				}
				if ( isAbsolute ) {
					script.setAttribute( 'src', fileName );
				} else {
					var path;
					if ( isBackend ) {
						path = NettTv._backendPath;
					} else {
						path = NettTv._path;
					}
					if ( path === false ) {
						NettTv._message.add( 'Path not loaded correctly', tracelevel + 1, NETTTV_MESSAGE_WARNING );
						script.setAttribute( 'src', fileName );
					} else {
						script.setAttribute( 'src', path + fileName );
					}
				}
				document.getElementsByTagName( 'head' )[0].appendChild( script );
				NettTv._tools.requireCache[fileName] = true;
			}
			return true;
		}
	};
}
NettTv._hooks = {
	next : false,
	play : false,
	load : false,
	progress : false,
	volume : false,
	duration : false,
	buffer : false,
	status : false,
	finished : false,
	newPlaylist : false,
	newVideo : false,
	finishedVideo : false,
	playerNotSupported : false,
	domainBlocked : false,
	geoBlocked : false,
	related : false,
	click : false,
	loading : {}
};
NettTv._action = {
	playerNotSupported : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.playerNotSupported()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._hooks.playerNotSupported === 'function' ) {
			NettTv._hooks.playerNotSupported();
		}
	},
	playAPI : function( tracelevel, videoId, parentElement, pageType, skinName, width, height, index ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.playAPI()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof videoId !== 'object' ) {
			videoId = [videoId];
		}
		var validVideoIds = [];
		if ( typeof videoId === 'object' && videoId !== null && videoId.constructor === Array && videoId.length > 0 ) {
			for ( var i = 0, iMax = videoId.length; i < iMax; i++ ) {
				if ( typeof videoId[i] === 'number' && Math.round( videoId[i] ) > 0 ) {
					validVideoIds.push( Math.round( videoId[i] ) );
				}
			}
		}
		if ( validVideoIds.length < 1 ) {
			return false;
		}
		// @todo document and debug
		var playlistId = NettTv._player.playlist.length;
		NettTv._player.playOrder[0] = playlistId;
		NettTv._player.playlist[playlistId] = {'playlistId':playlistId,'videoId':videoId};
		if ( validVideoIds.length > 1 ) {
			for ( var j = 1, jMax = validVideoIds.length; j < jMax; j++ ) {
				NettTv._player.addToPlaylist( validVideoIds[j], 1 );
			}
		}
		if ( typeof parentElement === 'string' && parentElement.length > 0 ) {
			NettTv._message.add( 'Recieved id-string to parent element, calling getElementById()', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			parentElement = document.getElementById( parentElement );
		}
		var dimensions;
		if ( typeof parentElement === 'object' && parentElement && parentElement.nodeType === 1 ) {
			NettTv._message.add( 'Parent element is an element and will be used', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			NettTv._player.videoParent = parentElement;
			dimensions = NettTv._tools.getDimensions( parentElement, width, height );
			if ( typeof dimensions[0] === 'number' ) {
				NettTv._player.objectWidth = dimensions[0];
			}
			if ( typeof dimensions[1] === 'number' ) {
				NettTv._player.objectHeight = dimensions[1];
			}
		} else {
			NettTv._message.add( 'Parent element is not an element', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			if ( !NettTv._player.videoParent ) {
				NettTv._message.add( 'Parent elment not set, trying to use default parent element id [' + NettTv._player.defaultVideoParentId + ']', tracelevel + 2, NETTTV_MESSAGE_WARNING );
				parentElement = document.getElementById( NettTv._player.defaultVideoParentId );
				if ( typeof parentElement === 'object' && parentElement && parentElement.nodeType === 1 ) {
					NettTv._message.add( 'Default parent found and will be used', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
					NettTv._player.videoParent = parentElement;
					dimensions = NettTv._tools.getDimensions( parentElement, width, height );
					if ( typeof dimensions[0] === 'number' ) {
						NettTv._player.objectWidth = dimensions[0];
					}
					if ( typeof dimensions[1] === 'number' ) {
						NettTv._player.objectHeight = dimensions[1];
					}
				} else {
					NettTv._message.add( 'No parent element available, aborting playback', tracelevel + 3, NETTTV_MESSAGE_FATAL );
					return false;
				}
			} else {
				dimensions = NettTv._tools.getDimensions( false, width, height );
				if ( typeof dimensions[0] === 'number' ) {
					NettTv._player.objectWidth = dimensions[0];
				}
				if ( typeof dimensions[1] === 'number' ) {
					NettTv._player.objectHeight = dimensions[1];
				}
				NettTv._message.add( 'Parent element previously set, using it', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
			}
		}
		// @todo document and debug
		if ( typeof skinName === 'string' && skinName.length > 0 ) {
			NettTv._player.playerPath = skinName;
		}
		if ( typeof pageType === 'string' ) {
			NettTv._action.setPageType( pageType, tracelevel + 1 );
		}
		return NettTv._action.play( tracelevel + 1, validVideoIds[0], index );
	},
	play : function( tracelevel, videoId, index ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.play()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( !( typeof index === 'number' && index > 0 ) ) {
			index = null;
		}
		if ( NettTv._settings.nettTvLoaded === true ) {
			NettTv._message.add( 'NettTv has previously completed loading', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			if ( typeof NettTv._player.videos['v' + videoId] === 'object' ) {
				NettTv._message.add( 'Video is already loaded', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				var video = NettTv._player.videos['v' + videoId];
				if ( !video ) {
					NettTv._message.add( 'Video does not exist, trying to play next video in playlist', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
					return NettTv._action.next( tracelevel + 4 );
				}
				if ( typeof video.player === 'string' ) {
					if ( typeof NettTv._player.players[video.player] === 'object' ) {
						NettTv._message.add( 'Required player already loaded, will play videoId with it', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
						NettTv._player.loading = null;
						NettTv._player.loadingIndex = null;
						NettTv._player.active = videoId;
						NettTv._player.activeIndex = index;
						if ( typeof video.isPlaylist === 'boolean' ) {
							var drKlikkEvent = { event: 'playlistplay', identification:videoId };
							if ( typeof video.category_id === 'number' ) {
								drKlikkEvent.text2 = video.category_id;
							}
							if ( typeof NettTv._settings.drKlikkSettings.prefix === 'string' ) {
								drKlikkEvent.text1 = NettTv._settings.drKlikkSettings.prefix + '-' + NettTv._settings.drKlikkSettings.pageType;
							}
							NettTv._message.add( 'Video is playlist, registering playback with DrKlikk', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
							NettTv._tools.drklikkRegister( drKlikkEvent, tracelevel + 4 );
						}
						var returnData = NettTv._player.players[video.player].play( tracelevel + 4 );
						if ( typeof NettTv._hooks.play === 'function' ) {
							NettTv._message.add( 'Found hook on action [play], calling it', tracelevel + 5, NETTTV_MESSAGE_NOTICE );
							NettTv._hooks.play( videoId );
						}
						return returnData;
					} else {
						NettTv._message.add( 'Loading required player [' + video.player + ']', tracelevel + 3, NETTTV_MESSAGE_NOTICE );
						NettTv._player.loading = videoId;
						NettTv._player.loadingIndex = index;
						return NettTv._tools.require( 'js/API-' + video.player + '.js', false, false, tracelevel + 4 );
					}
				} else {
					NettTv._message.add( 'Didnt find player in video', tracelevel + 2, NETTTV_MESSAGE_WARNING );
					return false;
				}
			} else {
				NettTv._message.add( 'Video not loaded, will load it', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				NettTv._player.loading = videoId;
				NettTv._player.loadingIndex = index;
				return NettTv._tools.require( '?do=js&id=' + videoId, true, false, tracelevel + 3 );
			}
		} else {
			NettTv._loadId = videoId;
			NettTv._loadIndex = index;
			NettTv._player.loading = null;
			NettTv._player.loadingIndex = null;
			NettTv._message.add( 'NettTv is not completely loaded, but a videoId is set for loading, will continue to load NettTv', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			NettTv._tools.extendedLoading( tracelevel + 2 );
		}
	},
	next : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.next()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.playOrder[1] === 'number' && typeof NettTv._player.playlist[NettTv._player.playOrder[1]] === 'object' ) {
			NettTv._message.add( 'Found video in playlist, playing it', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
			NettTv._action.play( tracelevel + 1, NettTv._player.playlist[NettTv._player.playOrder[1]].videoId );
			NettTv._player.playOrder.splice( 0, 1 );
			if ( typeof NettTv._hooks.next === 'function' ) {
				NettTv._message.add( 'Found hook on action [next], calling it', tracelevel + 2, NETTTV_MESSAGE_NOTICE );
				NettTv._hooks.next();
			}
			return true;	
		} else {
			NettTv._message.add( 'No video in playlist', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	nextClip : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.nextClip()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].next( tracelevel + 1 );
		}
	},
	previousClip : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.previousClip()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].previous( tracelevel + 1 );
		}
	},
	resume : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.resume()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].resume( tracelevel + 1 );
		}
	},
	stop : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.stop()', tracelevel, NETTTV_MESSAGE_NOTICE );
		NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].stop( tracelevel + 1 );
	},
	togglePause : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.togglePause()', tracelevel, NETTTV_MESSAGE_NOTICE );
		NettTv._player.players[NettTv._player.videos[NettTv._player.active].player].togglePause( tracelevel + 1 );
	},
	pause : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.pause()', tracelevel, NETTTV_MESSAGE_NOTICE );
		NettTv._player.players[NettTv._player.videos[NettTv._player.active].player].pause( tracelevel + 1 );
	},
	changeToLowBandwidth : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.changeToLowBandwidth()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].changeToLowBandwidth( tracelevel + 1 );
		}
	},
	changeToHighBandwidth : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.changeToHighBandwidth()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].changeToHighBandwidth( tracelevel + 1 );
		}
	},
	mute : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.mute()', tracelevel, NETTTV_MESSAGE_NOTICE );
		NettTv._player.players[NettTv._player.videos[NettTv._player.active].player].mute( tracelevel + 1 );
	},
	unmute : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.unmute()', tracelevel, NETTTV_MESSAGE_NOTICE );
		NettTv._player.players[NettTv._player.videos[NettTv._player.active].player].unmute( tracelevel + 1 );
	},
	toggleMute : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.toggleMute()', tracelevel, NETTTV_MESSAGE_NOTICE );
		NettTv._player.players[NettTv._player.videos[NettTv._player.active].player].toggleMute( tracelevel + 1 );
	},
	volume : function( value, tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.volume()', tracelevel, NETTTV_MESSAGE_NOTICE );
		NettTv._player.players[NettTv._player.videos[NettTv._player.active].player].volume( value, tracelevel + 1 );
	},
	setPageType : function( pageType, tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.setPageType()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( !( typeof pageType === 'string' && pageType.length > 0 && pageType.length < 32 ) ) {
			NettTv._message.add( 'pageType parameter not set or not valid value, aborting', 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
		NettTv._settings.drKlikkSettings.pageType = pageType;
		NettTv._message.add( 'Set new page type', 1, NETTTV_MESSAGE_NOTICE );
		return true;
	},
	destroyActiveVideoElement : function( tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_action.destroyActiveVideoElement()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].destroy( tracelevel + 1 );
		} else {
			NettTv._message.add( 'No active video', tracelevel + 1, NETTTV_MESSAGE_NOTICE );
		}
	}
};
NettTv._info = {
	isLoaded : function( videoId, tracelevel ) {
		if ( !( typeof tracelevel === 'number' && tracelevel >= 0 ) ) {
			tracelevel = 0;
		}
		NettTv._message.add( '_info.isLoaded()', tracelevel, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.videos['v' + videoId] === 'object' ) {
			return true;
		}
		return false;
	}
};
NettTv.API = {
	/**
	 * Sets the DOM-element that should be parent for the video window.
	 * The parameter can either be an element with nodeType = 1 or a string with the elements id.
	 * 
	 * @param string|object parentElement
	 * @return boolean
	 */
	setVideoParent : function( parentElement ) {
		NettTv._message.add( 'API->setVideoParent()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof parentElement === 'string' && parentElement.length > 0 ) {
			NettTv._message.add( 'Parameter is string, calling getElementById', 1, NETTTV_MESSAGE_NOTICE );
			parentElement = document.getElementById( parentElement );
		}
		if ( typeof parentElement === 'object' && parentElement && parentElement.nodeType === 1 ) {
			NettTv._message.add( 'Parent is a node, setting it as parent', 1, NETTTV_MESSAGE_NOTICE );
			NettTv._player.videoParent = parentElement;
			var dimensions = NettTv._tools.getDimensions( parentElement );
			if ( typeof dimensions[0] === 'number' ) {
				NettTv._player.objectWidth = dimensions[0];
			}
			if ( typeof dimensions[1] === 'number' ) {
				NettTv._player.objectHeight = dimensions[1];
			}
			return true;
		} else {
			NettTv._message.add( 'Parent isn\'t a node, video parent unchanged', 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
	},
	/**
	 * @todo : document and debug 
	 */
	setPlayerSkin : function( skinName ) {
		NettTv._message.add( 'API->setPlayerSkin()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof skinName === 'string' && skinName.length > 0 ) {
			NettTv._message.add( 'Parameter valid, setting as active skin', 1 );
			NettTv._player.playerPath = skinName;
			return true;
		}
		NettTv._message.add( 'Parameter not valid', 1, NETTTV_MESSAGE_NOTICE );
		return false;
	},
	/**
	 * Returns either a null-object or HTMLElement object
	 * 
	 * @return object
	 */
	getVideoParent : function() {
		// @todo document and debug
		return NettTv._player.videoParent;
	},
	/**
	 * Returns the videoId of the active video or false if there is no active video
	 *
	 * @return int|false
	 */
	getActive : function() {
		NettTv._message.add( 'API->getActive()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' ) {
			return NettTv._player.active;
		} else {
			return false;
		}
	},
	/**
	 * Plays immediately the video with the given videoId. Loads video if not loaded, loads player if not loaded, spawns player if not spawned. First parameter required, other optional.
	 *
	 * @param integer videoId
	 * @param string|object parentElement
	 * @param int width
	 * @param int height
	 * @return boolean
	 */
	play : function( videoId, parentElement, pageType, skinName, width, height, index ) {
		NettTv._message.add( 'API->play()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._action.playAPI( 1, videoId, parentElement, pageType, skinName, width, height, index );
	},
	/**
	 * Starts the loading of video info about the video with the given id.
	 * When the video is loaded the function in callback will be executed
	 * with the videoId as parameter.
	 *
	 * @param integer videoId
	 * @param function callback
	 * @return boolean
	 */
	load : function( videoId, callback ) {
		NettTv._message.add( 'API->load()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof videoId !== 'object' ) {
			videoId = [videoId];
		}
		// @todo document and debug
		var validVideoIds = [];
		if ( typeof videoId === 'object' && videoId !== null && videoId.constructor === Array && videoId.length > 0 ) {
			for ( var i = 0, iMax = videoId.length; i < iMax; i++ ) {
				if ( typeof videoId[i] === 'number' && Math.round( videoId[i] ) > 0 ) {
					validVideoIds.push( Math.round( videoId[i] ) );
				}
			}
		}
		if ( validVideoIds.length < 1 ) {
			return false;
		}
		for ( var j = 0, jMax = validVideoIds.length; j < jMax; j++ ) {
			if ( typeof NettTv._player.videos['v' + validVideoIds[j]] === 'object' ) {
				validVideoIds.splice( j, 1 );
				if ( typeof callback === 'function' ) {
					callback( validVideoIds[j] );
				}
			} else {
				if ( typeof callback === 'function' ) {
					NettTv._hooks.loading['v' + validVideoIds[j]] = callback;
				}
			}
		}
		NettTv._tools.require( '?do=js&id=' + validVideoIds.toString(), true, false, 2 );
		return true;
	},
	/**
	 * Returns an array with videoids
	 * 
	 * @return array
	 */
	getPlaylist : function() {
		NettTv._message.add( 'API->getPlaylist()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._player.getPlaylist( 1 );
	},	
	/**
	 * Adds the given videoId to the internal playlist.
	 * Returns the playlistId of the newly added video or false if operation failed.
	 *
	 * @param integer videoId
	 * @return int|false
	 */
	addToPlaylist : function( videoId ) {
		NettTv._message.add( 'API->addToPlaylist()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._player.addToPlaylist( videoId, 1 );
	},
	/**
	 * Removes a video from the internal playlist based on playlistId.
	 *
	 * @param integer playlistId
	 * @return boolean
	 */
	removeFromPlaylist : function( playlistId ) {
		NettTv._message.add( 'API->removeFromPlaylist()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._player.removeFromPlaylist( playlistId, 1 );
	},
	/**
	 * Moves a playlist item up based on playlistId
	 * 
	 * @param integer playlistId
	 * @return boolean
	 */
	moveUpInPlaylist : function( playlistId ) {
		NettTv._message.add( 'API->moveUpInPlaylist()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._player.moveUpInPlaylist( playlistId, 1 );
	},
	/**
	 * Moves a playlist item down based on playlistId
	 * 
	 * @param integer playlistId
	 * @return boolean
	 */
	moveDownInPlaylist : function( playlistId ) {
		NettTv._message.add( 'API->moveDownInPlaylist()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._player.moveDownInPlaylist( playlistId, 1 );
	},
	/**
	 * Moves a playlist item to the top of the playlist based on playlistId
	 * 
	 * @param integer playlistId
	 * @return boolean
	 */
	moveToTopOfPlaylist : function( playlistId ) {
		NettTv._message.add( 'API->moveToTopOfPlaylist()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._player.moveToTopOfPlaylist( playlistId, 1 );
	},
	/**
	 * Moves a playlist item to the bottom of the playlist based on playlistId
	 * 
	 * @param integer playlistId
	 * @return boolean
	 */
	moveToBottomOfPlaylist : function( playlistId ) {
		NettTv._message.add( 'API->moveToBottomOfPlaylist()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._player.moveToBottomOfPlaylist( playlistId, 1 );
	},
	/**
	 * Adds a callback function to a given event.
	 * Whenever the internal event happens, the function is executed.
	 *
	 * @param string eventName
	 * @param function callback
	 * @return boolean
	 */
	addHook : function( eventName, callback ) {
		NettTv._message.add( 'API->addHook()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof eventName === 'string' && typeof callback === 'function' ) {
			NettTv._message.add( 'Callback of type function and event of type string', 1, NETTTV_MESSAGE_NOTICE );
			switch( eventName ) {
				case 'play' :
				case 'next' :
				case 'load' :
				case 'progress' :
				case 'volume' :
				case 'duration' :
				case 'buffer' :
				case 'status' :
				case 'finished' :
				case 'newPlaylist' :
				case 'newVideo' :
				case 'finishedVideo' :
				case 'playerNotSupported' :
				case 'domainBlocked' :
				case 'geoBlocked' :
				case 'related' :
				case 'click' :				
					NettTv._hooks[eventName] = callback;
					NettTv._message.add( 'Hook added to event ' + eventName, 2, NETTTV_MESSAGE_NOTICE );
					break;
				default : 
					NettTv._message.add( 'Unknown event name', 2, NETTTV_MESSAGE_NOTICE );
					return false;
			}
		} else {
			NettTv._message.add( 'Either event name or callback of invalid format', 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
		return true;
	},
	/**
	 * Removes a hook from an event.
	 * Returns true if hook was set, false otherwise
	 * 
	 * @param string eventName
	 * @return boolean
	 */
	removeHook : function( eventName ) {
		NettTv._message.add( 'API->removeHook()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof eventName === 'string' ) {
			NettTv._message.add( 'Event of type string', 1, NETTTV_MESSAGE_NOTICE );
			if ( typeof NettTv._hooks[eventName] === 'function' ) {
				NettTv._message.add( 'Removing hook for event [' + eventName + ']', 2, NETTTV_MESSAGE_NOTICE );
				NettTv._hooks[eventName] = false;
				return true;
			}
			NettTv._message.add( 'No hook set to that event', 2, NETTTV_MESSAGE_NOTICE );
		} else {
			NettTv._message.add( 'Either event name of invalid format', 1, NETTTV_MESSAGE_NOTICE );
			return false;
		}
		return true;
	},
	/**
	 * Tells the player to switch to a low bandwidth stream
	 * 
	 * @return boolean
	 */
	changeToLowBandwidth : function() {
		NettTv._message.add( 'API->changeToLowBandwidth()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._action.changeToLowBandwidth( 1 );
	},
	/**
	 * Tells the player to switch to a high bandwidth stream
	 * 
	 * @return boolean
	 */
	changeToHighBandwidth : function() {
		NettTv._message.add( 'API->changeToHighBandwidth()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._action.changeToHighBandwidth( 1 );
	},
	/**
	 * Will have the system play the next video id in the playlist if there is one. NB, note difference between functions next and nextClip.
	 *
	 * @return boolean
	 */
	next : function() {
		NettTv._message.add( 'API->next()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._action.next( 1 );
	},
	/**
	 * Tells the player to jump to the next clip in the current video ids tracklist. NB, not the difference between functions next and nextClip.
	 * 
	 * @return boolean
	 */
	nextClip : function() {
		NettTv._message.add( 'API->nextClip()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._action.nextClip( 1 );
	},
	/**
	 * Tells the player to jump to the previous clip in the current video ids tracklist
	 * 
	 * @return boolean
	 */
	previousClip : function() {
		NettTv._message.add( 'API->previousClip()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._action.previousClip( 1 );
	},
	/**
	 * Will rewind and stop the currently active player.
	 * NB! Notice the difference between play, stop, pause and resume.
	 *
	 * @return boolean
	 */
	stop : function() {
		NettTv._message.add( 'API->stop()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._message.add( 'A video and its player is active, stopping it', 1, NETTTV_MESSAGE_NOTICE );
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].stop( 2 );
		} else {
			NettTv._message.add( 'No video active or player of active video not loaded yet', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Will pause the currently active player.
	 *
	 * @return boolean;
	 */
	pause : function() {
		NettTv._message.add( 'API->pause()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._message.add( 'A video and its player is active, pausing it', 1, NETTTV_MESSAGE_NOTICE );
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].pause( 2 );
		} else {
			NettTv._message.add( 'No video active or player of active video not loaded yet', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Will resume the currently active player
	 * 
	 * @return boolean
	 */
	resume : function() {
		NettTv._message.add( 'API->resume()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._message.add( 'A video and its player is active, resuming it', 1, NETTTV_MESSAGE_NOTICE );
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].resume( 2 );
		} else {
			NettTv._message.add( 'No video active or player of active video not loaded yet', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Will toggle the pause status of the currently active player
	 * 
	 * @return boolean
	 */
	togglePause : function() {
		NettTv._message.add( 'API->togglePause()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._message.add( 'A video and its player is active, toggling its pause status', 1, NETTTV_MESSAGE_NOTICE );
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].togglePause( 2 );
		} else {
			NettTv._message.add( 'No video active or player of active video not loaded yet', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;		
	},
	/**
	 * Will mute the currently active player
	 * 
	 * @return boolean
	 */
	mute : function() {
		NettTv._message.add( 'API->mute()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._message.add( 'A video and its player is active, muting it', 1, NETTTV_MESSAGE_NOTICE );
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].mute( 2 );
		} else {
			NettTv._message.add( 'No video active or player of active video not loaded yet', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Will unmute the currently active player
	 * 
	 * @return boolean
	 */
	unmute : function() {
		NettTv._message.add( 'API->unmute()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._message.add( 'A video and its player is active, unmuting it', 1, NETTTV_MESSAGE_NOTICE );
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].unmute( 2 );
		} else {
			NettTv._message.add( 'No video active or player of active video not loaded yet', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Will toggle the mute status of the currently active player
	 * 
	 * @return boolean
	 */
	toggleMute : function() {
		NettTv._message.add( 'API->toggleMute()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			NettTv._message.add( 'A video and its player is active, toggling its mute status', 1, NETTTV_MESSAGE_NOTICE );
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].toggleMute( 2 );
		} else {
			NettTv._message.add( 'No video active or player of active video not loaded yet', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Returns a boolean value indicating whether the video is loaded
	 * 
	 * @param integer videoId
	 * @return boolean
	 */
	isLoaded : function( videoId ) {
		NettTv._message.add( 'API->isLoaded()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.videos['v' + videoId] === 'object' ) {
			return true;
		} else {
			NettTv._message.add( 'VideoId of invalid format', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Returns the duration of a clip in milliseconds. Parameter is optional and will if empty return the duration of the currently playling video. Returns zero on no clip playing or if videoId not loaded.
	 * 
	 * @return int
	 */
	getDuration : function( videoId ) {
		NettTv._message.add( 'API->getDuration()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof videoId === 'undefined' && typeof NettTv._player.active === 'number' && NettTv._info.isLoaded( NettTv._player.active, 1 ) && typeof NettTv._player.videos['v' + NettTv._player.active].duration === 'number' ) {
			return NettTv._player.videos['v' + NettTv._player.active].duration;
		} else if ( typeof videoId === 'number' && NettTv._info.isLoaded( videoId, 1 ) && typeof NettTv._player.videos['v' + videoId].duration === 'number' ) {
			return NettTv._player.videos['v' + videoId].duration;
		} else {
			return 0;
		}
	},
	/**
	 * Returns the playback position of the currently playing video or false if no video is playing.
	 * 
	 * @return false|int
	 */
	getPosition : function() {
		NettTv._message.add( 'API->getPosition()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].getPosition( 1 );
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 0, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Returns the title of a video
	 * Returns false if video not loaded or parameter in invalid format
	 * 
	 * @param integer videoId
	 * @return string|false
	 */
	getTitle : function( videoId ) {
		NettTv._message.add( 'API->getTitle()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof videoId === 'number' && NettTv._info.isLoaded( videoId, 1 ) && typeof NettTv._player.videos['v' + videoId].title === 'string' ) {
			return NettTv._player.videos['v' + videoId].title;
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Returns the category id of a video
	 * Returns false if video not loaded or parameter in invalid format
	 * 
	 * @author haakon@aptoma.com
	 * @param integer categoryId
	 * @return string|false
	 */
	getCategory : function( videoId ) {
		NettTv._message.add( 'API->getCategory()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof videoId === 'number' && NettTv._info.isLoaded( videoId, 1 ) && typeof NettTv._player.videos['v' + videoId].category_id === 'number' ) {
			return NettTv._player.videos['v' + videoId].category_id;
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},	
	/**
	 * Returns the preamble of a video
	 * Returns false if video not loaded or parameter in invalid format
	 * 
	 * @param integer videoId
	 * @return string|false
	 */
	getPreamble : function( videoId ) {
		NettTv._message.add( 'API->getPreamble()', 0, NETTTV_MESSAGE_NOTICE );
		if ( NettTv._info.isLoaded( videoId, 1 ) && typeof NettTv._player.videos['v' + videoId].preamble === 'string' ) {
			return NettTv._player.videos['v' + videoId].preamble;
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Returns the URL to the videos image
	 * Returns false if video not loaded or parameter in invalid format
	 * 
	 * @param integer videoId
	 * @return string|false
	 */
	getImage : function( videoId, width ) {
		NettTv._message.add( 'API->getImage()', 0, NETTTV_MESSAGE_NOTICE );
		if ( NettTv._info.isLoaded( videoId, 1 ) && typeof NettTv._player.videos['v' + videoId].images === 'object' ) {
			if ( NettTv._player.videos['v' + videoId].images.length > 0 ) {
				if ( NettTv._player.videos['v' + videoId].images.length === 1 ) {
					NettTv._message.add( 'Video has only one image, returning it', 1, NETTTV_MESSAGE_NOTICE );
					return NettTv._player.videos['v' + videoId].images[0].url;
				}
				if ( typeof width === 'number' ) {
					NettTv._message.add( 'Width parameter set, looping over image list for it', 1, NETTTV_MESSAGE_NOTICE );
					for ( var i = 0, iMax = NettTv._player.videos['v' + videoId].images.length; i < iMax; i++ ) {
						if ( NettTv._player.videos['v' + videoId].images[i].width > width ) {
							NettTv._message.add( 'Found first image larger than desired size, returning it', 2, NETTTV_MESSAGE_NOTICE );
							return NettTv._player.videos['v' + videoId].images[i].url;
						} else if ( NettTv._player.videos['v' + videoId].images[i].width === width ) {
							NettTv._message.add( 'Found image with desired size, returning it', 2, NETTTV_MESSAGE_NOTICE );
							return NettTv._player.videos['v' + videoId].images[i].url;
						} else {
							if ( i === ( iMax - 1 ) ) {
								NettTv._message.add( 'Came to the end of the list without finding big enough image, returning last', 2, NETTTV_MESSAGE_NOTICE );
								return NettTv._player.videos['v' + videoId].images[i].url;
							} else if ( NettTv._player.videos['v' + videoId].images[i + 1].width > width ) {
								if ( ( ( width - NettTv._player.videos['v' + videoId].images[i].width ) - ( NettTv._player.videos['v' + videoId].images[i + 1].width - width ) ) < 0 ) {
									NettTv._message.add( 'Found image smaller than desired as the best match', 2, NETTTV_MESSAGE_NOTICE );
									return NettTv._player.videos['v' + videoId].images[i].url;
								} else {
									NettTv._message.add( 'Found image larger than desired as the best match', 2, NETTTV_MESSAGE_NOTICE );
									return NettTv._player.videos['v' + videoId].images[i + 1].url;
								}
							}
						}
					}
				} else {
					NettTv._message.add( 'Width parameter not set, returning first image', 1, NETTTV_MESSAGE_NOTICE );
					return NettTv._player.videos['v' + videoId].images[0].url;
				}
			} else {
				NettTv._message.add( 'Video does not contain any images', 1, NETTTV_MESSAGE_NOTICE );
			}
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 1, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Returns the date the video was published
	 * Returns false if video not loaded or parameter in invalid format
	 * 
	 * @param integer videoId
	 * @return string|null
	 */
	getDatePublished : function( videoId ) {
		NettTv._message.add( 'API->getDatePublished()', 0, NETTTV_MESSAGE_NOTICE );
		if ( NettTv._info.isLoaded( videoId, 1 ) && typeof NettTv._player.videos['v' + videoId].published === 'number' ) {
			var datePublished = new Date();
			datePublished.setTime( 1000 * parseInt( NettTv._player.videos['v' + videoId].published, 10 ) );
			return datePublished;
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 1, NETTTV_MESSAGE_NOTICE );
		}
		return null;
	},
	/**
	 * Returns an array of indexes for a videoId or null if video not loaded or has no indexes.
	 * 
	 * @return null|array
	 */
	getIndexes : function( videoId ) {
		if ( NettTv._info.isLoaded( videoId, 1 ) && typeof NettTv._player.videos['v' + videoId].indexes === 'object' ) {
			return NettTv._player.videos['v' + videoId].indexes;
		} else {
			return null;
		}
	},
	/**
	 * Returns the volume (0 to 100) of the currently active player
	 * 
	 * @return integer|null
	 */
	getVolume : function() {
		NettTv._message.add( 'API->getVolume()', 0, NETTTV_MESSAGE_NOTICE );
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].getVolume( 1 );
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 0, NETTTV_MESSAGE_NOTICE );
		}
		return null;
	},
	/**
	 * Sets the volume of the currently active player (0 to 100)
	 * 
	 * @param integer volume
	 * @return boolean
	 */
	setVolume : function( volume ) {
		NettTv._message.add( 'API->setVolume()', 0, NETTTV_MESSAGE_NOTICE );
		volume = parseInt( volume, 10 );
		if ( volume > 100 ) {
			volume = 100;
		} else if ( volume < 0 ) {
			volume = 0;
		}
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].setVolume( volume, 1 );
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 0, NETTTV_MESSAGE_NOTICE );
		}
		return false;
	},
	/**
	 * Seeks (jumps) to a position in the clip based on the milliseconds parameter.
	 * 
	 * @return boolean
	 */
	seek : function( milliseconds ) {
		NettTv._message.add( 'API->seek()', 0, NETTTV_MESSAGE_NOTICE );
		if ( !( typeof milliseconds === 'number' && milliseconds >= 0 ) ) {
			NettTv._message.add( 'Milliseconds parameter not valid', 1, NETTTV_MESSAGE_WARNING );
			return false;
		}
		if ( typeof NettTv._player.active === 'number' && typeof NettTv._player.videos['v' + NettTv._player.active] === 'object' ) {
			return NettTv._player.players[NettTv._player.videos['v' + NettTv._player.active].player].seek( milliseconds, 1 );
		} else {
			NettTv._message.add( 'VideoId not loaded or videoId in invalid format', 1, NETTTV_MESSAGE_WARNING );
		}
	},
	/**
	 * Sets the desired dimension of _future_ spawned video windows. NB, must be set after setVideoParent if both commands used
	 * 
	 * @return boolean
	 */
	setDimensions : function( width, height ) {
		if ( typeof width === 'number' && typeof height === 'number' ) {
			width = Math.round( width );
			height = Math.round( height );
			if ( width > 0 && height > 0 ) {
				NettTv._player.objectWidth = width;
				NettTv._player.objectHeight = height;
				return true;
			}
		}
		return false;
	},
	/**
	 * Sets the page type, eg. portal and article
	 * 
	 * @param string pageType
	 * @return bool
	 */
	setPageType : function( pageType ) {
		NettTv._message.add( 'API->setPageType()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._action.setPageType( pageType );
	},
	destroyActiveVideoElement : function() {
		NettTv._message.add( 'API->destroyActiveVideoElement()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._action.destroyActiveVideoElement( 1 );
	}
};
NettTv.__API = {
	getUrl : function( urlName )
	{
		return NettTv._tools.getUrl( urlName );
	},
	event : function( eventObject ) {
		if ( typeof eventObject === 'object' && typeof eventObject.eventType === 'string' ) {
			var drKlikkEvent;
			switch ( eventObject.eventType ) {
				// deprecated?
				case 'playerReady' :
					NettTv._message.add( '*F : Flashplayer ready for commands', 0, NETTTV_MESSAGE_SPAM );
					NettTv._player.players.flash.initDone( 1 );
					break;
				case 'playerStarted' :
					NettTv._message.add( '*F : Flashplayer started', 0, NETTTV_MESSAGE_SPAM );
					NettTv._player.players.flash.playerVersion = eventObject.playerVersion;
					break;
				case 'metadataReceived' :
					NettTv._message.add( '*F : Metadata recieved', 0, NETTTV_MESSAGE_SPAM );
					if ( typeof eventObject.duration === 'number' && typeof eventObject.id === 'number' ) {
						if ( NettTv._info.isLoaded( eventObject.id, 1 ) ) {
							NettTv._player.videos['v' + eventObject.id].duration = eventObject.duration;
						}
						if ( typeof NettTv._hooks.duration === 'function' ) {
							NettTv._hooks.duration( eventObject.duration, eventObject.id );
						}
					}
					break;
				case 'playlistStarted' :
					// @todo : Add additions to numClips for each video type.
					NettTv._message.add( '*F : Loaded playlist with ' + eventObject.numClips + ' clips', 0, NETTTV_MESSAGE_SPAM );
					if ( typeof NettTv._hooks.newPlaylist === 'function' ) {
						NettTv._hooks.newPlaylist( eventObject.numClips, eventObject.initialVolume );
					}
					break;
				case 'playlistFinished' :
					NettTv._message.add( '*F : Finished entire playlist', 0, NETTTV_MESSAGE_SPAM );
					NettTv._action.next();
					if ( typeof NettTv._hooks.finished === 'function' ) {
						NettTv._hooks.finished();
					}
					break;
				case 'netstatus' :
					NettTv._message.add( '*F : NetStatus message [' + eventObject.code + ']', 0, NETTTV_MESSAGE_SPAM );
					break;
				case 'streamConnected' :
					NettTv._message.add( '*F : Connected to stream', 0, NETTTV_MESSAGE_SPAM );
					break;
				case 'clipStarted' :
					NettTv._message.add( '*F : Started playing clip [' + eventObject.id + '] with role [' + eventObject.role + '] at position [' + eventObject.initialPosition + ']', 0, NETTTV_MESSAGE_SPAM );
					drKlikkEvent = {identification:eventObject.id};
					switch ( eventObject.role ) {
						case 'video' :
						case 'live' :
							drKlikkEvent.event = 'videoplay';
							break;
						case 'roll' :
							drKlikkEvent.event = 'rollplay';
							break;
						case 'ad' :
							drKlikkEvent.event = 'adplay';
							break;
					}
					if ( typeof NettTv._player.videos['v' + eventObject.id] === 'object' && NettTv._player.videos['v' + eventObject.id] && typeof NettTv._player.videos['v' + eventObject.id].category_id === 'number' ) {
						drKlikkEvent.text2 = NettTv._player.videos['v' + eventObject.id].category_id;
					}
					if ( typeof NettTv._settings.drKlikkSettings.prefix === 'string' ) {
						drKlikkEvent.text1 = NettTv._settings.drKlikkSettings.prefix + '-' + NettTv._settings.drKlikkSettings.pageType;
					}
					NettTv._message.add( 'Registering playback with DrKlikk', 0, NETTTV_MESSAGE_NOTICE );
					NettTv._tools.drklikkRegister( drKlikkEvent, 1 );
					if ( typeof NettTv._hooks.newVideo === 'function' ) {
						NettTv._hooks.newVideo( eventObject.id, eventObject.role, eventObject.playlistPosition, eventObject.hasPrevious, eventObject.hasNext );
					}
					break;
				case 'clipFinished' :
					NettTv._message.add( '*F : Finished playing clip [' + eventObject.id + '] with role [' + eventObject.role + ']', 0, NETTTV_MESSAGE_SPAM );
					if ( typeof NettTv._hooks.finishedVideo === 'function' ) {
						NettTv._hooks.finishedVideo( eventObject.id, eventObject.role );
					}
					break;
				case 'playstateChanged' :
					if ( typeof NettTv._hooks.status === 'function' ) {
						NettTv._hooks.status( eventObject.playstate );
					}
					NettTv._message.add( '*F : Playstate changed to [' + eventObject.playstate + '] at position [' + eventObject.position + ']', 0, NETTTV_MESSAGE_SPAM );
					break;
				case 'bufferChange' :
					if ( typeof NettTv._hooks.buffer === 'function' ) {
						NettTv._hooks.buffer( eventObject.status, eventObject.isLowBitrate, eventObject.numberOfTimesBufferEmptyOnThisUri );
					}
					if ( eventObject.status === 'full' ) {
						NettTv._message.add( '*F : Buffer is full on ' + ( eventObject.isLowBitrate ? '[low]' : '[high]' ) + ' bitrate stream for id [' + eventObject.id + '] at URI [' + eventObject.URI + ']', 0, NETTTV_MESSAGE_SPAM );
					} else if ( eventObject.status === 'flush' ) {
						NettTv._message.add( '*F : Buffer flushed on ' + ( eventObject.isLowBitrate ? '[low]' : '[high]' ) + ' bitrate stream for id [' + eventObject.id + '] at URI [' + eventObject.URI + ']', 0, NETTTV_MESSAGE_SPAM );
					} else if ( eventObject.status === 'empty' ) {
						NettTv._message.add( '*F : Buffer empty for the [' + eventObject.numberOfTimesBufferEmptyOnThisUri + ']\'th time on this ' + ( eventObject.isLowBitrate ? '[low]' : '[high]' ) + ' bitrate stream for id [' + eventObject.id + '] at URI [' + eventObject.URI + ']', 0, NETTTV_MESSAGE_SPAM );
					}
					break;
				case 'playProgress' :
					NettTv._message.add( '*F : Player has progressed one second to position [' + eventObject.position + '] on video [' + eventObject.id + '] with role [' + eventObject.role + ']', 0, NETTTV_MESSAGE_SPAM );
					if ( typeof NettTv._hooks.progress === 'function' ) {
						NettTv._hooks.progress( eventObject.position, eventObject.id );
					}
					break;
				case 'trace' :
					//NettTv._message.add( '*F : Debug information : ' + eventObject.description, 0, NETTTV_MESSAGE_NOTICE );
					break;
				case 'volumeChanged' :
					NettTv._message.add( '*F : Volume changed, mute status is [' + ( eventObject.isMuted ? 'true' : 'false' ) + '] and volume is [' + eventObject.volume + ']', 0, NETTTV_MESSAGE_SPAM );
					if ( typeof NettTv._hooks.volume === 'function' ) {
						NettTv._hooks.volume( eventObject.isMuted, eventObject.volume );
					}
					break;
				case 'lowBandwidthSwitch' :
					drKlikkEvent = {event:'lowbandwidth'};
					NettTv._message.add( 'Registering low bandwidth swtich with DrKlikk', 0, NETTTV_MESSAGE_NOTICE );
					NettTv._tools.drklikkRegister( drKlikkEvent, 1 );
					NettTv._message.add( '*F : Switched to a low bandwidth stream', 0, NETTTV_MESSAGE_SPAM );
					break;
				case 'highBandwidthSwitch' :
					NettTv._message.add( '*F : Switched to a high bandwidth stream', 0, NETTTV_MESSAGE_SPAM );
					break;
				case 'fullscreenChanged' :
					if ( eventObject.isFullscreen ) {
						drKlikkEvent = {event:'fullscreen'};
						NettTv._message.add( 'Registering fullscreen activation with DrKlikk', 0, NETTTV_MESSAGE_NOTICE );
						NettTv._tools.drklikkRegister( drKlikkEvent, 1 );
					}
					NettTv._message.add( '*F : Fullscreen status changed', 0, NETTTV_MESSAGE_SPAM );
					break;
				case 'smoothingChange' :
					NettTv._message.add( '*F : Smoothing set to ' + eventObject.status, 0, NETTTV_MESSAGE_SPAM );
					break;
				case 'error' :
					NettTv._message.add( '*F : Error: ' + eventObject.description, 0, NETTTV_MESSAGE_WARNING );
					break;
				case 'warning' :
					NettTv._message.add( '*F : Fullscreen status changed', 0, NETTTV_MESSAGE_NOTICE );
					break;
				case 'allStreamLocationsFailed' :
					NettTv._message.add( '*F : All stream locations failed', 0, NETTTV_MESSAGE_NOTICE );
					NettTv.API.nextClip();
					break;
				case 'streamFailed' :
					NettTv._message.add( '*F : Stream location failed', 0, NETTTV_MESSAGE_NOTICE );
					break;
				case 'geoBlocked' :
					NettTv._message.add( '*F : geo block detected', 0, NETTTV_MESSAGE_NOTICE );
					drKlikkEvent = {event:'geoblocked'};
					try {
						if ( 'java' in window && typeof window.java === 'object' && typeof window.java.net === 'object' && typeof window.java.net.InetAddress === 'object' && typeof window.java.net.InetAddress.getLocalHost === 'function' ) {
							var localHost = window.java.net.InetAddress.getLocalHost();
							if ( typeof localHost.getHostAddress === 'function' ) {
								localHost = localHost.getHostAddress();
								if ( typeof localHost === 'string' && localHost ) {
									localHost += '';
									if ( localHost.length >= 7 && localHost.length <= 15 && localHost !== '127.0.0.1' ) {
										drKlikkEvent.identification = localHost;
									}
								}
							}
						}
					} catch ( error ) {
						NettTv._message.add( 'Error getting user IP', 1, NETTTV_MESSAGE_VERBOSE );
					}
					NettTv._message.add( 'Registering geo block with DrKlikk', 2, NETTTV_MESSAGE_NOTICE );
					NettTv._tools.drklikkRegister( drKlikkEvent, 1 );
					if ( typeof NettTv._hooks.geoBlocked === 'function' ) {
						NettTv._hooks.geoBlocked();
					}
					break;
				case 'relatedClipPlayed' :
					NettTv._message.add( '*F : User clicked related video', 0, NETTTV_MESSAGE_NOTICE );
					drKlikkEvent = {event:'relatedclick'};
					NettTv._message.add( 'Registering related click with DrKlikk', 0, NETTTV_MESSAGE_NOTICE );
					NettTv._tools.drklikkRegister( drKlikkEvent, 1 );
					if ( typeof NettTv._hooks.related === 'function' ) {
						NettTv._message.add( 'Found hook on action [related], calling it', 1, NETTTV_MESSAGE_NOTICE );
						NettTv._hooks.related( eventObject.toClipId, eventObject.fromClipId );
					}
					if ( typeof NettTv._hooks.play === 'function' ) {
						NettTv._message.add( 'Found hook on action [play], calling it', 1, NETTTV_MESSAGE_NOTICE );
						NettTv._hooks.play( eventObject.toClipId );
					}
					break;
				case 'clickUrlClicked' :
					NettTv._message.add( '*F : User clicked video url', 0, NETTTV_MESSAGE_NOTICE );
					drKlikkEvent = {event:'videourlclick'};
					NettTv._message.add( 'Registering video url click with DrKlikk', 0, NETTTV_MESSAGE_NOTICE );
					NettTv._tools.drklikkRegister( drKlikkEvent, 1 );
					if ( typeof NettTv._hooks.click === 'function' ) {
						NettTv._message.add( 'Found hook on action [click], calling it', 1, NETTTV_MESSAGE_NOTICE );
						// @todo: Put parameters in this call
						NettTv._hooks.click();
					}
					break;
				default :
					NettTv._debug.output( eventObject );
			}
		}
	},
	getOverlayUrl : function( name ) {
		NettTv._message.add( '__API : getOverlayUrl()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._tools.getUrl( name );
	},
	getOverlayUrls : function() {
		NettTv._message.add( '__API :: getOverlayUrls()', 0, NETTTV_MESSAGE_NOTICE );
		return NettTv._tools.getUrls();
	},
	persistentSet : function( name, value, expire ) {
		var cookie = {};
		cookie.name = name;
		cookie.value = value;
		cookie.expire = expire;
		NettTv._message.add( '__API : persistentSet()', 0, NETTTV_MESSAGE_NOTICE, cookie );
		return NettTv._cookie.set( 0, name, value, expire );
	},
	persistentGet : function( name ) {
		NettTv._message.add( '__API : persistentGet()', 0, NETTTV_MESSAGE_NOTICE, name );
		return NettTv._cookie.get( 0, name );
	},
	persistentErase : function( name ) {
		NettTv._message.add( '__API : persistentErase()', 0, NETTTV_MESSAGE_NOTICE, name );
		return NettTv._cookie.erase( 0, name );
	}
};
NettTv._cookie = {
	get : function( tracelevel, name ) {
		var nameEq = name + "=";
		var ca = document.cookie.split( ';' );
		for( var i = 0, iMax = ca.length; i < iMax; i++ ){
			var c = ca[i];
			while ( c.charAt( 0 ) === ' ' ) {
				c = c.substring( 1, c.length );
			}
				
			if ( c.indexOf( nameEq ) === 0 ) {
				var cookie = c.substring( nameEq.length, c.length );
				var result = null;
				try {
					result = decodeURIComponent( cookie.replace( /\+/g, ' ' ) );
				} catch ( e ) {}
				return result;
			}
		}
		return null;
	},
	set : function( tracelevel, name, value, expire ) {
		var expires = "";
		if ( expire ){
			var date = new Date();
			date.setTime( date.getTime() + ( expire * 1000 ) );
			expires = '; expires=' + date.toGMTString();
		}
		document.cookie = name + '=' + value + expires + '; path=/';
	},
	erase : function( tracelevel, name ) {
		this.set( name, '', -999999 );
	}
};
NettTv._message = {
	messages : [],
	add : function( message, tracelevel, importance, object ) {
		var newMessage = {};
		newMessage.message = message;
		newMessage.tracelevel = tracelevel;
		newMessage.importance = importance;
		newMessage.object = object;
		if ( NettTv._message.validate( newMessage ) ) {
			NettTv._message.messages.push( newMessage );
			NettTv._message.display( newMessage, tracelevel );
			return true;
		}
		return false;
	},
	validate : function( message ) {
		if ( typeof message === 'object' && typeof message.message === 'string' && message.message.length > 0 ) {
			if ( typeof message.tracelevel != 'number' ) {
				message.tracelevel = 0;
			}
			if ( typeof message.importance != 'number' ) {
				message.importance = NETTTV_MESSAGE_NOTICE;
			} else {
				switch ( message.importance ) {
					case NETTTV_MESSAGE_SPAM :
					case NETTTV_MESSAGE_NOTICE :
					case NETTTV_MESSAGE_WARNING :
					case NETTTV_MESSAGE_FATAL :
						break;
					default :
						message.importance = NETTTV_MESSAGE_NOTICE;
						break;
				}
			}
			if ( typeof message.object === 'undefined' ) {
				message.object = null;
			}
			return true;
		}
		return false;
	},
	display : function( message, tracelevel ) {
		if ( NettTv._message.validate( message ) ) {
			if ( NettTv._debug.active && NettTv._debug.importance >= message.importance ) { 
				NettTv._debug.output( message.message, tracelevel );
			}
			return true;
		} else {
			return false;
		}
	},
	dump : function( importance ) {
		if ( typeof importance !== 'number' ) {
			importance = NETTTV_MESSAGE_NOTICE;
		}
		NettTv._debug.output( 'Has ' + NettTv._message.messages.length + ' message(s), filtering at level ' + importance );
		for ( var i = 0, iMax = NettTv._message.messages.length; i < iMax; i++ ) {
			if ( NettTv._message.messages[i].importance <= importance ) {
				NettTv._debug.output( NettTv._message.messages[i] );
			}
		}
	},
	read : function( importance ) {
		if ( typeof importance !== 'number' ) {
			importance = NETTTV_MESSAGE_NOTICE;
		}
		var messages = [];
		for ( var i = 0, iMax = NettTv._message.messages.length; i < iMax; i++ ) {
			if ( NettTv._message.messages[i].importance <= importance ) {
				messages[messages.length] = NettTv._message.messages[i];
			}
		}
		return messages;
	}
};
NettTv._tools.extendedPreloading();
