/**

 * Copyright (C) 2005 Brightcove, Inc.  All Rights Reserved.  No

 * use, copying or distribution of this work may be made except in

 * accordance with a valid license agreement from Brightcove, Inc.

 * This notice must be included on all copies, modifications and

 * derivatives of this work.

 *

 * Brightcove, Inc MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT

 * THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED,

 * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF

 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR

 * NON-INFRINGEMENT. BRIGHTCOVE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED

 * BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS

 * SOFTWARE OR ITS DERIVATIVES.

 *

 * "Brightcove" is a trademark of Brightcove, Inc.

 **/



/*********************************************** CONFIGURATION ************************************************/



/**

 * This is the API Token assigned to each Brightcove customer that allows for the use of Brightcove's Media Read API.

 * Fill in your read API token (there are two versions, but you want the one that includes URL responses) here.

 */

var BCReadAPIToken = "UQWEKNt3Cn5YpiZlH2SZNZqnc2iECevS4Y2rLKgXJfG19ydGiPc1YQ..";



/**

 * This value indicates whether or not your account is set-up for UDS. HTML5 requires that the files be delivered

 * over HTTP.  This is accomplished by having an account that is configured for HTTP (PD) delivery or that is set-up

 * for UDS. 

 */

var isUDS = true;



/* This variable is a dictionary that contains information about the location of each

 * Brightcove video object within the DOM of the page. Specifically, it is an associative array

 * where, for each stored mapping, the keys is the playerID of a given video, and the value is

 * the next sibling of that video object in the DOM. Keeping track of this sibling will allow

 * us to re-insert the mobile compatible <video> tag into the correct place (before this sibling)

 * in the DOM of the original page.

 */

var pagePlacementInfo = new Object();



/**********************************************************************************************************************/

/*********************************************** DOM MODIFICATION CODE ************************************************/

/**********************************************************************************************************************/



/* This is the main entry function. It goes through the list of all video objects that need to be removed,

 * and one by one, initiates a request that causes that object to be removed and replaced by the

 * appropriate <video> tag (if the JS detects that the browser is on a smartphone).

 */

function runMobileCompatibilityScript(bcExperienceID, videoTagID){

	//detect if this is a smartphone or not

	var thisIsSmartPhone = DetectSmartphone();

		

	if (!thisIsSmartPhone) {

	    return;

	}



	

	makeMobileCompatible(bcExperienceID, videoTagID);

}



/* This method works on a specific object, represented by id "strObjID". The method retrieves the

 * element with the given ID from the DOM, and then extracts the player ID from the video

 * object. Then, it removes the video object from the page's DOM and stores its location in the page

 * in a global dictionary variable (this will be useful when we want to add the corresponding

 * video tag back in the page in the appropriate place).

 *

 * Finally, the method submits an API Read request to the Brightcove server through the initiateMobileVideoRetrieval()

 * method in order to retrieve the sepcific Video URL corresponding to the given object.

 */

function makeMobileCompatible(strObjID, videoTagID){

	//our video object (which we need to remove)

	var vidObj = document.getElementById(strObjID);

	

	//extract the playerID of this video object before deleting it

	var vidPlayerID = getParamValueForVidObject(vidObj, 'playerID');

	var programmedVideo = getParamValueForVidObject(vidObj, '@videoPlayer');



	//if the video player ID could not be extracted from the Source Code, for some reason,

	//then refer to the dictionary provided by the user

	if (vidPlayerID == null || typeof vidPlayerID == 'undefined'){

			vidPlayerID = BCVidObjects[strObjID];

	}



	//store the parent of the node we wish to remove

	var parentObj = vidObj.parentNode;

	

	//this is the object before which our vidObj element occurs in the parent element's DOM.

	//likewise, when we insert our <video> tag, we will insert it BEFORE this element,

	//in order to maintain the look of the page (this is the best that we can do...)

	var nextAdjacentNode = vidObj.nextSibling;

	

	//if there are no nodes after this node that was removed, then store 'null' to indicate that this was the last

	//child.

	if (nextAdjacentNode == null){

		pagePlacementInfo[""+strObjID] = null;

	}

	//otherwise store the next sibling

	else {

		pagePlacementInfo[""+strObjID] = nextAdjacentNode;	

	}

	

	//now, dynamically remove the video object from the DOM

	parentObj.removeChild(vidObj);



	//this procedure will make the appropriate API calls to get the first video corresponding to the player ID 

	//of the object we just removed.

	

	initiateMobileVideoRetrieval(vidPlayerID, programmedVideo, BCReadAPIToken, videoTagID, strObjID);

}





