﻿
/**
* StarzVideoPlayer 1.0
* (c) 2011 Starz Entertainment, LLC
* http://www.starz.com
*
* sogden 9-28-11 patch26
*
* DESCRIPTION:  Generates either the flash or html5 Starz video player experience based on playerType ( single | multi | extras | embedded | mm )
*
*                   -> Initially shows an image or slideshow of images along with simple metaData
*                   -> Allows the user to 'watch preview' which launches a video experience
*                   -> Allows the user to view 'more info' which forces the browser to a new url
*
* REQUIRES:     innerXHTML.js
*               prototype.js
*               moo.fx.js
*               swfobject.js
*               swfaddress.js
*
* USAGE:        new StarzVideoPlayer(   
aWidth,                 // String: the width of the video player in px
aHeight,                // String: the height of the video player in px
aPlayerType,			// String: the type of player to use : single | multi | extras
aPlayerData,            // String: the player data xml
aConfigFile,            // String: the path to the configuration file
aPageName,              // String: the name of the internal starz.com page -- used for omniture tracking 

aTargetDivID,           // String: the ID of the <div> element the video player is written into
aTargetFallbackDivID,   // String: the ID of the <div> element which displays if flash/html5 is not available

aForceHTML5,            // Boolean: (optional) used to force the player to only render in html5 mode
aMediaServerURL,		// String: (optional) used to switch the player to an alternate mediaServerURL 
default is rtmp://video.starz.com/ondemand/	
);
*
* RETURNS:  The instance of the new StarzVideoPlayer class 

* NOTES:    This file can be used with basic HTML markup... 
*
* 1) Include the starzVideoPlayer.js file in the <head> element
 
<script type="text/javascript" src="http://www.starz.com/JsLib/starzVideoPlayer.js" ></script>

* 2) Create the necessary placeholders in the <body> element as <div> tags
*    One <div> will hold the actual video element, while the other will hold the 'fallback' image if the browser does not support flash or html5

<div id="VideoPlayer" style="width: 685px; height:385px;"> </div>     
<div id="VideoPlayerFallback" style="display: none; color: #FFF;"> You need Flash! </div>

* 3) Make a new starz video player using javascript!

<script type="text/javascript">
var StarzVideoPlayer1 = new StarzVideoPlayer(
"685", 
"385", 
"... player data ...",
"/VideoConfigLib/Originals_Spartacus.xml",
s.pageName,
"VideoPlayer", 
"VideoPlayerFallback");
</script>

*/

//alert('BEGIN starzVideoPlayer');
//console.log('BEGIN starzVideoPlayer');

//======================
// Stylesheet
//======================

// this line includes the styleSheet needed for the html5 implementation
document.write('<link rel="stylesheet" type="text/css" href="/CssLib/starzVideoPlayer.css" />');

//======================
// StarzVideoPlayer
//======================

