/* ! VideoViewer - Video player & details control */

var VideoViewer = {
    
    
    _$actions: null,
    _$description: null,
    _$likeWidget: null,
    _$ratingWidget: null,
    _$title: null,
    _player: null,
    _playerReady: false,  // player loaded and API ready to accept calls
    _videoQueue: null,
    
    
    init: function() {
        // store references to the main elements
        VideoViewer._$description = jQuery('#vtitle');
        VideoViewer._$title = jQuery('#vdescription');
        VideoViewer._$actions = jQuery('.vactions', '#vcontent');
        VideoViewer._$likeWidget = jQuery('.vlike', '#vcontent');
        
        
        // prep the Like widget
        if (VideoViewer._$likeWidget.length > 0) {
            LikeWidget.init(VideoViewer._$likeWidget);
        }
        
        
        // add the rating widget
        var widget = RatingWidgets.buildWidget();
        VideoViewer._$ratingWidget = VideoViewer._$actions
            .children('.vrating').html(widget)  // add the widget HTML
            .children('.rating-widget').stars({  // init the widget
                inputType: 'select',
                starWidth: 18,  // width of our star graphic
                oneVoteOnly: true,
                disabled: true,  // disable until API ready
                split: 2,  // enable half stars
                callback: VideoViewer._ratingClick
            });
    },
    
    // handles the player's change events
    playerEvent: function(playerId, eventName, eventParams) {
        //console.log("Player event:  " + eventName);
        
        // store Ooyala player object; call API setters/getters upon this object
        if (!VideoViewer._player) {
            VideoViewer._player = document.getElementById(playerId);
        }
        
        // determine the event received
        switch(eventName){
            
            case "apiReady": // (last event) wait for this event to be dispatched before making any API calls; fired after each channel change
                
                // mark the player as being loaded/ready
                VideoViewer._playerReady = true;
                
                
                // check for any queued videos to load (from a channel change)
                if (VideoViewer._videoQueue) {
                    // load up the queued video embed code
                    VideoViewer._loadVideoQueue();
                } else {
                    // update the new video info
                    VideoViewer._updateVideoInfo();
                }
                
                
                // load the ratings API
                VideoViewer._player.loadRatingsApi();
                
                break;
            
            case "embedCodeChanged":  // (1st event) top-level (i.e. - channel) embed code changed; API will reload
                
                // new channel so the player's API needs to reset
                VideoViewer._playerReady = false;
                
                break;
                
            case "currentItemEmbedCodeChanged":  // (2nd, or 1st, event) new item/video embed code
                
                //console.log('item embed code changed; api ready?  ' + VideoViewer._playerReady);
                if (VideoViewer._playerReady) {
                    // API already loaded (same channel), update the current video info
                    VideoViewer._updateVideoInfo();
                }
                
                // scroll player into view //updated 8/5/2010 to go all the way to top
                document.getElementById('wrapper').scrollIntoView(true);
                
                break;
            
            case "ratingsApiReady":  // (after main API) can now set the rating
                
                // enable the rating widget
                VideoViewer._$ratingWidget.stars('enable');
                
                break;
        }
    },
    
    _changeVideo: function(embedCode) {
        //console.log('change video to: ' + embedCode);
        
        // locate key elements
        var $channelContainer = jQuery('#' + embedCode).closest('.stepcarousel, .thumbs').parent();
        var channelID = $channelContainer.attr('id');
        
        // check the player's current channel [embed code] against the requested video's channel
        var currentChannelCode = VideoViewer._player.getEmbedCode();
        var targetChannelCode = ChannelSurfer.getChannel(channelID).embedCode;
        
        //console.log('current,target channel codes:  ' + [currentChannelCode, targetChannelCode]);
        
        // check if we're switching to a new channel
        if (currentChannelCode != targetChannelCode) {
            //console.log("cache!!");
            
            // store the embed code for the video to load after the channel update
            VideoViewer._videoQueue = embedCode;
            
            // change the player's channel first (letting the normal playerChangeHandler take care of the rest)
            VideoViewer._player.setEmbedCode(targetChannelCode);
        } else {
            // already in the correct channel, just change the video embed code
            VideoViewer._updatePlayer(embedCode);
        }
    },
    
    _updatePlayer: function(embedCode) {
        //console.log('update player with: ' + embedCode);
        
        var autoplay = true;
        
        if (VideoViewer._player.changeCurrentItem(embedCode)) {
            //if autoplay is on, then automatically play video after switch
            if (autoplay) VideoViewer._player.playMovie();
        }
    },
    
    _updateVideoInfo: function() {
        //console.log('player video changed; update info');
        
        // update the HTML
        VideoViewer._$description.html(VideoViewer._player.getCurrentItemTitle());
        VideoViewer._$title.html(VideoViewer._player.getCurrentItemDescription());
        
        
        // update the ratings
        var rating = RatingWidgets.calcRating(VideoViewer._player.getCurrentItemRatings());
        //console.log('rating:  ' + rating);
        
        VideoViewer._$ratingWidget.stars('select', rating);
        
        
        // update the Facebook Like widget
        LikeWidget.updateEmbedCode(VideoViewer._player.getCurrentItemEmbedCode());
        
        
        // highlight the video in the channel
        var videoID = VideoViewer._player.getCurrentItemEmbedCode();
        ChannelSurfer.videoChange(videoID);
    },
    
    _loadVideoQueue: function() {
        //console.log('queued video to load: ' + VideoViewer._videoQueue);
        
        // check if already the player's current item
        if (VideoViewer._videoQueue != VideoViewer._player.getCurrentItemEmbedCode()) {
            // update the player item embed code
            VideoViewer._updatePlayer(VideoViewer._videoQueue);
        } else {
            // must be first (default) video in the new channel; no need to change the player code, just update info
            VideoViewer._updateVideoInfo();
            
            // …and start the playhead
            VideoViewer._player.playMovie()
        }
        
        // clear the queued item
        VideoViewer._videoQueue = null;        
    },
    
    _ratingClick: function(ui, type, value) {
        //console.log('set rating:  ' + value);
        
        VideoViewer._player.incrementCurrentItemRating(value);
    },
    
    
    // Setters
    setVideo: function(embedCode) {
        VideoViewer._changeVideo(embedCode);
    },
    
    
    // Getters
    getPlayer: function() {
        return VideoViewer._player;
    },
    
    isPlayerLoaded: function() {
        return VideoViewer._playerReady;
    }
}



