/**
 * @name	GLOBALS FOR THE FLOWPLAYER POINTER AND CONFIGURATION
 * @purpose	define some global consts and variables
 */
var FE = null;            // global pointer to the flashembed (api)
var FP = null;            // global pointer to the flowplayer (api)
var FP_LOAD_DELAY = 1500; // flowplayer delays loading in milliseconds
/**
 * global arrays holding lists of html elements
 */
var TL = new Array();  // track list
var TSL = new Array(); // track subtitle list
var TAL = new Array(); // track annotation list


/**
 * @name	setupFlowPlayerShockwaveObject
 * @purpose	writes the content of the videoplayer box through javascript
 * @param  name (String) of a container (i.e. CSS Identifier)
 * @param  flowplayer configuration as a javascript json object
 * @returns pointer to the shockwave object to allow API access
 * @note	in principle the retuned value should allow multiple instances
 *			of the player but this is completly untested!
 * @note	see http://flowplayer.org/tools/flashembed.html for all options
 *			of flashembed used herein
 */
function setupFlowPlayerShockwaveObject(container, fpconfig)
{
	/*
	 * variables to setup and config flash plugin
	 */
	var _fe;
//	var _swfSrc = "swf/clock.swf"; // small test shockwave
//	var _swfSrc = "swf/FlowPlayerDark-2.1.3.swf"; // error prone latest commercial
	var _swfSrc = "swf/FlowPlayerDark-2.2.4.swf"; // currently used self build version
//	var _minVer = [20,0];  // non existend to test on fail function
	var _minVer = [9,115]; // minimum version of flash plugin required to work
	var _bgColor = "#000000";
	var _winMode = "opaque";
	var _w3cStd = true;
	var _flashConf;		// configures the flash plugin
	/*
	 * variables to setup and config flowplayer shockwave
	 */
	var _flowpConf;		// string holding all variable flowplayer options
	/*
	 * if plugin version is too old for flowplayer
	 * onFail is called through flashemded()
	 */
	var _onFail = function onFail()
	{
		document.getElementById(container).innerHTML =
			"<dfn>Channel-in-a-Box</dfn> ben&ouml;tigt das Flash Plugin <u>mindestens</u> in der Version "
			+ _minVer + ". <br /><br />"
			+ "<img src=\"img/flashplayer_100x100.jpg\" /> <br /><br />"
			+ "Deine Version ("
			+ this.getVersion()
			+ ") scheint leider &auml;lter zu sein. <br />"
			+ "Hole Dir die <a style=\"color:#b22222;text-decoration:none;\" href=\"http://get.adobe.com/flashplayer/\">aktuelle Flash Version</a> ...";
	}
	_flashConf = {
		src:		_swfSrc,
		version:	_minVer,
		onFail:		_onFail,
		w3c:		_w3cStd,
		bgcolor:	_bgColor,
		wmode:		_winMode
	};
	if (typeof console != "undefined") {
		console.log("setupFlowPlayerShockwaveObject(): flowplayer configuration: " + fpconfig);
	}
	// next is just a live _example_ for a directly constructed JSON object
	_flowpConf = {
		config: {
			initialScale:'scale',controlBarGloss:'none',showStopButton:false,showPlayListButtons:true
		}
	};
	// BUT THE CRUX IS, THAT ALL WE HAVE IS A STRING THAT JUST _LOOKS_ LIKE A JSON OBJECT
	// but don't panic hitchhiker! here's your towel:
	// "To convert a JSON text into an object, you can use the eval() function.
	// eval() invokes the JavaScript compiler. Since JSON is a proper subset of
	// JavaScript, the compiler will correctly parse the text and produce an
	// object structure. The text must be wrapped in parens to avoid tripping
	// on an ambiguity in JavaScript's syntax."
	// (from: http://www.json.org/js.html)
	// using the 'towel' it reads as:
	_flowpConf = eval('(' +  "{ config: { " + fpconfig + " } }" + ')');
	_fe = flashembed(container, _flashConf, _flowpConf );
	return _fe;
}
/**
 * @name	getCurrentClipIndex
 * @type	ciab function to control flowplayer
 * @purpose	shell for the error prone flowplayer api
 * @param	-
 * @returnsinteger from 1 to n
 */