StarzVideoPlayer = Class.create({

    width: String, 		// in pixels, the width of the player
    height: String, 		// in pixels, the height of the player

    playerType: String,
    playerData: String, 	// XML
    configFile: String, 	// path to the configuration xml	

    pageName: String, 	// used for omniture tracking

    targetDivID: String,
    targetFallbackDivID: String,

    forceHTML5: Boolean,
    mediaServerURL: String,

    configFileXML: Object, 	// the actual xml that gets loaded for the html5 implementation

    titles: Array,
    slides: Array,
    relatedTitles: Array,
    relatedSlides: Array,

    currentSlide: String,
    currentIndex: Number,
    currentImage: Image,

    titleName: String,
    description: String,
    pageURL: String,
	
	imageLinkUrl:String,
	imageLinkTarget:String,
	
    videoSource: String,

    isShowingVideo: Boolean,
    isAutoCycle: Boolean,

    autoTimerDelay: Number,
    autoTimerID: Number,

    // DEBUG
    logging: Boolean,
    forceNoFlash: Boolean,
    forceIpad: Boolean,


    //======================
    // Constructor
    //======================    

    initialize: function (aWidth,
                            aHeight,
							aPlayerType,
							aPlayerData,
							aConfigFile,
							aPageName,
                            aTargetDivID,
                            aTargetFallbackDivID,
                            aForceHTML5,
                            aMediaServerURL
                            ) {

        //======================
        // Properties
        //======================

        // do null checks -> set up defaults

        if (!aWidth || aWidth == "") { aWidth = "685"; }
        if (!aHeight || aHeight == "") { aHeight = "385"; }

        if (!aPlayerType || aPlayerType == "") { aHeight = "single"; }

        // todo: default starz image!		
        if (!aPlayerData || aPlayerData == "") { aPlayerData = "<fubar>noData</fubar>"; }

        if (!aConfigFile) { aConfigFile = ""; }
        if (!aPageName) { aPageName = ""; }

        // todo: manually inject a targetDiv/fallbackDiv if not supplied?
        if (!aTargetDivID || aTargetDivID == "") {
            //aTargetDivID = document.createElement('div');
            //$(aTargetDivID).innerHTML = '<div id="svp_TargetDivID" style="width: 685px; height:385px;"> </div>';
        }
        if (!aTargetFallbackDivID || aTargetFallbackDivID == "") {
            //aTargetFallbackDivID = document.createElement('div');
            //$(aTargetFallbackDivID).innerHTML = '<div id="svp_TargetFallbackDivID" style="display: none; color: #FFF;"><a href="http://www.adobe.com/go/getflashplayer" target="_blank"><img src="/siteImagesLib/-image-980.jpg" alt="Update Flash Player image"/></a></div>';
        }

        if (!aForceHTML5) { aForceHTML5 = false; }
        if (!aMediaServerURL || aMediaServerURL == "") { aMediaServerURL = "rtmp://video.starz.com/ondemand/"; }

        this.width = aWidth;
        this.height = aHeight;
        this.playerType = aPlayerType;
        this.playerData = aPlayerData;
        this.configFile = aConfigFile;
        this.pageName = aPageName;
        this.targetDivID = aTargetDivID;
        this.targetFallbackDivID = aTargetFallbackDivID;
        this.forceHTML5 = aForceHTML5;
        this.mediaServerURL = aMediaServerURL;

        this.logging = false;
        this.forceNoFlash = false;
        this.forceIpad = false;

        this.autoTimerDelay = 6000; // milli-vanilli seconds
        this.fadeInDuration = 1000;
        this.fadeOutDuration = 333;

        this.currentIndex = -1;
        this.isAutoCycle = true;

        //======================
        // DEBUGGIN setups
        //======================

        // this.logging = true;

        // NOTE: ie doesn't have a built-in console logger!
        if ((this.logging == true) && (typeof (console) == "undefined")) { this.logging = false; }

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // force the iPad experience
        //this.forceIpad = true; this.logging = true; this.forceHTML5 = this.forceIpad;
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // force the 'no flash' experience
        //this.forceNoFlash = true; this.logging = false; this.forceHTML5 = false; this.forceIpad = false;
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


        //======================
        // Go!
        //======================
        this.showFlashVideoPlayer();
    },

    //======================
    // Methods
    //======================

    /***
    * Shows the flash video player and defaults to the HTML5 video player if needed
    *  if neither browser component is available, the default 'get flash' message is displayed
    */
    showFlashVideoPlayer: function () {

        // we can choose to go directly into HTML5 mode if specified, or if flash is not available, or if we are forcing iPad debuggin
        var skipFlash = (this.forceNoFlash) ? true : this.forceHTML5;

        //if (this.logging) console.log('showFlashVideoPlayer');

        var requiredFlashVersion = "10.0.2";

        if (typeof (swfobject) == "undefined") {
            // i have no idea why this didn't load, 
            // but SWFObject isn't available so skip flash and try html5 instead
            // <steveJobsHatesFlash>iPad</steveJobsHatesFlash>
            skipFlash = true;
        }

        if (!swfobject.hasFlashPlayerVersion(requiredFlashVersion)) { skipFlash = true; }

        if (skipFlash != true) {

            var flashvars = {
                playerType: this.playerType,
                playerData: encodeURIComponent(this.playerData),
                playerConfig: this.configFile,
                pageName: this.pageName,
                mediaServerURL: this.mediaServerURL
            };

            var params = {
                allowFullScreen: "true",
                allowScriptAccess: "sameDomain",
                menu: "false",
                wmode: "transparent",
                swLiveConnect: "true"
            };

            var atts = {};

            var swfURL = "/SwfLib/StarzVideoPlayer.swf";

            if (this.logging) console.log('showFlashVideoPlayer.embedSWF: ' + swfURL, this.targetDivID);

            swfobject.embedSWF(swfURL, this.targetDivID, this.width, this.height, requiredFlashVersion, false, flashvars, params, atts);

        } else {

            // if this is the iPad, we will show the javascript slideshow,
            // otherwise, we will show the 'missing flash' image and only the first image of the slideshow
            if (this.isIPad()) {
                this.showHtmlSlideshow();
            }
            else {
                //alert('you are missing flash!');
                jQuery("#" + this.targetFallbackDivID).show();
            }
        }
    },

    /***
    * Loads the configuration file from the player async
    * Renders the HTML version of the slideshow to the targetDivID
    */
    showHtmlSlideshow: function () {
        if (typeof this.configFile != "undefined" && this.configFile != "") {
            this.loadConfigFile();
        } else {
            this.createHtmlSlideshow();
        }
    },

    /***
    * Loads the XML configuration file supplied as an async Ajax request
    */
    loadConfigFile: function () {

        if (this.logging) console.log("loadConfigFile: " + this.configFile);

        // make the ajax request to the XML configuration file   

        new Ajax.Request(this.configFile, {
            method: 'get',
            contentType: 'application/xml',
            onSuccess: this.configFileLoaded.bind(this),
            onFailure: this.configFileError.bind(this)
        });
    },

    /***
    * Gets a configuration value from either the XML configuration file or the default values
    */
    getConfigValue: function (aConfigNodeName) {
		
        if (this.configFile == "") {
            return this.getDefaultConfig(aConfigNodeName);
        } else {

            var tArray = $(this.configFileXML).getElementsByTagName(aConfigNodeName);

            if (tArray.length > 0) {
				if( tArray[0].childNodes.length > 0 )
				{
                	return tArray[0].childNodes[0].nodeValue.strip();
				}
				else
				{
					// the config file does not contain this value
					return this.getDefaultConfig(aConfigNodeName);
				}
            }
            else {				
                return this.getDefaultConfig(aConfigNodeName);
            }
			
        }
    },

    /***
    * Gets a configuration value from either the XML configuration file or the default values
    */
    getConfigValueAsBoolean: function (aConfigNodeName) {

        var tBool = this.getConfigValue(aConfigNodeName);

        if (tBool.toLowerCase() == "true") return true;
        return false;
    },

    /***
    * Returns a default value based on the configuration node name requested from the GUI
    *      @see Starz.Flash.VideoPlayers\trunk\source\classes\as3\com\starz\video\util\ConfigUtil.as
    */
    getDefaultConfig: function (aConfigNodeName) {

        var tStr = "";

        switch (aConfigNodeName) {

            case "themeColor": tStr = "f47920";
                break;

            case "itemNavColor": tStr = "ffffff";
                break;

            case "itemNavSelectedColor": tStr = "f47920";
                break;

            case "itemCaptionTitleTextColor": tStr = "000000";
                break;

            case "itemCaptionDescriptionTextColor": tStr = "000000";
                break;

            case "itemCaptionDescriptionBgColor": tStr = "ffffff";
                break;

            case "itemCaptionDescriptionBgAlpha": tStr = ".70";
                break;

            case "itemCaptionButtonTextFont": tStr = "Arial";
                break;

            case "itemCaptionButtonTextColor": tStr = "000000";
                break;

            case "itemCaptionButtonTextSize": tStr = "12";
                break;

            case "itemCaptionButtonTextBold": tStr = "true";
                break;

            case "videoOverlayPath": tStr = "/SiteImagesLib/PlayerExtras_Overlay.gif"; // just transparent
                break;

            default:
                if (this.logging) console.log("TODO: Create default style for -> " + aConfigNodeName);
                break;
        }

        return tStr;
    },

    /***
    * Either displays a single image or creates the image slideshow from the faustData based on playerType
    */
    createHtmlSlideshow: function () {

        //if (this.logging) console.log("createHtmlSlideshow");
        //if( this.logging ) console.log( "decoding playerData: " + this.playerData );

        // except for the homepage, the faustData must be decoded before we deal with it..
        this.playerData = decodeURIComponent(this.playerData);

        // a javascript string and not an HTML object...
        var tDiv;
        if (typeof this.playerData == "string") {
            tDiv = document.createElement('div');
            $(tDiv).innerHTML = this.playerData;
        } else {
            tDiv = this.playerData;
        }

        this.playerData = tDiv;

        this.titles = $(tDiv).getElementsBySelector("slides");

        // note: the extras player has no 'slides' only a playlist of videos... until the iPad can play the videos we opt to just display the default overlay image
        if (this.playerType.toLowerCase() == "extras") {
            var tVideoOverlay = this.getConfigValue("videoOverlayPath");
            this.titles[0].innerHTML = "<slide src=\"" + tVideoOverlay + "\" title=\"\" description=\"\" link=\"\" />";
        }

        if (this.titles.length > 0) this.slides = this.titles[0].getElementsBySelector("slide");
        this.relatedTitles = $(tDiv).getElementsBySelector("related");
        if (this.relatedTitles.length > 0) this.relatedSlides = this.relatedTitles[0].getElementsBySelector("video");

        //if (this.logging) console.log(this.titles);
        //if( this.logging ) console.log( this.slides );
        //if (this.logging) console.log(this.relatedTitles);
        //if( this.logging ) console.log( this.relatedSlides );

        this.filterSlides();
        this.showNextSlide();
    },

    /***
    * Filters out all non-standard images from the slides array
    *      Currently, this means no SWFs !
    */
    filterSlides: function () {

        //if (this.logging) console.log("filterSlides: " + this.slides.length);

        for (var i = 0; i < this.slides.length; i++) {

			// REPLACE SWFS WITH JPGS
            var tImgSrc = this.slides[i].readAttribute('src');
			if (tImgSrc.indexOf(".swf") != -1) {
				tImgSrc = tImgSrc.split(".swf").join(".jpg");				
				this.slides[i].writeAttribute('src',tImgSrc);
			}
			
			/*
			// REMOVE SWFS
            // right now, just remove any swf reference
            if (tImgSrc.indexOf(".swf") != -1) {

                if (this.logging) console.log("REMOVED: " + tImgSrc);
                this.slides.splice(i, 1);
                i--; // props to sagar for thinking of this! 
                // splice is actively cutting the length down, so we will skip an element if we don't go back one index each time we splice one from the array                
            }
			*/

        }

        if (this.slides.length <= 1) this.isAutoCycle = false;

        //if (this.logging) console.log("autoCycle: " + this.isAutoCycle);

    },

   /***
    * Removes the slide at a particular index in the slides array
    */
    removeSlideAtIndex: function (aSlideIndex) {

        if (this.logging) console.log("removeSlideAtIndex: " + aSlideIndex);

	// ensure the index exists in the bounds of the array
	if( aSlideIndex <= -1 ) return;
	if( aSlideIndex > this.slides.length ) return;

	this.slides.splice(aSlideIndex, 1);
    },

    /***
    * Steps the currentIndex and shows the next slide in the slides array
    *  If aStopImageCycle is true, the autoCycle feature is turned off and the user must click a chicklet to load the next image
    */
    showNextSlide: function (aStopImageCycle) {

        if (aStopImageCycle == true) { this.isAutoCycle = false; }

        if (this.isShowingVideo == true) return;

        // fade the last slide out... wait
        //setTimeout(this.fadeImageOut.bind(this), 1);
        //setTimeout(this.resumeShowNextSlide.bind(this), this.fadeOutDuration + 1);

        this.resumeShowNextSlide();
    },

    /***
    * Steps the currentIndex and shows the next slide in the slides array
    *  If aStopImageCycle is true, the autoCycle feature is turned off and the user must click a chicklet to load the next image
    */
    resumeShowNextSlide: function () {

        try {
            // step the index and ensure we haven't hit the end...
            this.currentIndex++; if (this.currentIndex >= this.slides.length) this.currentIndex = 0;

            if (this.logging) console.log('showNextSlide: ' + (this.currentIndex+1) + "/" + this.slides.length);


            this.currentSlide = this.slides[this.currentIndex];
            var tImageSrc = $(this.currentSlide).readAttribute('src');

            this.titleName = $(this.currentSlide).readAttribute('title');
            if (this.titleName == null) this.titleName = "";

            this.description = $(this.currentSlide).readAttribute('description');
            if (this.description == null) this.description = "";

            this.pageURL = $(this.currentSlide).readAttribute('link');
            if (this.pageURL == null) this.pageURL = "";
			
			this.imageLinkUrl = $(this.currentSlide).readAttribute('imageLinkUrl');
			if (this.imageLinkUrl == null) this.imageLinkUrl = "";
			
			this.imageLinkTarget = $(this.currentSlide).readAttribute('imageLinkTarget');
			if (this.imageLinkTarget == null) this.imageLinkTarget = "";
			
            var tWatchPreviewHTML = this.getWatchPreviewHTML();
            var tMoreInfoHTML = this.getMoreInfoHTML();

            var itemCaptionTitleTextColor = this.getConfigValue("itemCaptionTitleTextColor");
            var itemCaptionDescriptionTextColor = this.getConfigValue("itemCaptionDescriptionTextColor");
            var itemCaptionDescriptionBgColor = this.getConfigValue("itemCaptionDescriptionBgColor");
            var itemCaptionDescriptionBgAlpha = this.getConfigValue("itemCaptionDescriptionBgAlpha");

            var tTextHTML = "";	
			
			var needsOverlay = true;			
			
			if (this.titleName != "" ||
				this.description != "" || 
				tMoreInfoHTML != "") {
			   	needsOverlay = true;
			}
			
			// CMS will enter "&nbsp;" to defer the creation of the background
			if( (this.titleName == "&nbsp;" && this.description == "") || 
				(this.titleName == "" && this.description == "") ) {
				needsOverlay = false;
			}
			
            if (needsOverlay) {
                tTextHTML = "<div class='slideShowOverlayBackgroundMulti' style='" +
                                "width:" + this.width + "px; " +
                                "background-color:#" + itemCaptionDescriptionBgColor + "; " +
                                "opacity:" + itemCaptionDescriptionBgAlpha + "; " +
                                "'>" +
							    "<div class='slideShowOverlayTitle' style='color:#" + itemCaptionTitleTextColor + ";'>" + this.titleName + "</div>" +
								"<div class='slideShowOverlayDescription' style='color:#" + itemCaptionDescriptionTextColor + ";'>" + this.description + "</div>" +
								tWatchPreviewHTML +
								((tMoreInfoHTML != "") ? tMoreInfoHTML : "<br/>") +
							"</div>";

            }

            var tHTML = "<div class='starzVideoPlayer'>" +
							this.getSlideImageHTML(tImageSrc,this.imageLinkUrl,this.imageLinkTarget) +
							tTextHTML + this.getSlideNavigationHTML() +
							"</div>";

            $(this.targetDivID).setStyle({ display: 'block' });

            //$('slideShowOverlayBackgroundMulti').setOpacity(0);

            $(this.targetDivID).innerHTML = tHTML;

            // if any buttons exist, observe the clicks!

            var tSlideNavigationItems = $(this.targetDivID).getElementsByClassName("slideShowOverlayNavigationItem");
            if (tSlideNavigationItems.length) {
                for (var i = 0; i < tSlideNavigationItems.length; i++) {
                    tSlideNavigationItems[i].observe('click', this.showSlideAtID.bindAsEventListener(this, i));
                }
            }

            // commenting this out until we get iPad videos playing
            /*
            var tWatchPreviewButton = $(this.targetDivID).getElementsByClassName("slideShowOverlayButtonWatchPreview");                            
            if (tWatchPreviewButton[0]) tWatchPreviewButton[0].observe('click', this.showHtmlVideo.bind(this));
            */

            var tMoreInfoButton = $(this.targetDivID).getElementsByClassName("slideShowOverlayButtonMoreInfo");
            if (tMoreInfoButton[0]) tMoreInfoButton[0].observe('click', this.showInfo.bind(this));

        }
        catch (e) {
            //this.showNextSlide(true);
            this.showNextSlide(false);
        }

    },

    /***
    * Gets the HTML for the 'chicklet' images with the correct configuration colors
    */
    getSlideNavigationHTML: function () {

        var tHTML = "";
        if (this.slides.length <= 1) return tHTML;

        var itemNavColor = this.getConfigValue("itemNavColor");
        var itemNavSelectedColor = this.getConfigValue("itemNavSelectedColor");

        for (var i = 0; i < this.slides.length; i++) {
            tHTML += (i != this.currentIndex) ?
            "<div class='slideShowOverlayNavigationItem' style='background-color:#" + itemNavColor + "' ></div>" :
            "<div class='slideShowOverlayNavigationItem' style='background-color:#" + itemNavSelectedColor + "' ></div>";
        }

        return "<div class='slideShowOverlayNavigation' >" + tHTML + "</div>";
    },

    /***
    * Gets the HTML for the slide image to display based on a source url
    */
    getSlideImageHTML: function (aImageSrc,aImageLinkUrl,aImageLinkTarget) {

        this.currentImage = new Image();
        this.currentImage.src = aImageSrc;
        this.currentImage.width = this.width;
        this.currentImage.height = this.height;

        //if( this.logging ) console.log( "imageHTML: " + aImageSrc + " -- " + this.width + "x" + this.height );

        //$(this.currentImage).setOpacity(0); // let the image fade in later?... see @fadeImageIn

        //if( this.logging ) console.log('getSlideImageHTML :: ' + aImageSrc + '\r\nautoCycle: ' + this.isAutoCycle);

        if (this.isAutoCycle == true) {
            $(this.currentImage).observe('load', this.slideLoaded.bind(this));
            $(this.currentImage).observe('error', this.slideError.bind(this));
        }
		
		var tHtml = this.currentImage.outerHTML;
		if( aImageLinkUrl != "" ) tHtml = "<a href='"+aImageLinkUrl+"' target='"+aImageLinkTarget+"'>" + tHtml + "</a>";

        return tHtml;
    },

    /***
    * Gets the HTML for the 'watch preview' button
    *  IF no source exists, an empty string is returned
    */
    getWatchPreviewHTML: function () {

    	return "";
    	//if (!this.pageURL) return "";
    	
    	/*

        var itemCaptionButtonTextFont = this.getConfigValue("itemCaptionButtonTextFont");
        var itemCaptionButtonTextColor = this.getConfigValue("itemCaptionButtonTextColor");
        var itemCaptionButtonTextSize = this.getConfigValue("itemCaptionButtonTextSize");

        var itemCaptionButtonTextBold = this.getConfigValueAsBoolean("itemCaptionButtonTextBold");


        var tHtml = "<div class='slideShowOverlayButtonWatchPreviewBtn'><div class='slideShowOverlayButtonWatchPreview' style='" +
                        "color:#" + itemCaptionButtonTextColor + "; " +
                        "font-family:" + itemCaptionButtonTextColor + "; " +
                        "font-size:" + itemCaptionButtonTextSize + "px; " +
                        ((itemCaptionButtonTextBold) ? "font-weight:bold" : "") +
                        "' >WATCH PREVIEW</div></div>";

        return tHtml;
        */
    },

    /***
    * Gets the HTML for the 'more info' button
    */
    getMoreInfoHTML: function () {

        //if (this.logging) console.log("getMoreInfoHTML? " + this.pageURL);

        if (!this.pageURL) return "";

        var itemCaptionButtonTextFont = this.getConfigValue("itemCaptionButtonTextFont");
        var itemCaptionButtonTextColor = this.getConfigValue("itemCaptionButtonTextColor");
        var itemCaptionButtonTextSize = this.getConfigValue("itemCaptionButtonTextSize");

        var itemCaptionButtonTextBold = this.getConfigValueAsBoolean("itemCaptionButtonTextBold");


        var tHtml = "<div class='slideShowOverlayButtonMoreInfoBtn'><div class='slideShowOverlayButtonMoreInfo' style='" +
                        "color:#" + itemCaptionButtonTextColor + "; " +
                        "font-family:" + itemCaptionButtonTextColor + "; " +
                        "font-size:" + itemCaptionButtonTextSize + "px; " +
                        ((itemCaptionButtonTextBold) ? "font-weight:bold" : "") +
                        "' >MORE INFO</div></div>";

        return tHtml;

    },

    /***
    * Creates the HTML5 <video> element
    *
    *  THIS IS NOT FULLY IMPLEMENTED
    */
    createHtmlVideo: function () {

        var tCloseHtml = "<div class='videoControlsCloseButton' >CLOSE</div>";

        //var tHTML = tCloseHtml + "<br/><br/>" + "<video width='" + this.width + "' height='" + this.height + "' controls='true' autoplay='true'><source src='http://192.168.172.77:1935/vod/mp4:Spartacus102.m4v/playlist.m3u8' />Your browser does not support the video tag.</video>";

        var tHTML = "<video width='" + this.width + "' height='" + this.height + "' controls='true' autoplay='true'>" +
        		"<source src='http://videoassets.starz.com/test/ipadtest/toy_story01/prog_index.m3u8' />Your browser does not support the video tag.</video>";

        if (this.logging) console.log(tHTML);

        $(this.targetDivID).innerHTML = tHTML;

        // TODO Create our own player controls and add the 'close' button so the user can get back to the slideshow

        //var tCloseButton = $(this.targetDivID).getElementsByClassName("videoControlsCloseButton")[0];
        //tCloseButton.observe('click', this.closeHtmlVideo.bind(this));
    },

    /***
    * Closes the HTML5 video experience and returns to the image slideshow
    */
    closeHtmlVideo: function () {

        this.currentIndex--; if (this.currentIndex < 0) this.currentIndex = 0;

        this.isShowingVideo = false;
        this.showNextSlide();
    },

    //======================
    // Tweens
    //======================

    /***
    * Fades an image in using new Fx.Style
    */
    fadeImageIn: function () {

        // TODO evaluate if crossfade or ANY fade is good at this point...
        //      I don't think it looks very good on the iPad

        var imgs = $(this.targetDivID).getElementsBySelector("img");

        this.fader = new Fx.Style(imgs[0], 'opacity', {
            duration: this.fadeInDuration,
            transition: Fx.Transitions.linear,
            wait: false
        });

        this.fader.custom(0, 1);

        var bgs = $(this.targetDivID).getElementsByClassName("slideShowOverlayBackgroundMulti");

        if (bgs[0]) {
            this.fader2 = new Fx.Style(bgs[0], 'opacity', {
                duration: this.fadeInDuration,
                transition: Fx.Transitions.linear,
                wait: false
            });
        }

        this.fader2.custom(0, 1);
    },

    /***
    * Fades an image out using new Fx.Style
    */
    fadeImageOut: function () {

        // TODO evaluate if crossfade or ANY fade is good at this point...
        //      I don't think it looks very good on the iPad

        var imgs = $(this.targetDivID).getElementsBySelector("img");

        this.fader = new Fx.Style(imgs[0], 'opacity', {
            duration: this.fadeOutDuration,
            transition: Fx.Transitions.linear,
            wait: false
        });

        this.fader.custom(1, 0);

        var bgs = $(this.targetDivID).getElementsByClassName("slideShowOverlayBackgroundMulti");
        if (bgs[0]) {
            this.fader2 = new Fx.Style(bgs[0], 'opacity', {
                duration: this.fadeOutDuration,
                transition: Fx.Transitions.linear,
                wait: false
            });

            this.fader2.custom(1, 0);
        }


    },


    //======================
    // Button Click Events
    //======================

    /***
    * Click handler for the slideshow 'chicklet' buttons
    *  Shows the slide at a particular position in the array according to the position of the chicklet in the GUI
    */
    showSlideAtID: function (e, aIndex) {

        this.currentIndex = aIndex - 1; // the index will naturally step forward using showNextSlide, so subtract one!

        if (this.logging) console.log("showSlideAtID: " + aIndex);

        // stop the imageCycle and just show the slide
        clearTimeout(this.autoTimerID);
        this.showNextSlide(true);
    },

    /***
    * Click handler for the 'watch preview' button
    *  Shows the HTML5 video experience
    */
    showHtmlVideo: function () {

        this.isShowingVideo = true;
        this.createHtmlVideo();

    },

    /***
    * Click handler for the 'more info' button
    *  Sends the browser to a new url
    */
    showInfo: function () {

        window.location = this.pageURL;

    },

    //======================
    // Events
    //======================

    /***
    * Success event handler for the Ajax request to the XML configuration file
    */
    configFileLoaded: function (e) {

        //if (this.logging) console.log('configFileLoaded');

        this.configFileXML = e.responseXML;
        this.createHtmlSlideshow();
    },

    /***
    * Error event handler for the Ajax request to the XML configuration file
    */
    configFileError: function (e) {

        if (this.logging) console.log('configFileError: ' + e);

        this.createHtmlSlideshow();
    },

    /***
    * Load event handler for the requested slide image
    */
    slideLoaded: function (e) {

        //if (this.logging) console.log('slideLoaded :: ' + this.currentImage + '\r\nautoCycle: ' + this.isAutoCycle);

        // now fade the image in
        //setTimeout(this.fadeImageIn.bind(this), 100);

        // and continue the autoCycle if needed                
        if (this.isAutoCycle == true) {
            this.autoTimerID = setTimeout(this.showNextSlide.bind(this), this.autoTimerDelay);
        }
    },

    /***
    * Error event handler for the load request of the next slide image
    */
    slideError: function (e) {
        
        if (this.logging) console.log('slideError at index ' + this.currentIndex );

        // remove this image from the list and proceed
	this.removeSlideAtIndex(this.currentIndex);
	this.currentIndex--;

	// automatically show the next slide since this one is invalid
        this.resumeShowNextSlide();        
    },

    //======================
    // Helpers
    //======================

    isIPad: function () {
        if (this.logging) console.log(navigator.userAgent);
        if (this.forceIpad) return true;
        return navigator.userAgent.match(/iPad/i) != null;
    },

    /***
    * Checks for basic HTML5 video support
    */
    supports_html5video: function () {

        var tSupport = !!document.createElement('video').canPlayType;

        if (this.logging) console.log('supports_html5video: ' + tSupport);

        return tSupport;
    },

    /***
    * Checks for 'h264 baseline' HTML5 video support
    */
    supports_h264_baseline_video: function () {

        if (!this.supports_html5video()) { return false; }

        var v = document.createElement("video");
        var tCanPlayType = v.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');

        // http://www.w3.org/TR/html5/video.html
        //	NOTE: canPlayType Returns the empty string (a negative response), "maybe", or "probably" based on how confident the user agent is that it can play media resources of the given type.
        var tSupport = (tCanPlayType == "probably" || tCanPlayType == "maybe") ? true : false;

        if (this.logging) console.log('canPlayType video/mp4; codecs="avc1.42E01E, mp4a.40.2: ' + tCanPlayType);
        if (this.logging) console.log('supports_h264_baseline_video: ' + tSupport);

        return tSupport;
    }

});


//======================
// END StarzVideoPlayer
//======================

//console.log('END starzVideoPlayer.js');

//alert('END starzVideoPlayer');