/** 

 * This function takes an object representing a Brigthcove video embed and a particular 'parameter' that was

 * passed to the Brightcove video object and returns the parameter.

 */

function getParamValueForVidObject(vidObj, paramName) {

	//these are the children nodes of the given object in the DOM

	var childrenNodes = vidObj.childNodes;

	var tagName;

	

	//loop through all children of the video object, searching for <param> tags.

	//each time we find a <param> tag, we check whether its name is 'flashVars'.

	//if so, we store the param's value and break from the loop, otherwise we

	//continue

	for (var i = 0; i < childrenNodes.length; i++){

	    if (childrenNodes[i].nodeType != 1) {

		continue;

	    }



	    tagName = childrenNodes[i].tagName.toLowerCase();

	    if (tagName == "param"){

		if (childrenNodes[i].getAttribute("name") == paramName){

		    return childrenNodes[i].getAttribute("value");

		}

	    }

	}



	return null;

}



/**

 * Takes a string 'str' that consists of multiple arguments separated by ampersands (&),

 * and breaks it down so that it can extract and return the paramName from the string.

 */

function parseParamFromString(str, paramName) {

	var params = str.split("&"); //array of strings

	for (var i = 0; i < params.length; i++){

		if (params[i].indexOf(paramName) != -1){

			return params[i].substr(params[i].indexOf("=")+1);

		}

	}

	

	// if we could not find the param then return null

	return null;

}







/**********************************************************************************************************************/

/****************************************** MEDIA API CALLS & VIDEO TAG INSERTION *************************************/

/**********************************************************************************************************************/



/* This method calls the Brightcove Media API to get all playlists included within a particular

 * playerID.

 */

function initiateMobileVideoRetrieval(playerID, programmedVideoID, readAPIToken, videoTagID, strObjID) {

    var APICall;

    var scriptNode;

    var scriptText;

    var callbackMethodName;



    if (programmedVideoID) {

	if (programmedVideoID.indexOf('ref:') != -1) {

	    APICall = "http://api.brightcove.com/services/library?command=find_video_by_reference_id&reference_id="+programmedVideoID.substring(4)+"&token="

		+readAPIToken;

	}

	else {

	    APICall = "http://api.brightcove.com/services/library?command=find_video_by_id&video_id="+programmedVideoID+"&token="

		+readAPIToken;

	}



	//when we make the API call, we specify a response handler (known as a callback method) that will deal with the response from

	//the Brightcove server. However, we create a customized 'callback' method for each playerID, so that when we are 'inside' the

	//callback method (after receiving the server's reponse), we will know which playerID the response corresponds to. This variable

	//stores the name (which includes the playerID) of that callback method.

	callbackMethodName = "handleJSONResponseForID"+new Date().getTime();

	scriptNode = document.createElement("script");

	scriptNode.setAttribute("language", "javascript");

	scriptText = 

		"function "+callbackMethodName+"(JSONResponse){\n" + 

			"\thandleVideoResponse(JSONResponse, '"+playerID+"', '"+videoTagID+"', '"+strObjID+"');\n"+

		"}\n";

    }

    else {

	APICall = "http://api.brightcove.com/services/library?command=find_playlists_for_player_id&player_id="+playerID+"&token="

								+readAPIToken;

	callbackMethodName = "handleJSONResponseForID"+ new Date().getTime();

	scriptNode = document.createElement("script");

	scriptNode.setAttribute("language", "javascript");

	scriptText = 

		"function "+callbackMethodName+"(JSONResponse){\n" + 

			"\thandlePlaylistResponse(JSONResponse, '"+playerID+"', '"+videoTagID+"', '"+strObjID+"');\n"+

		"}\n";

    }



    if (isUDS) {

	APICall += "&media_delivery=http";

    }



	//NOTE: we add to the end of the body, so that we do not disrupt any of the order of the children

	//at the top of the body's DOM tree

	var scriptTextNode = document.createTextNode(scriptText);

	scriptNode.appendChild(scriptTextNode);

	document.body.appendChild(scriptNode);

	

	//make the API call, specifying the unique callback method for this request

	addScriptTag("getMobileRendition",  APICall, callbackMethodName);

}