function getCurrentClipIndex()
{
	var _cc;
	try {
		_cc = FP.getCurrentClip();
	} catch(e) {
	} finally {
		if (_cc) {
			return _cc;
		} else {
			return 1;
		}
	}
}
/**
 * @name	selectTrack
 * @purpose	to be referenced in the track list elements (links)
 * @param	track index
 * @note	track index starts with 1
 */
function selectTrack(index)
{
	if (typeof console != "undefined") {
		console.log("SelectTrack(): User selected from list track no: " + index);
	}
	try {
		callBoxFunc('ciabVideoPlayerBox','onSelectTrack',index);
	} catch (err) {
		if (typeof console != "undefined") {
			console.error("SelectTrack(): User selected from list track no: " + index + " but box call failed");
		}
	}
}
/**
 * @name	onSelectTrack
 * @purpose	jump to the clip and start playing (if not playing yet)
 *          and being the hook (aka callback) for the selectTrack
 *          function in the tracklist box
 * @param	track index
 * @note	track index starts with 1
 * @returns	-
 */
function onSelectTrack(index)
{
	if (typeof console != "undefined") {
		console.log("onSelectTrack(): request started to play track no: " + index);
	}
	//FP.DoStop();
  // loading next clip might take a while. users should not get
  // confused by still reading the subtitel of the last played clip
	unshowAllTrackSubtitels();
	FP.ToClip(index);
	//FP.DoPlay();
	if (typeof console != "undefined") {
		console.log("onSelectTrack(): request finished: ");
	}
}
/**
 * @name	showTrackSubtitel
 * @purpose	displays an element of the subtitel 'list'
 * @param	track number
 * @note	trackNum starts with 1
 * @returns	-
 */
function showTrackSubtitel(trackNum)
{
  if (typeof console != "undefined") {
    console.log("showTrackSubtitel(): showing subtitle of track number: "+trackNum);
  }
  unshowAllTrackSubtitels();
	// trackNum starts with 1 but html elements with 0
	if (trackNum > 0)
	{
		TSL[trackNum-1].style.display = "block";
	} else {
		if (typeof console != "undefined") {
			console.log("showTrackSubtitel(): No valid track number: "+trackNum);
		}
	}
}
/**
 * @name	unshowTrackSubtitel
 * @type	ciab function to control ciab
 * @purpose	hides an element of the subtitel 'list'
 * @param	track number
 * @note	trackNum starts with 1
 * @returns	-
 */
function unshowTrackSubtitel(trackNum)
{
	// trackNum starts with 1 but html elements with 0
	if (trackNum > 0)
	{
		TSL[trackNum - 1].style.display = "none";
	} else {
		if (typeof console != "undefined") {
			console.log("unshowTrackSubtitel(): No valid track number: "+trackNum);
		}
	}
}
/**
 * @name	unshowAllTrackSubtitels
 * @type	ciab function to control ciab
 * @purpose	hide (i.e. undisplay) all subtitle (elements)
 * @param	-
 * @note	-
 * @returns	-
 */
function unshowAllTrackSubtitels()
{
	var i;
	var _last = TSL.length;
	// we loop here over our (logical) track list (i.e. starting with 1)
	if (_last > 0) {
		for (i = 1; i <= _last; i++) {
			unshowTrackSubtitel(i);
		}
	} else {
		if (typeof console != "undefined") {
			console.log("unshowAllTrackSubtitels(): No subtitel items found");
		}
	}
}
/**
 * @name	getPlaylistMetaData
 * @type	ciab custom
 * @purpose	provides data from the playlist meta data array
 * @param	index in the array
 * @param	name of object key
 * @note	global name of the array: PLAYLIST_META
 * @returnsa string containing the data
 */
function getPlaylistMetaData(index, key) {
	// return value from global playlist meta array
	return PLAYLIST_META[index][key];
}
/**
 * @name	doGoogleAnalyticsPageviewTracking
 * @type	ciab function wrapping _trackPageview
 * @purpose	does the actual call to google analytics
 * @param	a google analytics track id
 * @param	a virtual url to be tracked as a pageview
 * @note	-
 * @returns WOULD RETURN TRUE OR FALSE ON SUCCESS, BUT
 *          THERE IS NO RETURN VALUE FROM THE GOOGLE CODE
 */