/* ! ChannelSurfer - Channel lists control */

var ChannelSurfer = {
    
    
    _apiProxyURL: 'javascript/ooyalabacklotapi.php',
    _channels: {},  // _channels.channelid = {embedCode: '', videos: [], videoUpdateCount: 0}
    _numChannels: 0,
    _numChannelsBuilt: 0,
    _numVisibleThumbs: 4,
    _thumbnailsWidth: 155,
    _thumbnailsHeight: 115,
    pageLimit: 8,  // number of thumbs to display in the scroller/one page of View All; -1 = no limit
    view: 'scroll',  // initial display view (i.e. - 'all')
    
    
    init: function() {
        // loop through the channel elements
        jQuery('.channel-wrapper', '#scroller').each(function(){
            // store the channels' info
            var embedCode = jQuery(this).attr('id');
            
            //console.log('init channel:  ' + embedCode);
            
            var channel = {
                embedCode: embedCode,  // the channels embed code
                videos: [],  // array of video data objects (to be loaded)
                videoUpdateCount: 0,  // number of videos whose's [thumbnail] data has been updated in individual calls
                numPages: 0,  // number of pages for the pager
                currentPage: 1,  // active page
                view: ChannelSurfer.view  // copy of the view value for building each channel
            };
            
            ChannelSurfer._channels[embedCode] = channel;
            ChannelSurfer._numChannels++;
            
            
            // hide the controls
            jQuery(this).find('.viewall, .arrow').hide();
            
            
            // create a loop closure to keep the correct channel value
            var loadHandler = function(channel) {
                // the inner function actually handles the get() callback
                return function(data, textStatus, XMLHttpRequest) {
                    //console.log('channel ' + channel.embedCode + ' feed loaded');
                    
                    ChannelSurfer._parseChannel(channel, data);
                }
            }(channel);
            
            // load the channel's data feed
            jQuery.get(
                ChannelSurfer._apiProxyURL,
                {
                    type: 'channel',
                    embedCode: embedCode
                },
                loadHandler,
                'xml'
            );
        });
    },
    
    _parseChannel: function(channel, data) {
        // parse and store the returned channel XML data
        jQuery('channel > item', data).each(function() {
            var video = {
                title: jQuery('title', this).text(),
                description: jQuery('description', this).text(),
                thumbnailURL: jQuery('thumbnail', this).text(),
                thumbnailUpdated: false,  // if the full size thumbnail URL has been set
                embedCode: jQuery('embedCode', this).text(),
                length: '',  // loads from metadata request
                ratings: []  // loads from metadata request
            };
            
            channel.videos.push(video);
        });
        
        
        // calc number of pages
        channel.numPages = Math.ceil(channel.videos.length / ChannelSurfer.pageLimit);
        
        
        // load additional video details not in the channel feed
        ChannelSurfer._updateVideosMeta(channel);
    },
    
    _updateVideosMeta: function(channel) {
        // fetch all the video embed codes for the channel
        var embedCodes = [];
        
        for (var i = 0, ii = channel.videos.length; i < ii; i++) {
            embedCodes.push(channel.videos[i].embedCode);
        }
        
        
        // create closure to maintain channel object reference
        var loadHandler = function(channel) {
            // the inner function actually handles the get() callback
            return function(data, textStatus, XMLHttpRequest) {
                //console.log('channel ' + channel.embedCode + ' metadata loaded');
                
                ChannelSurfer._parseVideosMeta(channel, data);
            }
        }(channel);
        
        // load the metadata feed
        jQuery.get(
            ChannelSurfer._apiProxyURL,
            {
                type: 'metadata',
                embedCode: embedCodes.join(',')
            },
            loadHandler,
            'xml'
        );
    },
    
    _parseVideosMeta: function(channel, data) {
        // loop through the data and assign extra meta to the matching channel video
        jQuery('list > item', data).each(function() {
            var embedCode = jQuery('embedCode', this).text();
            
            // add video details
            var video = ChannelSurfer.getVideo(channel.embedCode, embedCode);
            
            video.length = ChannelSurfer._formatLength(jQuery('length', this).text());
            video.ratings = jQuery('movieRatings', this).text().split(';');
            
            //console.log('updated meta for video:'); console.log(video);
        });
        
        
        // now update the thumbnails
        ChannelSurfer._updateVideosThumbs(channel, 0, ChannelSurfer.pageLimit);
    },
    
    _updateVideosThumbs: function(channel) {
        // reset the update count
        channel.videoUpdateCount = 0;
        
        
        // find the start and end index based on the current page and page limit
        var startIndex = (channel.currentPage - 1) * ChannelSurfer.pageLimit;
        var endIndex = startIndex + ChannelSurfer.pageLimit;
        //console.log('videos start, end index:  ' + [startIndex, endIndex]);
        
        
        // load the proper resolution thumbnail for each video
        for (var i = startIndex; i < endIndex; i++) {
            var video = channel.videos[i];
            
            // only request the larger thumb URL once
            if (!video || video.thumbnailUpdated) {
                // either already loaded or reached the end of the videos; so just increment the counter
                channel.videoUpdateCount++;
            } else {
                //console.log('load thumb for video #' + i);
                
                // create a loop closure to hold the correct id & video index
                var loadHandler = function(channel, videoIndex) {
                    // the inner function actually handles the get() callback
                    return function(data, textStatus, XMLHttpRequest) {
                        //console.log('loaded thumbnail info for video index: ' + videoIndex);
                        
                        ChannelSurfer._parseVideoThumbnail(channel, videoIndex, data);
                    }
                }(channel, i);
                
                // load the video's thumbnail feed
                jQuery.get(
                    ChannelSurfer._apiProxyURL,
                    {
                        type: 'thumbnails',
                        embedCode: video.embedCode,
                        range: '0-0',  // just the first thumbnail
                        resolution: ChannelSurfer._thumbnailsWidth + 'x' + ChannelSurfer._thumbnailsHeight
                    },
                    loadHandler,
                    'xml'
                );
            }
        }
        
        
        // all the new thumb URLs may have already been loaded
        if (channel.videoUpdateCount >= ChannelSurfer.pageLimit) {
            // build the final channel markup
            ChannelSurfer._buildChannel(channel);
        }
    },
    
    _parseVideoThumbnail: function(channel, videoIndex, data) {
        var video = channel.videos[videoIndex];
        
        // replace the thumbnail source with the new one
        video.thumbnailURL = jQuery('thumbnails > promoThumbnail', data).text();
        video.thumbnailUpdated = true;
        
        
        // check if all the videos in this channel have been updated
        channel.videoUpdateCount++;
        
        if (channel.videoUpdateCount >= ChannelSurfer.pageLimit) {
            // build the final channel markup
            ChannelSurfer._buildChannel(channel);
        }
    },
    
    _buildChannel: function(channel) {
        //console.log('building channel:  ' + channel.embedCode);
        
        // add the thumbnail HTML to the channel's 'belt'
        var thumbnailsHTML = ChannelSurfer._generateThumbnailHTML(channel);
        
        var $wrapper = jQuery('#' + channel.embedCode)
            .find('.belt').html(thumbnailsHTML)
            .end();
        
        
        // init the rating widgets (read only)
        $wrapper.find('.rating-widget')
            .stars({
                inputType: 'select',
                starWidth: 18,
                split: 2,
                disabled: true
            });
        
        
        // add a delegate to listen for thumb selections
        $wrapper.delegate('a.panel', 'click', ChannelSurfer._thumbClick);
        
        // bind inline View All control listener (not [home] buttons which link to section pages)
        jQuery('[href=#viewall].viewall', $wrapper)
            .bind('click', ChannelSurfer._viewAllClick);
        
        // bind listeners for arrow clicks
        jQuery('.arrow a', $wrapper)
            .bind('click', ChannelSurfer._arrowClick);
        
        
        // initialize the display
        if (channel.view == 'all') {
            // initial view is set to 'all'
            ChannelSurfer.viewAll(channel.embedCode);
        } else if (channel.view == 'scroll') {
            // init the carousel scroller
            ChannelSurfer._initScroller(channel.embedCode);
            
            // show the controls
            jQuery('.viewall, .arrow', $wrapper).fadeIn();
        }
        
        // clear the view value so above only runs once
        channel.view = null;
        
        
        // after all the channels are built & displayed, highlight the first video's thumb (if the player is already loaded)
        ChannelSurfer._numChannelsBuilt++;
        
        if ((ChannelSurfer._numChannelsBuilt >= ChannelSurfer._numChannels) && VideoViewer.isPlayerLoaded()) {
            var player = VideoViewer.getPlayer();
            
            ChannelSurfer._highlightThumb(player.getCurrentItemEmbedCode());
        }
    },
    
    _generateThumbnailHTML: function(channel) {
        // find the start and end index based on the current page and page limit
        var startIndex = (channel.currentPage - 1) * ChannelSurfer.pageLimit;
        var endIndex = startIndex + ChannelSurfer.pageLimit;
        
        
        // create the HTML string
        var html = "";
        
        for (var i = startIndex; i < endIndex; i++) {
            var video = channel.videos[i];
            
            if (video) {
                html += "<a href='#' class='panel' onclick='s.tl(this,\"o\",\"Video: " + video.title + "\");' >";
                html += "<img border='0' width='" + ChannelSurfer._thumbnailsWidth + "px' height='" + ChannelSurfer._thumbnailsHeight + "px' alt='" + video.title + "' title='" + video.title + "' id='" + video.embedCode + "' src='" + video.thumbnailURL + "' />";
                html += RatingWidgets.buildWidget(RatingWidgets.calcRating(video.ratings));
                html += "<h4>" + video.title + "</h4>";
                html += "<p class='vlength'>" + video.length + "</p>";
                html += "</a>";
            }
        }
        
        return html;
    },
    
    _generatePagerHTML: function(channelID) {
        var channel = ChannelSurfer.getChannel(channelID);
        
        var html = '';
        
        if (channel.numPages > 1) {
            html += '<ul class="pager">';
            html += '<li><a href="#previous">&lt;</a></li>';
            
            for (var i = 0, ii = channel.numPages; i < ii; i++) {
                html += '<li><a href="#page-' + (i + 1) + '">' + (i + 1) + '</a></li>';
            }
            
            html += '<li><a href="#next">&gt;</a></li>';
            html += '</ul>';
            
            return html;
        } else {
            return;
        }
    },
    
    _initScroller: function(id) {
        //console.log('init scroll carousel for channel:  #' + id);
        
        stepcarousel.setup({
           galleryid: id, //id of carousel DIV
           beltclass: 'belt', //class of inner "belt" DIV containing all the panel DIVs
           panelclass: 'panel', //class of panel DIVs each holding content
           autostep: {enable:false, moveby:1, pause:6000}, //auto scroll options
           panelbehavior: {speed:500, wraparound:true, persist:false}, //speed, looping, cookies of scrolling
           contenttype: ['inline'] //do not change
        });
    },
    
    _thumbClick: function(event) {
        // retreive the target video embed code from the link's child image
        var embedCode = jQuery('img', this).attr('id');
        
        VideoViewer.setVideo(embedCode);
        
        
        event.preventDefault();
    },
    
    _arrowClick: function(event) {
        var $link = jQuery(this);
        
        // calc the number of steps to scroll
        var increment = ChannelSurfer._numVisibleThumbs;
        
        if ($link.attr('href') == '#back') {
            increment = -increment;
        }
        //console.log('scroll carousel ' + increment + ' steps');
        
        
        // scroll the carousel
        var $container = $link.closest('.channel-wrapper');
        stepcarousel.stepBy($container.attr('id'), increment);
        
        
        event.preventDefault();  
    },
    
    _viewAllClick: function(event) {
        //console.log('view all');
        
        var $container = jQuery(this).closest('.channel-wrapper');
        ChannelSurfer.viewAll($container.attr('id'));
        
        
        event.preventDefault();
    },
    
    viewAll: function(channelID){
        //console.log("View all in:  " + channelID);
        
        var $wrapper = jQuery('#' + channelID);
        
        
        // hide the View All and scroll buttons
        jQuery('.viewall, .arrow', $wrapper).hide();
        
        
        // update the carousel area to display full view
        jQuery('.stepcarousel', $wrapper)
            .attr('id', 'thumbnailsall')  // change the ID
            .removeClass('stepcarousel').addClass('thumbs')  // swap the class
            .find('.belt, .panel')  // scrub dynamically inline styles added from the carousel
                .removeAttr('style');
        
        
        // add a pager element
        var pagerHTML = ChannelSurfer._generatePagerHTML(channelID);
        
        if (pagerHTML) {
            $wrapper.append(pagerHTML);
            
            // delegate pager link clicks
            $wrapper.delegate('.pager a', 'click', ChannelSurfer._pagerClick);
            
            
            // update the pager display
            ChannelSurfer._updatePager(channelID);
        }
    },
    
    _updatePager: function(channelID) {
        var channel = ChannelSurfer.getChannel(channelID);
        var $wrapper = jQuery('#' + channelID);
        
        // enable/disable previous link
        var $prevLink = $wrapper.find('.pager a[href=#previous]');
        
        if (channel.currentPage > 1) {
            $prevLink.removeClass('disabled');
        } else {
            $prevLink.addClass('disabled');
        }
        
        
        // enable/disable next link
        var $nextLink = $wrapper.find('.pager a[href=#next]');
        
        if (channel.currentPage < channel.numPages) {
            $nextLink.removeClass('disabled');
        } else {
            $nextLink.addClass('disabled');
        }
        
        
        // enable/disable page links
        $wrapper
            .find('.pager a[href|=#page]')
                .removeClass('disabled')  // enable all
            .end()
            .find('.pager a[href=#page-' + channel.currentPage + ']')
                .addClass('disabled')  // disable active page's link
    },
    
    _pagerClick: function(event) {
        var $link = jQuery(this);
        
        if (!$link.hasClass('disabled')) {
            var $wrapper = $link.closest('.channel-wrapper');
            var page = null;
            
            switch ($link.attr('href')) {
                
                case '#previous':
                    page = 'prev';
                    
                    break;
                
                case '#next':
                    page = 'next';
                    
                    break;
                    
                default:
                    page = parseInt($link.text());
                    
            }
            
            ChannelSurfer._pageChannelTo($wrapper.attr('id'), page);
        }
        
        
        event.preventDefault();
    },
        
    _pageChannelTo: function(channelID, page) {
        var channel = ChannelSurfer.getChannel(channelID);
        
        switch (page) {
            
            case 'prev':
                page = channel.currentPage - 1;
                
                break;
                
            case 'next':
                page = channel.currentPage + 1;
                
                break;
                
            default:
                // none
        }
        //console.log('page to:  ' + page);
        
        
        // set the new page value
        channel.currentPage = page;
        ChannelSurfer._updatePager(channelID);
        
        
        // start by loading any missing large thumbs
        ChannelSurfer._updateVideosThumbs(channel);
    },
    
    videoChange: function(videoID) {
        // change the highlighted thumbnail
        var $highlightedThumb = ChannelSurfer._highlightThumb(videoID);
        
        
        // scroll the carousel to the current (highlighted) thumb
        var $carousel = $highlightedThumb.closest('.stepcarousel');
        
        if ($highlightedThumb.length > 0 && $carousel.length > 0) {
            // find all the active carousel's thumb images
            var $wrapper = $carousel.closest('.channel-wrapper');
            var $channelThumbs = jQuery('.belt img', $wrapper);
            
            
            // determine the current (highlighted) thumb's index within the images
            var highlightIndex = $channelThumbs.index($highlightedThumb);
            
            
            // the step carousel function expects a 1-based index
            var stepToIndex = highlightIndex + 1;
            
            // keep carousel full with thumbs, even when last hightlight, to mimic the behavior using the scroll arrows
            if (stepToIndex > ($channelThumbs.length - ChannelSurfer._numVisibleThumbs) + 1) {
                stepToIndex = ($channelThumbs.length - ChannelSurfer._numVisibleThumbs) + 1;
            }
            
            
            // scroll the step carousel
            var channelID = $wrapper.attr('id');
            stepcarousel.stepTo(channelID, stepToIndex);
        }
    },
    
    _highlightThumb: function(videoID) {
        // remove previous highlighting
        jQuery('.belt .highlighted').removeClass('highlighted');
        
        
        // find the thumb with the matching video ID and highlight it
        return jQuery('#' + videoID).addClass('highlighted');
    },
    
    _formatLength : function(millisec) {
        // convert the length to total seconds
        var length = parseInt(millisec) / 1000;
        
        // calc the time units
        var seconds = Math.floor(length % 60);
        var minutes = Math.floor((length / 60) % 60);
        var hours = Math.floor((length / 60 / 60) % 24);
        
        // combine the time string
        var time = '';
        if (hours > 0) {
            time += (hours < 10 ? '0' : '') + hours.toString() + ':';
        }
        time += (minutes < 10 ? '0' : '') + minutes.toString() + ':';
        time += (seconds < 10 ? '0' : '') + seconds.toString();
        
        return time;
    },
    
    
    // Getters
    getChannel: function(id) {
        return ChannelSurfer._channels[id];
    },
    
    getVideo: function(channelID, videoID) {
        var channel =  ChannelSurfer.getChannel(channelID);
        
        // loop through the channels' videos to find a embedCode match
        for (var i = 0, ii = channel.videos.length; i < ii; i++) {
            var video = channel.videos[i];
            
            if (video.embedCode == videoID) {
                return video;
            }
        }
        
        return;
    }
}