/* Methods needed to make API Calls to the Brightcove server*/

function addScriptTag(id, url, callback) {

	var scriptTag = document.createElement("script");

	var noCacheIE = '&noCacheIE=' + (new Date()).getTime();

   

   // Add script object attributes

   scriptTag.setAttribute("type", "text/javascript");

   scriptTag.setAttribute("charset", "utf-8");

   scriptTag.setAttribute("src", url + "&callback=" + callback + noCacheIE);

   scriptTag.setAttribute("id", id);

	

	var head = document.getElementsByTagName("head").item(0);	

	head.appendChild(scriptTag);

}



/**

 * This is the general response-handler for the JSON response from the Brightcove server for playlist based players.

 * The arguments to the method include the response object, as well as the playerID of the 

 * object which this response pertains to.

 *

 */

function handlePlaylistResponse(JSONResponse, playerID, videoTagID, strObjID) {

	//obtain first playlist in Brightcove Player given corresponding to this playerID

	var firstPlaylist = JSONResponse.items[0];

	

	//obtain the first video from our first playlist

	var firstVideo = firstPlaylist.videos[0];



	embedHTML5PlayerForVideo(firstVideo, playerID, videoTagID, strObjID);

}



/**

 * This is the general response-handler for the JSON response from the Brightcove server for playlist based players.

 * The arguments to the method include the response object, as well as the playerID of the 

 * object which this response pertains to.

 *

 */

function handleVideoResponse(JSONResponse, playerID, videoTagID, strObjID) {

    embedHTML5PlayerForVideo(JSONResponse, playerID, videoTagID, strObjID);

}



/** 

 * For a given video object (from the BC APIs) we will embed an HTML 5 'video' tag.

 * Requires searching through the renditions associated with the video object

 * for a rendition that is a 'best' match and passing the URL to the video

 * tag.

 *

 * In this handler, we explore the JSON object in search of the first video in the

 * first playlist that is returned by the Brightcove server. Then, once we identify

 * this first video, we examine the various renditions of the video and search

 * for the rendition that is most appropriate for a mobile (H.264 encoding 

 * and 256 kbps). 

 */