function doGoogleAnalyticsPageviewTracking(gatId, virtualPageUrl) {
	try {
		// get the ciab tracker (object)
		var _pageTracker = _gat._getTracker(gatId);
		// and track the (virtual) url
		_pageTracker._trackPageview(virtualPageUrl);
		// print message to the firebug console (if present)
		if (typeof console != "undefined") {
			console.log("doGoogleAnalyticsPageviewTracking("+gatId+"): pageview tracked: "+virtualPageUrl);
		}
	} catch(err) {
		if (typeof console != "undefined") {
			console.log("doGoogleAnalyticsPageviewTracking("+gatId+"): tracking pageview failed for: "+virtualPageUrl)+" with error: "+err;
		}
	}
}
/**
 * @name	doGoogleAnalyticsEventTracking
 * @type	ciab function wrapping _trackEvent
 * @purpose	does the actual call to google analytics
 * @param	a google analytics track id
 * @param	a event name to be tracked as a pageview
 * @note	-
 * @returns TRUE OR FALSE ON SUCCESS AT GOOGLE
 */
function doGoogleAnalyticsEventTracking(gatId, category, action, label, value) {
	try {
		// get the ciab tracker (object)
		var _pageTracker = _gat._getTracker(gatId);
		_pageTracker._initData();
		// and track the (virtual) url
		if (_pageTracker._trackEvent(category, action, label)) {
			// print message to the firebug console (if present)
			if (typeof console != "undefined") {
				console.log("doGoogleAnalyticsEventTracking("+gatId+"): event tracked :: action: "+action+" label: "+label+" value: "+value);
			}
		} else {
			if (typeof console != "undefined") {
				console.log("doGoogleAnalyticsEventTracking("+gatId+"): tracking event failed at GA for action: "+action);
			}
		}
	} catch(err) {
		if (typeof console != "undefined") {
			console.log("doGoogleAnalyticsEventTracking("+gatId+"): tracking event failed for action: "+action)+" with error: "+err;
		}
	}
}
/**
 * @name	doCiabAnalyticsPageviewTracking
 * @type	ciab custom analytics helper
 * @purpose	track to ciab private analytics
 * @param	-
 * @returns	-
 */
//]]>
function doCiabAnalyticsPageviewTracking(virtualPageUrl)
{
	// track with CiaB's own  tracker
	doGoogleAnalyticsPageviewTracking(CIAB_GAT, virtualPageUrl);
}
/**
 * @name	doCustomerAnalyticsPageviewTracking
 * @type	ciab custom analytics helper
 * @purpose	track to customer analytics
 * @param	-
 * @returns	-
 */
//]]>
function doCustomerAnalyticsPageviewTracking(virtualPageUrl)
{
	// track with customers tracker if present
	if (CUST_GAT)
	{
		doGoogleAnalyticsPageviewTracking(CUST_GAT, CUST_GAT_PREFIX+virtualPageUrl);
	}
}
/**
 * @name	doCiabAnalyticsEventTracking
 * @type	ciab custom analytics helper
 * @purpose	track to ciab private analytics
 * @param	-
 * @returns	-
 */
//]]>
function doCiabAnalyticsEventTracking(category, action, label, value)
{
	// track with CiaB's own tracker
	doGoogleAnalyticsEventTracking(CIAB_GAT, category, action, label, value);
}
/**
 * @name	doCustomerAnalyticsEventTracking
 * @type	ciab custom analytics helper
 * @purpose	track to customer analytics
 * @param	-
 * @returns	-
 */
//]]>
function doCustomerAnalyticsEventTracking(category, action, label, value)
{
	// track with customers tracker if present
	if (CUST_GAT)
	{
		doGoogleAnalyticsEventTracking(CUST_GAT, CUST_GAT_PREFIX+_category, action, label, value);
	}
}
/**
 * @name	trackChannelImpression
 * @type	ciab custom analytics helper
 * @purpose	track a channel impression as a virtual pageview
 * @param	-
 * @returns	-
 */