/* ! RatingWidgets - Star ratings widget methods */

var RatingWidgets = {
    
    
    _options: ['Very Poor', 'Poor', 'Not Bad', 'Fair', 'Average', 'Pretty Good', 'Good', 'Very Good', 'Excellent', 'Perfect'],
    
        
    init: function() {
        // null
    },
    
    // builds the HTML for a rating widget
    buildWidget: function(selectedRating) {
        //console.log('building rating widget with  ' + selectedRating + '  selected');
        
        var widget = '<div class="rating-widget">';
        widget += '<select name="rating" title="rate this video">';
        
        for (var i = 0, ii = RatingWidgets._options.length; i < ii; i++) {
            // determine if this rating should be selected at start
            var selected = '';
            if (selectedRating == (i + 1)){
                selected = ' selected="selected"';
            }
            
            widget += '<option value="' + (i + 1) + '"' + selected + '>' + RatingWidgets._options[i] + '</option>';
        }
        
        widget += '</select>';
        widget += '</div>';
        
        return widget;
    },
    
    // calculates the rating from the API into an average score
    calcRating: function(ratings) {
        //console.log('calc rating from API ratings:  ' + ratings);
        
        var average = 0;
        var numRatings = 0;
        var score = 0;
        
        // the API gives us an array of counts for each rating value; we skip the first which is 0
        for (var i = 1, ii = ratings.length; i < ii; i++) {
            var ratingCount = parseInt(ratings[i]);
            
            numRatings += ratingCount;
            score += (i * ratingCount);
        }
        
        // don't want to divide by zero, now do we
        if (numRatings > 0) {
            average = Math.round(score / numRatings)
        }
        
        return average;
    }
};