function embedHTML5PlayerForVideo(video, playerID, videoTagID, strObjID) {

	//obtain the array of various renditions that exist for this video.

	//NOTE: a rendition, from our perspective, has a certain encoding rate,

	//      and a certain encoding format. We wish to find the best rendition for

	//      a smartphone.

	var renditions = video.renditions;

	

	//In the for-loop that follows, we traverse all renditions of this first video, searching

	//for the H.264 (mobile-compatible) rendition whose encoding rate is closest to 256kbps

	var bestRenditionIndex = -1;

	var bestEncodingRateSoFar = -1;

	

	for (var i = 0; i < renditions.length; i = i+1){

		//if this rendition is not H264, skip it and move on to the next

		if (renditions[i].videoCodec != "H264"){

			continue;

		}

		

		//if best rendition index variable is uninitialized, then initialize it to

		//this rendition (which is H.264) - we need this because it's possible that

		//there are no H264 renditions at all, and starting our bestRenditionIndex at

		//an invalid value will help us figure out whether we came across any H264 renditions

		//as we were looping.

		if (bestRenditionIndex == -1){

			bestRenditionIndex = i;

			bestEncodingRateSoFar = renditions[i].encodingRate;

		}

		

		//otherwise check to see if this rendition has a better encoding rate than the best one before this

		else if (betterEncodingForMobile(renditions[i].encodingRate, bestEncodingRateSoFar) == renditions[i].encodingRate){

			//if so, then record this rendition as the best one so far

			bestRenditionIndex = i;

			bestEncodingRateSoFar = renditions[i].encodingRate;

		}

	}

	

	//after the for-loop has terminated, if best rendition index still == -1,

	//then that means we don't have ANY H264 renditions. so let the user know,

	//and don't add anything to the page

	if (bestRenditionIndex == -1){

	    bestRendition = video.videoFullLength;

	}

	else {

		bestRendition = renditions[bestRenditionIndex];

	}





	var bestRenditionURL = bestRendition.url;

	

	var vidName = video.name;

	var vidHeight = bestRendition.frameHeight;

	var vidWidth = bestRendition.frameWidth;

	var vidStillURL = video.videoStillURL;

		

	//construct the <video> tag as a DOM element

	var videoScriptTag = formVideoTagFromInfo(videoTagID, vidName, bestRenditionURL, vidWidth, vidHeight, vidStillURL);

	

	//retrieve the component before which this video tag needs to be inserted

	var nextSiblingOfVideo = pagePlacementInfo[strObjID];

	var videoTagParent = nextSiblingOfVideo.parentNode; //the sibling and this video share the same parent node!

		

	//if 'nextSibling' value is null, then we want to add our video as the last child of the parent,

	//so we use the append() method; if 'nextSibling' is defined, then we use insertBefore() to add our video tag

	//into the appropriate location in our page.

	if (nextSiblingOfVideo == null){

		videoTagParent.appendChild(videoScriptTag);

	}

	else{

		videoTagParent.insertBefore(videoScriptTag, nextSiblingOfVideo);

	}

}



/* This function takes two encoding rates and returns the one that

 * is more apprporiate for mobile phones.

 */

function betterEncodingForMobile(encoding1, encoding2){

	IDEAL_ENCODING_RATE = 256000; //bits per second; equivalent to 256 kbps

	

	diff1 = Math.abs(encoding1 - IDEAL_ENCODING_RATE);

	diff2 = Math.abs(encoding2 - IDEAL_ENCODING_RATE);

	

	return ((diff1 <= diff2) ? encoding1 : encoding2);

}



/**

 * This method takes properties of a video, its dimensions, and its poster (still image),

 * inserts them into an HTML 5.0 <video> tag. This <video> object is then returned.

 */

function formVideoTagFromInfo(videoTagID, videoID, videoURL, vidWidth, vidHeight, vidImageURL){

	var videoTag = document.createElement("video");

	if (videoTagID) {

	    videoTag.setAttribute("id", videoTagID);

	}

	else {

	    videoTag.setAttribute("id", videoID);

	}



	videoTag.setAttribute("poster", vidImageURL);

	videoTag.setAttribute("width",""+vidWidth);

	videoTag.setAttribute("height", ""+vidHeight);

	videoTag.setAttribute("controls", "true");

	videoTag.setAttribute("src", videoURL);

	

	//if this device is an ANDROID device, then add an onclick handler to the

	//video since this does not exist by default.

	var isAndroidPhone = DetectAndroid();



	if (isAndroidPhone){

		addClickHandlerToVid(videoTag);

	}



	return videoTag;

}



/**

 * This method adds an 'onclick' handler to the provided video object so that clicking on the

 * 'poster' image of the video casues the video to play.

 */

function addClickHandlerToVid(obj){

	obj.addEventListener('click', function(videoNode) {

          return function() {

            videoNode.play();

          };

    }(obj));

}



/**********************************************************************************************************************/

/****************************************** MOBILE BROWSER DETECTION CODE *********************************************/

/**********************************************************************************************************************/



// JavaScript Document



// Anthony Hand, ahand@hand-interactive.com

// Web: www.hand-interactive.com

// 

// License info: http://creativecommons.org/licenses/by/3.0/us/



//Initialize some initial string variables we'll look for later.

var deviceIphone = "iphone";

var deviceIPad = "ipad";

var deviceIpod = "ipod";

var devicePlaystation = "playstation";

var deviceWap = "wap";



var deviceWinMob = "windows ce";

var enginePie = "wm5 pie";

var deviceIeMob = "iemobile";



var deviceS60 = "series60";

var deviceSymbian = "symbian";

var deviceS60 = "series60";