function trackChannelImpression () {
	// use value from global channel meta array
	var _channel = CHANNEL_META["channel"];
	// channel might not be set
	if (_channel) {
		// build a virtual url to track
		var _virtualPageUrl = GAT_CHANNEL_PREFIX+"/"+_channel;
		// track with CiaB's own  tracker
		doCiabAnalyticsPageviewTracking(_virtualPageUrl);
		// track with customers tracker
		doCustomerAnalyticsPageviewTracking(_virtualPageUrl);
	}
}
/**
 * @name	trackProgramImpression
 * @type	ciab custom analytics helper
 * @purpose	track a program impression as a virtual pageview
 * @param	-
 * @returns	-
 */
function trackProgramImpression () {
	// use value from global channel meta array
	var _program = CHANNEL_META["program"];
	// program shall be set
	if (_program) {
		// build a virtual url to track
		var _virtualPageUrl = GAT_PROGRAM_PREFIX+"/"+_program;
		// track with CiaB's own  tracker
		doCiabAnalyticsPageviewTracking(_virtualPageUrl);
		// track with customers tracker
		doCustomerAnalyticsPageviewTracking(_virtualPageUrl);
	}
}
/**
 * @name	trackClipView
 * @type	ciab custom analytics helper
 * @purpose	track a clip impression as a virtual pageview
 * @param	index number of clip viewed
 * @note	-
 * @returns-
 */
function trackClipView(index) {
	// get values from global playlist meta array
	var _clip = PLAYLIST_META[index]["clip"];
	var _link = PLAYLIST_META[index]["link"];
	var _artist = PLAYLIST_META[index]["artist"];
	var _titel = PLAYLIST_META[index]["titel"];
	// build a virtual url to track
	var _virtualPageUrl = GAT_CLIP_PREFIX+"/"+_artist+"/"+_titel+"/"+_clip;
	// track with CiaB's own  tracker
	doCiabAnalyticsPageviewTracking(_virtualPageUrl);
	// track with customers tracker
	doCustomerAnalyticsPageviewTracking(_virtualPageUrl);
}
/**
 * @name	trackClipClick
 * @type	ciab custom analytics helper
 * @purpose	track a clip click as a virtual pageview
 * @param	index number of clip viewed
 * @note	-
 * @returns-
 */
function trackClipClick(index) {
	// get values from global playlist meta array
	var _clip = PLAYLIST_META[index]["clip"];
	var _link = PLAYLIST_META[index]["link"];
	var _artist = PLAYLIST_META[index]["artist"];
	var _titel = PLAYLIST_META[index]["titel"];
	// build a virtual url to track
	var _virtualPageUrl = GAT_CLICK_PREFIX+"/"+_artist+"/"+_titel+"/"+_clip+"/"+_link;
	// track with CiaB's own  tracker
	doCiabAnalyticsPageviewTracking(_virtualPageUrl);
	// track with customers tracker
	doCustomerAnalyticsPageviewTracking(_virtualPageUrl);
}
/**
 * @name	trackClipPause
 * @type	ciab custom analytics helper
 * @purpose	track a clip pause click as an event
 * @param	index number of clip viewed
 * @note	-
 * @returns-
 */
function trackClipPause(index) {
	// get values from global playlist meta array
	var _clip = PLAYLIST_META[index]["clip"];
	var _artist = PLAYLIST_META[index]["artist"];
	var _titel = PLAYLIST_META[index]["titel"];
	// track as event
	var _category = 'Clips';
	var _action = 'Pause';
	var _label = "/"+_artist+"/"+_titel+"/"+_clip;
	var _value = parseInt(FP.getTime());
	// track with CiaB's own  tracker
	doCiabAnalyticsEventTracking(_category, _action, _label, _value);
	// track with customers tracker
	doCustomerAnalyticsEventTracking(_category, _action, _label, _value);
}
/**
 * @name	openLink
 * @type	ciab custom
 * @purpose	opens clips link url in new a window and track it
 * @param	-
 * @note	this function name is referenced in the fp configuration
 * @returns	-
 */
function openLink(index) {
	// open link url in new window
	if (PLAYLIST_META[index]["link"])
	{
		var _link = PLAYLIST_META[index]["link"];
		window.open(_link);
		// track that one
		trackClipClick(index);
		// message in a bottle
		if (typeof console != "undefined") {
			console.log("openLink("+index+"): opened window with url: "+_link);
		}
	}
}
/**
 * @name	callBoxFunc
 * @type	ciab custom
 * @purpose	call a ciab function in a sibling iframe (aka box) or in same box
 * @param	frame name (same as tag parameter)
 * @param	function name in sibling box
 * @param	function arguments
 * @note	this is the workhorse of iframe'd box communication
 * @returns	-
 */