/* ! LikeWidget - Facebook Like button manipulation per video */

var LikeWidget = {
    
    
    _$widget: null,
    _url: '',
    _query: {},
    
    
    init: function($target) {
        // store the widget element reference
        LikeWidget._$widget = $target;
        
        
        // parse the URL values
        LikeWidget._parseSrcURL(LikeWidget._$widget.attr('src'));
        
        //console.log(LikeWidget._url);
        //console.log(LikeWidget._query);
    },
    
    _parseSrcURL: function(src) {
        var parts = src.split('?');
        
        LikeWidget._url = parts[0];
        
        
        // loop through the query string arguments
        var args = parts[1].split('&');
        //console.log(args);
        
        for (var i = 0, ii = args.length; i < ii; i++) {
            // convert each argument to a name value pair
            var pair = args[i].split('=');
            
            var name = decodeURIComponent(pair[0]);
            var value = decodeURIComponent(pair[1]);
            
            
            // store the named value
            LikeWidget._query[name] = value;
        }
    },
    
    updateEmbedCode: function(embedCode) {
        var url = LikeWidget._url;
        
        var args = [];
        for (var name in LikeWidget._query) {
            var append = '';
            if (name == 'href') {
                append = '?embedCode=' + embedCode;
            }
            
            args.push(encodeURIComponent(name) + '=' + encodeURIComponent(LikeWidget._query[name] + append));
        }
        
        url += '?' + args.join('&');
        
        //console.log(url);
        
        
        // update the widget element's SRC attribute
        LikeWidget._$widget.attr('src', url);
    }
};


// map expected callback function name for Player API to our handler
var receiveOoyalaPlayerEvent = VideoViewer.playerEvent;


// ! document ready initialization
jQuery(document).ready(function() {
    VideoViewer.init();
    ChannelSurfer.init();
})