var deviceS70 = "series70";

var deviceS80 = "series80";

var deviceS90 = "series90";



var deviceBB = "blackberry";



var deviceAndroid = "android";

var motorollaDroid = " droid ";



var deviceMidp = "midp";

var deviceWml = "wml";

var deviceBrew = "brew";



var devicePalm = "palm";

var engineXiino = "xiino";

var engineBlazer = "blazer"; //Old Palm



var devicePda = "pda";

var deviceNintendoDs = "nitro";



var engineWebKit = "webkit";

var engineNetfront = "netfront";





var manuSonyEricsson = "sonyericsson";

var manuericsson = "ericsson";

var manuSamsung1 = "sec-sgh";



var svcDocomo = "docomo";

var svcKddi = "kddi";

var svcVodafone = "vodafone";



//Due to the flexibility of the S60 OSSO Browser, 

//   you may wish to let new S60 devices get the regular pages instead.

var s60GetsMobile = true;





//Due to the flexibility of the iPhone/iPod Touch Browser, 

//   you may wish to let new S60 devices get the regular pages instead.

var iphoneIpodGetsMobile = true;





//Initialize our user agent string.

var uagent = navigator.userAgent.toLowerCase();





//**************************

// Detects if the current device is an iPhone.

function DetectIphone()

{

   if (uagent.search(deviceIphone) > -1)

   {

      //The iPod touch says it's an iPhone! So let's disambiguate.

      if (uagent.search(deviceIpod) > -1)

         return false;

      else 

         return true;

   }

   else

      return false;

}



//**************************

// Detects if the current device is an iPhone.

function DetectIPad()

{

    if (uagent.search(deviceIPad) > -1) {

	return true;       

   }

    else {

      return false;

    }

}



//**************************

// Detects if the current device is an iPod Touch.

function DetectIpod()

{

   if (uagent.search(deviceIpod) > -1)

      return true;

   else

      return false;

}



//**************************

// Detects if the current device is an iPhone or iPod Touch.

function DetectIphoneOrIpodOrIPad()

{

   //We repeat the searches here because some iPods 

   //  may report themselves as an iPhone, which is ok.

   if (uagent.search(deviceIphone) > -1 ||

       uagent.search(deviceIpod) > -1 ||

       uagent.search(deviceIPad) > -1)



       return true;

    else

       return false;

}



//**************************

// Detects if the current device is an Android OS-based device.

function DetectAndroid()

{

   if (uagent.search(deviceAndroid) > -1)

      return true;

   else

      return false;

}



function DetectMotorollaDroid()

{

	if (uagent.search(motorollaDroid) > -1)

		return true;

	else

		return false;

}



//**************************

// Detects if the current device is an Android OS-based device and

//   the browser is based on WebKit.

function DetectAndroidWebKit()

{

   if (DetectAndroid())

   {

     if (DetectWebkit())

        return true;

     else

        return false;

   }

   else

      return false;

}



//**************************

// Detects if the current browser is based on WebKit.

function DetectWebkit()

{

   if (uagent.search(engineWebKit) > -1)

      return true;

   else

      return false;

}



//**************************

// Detects if the current browser is the Nokia S60 Open Source Browser.

function DetectS60OssBrowser()

{

   if (DetectWebkit())

   {

     if ((uagent.search(deviceS60) > -1 || 

          uagent.search(deviceSymbian) > -1))

        return true;

     else

        return false;

   }

   else

      return false;

}



//**************************

// Detects if the current device is any Symbian OS-based device,

//   including older S60, Series 70, Series 80, Series 90, and UIQ, 

//   or other browsers running on these devices.

function DetectSymbianOS()

{

   if (uagent.search(deviceSymbian) > -1 ||

       uagent.search(deviceS60) > -1 ||

       uagent.search(deviceS70) > -1 ||

       uagent.search(deviceS80) > -1 ||

       uagent.search(deviceS90) > -1)

      return true;

   else

      return false;

}





//**************************

// Detects if the current browser is a BlackBerry of some sort.

function DetectBlackBerry()

{

   if (uagent.search(deviceBB) > -1)

      return true;

   else

      return false;

}