function callBoxFunc(frameName, functName, functArgs)
{
  if (typeof console != "undefined") {
    console.log("callBoxFunc(): Calling: "  + functName + "(" + functArgs + ")");
  }
  var _returns; // holds remote procedure return values
	if (window.parent.frames.length > 1) {
		if (typeof(window.parent.frames[frameName]) != "undefined")
		{
      if (typeof console != "undefined") {
        console.log("callBoxFunc(): Trying remote call: "  + functName + "(" + functArgs + ")");
      }
      try {
				_returns = eval('window.parent.frames["' +frameName + '"].' + functName + '(' + functArgs + ')');
				return _returns;
			}
			catch (err) {
				if (typeof console != "undefined") {
					console.error("callBoxFunc(): Remote box call failed: " + frameName + "," + functName + "," + functArgs + err);
				}
			}
      return;
    }
  }
  /* if we have no frames at all or just all in one */
  if (typeof console != "undefined") {
    console.log("callBoxFunc(): Trying local call: "  + functName + "(" + functArgs + ")");
  }
  try {
    _returns = eval(functName + '(' + functArgs + ')');
    return _returns;
  }
  catch (err) {
    if (typeof console != "undefined") {
      console.error("callBoxFunc(): Local call failed: " + frameName + "," + functName + "," + functArgs + err);
    }
    return false;
  }
}
/**
 * showTrackAnnotation
 */
function showTrackAnnotation(index)
{
	callBoxFunc('ciabTrackAnnotationBox','onShowTrackAnnotation',index);
}
/**
 * onShowTrackAnnotation
 */
function onShowTrackAnnotation(index) {
	// hide all elements first
	for (var i=1; i<=TAL.length; i++) {
		TAL[i-1].style.display = "none";
	}
	// but show the one for clip at index
	TAL[index-1].style.display = "block";
}
/**
 * highlightCurrentTrack
 */
function highlightCurrentTrack(index)
{
  if (typeof console != "undefined") {
    console.log("highlightCurrentTrack(): higlighting track list item number: "+index);
  }
  callBoxFunc('ciabTrackListBox','onHighlightCurrentTrack',index);
}
/**
 * onHighlightCurrentTrack
 * highlight the curent clip in the list by changing it's class name
 * this is the hook for the remote box call from the video box
 */
function onHighlightCurrentTrack(index)
{
  if (typeof console != "undefined") {
    console.log("onHighlightCurrentTrack(): higlighting track list item number: "+index);
  }
  // remove css class for all elements first
  for (var i=1; i<=TL.length; i++) {
    TL[i-1].className = TL[i-1].className.replace(/\bplaying\b/,'');
  }
  // but add css clas at index
  TL[index-1].className += " playing";
}
/**
 * @name	onLoadBegin
 * @type	flowplayer callback
 * @purpose	do stuff when a clip has started to load
 * @param	flowplayers clip object
 * @returns	true or false (takes event from queue)
 */
function onLoadBegin(clip)
{
	var _index;
	_index = getCurrentClipIndex();
	if (typeof console != "undefined") {
		console.log("onLoadBegin(): loading clip number: "+_index);
	}
	// switch to current tracks subtitel
//	unshowAllTrackSubtitels();
	showTrackSubtitel(_index);
  // highlight current track in playlist box
  highlightCurrentTrack(_index);
	// display track annotation infos in annotation box
	showTrackAnnotation(_index);
	// compute and insert cuepoints for onPercent Events
//	addVastPercentageCuePoints(_index);
  if (typeof console != "undefined") {
    console.log("onLoadBegin(): clip loaded");
  }
}
/**
 * @name	onStartBuffering
 * @type	flowplayer callback
 * @purpose	do stuff when clips starts buffering
 * @param	flowplayers clip object
 * @returns	true or false (takes event from queue)
 */
function onStartBuffering(clip)
{
	if (typeof console != "undefined") {
		console.log("onStartBuffering(): started buffering");
	}
}
/**
 * @name	onBufferFull
 * @type	flowplayer callback
 * @purpose	do stuff when clips buffer full (ie. can start playing)
 * @param	flowplayers clip object
 * @returns	true or false (takes event from queue)
 */
function onBufferFull(clip)
{
	if (typeof console != "undefined") {
		console.log("onBufferFull(): buffer full");
	}
}
/**
 * @name	onPlay
 * @type	flowplayer callback
 * @purpose	do stuff when a clip has started playing
 * @param	flowplayers clip object
 * @returns	true or false (takes event from queue)
 * NOTE:
 * seems to be called exactly one time per clip. even
 * if clip is played again, this is _not_ called again
 */
function onPlay(clip)
{
	var _index;
	_index = getCurrentClipIndex();
	if (typeof console != "undefined") {
		console.log("onPlay(): playing clip number: "+_index);
	}
	// track that
	trackClipView(_index);
	// reset quartile report done flags
	percent25done = false;
	percent50done = false;
	percent75done = false;
}
/**
 * @name	onPause
 * @type	flowplayer callback
 * @purpose	do stuff when player is set to pause mode
 * @param	-
 * @returns	-
 */
function onPause()
{
	var _index;
	_index = getCurrentClipIndex();
	// track as event
	trackClipPause(_index);
	// log to console if present
	if (typeof console != "undefined") {
		console.log("onPause(): Player switched to Pause state");
	}
}
/**
 * @name	onFullScreen
 * @type	flowplayer callback
 * @purpose	do stuff when player is switsched to fullscreen
 * @param	-
 * @returns	-
 * NOTES	callback _not_available_ in flowplayer v2
 */
function onFullScreen()
{
	var _index;
	_index = getCurrentClipIndex();
	// track as event
//	trackClipFullscreen(_index);
	// log to console if present
	if (typeof console != "undefined") {
		console.log("onFullScreen(): Player switched to Fullscreen state");
	}
}
/**
 * @name	onClipChanged
 * @type	flowplayer callback
 * @purpose	do stuff when user or playlist has moved to another clip
 * @param	flowplayers clip object
 * @returns	true or false (takes event from queue)
 * @WARNING	event is not fired for the first clip if autoPlay is true
 *			i.e.: clip 0 is not loaded for autoPlay=true
 */
function onClipChanged(clip)
{
	if (typeof console != "undefined") {
		console.log("onClipChanged(): clip changed");
	}
	PERCENTAGE_CUEPOINTS_SET = false;
}
/**
 * @name	onClipDone
 * @type	flowplayer callback
 * @purpose	do stuff when clip has played to the end
 * @param	flowplayers clip object
 * @returns	true or false (takes event from queue)
 */
function onClipDone(clip)
{
	if (typeof console != "undefined") {
		console.log("onClipDone(): clip 100% done");
	}
	// get values from global playlist meta array
	var _index;
	_index = getCurrentClipIndex();
	var _clip = PLAYLIST_META[_index]["clip"];
	var _artist = PLAYLIST_META[_index]["artist"];
	var _titel = PLAYLIST_META[_index]["titel"];
	// track as event
	var _category = 'Clips';
	var _action = 'Complete'; // VAST compliant event name
	var _label = "/"+_artist+"/"+_titel+"/"+_clip;
	// track with CiaB's own tracker
	doCiabAnalyticsEventTracking(_category, _action, _label);
	// track with customers tracker
	doCustomerAnalyticsEventTracking(_category, _action, _label);
}
/**
 * @name	addPercentageCuePoints
 * @type
 * @purpose	add cuepoints every 10 seconds
 * @param	-
 * @returns	-
 */
function addPercentageCuePoints()
{
	var _cuepointtime = 0;
	var _MAX = 1000;
	while (_cuepointtime < _MAX) {
		_cuepointtime += 10;
		FP.addCuePoint(_cuepointtime,"percentage");
	}
	if (typeof console != "undefined") {
		console.log("addPercentageCuePoints(): added cuepoints until: " + _cuepointtime + " seconds");
	}
}
/**
 * @name	addVastPercentageCuePoints
 * @type
 * @purpose	add cuepoints individualy computed per clip
 * @param	clip index (just for the debugging message)
 * @returns	-
 * @NOTE	this would require either per clip cuepoint handling by
 * 			flowplayer or a actionscript callback removeCuePoint by name
 */