//**************************

// Detects if the current browser is a Windows Mobile device.

function DetectWindowsMobile()

{

   //Most devices use 'Windows CE', but some report 'iemobile' 

   //  and some older ones report as 'PIE' for Pocket IE. 

   if (uagent.search(deviceWinMob) > -1 ||

       uagent.search(deviceIeMob) > -1 ||

       uagent.search(enginePie) > -1)

      return true;

   else

      return false;

}



//**************************

// Detects if the current browser is on a PalmOS device.

function DetectPalmOS()

{

   //Most devices nowadays report as 'Palm', 

   //  but some older ones reported as Blazer or Xiino.

   if (uagent.search(devicePalm) > -1 ||

       uagent.search(engineBlazer) > -1 ||

       uagent.search(engineXiino) > -1)

      return true;

   else

      return false;

}



//**************************

// Sets whether S60 devices running the 

//   Open Source Browser (based on WebKit)

//   should be detected as 'mobile' or not.

//   Set TRUE to be detected as mobile.

//   Set FALSE and it will not be detected as mobile.

function SetS60GetsMobile(setMobile)

{

   s60GetsMobile = setMobile;

};



//**************************

// Sets whether iPhone/iPod Touch devices running the 

//   Open Source Browser (based on WebKit)

//   should be detected as 'mobile' or not.

//   Set TRUE to be detected as mobile.

//   Set FALSE and it will not be detected as mobile.

function SetS60GetsMobile(setMobile)

{

   iphoneIpodGetsMobile = setMobile;

};





//**************************

// Check to see whether the device is a 'smartphone'.

//   You might wish to send smartphones to a more capable web page

//   than a dumbed down WAP page. 

function DetectSmartphone()

{

   //First, look for iPhone and iPod Touch.

   if (DetectIphoneOrIpodOrIPad())

      return true;



   if (DetectAndroid())

      return true;

		

   //Now, look for S60 Open Source Browser on S60 release 3 devices.

   if (DetectS60OssBrowser())

      return true;



   //Check for other Symbian devices - older S60, UIQ, other.

   if (DetectSymbianOS())

      return true;



   //Check for Windows Mobile devices.

   if (DetectWindowsMobile())

      return true;



   //Next, look for a BlackBerry

   if (DetectBlackBerry())

      return true;



   //PalmOS.

   if (DetectPalmOS())

      return true;



   //Otherwise, return false.

   return false;

};





//**************************

// Detects if the current device is a mobile device.

//  This method catches most of the popular modern devices.

function DetectMobileQuick()

{

   //Attempt to detect most mobile devices, 

   //   especially mass market feature phones.

   // NOTE: Doesn't usually work reliably...

   if (uagent.search(deviceWap) > -1   || 

	uagent.search(deviceMidp) > -1 ||

	uagent.search(deviceWml) > -1  ||

	uagent.search(deviceBrew) > -1  )

   {

      return true;

   }



   //Detect for most smartphones.

   if (DetectSmartphone())

      return true;



   //Check for a NetFront browser

   if (uagent.search(engineNetfront) > -1)

      return true;



   //Check for a Playstation

   if (uagent.search(devicePlaystation) > -1)

      return true;



   //Check for a generic PDA

   if (uagent.search(devicePda) > -1)

      return true;



   return false;

};





//**************************

// Detects in a more comprehensive way if the current device is a mobile device.

function DetectMobileLonger()

{

   //Run the quick check first.

   if (DetectMobileQuick())

      return true;



   //Check for NTT Docomo

   if (uagent.search(svcDocomo) > -1)

      return true;



   //Check for KDDI

   if (uagent.search(svcKddi) > -1)

      return true;



   //Check for Nintendo DS

   if (uagent.search(deviceNintendoDs) > -1)

      return true;



   //Check for Vodafone 3G

   if (uagent.search(svcVodafone) > -1)

      return true;



   //Finally, detect for certain very old devices with stupid useragent strings.

   if (uagent.search(manuSamsung1) > -1 ||

	uagent.search(manuSonyEricsson) > -1 || 

	uagent.search(manuericsson) > -1)

   {

      return true;

   }



   return false;

};