var PERCENTAGE_CUEPOINTS_SET = false;
function addVastPercentageCuePoints(index)
{
	// get clips total duration and compute cuepoints seconds
	var _duration = parseInt(FP.getDuration());
	if (_duration > 0 && PERCENTAGE_CUEPOINTS_SET == false) {
		var _secsAt25 = parseInt(_duration / 100 * 25);
		var _secsAt50 = parseInt(_duration / 100 * 50);
		var _secsAt75 = parseInt(_duration / 100 * 75);
		FP.addCuePoint(_secsAt25,"Done25"); // VAST:firstQuartile
		FP.addCuePoint(_secsAt50,"Done50"); // VAST:midpoint
		FP.addCuePoint(_secsAt75,"Done75"); // VAST:thirdQuartile
		if (typeof console != "undefined") {
			console.log("addVastPercentageCuePoints(): duration of clip #" + index + " total: " + _duration);
			console.log("addVastPercentageCuePoints(): added cuepoint 25% at: " + _secsAt25 + "s");
			console.log("addVastPercentageCuePoints(): added cuepoint 50% at: " + _secsAt50 + "s");
			console.log("addVastPercentageCuePoints(): added cuepoint 75% at: " + _secsAt75 + "s");
		}
		PERCENTAGE_CUEPOINTS_SET = true;
	}
}
/**
 * @name	onCuePoint
 * @type	flowplayer callback
 * @purpose	do stuff when clip has reached cuepoint
 * @param	flowplayers clip object
 * @returns	true or false (takes event from queue)
 */
var percent25done = false;
var percent50done = false;
var percent75done = false;
function onCuePoint(cuePoint)
{
	// get values from global playlist meta array
	var _index;
	_index = getCurrentClipIndex();
	var _clip = PLAYLIST_META[_index]["clip"];
	var _artist = PLAYLIST_META[_index]["artist"];
	var _titel = PLAYLIST_META[_index]["titel"];

	// track as event
	var _category = 'Clips';
	var _label = "/"+_artist+"/"+_titel+"/"+_clip;

	var _total = parseInt(FP.getDuration());
	var _elapsed = parseInt(FP.getTime());
	var _value = _elapsed;

	var _cptime = cuePoint.time;
	var _percent = parseInt(100 * _cptime / _total);

	if (typeof console != "undefined") {
		console.log("onCuePoint(): clip elapsed seconds: " + _elapsed + " of total: " + _total + " percent: " + _percent + "%");
	}

	if (cuePoint.name == "percentage") {
		if (_percent >= 25 && _percent < 50 && !percent25done) {
			// track with CiaB's own tracker
			doCiabAnalyticsEventTracking(_category, "Done25", _label, _value);
			// track with customers tracker
			doCustomerAnalyticsEventTracking(_category, "Done25", _label, _value);
			// remember that
			percent25done = true;
		// do not count if prior quartile has not been reached
		} else if (_percent >= 50 && _percent < 75 && !percent50done && percent25done ) {
			// track with CiaB's own tracker
			doCiabAnalyticsEventTracking(_category, "Done50", _label, _value);
			// track with customers tracker
			doCustomerAnalyticsEventTracking(_category, "Done50", _label, _value);
			// remember that
			percent50done = true;
		// do not count if prior quartiles have not been reached
		} else if (_percent >= 75 && _percent < 100 && !percent75done && percent50done && percent25done ) {
			// track with CiaB's own tracker
			doCiabAnalyticsEventTracking(_category, "Done75", _label, _value);
			// track with customers tracker
			doCustomerAnalyticsEventTracking(_category, "Done75", _label, _value);
			// remember that
			percent75done = true;
		}
	}
}
/**
 * @name	writeVideoPlayerLoadingMessage
 * @purpose	replaces the content of the videoplayer box through javascript
 * @param	-
 * @returns	-
 * @note	this will _not_ happen if JS is disabled. so if JS is disabled
 *			all text that displays is the noscript warning
 * @TODO	add parameter container name (makes the reference more transparent)
 * @TODO	add parameter language (de,en)
 */
function writeVideoPlayerLoadingMessage()
{
	try {
		var _here = document.getElementById("ciabFlowplayerContainer");
		_here.innerHTML = "<div id=\"loadingMessage\">Channel-in-a-Box Videoplayer l&auml;dt ...<br /><br /><br /><br /><br /><br /></div>";
	} catch (e) {
	}
}
/**
 * @name	onWindowLoad
 * @purpose	do stuff when document have been loaded completly
 * @param	-
 * @returns	-
 * @note	FOR SOME REASON THE FE POINTER IS NOT VALID
 *          IF WE FIRE FLOWPLAYER SETUP ON A TIMEOUT !?!?
 */
window.onload =
function onWindowLoad() {
	if (typeof console != "undefined") {
		console.log("window.onload(): box=" + BOX_NAME);
	}

  if (BOX_NAME == "ciabVideoPlayerBox" || BOX_NAME == "ciabAllinOneBox") {
		/*
		 * setup and config the flowplayer with dynamic config
		 */
		FE = setupFlowPlayerShockwaveObject("ciabFlowplayerContainer", FP_CONFIG);
		/*
		 * init the global SubTitelList pointer by id and tag name
		 */
		try {
			TSL = document.getElementById("ciabTrackSubtitelList").getElementsByTagName("div");
			if (typeof console != "undefined") {
				console.log("onWindowLoad(): found subtitel elements: "+TSL.length);
			}
		} catch (e) {
			if (typeof console != "undefined") {
				console.error("onWindowLoad(): ERROR: subtitel container element not found");
			}
		}
    if (TSL.length > 0)
    {
      showTrackSubtitel(1);
    }
		/*
		 * track as channel if we have a channel (id)
		 */
		if (CHANNEL_META["channel"]) {
			trackChannelImpression();
		}
		/*
		 * track as program as we have a program (id) always
		 */
		trackProgramImpression();
	}

  if (BOX_NAME == "ciabTrackListBox" || BOX_NAME == "ciabAllinOneBox") {
    try {
      TL = document.getElementById("ciabTrackList").getElementsByTagName("li");
      if (typeof console != "undefined") {
        console.log("onWindowLoad(): found tracklist elements: "+TL.length);
      }
    } catch (e) {
      if (typeof console != "undefined") {
        console.error("onWindowLoad(): ERROR: tracklist container element not found");
      }
    }
  }

  if (BOX_NAME == "ciabTrackAnnotationBox" || BOX_NAME == "ciabAllinOneBox") {
		try {
			TAL = document.getElementById("ciabTrackAnnotationList").getElementsByTagName("div");
			if (typeof console != "undefined") {
				console.log("onWindowLoad(): found annotation elements: "+TAL.length);
			}
			if (TAL.length > 0)
			{
				/* this is an optional implementation - very rarely usefull */
				var current_clip_index = callBoxFunc('ciabVideoPlayerBox','getCurrentClipIndex');
				if (current_clip_index >= 1) {
					onShowTrackAnnotation(current_clip_index);
				} else {
					onShowTrackAnnotation(1);
				}
			}
		} catch (e) {
			if (typeof console != "undefined") {
				console.error("onWindowLoad(): ERROR: no annotation elements found");
			}
		}
  }
}
  /**
 * @name	onFlowPlayerReady
 * @type	flowplayer callback
 * @purpose	do stuff when player is ready with setup
 * @param	-
 * @note	DON'T USE FLOWPLAYER API BEFORE THIS EVENT
 * @note	FOR SOME REASON THE FE POINTER IS NOT VALID
 *          IF WE FIRED FLOWPLAYER SETUP ON A TIMEOUT.
 *          ALTHOUGH THIS IS OBVIOUSLY AFTER LOADING THE
 *          WINDOW.
 * @returns	-
 */
function onFlowPlayerReady()
{
//	alert(document.location + "\n" + "onFlowPlayerReady()");
	var _flashVersion;
	_flashVersion = FE.getVersion();
	if (typeof console != "undefined") {
		console.log("onFlowPlayerReady(): Running Flash Version: "+_flashVersion);
	}
	// get the real flowplayer object and so it's API
	FP = FE.getApi();
	// insert cuepoints for onPercent Events
	addPercentageCuePoints();
}

