//  HULU CONFIDENTIAL MATERIAL. DO NOT DISTRIBUTE.
//  Copyright (C) 2009-2010 Hulu, LLC
//  All Rights Reserved
/**
 *
 * htvControls4.js
 *
 * Defines controls used by the Player UI.
 */
/*jslint maxerr: 1000, nomen: false, evil: false, immed: true, plusplus: false */
/*global LOG, describe */
var $htv;

$htv.Controls.PlayerInfoBar = function () {
    this.height = 0;
    this.width = 0;
    this.x = 0;
    this.y = 0;
    this.z = 0;
    this.className = "PlayerInfoBar";
    this.node = null;
    this.canvas = null;
    // platform ui components
    this.infoBarBlank = null;
    this.infoBarCCIcon = null;
    this.infoBarGloss = null;
    this.infoBarImage = null;
    this.infoBarPipe = null;
    this.infoBarStars = null;
    this.infoBarSubtitle = null;
    this.infoBarSubtitleContainer = null;
    this.infoBarTitle = null;
    this.infoBarTitleContainer = null;
    this.peekTimer = null;
    this.peekTime = -1;
    this.visible = false;
    this.has_captions = false;
    
    this.initialize = function (position, target, url, options) {
        this.height = position.height;
        this.width = position.width;
        this.x = position.x;
        this.y = position.y;
        this.z = position.z;
        this.node = target;
        this.peekTimer = $htv.Platform.createTimer(0, null, null);
        this.render();
    };
    
    // todo: positioning/scaling by this.position
    this.render = function () {
        if (this.infoBarBlank === null) {
            this.infoBarBlank = $htv.Platform.createImage({
                x: 47,
                y: 37,
                z: this.z + 2,
                width: 601,
                height: 91
            }, "images/info_bar_blank.png", this.canvas);
        }
        if (this.infoBarTitleContainer === null) {
            this.infoBarTitleContainer = $htv.Platform.createContainer({
                x: 210,
                y: 41,
                z: this.z + 3,
                width: 430,
                height: 85
            }, this.canvas, {vertical: true, spacing: 5, edgePadding: 0});
        } 
        if (this.infoBarTitle === null) {
            this.infoBarTitle = $htv.Platform.createLabel({
                x: 0,
                y: 0,
                z: this.z + 3,
                width: 428,
                height: 80
            }, "", this.canvas, { styleName: $htv.Styles.VideoInfoBarTitle });
            this.infoBarTitleContainer.addItem(this.infoBarTitle);
        } else {
            this.infoBarTitle.setText("");
        }
        
        if (this.infoBarImage === null) {
            this.infoBarImage = $htv.Platform.createImage({
                x: 53,
                y: 42,
                z: this.z + 3,
                width: 145,
                height: 80
            }, "", this.canvas);
        } else {
            this.infoBarImage.setURL("");
        }
        
        if (this.infoBarGloss === null) {
            this.infoBarGloss = $htv.Platform.createImage({
                x: 53,
                y: 41,
                z: this.z + 4,
                width: 593,
                height: 12
            }, "images/info_bar_gloss.png", this.canvas);
        }
        
        if (this.infoBarSubtitleContainer === null) {
            this.infoBarSubtitleContainer = $htv.Platform.createContainer({
                x: 2,
                y: 0,
                z: this.z + 3,
                width: 426,
                height: 25
            }, this.canvas, {vertical: false, spacing: 14, edgePadding: 0});
            this.infoBarTitleContainer.addItem(this.infoBarSubtitleContainer);
        }
        if (this.infoBarSubtitle === null) {
            this.infoBarSubtitle = $htv.Platform.createLabel({
                x: 0,
                y: 0,
                z: this.z + 3,
                width: 426,
                height: 25
            }, "", this.canvas, { styleName: $htv.Styles.VideoInfoBarSubtitle });
            this.infoBarSubtitleContainer.addItem(this.infoBarSubtitle);
        } else {
            this.infoBarSubtitle.setText("");
        }
        if (this.infoBarPipe === null) {
            this.infoBarPipe = $htv.Platform.createImage({
                x: 0,
                y: 0,
                z: this.z + 3,
                width: 1,
                height: 14
            }, "images/small_pipe.png", this.canvas);
            this.infoBarSubtitleContainer.addItem(this.infoBarPipe, {padding: {top: 3}, absolute_offset: {top : -1}});
        }
        if (this.infoBarStars === null) {
            this.infoBarStars = $htv.ControlPool.getObject("RatingStarsControl");
            this.infoBarStars.initialize({
                x: 0,
                y: 0,
                z: this.z + 3,
                width: 92,
                height: 16
            }, null, null, {canvas: this.canvas});
            this.infoBarSubtitleContainer.addItem(this.infoBarStars.getContainer(), {padding: {top: 1}, absolute_offset: {top : -1}});
        }
        if (this.infoBarCCIcon === null) {
            this.infoBarCCIcon = $htv.Platform.createImage({
                x: 0,
                y: 0,
                z: this.z + 3,
                width: 20,
                height: 14
            }, "images/cc-icon.png", this.canvas);
            this.infoBarSubtitleContainer.addItem(this.infoBarCCIcon, {padding: {top: 1}, absolute_offset: {top : 0}});
        }
        this.infoBarCCIcon.hide();
    };
    
    this.hide = function (peekMode) {
        if (peekMode !== true) {
            this.visible = false; // keeps its own state so it knows to not disappear during peek.
        }
        this.infoBarBlank.hide(250);
        this.infoBarImage.hide(250);
        this.infoBarGloss.hide(250);
        this.infoBarCCIcon.hide(250);
        this.infoBarPipe.hide();
        this.infoBarStars.hide();
        this.infoBarSubtitle.hide();
        this.infoBarTitle.hide();
        
        this.node.view.fireEvent("CONTROL_HIDDEN", {target: this.node});
    };
   
    this.peek = function (duration) {
        var now, hideTime;
        this.show(true);
        if (duration === null || duration === undefined) {
            duration = $htv.Constants.CONTROLS_PEEK_DURATION;
        }
        now = (new Date()).getTime();
        hideTime = now + duration;
        this.peekTime = Math.max(hideTime, this.peekTime);
        
        this.peekTimer.setCallback(this, this.peekTimerExpired);
        this.peekTimer.setInterval((this.peekTime - now));
        this.peekTimer.start();
    };
    
    this.peekTimerExpired = function () {
        this.peekTimer.stop();
        this.hide(true);
    };
    
    this.show = function (peekMode) {
        if (peekMode !== true) {
            this.visible = true; // keeps its own state so it knows to not disappear during peek.
        }
        this.infoBarBlank.show(250);
        this.infoBarImage.show(250);
        this.infoBarGloss.show(250);
        if (this.has_captions) {
            this.infoBarCCIcon.show(250);
        }
        this.infoBarPipe.show();
        this.infoBarStars.show();
        this.infoBarSubtitle.show();
        this.infoBarTitle.show();
        
        this.node.view.fireEvent("CONTROL_SHOWN", {target: this.node});
    };
    
    this.clearVideoMetadata = function () {
        this.infoBarTitle.setText("");
        this.infoBarSubtitle.setText("");
        this.infoBarImage.setURL("");
        this.infoBarStars.setRating(0);
        this.infoBarCCIcon.hide();
    };
    
    this.setVideoMetadata = function (videoMetadata) {
        if (videoMetadata.show_name !== videoMetadata.title) {
            this.infoBarTitle.setText(videoMetadata.show_name + ": " + videoMetadata.title);
        } else {
            this.infoBarTitle.setText(videoMetadata.title);
        }
        this.infoBarSubtitle.setText($htv.Utils.formatVideoSubtitle(videoMetadata));
        this.infoBarImage.setURL(videoMetadata.thumb_url);
        this.infoBarStars.setRating(videoMetadata.rating);
        this.has_captions = videoMetadata.has_captions;
        if (this.has_captions) {
            if (this.visible === true) {
                this.infoBarCCIcon.show();
            } else {
                this.infoBarCCIcon.hide();
            }
        }
        else {
            this.infoBarCCIcon.hide();
        }
    };
    
    this.focus = function () {
        
    };
    
    this.unfocus = function () {
        
    };
    
    this.dispose = function () {
        $htv.Platform.deleteItem(this.infoBarBlank);
        $htv.Platform.deleteItem(this.infoBarCCIcon);
        $htv.Platform.deleteItem(this.infoBarGloss);
        $htv.Platform.deleteItem(this.infoBarImage);
        $htv.Platform.deleteItem(this.infoBarPipe);
        this.infoBarStars.dispose();
        $htv.Platform.deleteItem(this.infoBarSubtitle);
        $htv.Platform.deleteItem(this.infoBarSubtitleContainer);
        $htv.Platform.deleteItem(this.infoBarTitle);
        $htv.Platform.deleteItem(this.infoBarTitleContainer);
        this.infoBarBlank = null;
        this.infoBarCCIcon = null;
        this.infoBarGloss = null;
        this.infoBarImage = null;
        this.infoBarPipe = null;
        this.infoBarStars = null;
        this.infoBarSubtitle = null;
        this.infoBarSubtitleContainer = null;
        this.infoBarTitle = null;
        this.infoBarTitleContainer = null;
        this.peekTimer = null;
    };
    
    this.handleEvent = function (eventName, eventData) {
        switch (eventName) {
        case "USER_INPUT":
            this.handleInput(eventData);
            break;
        case "PLAYER_METADATA_RECEIVED":
            this.setVideoMetadata(eventData.metadata);
            break;
        case "PLAYER_PLAYBACK_REQUESTED":
            this.clearVideoMetadata();
            break;
        default:
            
            break;
        }
    };
    
    this.handleInput = function (eventData) {
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        
        switch (eventData.action) {
        case "MOVE_UP":
           
            break;
        case "MOVE_LEFT":
            
            break;
        case "MOVE_RIGHT":
        
            break;
        case "MOVE_DOWN":
        
            break;
        case "PRESS_OK":
        
            break;
        default:
            
            break;
        }
    };
};

$htv.Controls.PlayerProgressBar = function () {
    this.height = 0;
    this.width = 0;
    this.x = 0;
    this.y = 0;
    this.z = 0;
    this.className = "PlayerProgressBar";
    this.node = null;
    this.canvas = null;
    // platform ui components
    this.progressBarBack = null;
    this.progressBarFull = null;
    this.progressBarTop = null;
    this.progressBarBottom = null;
    this.progressBarEmpty = null;
    this.progressBarGlossLeft1 = null;
    this.progressBarGlossLeft2 = null;
    this.progressBarGlossRight = null;
    this.adBreakDots = [];
    this.curTimeBackground = null;
    this.curTimeLabel = null;
    this.endTimeBackground = null;
    this.endTimeLabel = null;
    this.resumeLabel = null;
    this.resumeLabelTimer = $htv.Platform.createTimer(0, null, null);
    this.playlist = null; // todo: do i need to copy the playlist here?  maybe not..
    this.videoMetadata = null;
    this.peekTimer = $htv.Platform.createTimer(0, null, null);
    this.peekTime = -1;
    this.visible = false;
    this.currentTime = 0;
    
    this.initialize = function (position, target, url, options) {
        this.height = position.height;
        this.width = position.width;
        this.x = position.x;
        this.y = position.y;
        this.z = position.z;
        this.node = target;
        this.videoMetadata = {
            duration: 1000
        };
        this.currentTime = 0;
        
        this.render();
    };
    
    // todo: move positions to be relative to the control.
    this.render = function () {
        if (this.progressBarBack === null) {
            this.progressBarBack = $htv.Platform.createImage({
                x: 48,
                y: this.y + 37,
                z: this.z + 2,
                width: 864,
                height: 37
            }, "images/player-progress-back.png", this.canvas);
        }
     
        if (this.progressBarEmpty === null) {
            this.progressBarEmpty = $htv.Platform.createBox({
                x: 195,
                y: this.y,
                z: this.z + 3,
                width: 631,
                height: 39
            }, "PlayerProgressEmpty", this.canvas);
        }
        
        if (this.progressBarFull === null) {
            this.progressBarFull = $htv.Platform.createBox({
                x: 195,
                y: this.y + 2,
                z: this.z + 4,
                width: 0,
                height: 35
            }, "PlayerProgressFull", this.canvas);                
        }
        
        if (this.progressBarTop === null) {
            this.progressBarTop = $htv.Platform.createBox({
                x: 55,
                y: this.y,
                z: this.z + 4,
                width: 850,
                height: 2
            }, "PlayerProgressBar", this.canvas);                
        }
        
        if (this.progressBarBottom === null) {
            this.progressBarBottom = $htv.Platform.createBox({
                x: 49,
                y: this.y + 37,
                z: this.z + 4,
                width: 862,
                height: 2
            }, "PlayerProgressBar", this.canvas);                
        }
        
        while (this.adBreakDots.length > 0) { // no dots initially
            $htv.Platform.deleteItem(this.adBreakDots.pop());
        }
        
        if (this.curTimeBackground === null) {
            this.curTimeBackground = $htv.Platform.createImage({
                x: 100,
                y: this.y,
                z: this.z + 3,
                width: 95,
                height: 39
            }, "images/player-progress-elapsed.png", this.canvas);
        }
        
        if (this.curTimeLabel === null) {
            this.curTimeLabel = $htv.Platform.createLabel({
                x: 100,
                y: this.y + 9,
                z: this.z + 4,
                width: 93,
                height: 50
            }, "00:00", this.canvas, { styleName: $htv.Styles.ProgressBarTime });
        } else {
            this.curTimeLabel.setText("00:00");
        }
        
        if (this.endTimeBackground === null) {
            this.endTimeBackground = $htv.Platform.createImage({
                x: 816,
                y: this.y,
                z: this.z + 3,
                width: 96,
                height: 39
            }, "images/player-progress-total.png", this.canvas);
        }
        
        if (this.endTimeLabel === null) {
            this.endTimeLabel = $htv.Platform.createLabel({
                x: 818,
                y: this.y + 9,
                z: this.z + 4,
                width: 93,
                height: 50
            }, "00:00", this.canvas, { styleName: $htv.Styles.ProgressBarTime });
        } else {
            this.endTimeLabel.setText("00:00");
        }
        
        if (this.progressBarGlossLeft1 === null) {
            this.progressBarGlossLeft1 = $htv.Platform.createImage({
                x: 50,
                y: this.y + 2,
                z: this.z + 5,
                width: 49,
                height: 8
            }, "images/player-progress-gloss-left1.png", this.canvas);
        }
        
        if (this.progressBarGlossLeft2 === null) {
            this.progressBarGlossLeft2 = $htv.Platform.createImage({
                x: 101,
                y: this.y + 2,
                z: this.z + 5,
                width: 92,
                height: 7
            }, "images/player-progress-gloss-left2.png", this.canvas);
        }
        
        if (this.progressBarGlossRight === null) {
            this.progressBarGlossRight = $htv.Platform.createImage({
                x: 818,
                y: this.y + 2,
                z: this.z + 5,
                width: 92,
                height: 6
            }, "images/player-progress-gloss-right.png", this.canvas);
        }
        
        if (this.resumeLabel === null) {
            this.resumeLabel = $htv.Platform.createLabel({
                x: 203,
                y: this.y + 12,
                z: this.z + 5,
                width: 280,
                height: 50
            }, "", this.canvas, { styleName: $htv.Styles.ProgressBarResume });
        } 
    };
    
    this.updateProgress = function () {
        var currentTime = this.currentTime / 1000, currentWidth = 0;
        // catch undefined, null, or 0 duration
        if (this.videoMetadata.duration) {
            currentTime = Math.min(this.currentTime / 1000, this.videoMetadata.duration);
            currentWidth = Math.min(621, 621 * this.currentTime / 1000 / this.videoMetadata.duration);
        }
        
        this.progressBarFull.move({
            x: 195,
            y: this.y + 2,
            z: this.z + 4,
            width: currentWidth,
            height: 35
        });
        this.curTimeLabel.setText($htv.Utils.formatSecondsAsTimeCode(currentTime));
    };
    
    this.resetAdDotsColors = function () {
        var i;
        for (i = 0; i < this.adBreakDots.length; i++) {
            this.adBreakDots[i].setURL("images/ad-break-white.png");
        }
    };
    
    this.updateAdDotsColors = function (adBreakPos) {
        // Find the closest ad break dot (within 5s)
        
        var i = 0, minDiff = 5000, greenAdBreakIndex = -1;
        
        for (i = 0; i < this.adBreakDots.length; i++) {
            if (Math.abs(this.adBreakDots[i].pos - adBreakPos) < minDiff) {
                greenAdBreakIndex = i;
            }
        }
        
        for (i = 0; i < this.adBreakDots.length; i++) {
            if (i === greenAdBreakIndex) {
                this.adBreakDots[i].setURL("images/ad-break-green.png");
            }
            else {
                this.adBreakDots[i].setURL("images/ad-break-white.png");
            }
        }
    };
    
    this.renderAdDots = function () {
        // Only render if not already rendered and if duration has been received
        
        var dot, i, dotX;
        while (this.adBreakDots.length > 0) {
            $htv.Platform.deleteItem(this.adBreakDots.pop());
        }
        if (this.playlist.breaks) {
            
            for (i = 0; i < this.playlist.breaks.length; i++) {
                if (this.playlist.breaks[i].pos > 0 &&
                    this.playlist.breaks[i].pos < this.playlist.duration) {

                    
                    dotX = 195 - 12 + (621.0 * this.playlist.breaks[i].pos * 1.0 / this.playlist.duration);
                    dot = $htv.Platform.createImage({
                        x: dotX,
                        y: this.y + 8,
                        z: this.z + 5,
                        width: 24,
                        height: 23
                    }, "images/ad-break-white.png", this.canvas);
                    dot.pos = this.playlist.breaks[i].pos;
                    dot.hide();
                    this.adBreakDots.push(dot);
                }
            }
        }
    };
    
    this.updateSeekAdBreaks = function (start, end) {
        var i, startX, endX;
        startX = 195 - 12 + (621.0 * start / this.playlist.duration);
        endX = 195 - 12 + (621.0 * end / this.playlist.duration);
        for (i = 0; i < this.adBreakDots.length; i++) {
            // If ad break is in range
            if (this.adBreakDots[i].getPosition().x > startX &&
                this.adBreakDots[i].getPosition().x < endX &&
                // And is last ad break in range
                (i >= this.adBreakDots.length - 1 || this.adBreakDots[i + 1].getPosition().x > endX) &&
                // And accumulated threshold has been met
                $htv.Player.getAccumulatedPlaybackTime() >= $htv.Constants.AD_FREE_SEEK_PERIOD) {
                this.adBreakDots[i].setURL("images/ad-break-green.png");
            }
            else {
                this.adBreakDots[i].setURL("images/ad-break-white.png");
            }
        }
    };
    
    this.hide = function (peekMode) {
        var i;
        if (peekMode !== true) {
            this.visible = false; // keeps its own state so it knows to not disappear during peek.
        }
        this.progressBarBack.hide(250);        
        this.progressBarEmpty.hide(100);    // TODO: change to 250 once box tweening works
        this.progressBarFull.hide(100);
        this.progressBarTop.hide(100);
        this.progressBarBottom.hide(100);
        this.progressBarGlossLeft1.hide(250);
        this.progressBarGlossLeft2.hide(250);
        this.progressBarGlossRight.hide(250);
        for (i = 0; i < this.adBreakDots.length; i++) {
            this.adBreakDots[i].hide();
        }
        this.curTimeBackground.hide(250);
        this.curTimeLabel.hide();
        this.endTimeBackground.hide(250);
        this.endTimeLabel.hide();
        this.resumeLabel.hide();
        
        this.node.view.fireEvent("CONTROL_HIDDEN", {target: this.node});
    };
   
    this.peek = function (duration, clearPrevious) {
        var now, hideTime;
        this.show(true);
        if (duration === null || duration === undefined) {
            duration = $htv.Constants.CONTROLS_PEEK_DURATION;
        }
        now = (new Date()).getTime();
        hideTime = now + duration;
        if (clearPrevious === true) {
            this.peekTime = hideTime;
        }
        else {
            this.peekTime = Math.max(hideTime, this.peekTime);
        }
        
        this.peekTimer.setCallback(this, this.peekTimerExpired);
        this.peekTimer.setInterval((this.peekTime - now));
        this.peekTimer.start();
    };
    
    this.peekTimerExpired = function () {
        this.peekTimer.stop();
        if (this.visible !== true) {
            this.hide(true);
        } else {
            
        }
    };
    
    this.peekText = function (text, adBreakMaskWidth, textDuration, peekDuration) {
        textDuration = (textDuration === undefined ? 3500 : textDuration);
        peekDuration = (peekDuration === undefined ? 3000 : peekDuration);
        
        this.resumeLabel.setText(text);
        this.resumeLabelTimer.setCallback(this, this.peekTextHide);
        this.resumeLabelTimer.setInterval(textDuration);
        this.resumeLabelTimer.start();
        this.peek(peekDuration, true);
        for (var i = 0; i < this.adBreakDots.length; i++) {
            if (this.adBreakDots[i].getPosition().x < adBreakMaskWidth) {
                this.adBreakDots[i].hide();
                this.adBreakDots[i].masked = true;
            }
        }
    };
    
    this.peekTextHide = function () {
        this.resumeLabel.setText("");
        this.resumeLabelTimer.stop();
        for (var i = 0; i < this.adBreakDots.length; i++) {
            this.adBreakDots[i].masked = false;
        }
    };
    
    this.show = function (peekMode) {
        if (peekMode !== true) {
            this.visible = true; // keeps its own state so it knows to not disappear during peek.
        }
        this.progressBarBack.show(250);
        this.progressBarEmpty.show(250);
        this.updateProgress();
        
        this.progressBarFull.show(250);
        this.progressBarTop.show(250);
        this.progressBarBottom.show(250);
        for (var i = 0; i < this.adBreakDots.length; i++) {
            if (this.adBreakDots[i].masked !== true) {
                this.adBreakDots[i].show();
            }
        }
        this.curTimeBackground.show(250);
        this.curTimeLabel.show();
        this.endTimeBackground.show(250);
        this.endTimeLabel.show();
        this.resumeLabel.show();
        this.progressBarGlossLeft1.show(250);
        this.progressBarGlossLeft2.show(250);
        this.progressBarGlossRight.show(250);
        
        this.node.view.fireEvent("CONTROL_SHOWN", {target: this.node});
    };
    
    this.focus = function () {
        
    };
    
    this.unfocus = function () {
        
    };
    
    this.dispose = function () {
        $htv.Platform.deleteItem(this.progressBarBack);
        this.progressBarBack = null;
        $htv.Platform.deleteItem(this.progressBarEmpty);
        this.progressBarEmpty = null;
        $htv.Platform.deleteItem(this.progressBarFull);
        this.progressBarFull = null;
        $htv.Platform.deleteItem(this.progressBarTop);
        this.progressBarTop = null;
        $htv.Platform.deleteItem(this.progressBarBottom);
        this.progressBarBottom = null;
        $htv.Platform.deleteItem(this.progressBarGlossLeft1);
        this.progressBarGlossLeft1 = null;
        $htv.Platform.deleteItem(this.progressBarGlossLeft2);
        this.progressBarGlossLeft2 = null;
        $htv.Platform.deleteItem(this.progressBarGlossRight);
        this.progressBarGlossRight = null;
        while (this.adBreakDots.length > 0) {
            $htv.Platform.deleteItem(this.adBreakDots.pop());
        }
        $htv.Platform.deleteItem(this.curTimeBackground);
        this.curTimeBackground = null;
        $htv.Platform.deleteItem(this.curTimeLabel);
        this.curTimeLabel = null;
        $htv.Platform.deleteItem(this.endTimeBackground);
        this.endTimeBackground = null;
        $htv.Platform.deleteItem(this.endTimeLabel);
        this.endTimeLabel = null;
        $htv.Platform.deleteItem(this.resumeLabel);
        this.resumeLabel = null;
        this.videoMetadata = null;
    };
    
    this.handleEvent = function (eventName, eventData) {
        var i, durationTimeCode;
        switch (eventName) {
        case "USER_INPUT":
            this.handleInput(eventData);
            break;
        case "PLAYER_METADATA_RECEIVED":
            this.videoMetadata = eventData.metadata;
            durationTimeCode = $htv.Utils.formatSecondsAsTimeCode(this.videoMetadata.duration);
            this.endTimeLabel.setText(durationTimeCode);
            break;
        case "PLAYER_PLAYLIST_RECEIVED":
            this.playlist = eventData.playlist;
            this.renderAdDots();
            break;
        case "PLAYER_TIME_PROGRESS":
            this.currentTime = eventData.milliseconds;
            if (this.visible === true || this.peekTimer.running() === true) {
                this.updateProgress();
            }
            break;
        case "PLAYER_ADBREAK_PLAYING": 
            this.updateAdDotsColors(eventData.adBreakPos);
            break;
        case "PLAYER_QUALITY_CHANGED":
            this.peekText("Buffering...", 300);
            break;
        case "PLAYER_RESUMING":
            this.peekText("Resuming where you last left off...", 460);
            break;
        case "PLAYER_SEEKING":
            this.peekText("Seeking...", 260, 12000, 6000);
            break;
        case "PLAYER_SEEKING_TO_AD":
            this.peekText("Seeking...", 260);
            break;
        case "PLAYER_SEEK_COMPLETED":
            this.peekTextHide();
            break;
        default:
            
            break;
        }
    };
    
    this.handleInput = function (eventData) {
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        
        switch (eventData.action) {
        case "MOVE_UP":
           
            break;
        case "MOVE_LEFT":
            
            break;
        case "MOVE_RIGHT":
        
            break;
        case "MOVE_DOWN":
        
            break;
        case "PRESS_OK":
        
            break;
        default:
            
            break;
        }
    };
};

// doesn't explicitly hold focus but listens to events and renders.?
$htv.Controls.PlayerSeekControl = function () {
    this.aspect_ratio_str = "16x9";
    this.aspect_ratio_num = $htv.Utils.getAspectRatio(this.aspect_ratio_str);
    this.force_seek_preview_update = true;
    this.height = 0;
    this.width = 0;
    this.x = 0;
    this.y = 0;
    this.z = 0;
    this.className = "PlayerSeekControl";
    this.node = null;
    this.canvas = null;
    // platform ui components
    this.playArrow = null;
    this.seekBackground = null;
    this.seekFiller = null;
    this.seekImage = null;
    this.seekLabel = null;
    this.seekCursor = null;
    this.metadata = null;
    this.lastSeekImageTime = 0;
    
    this.initialize = function (position, target, url, options) {
        this.height = position.height;
        this.width = position.width;
        this.x = position.x;
        this.y = position.y;
        this.z = position.z;
        this.node = target;
        this.render();
    };
    
    // todo: positioning/scaling by this.position
    this.render = function () {
        if (this.seekBackground === null) {
            this.seekBackground = $htv.Platform.createImage({
                x: 0,
                y: 0,
                z: 0,
                width: 0,
                height: 0
            }, "", this.canvas);
        }
        this.seekBackground.hide();
        
        if (this.seekFiller === null) {
            this.seekFiller = $htv.Platform.createImage({
                x: 0,
                y: 0,
                z: 0,
                width: 0,
                height: 0
            }, "", this.canvas);
        }
        this.seekFiller.hide();
        
        if (this.seekImage === null) {
            this.seekImage = $htv.Platform.createImage({
                x: 0,
                y: 0,
                z: 0,
                width: 0,
                height: 0
            }, "", this.canvas);
        }
        this.seekImage.hide();
        
        if (this.playArrow === null) {
            this.playArrow = $htv.Platform.createImage({
                x: 960 / 2 - 66 / 2 + 8,
                y: 540 / 2 - 78 / 2 + 5,
                z: this.z + 2,
                width: 66,
                height: 78
            }, "images/play-arrow-preview-hover.png", this.canvas);
        }
        this.playArrow.hide();
        
        if (this.seekCursor === null) {
            this.seekCursor = $htv.Platform.createImage({
                x: -100,
                y: 437,
                z: this.z + 10,
                width: 6,
                height: 39
            }, "images/seek-preview-cursor.png", this.canvas);
        }
        this.seekCursor.hide();
        
        if (this.seekLabel === null) {
            // Base position off of this.seekImage
            this.seekLabel = $htv.Platform.createLabel({
                x: 291,
                y: 168 + 211 + 10,
                z: this.z + 3,
                width: 380,
                height: 40
            }, "", this.canvas, { styleName: $htv.Styles.SeekPreviewTime });
        } else {
            this.seekLabel.setText("");
        }
        this.seekLabel.hide();
    };
    
    this.hide = function () {
        this.playArrow.hide();
        this.seekBackground.hide();
        this.seekFiller.hide();
        this.seekImage.setURL("");
        this.seekImage.hide();
        this.seekCursor.hide();
        this.seekLabel.hide();
        this.node.view.fireEvent("CONTROL_HIDDEN", {target: this.node});
        
    };
    
    this.updatePreviewImagery = function () {
        if (this.force_seek_preview_update === true) {
            // Update the seek image.
            var MAX_IMAGE_WIDTH = 383,
                MAX_IMAGE_HEIGHT = 216,
                imageWidth = MAX_IMAGE_WIDTH,
                imageHeight = MAX_IMAGE_WIDTH / this.aspect_ratio_num,
                pillarBarWidth,
                seekFillerImage = "images/seek-preview-16-9-blank-back.png",
                seekBackgroundImage = "images/seek-preview-16-9-back.png";
                
            if (imageHeight > MAX_IMAGE_HEIGHT) {
                imageHeight = MAX_IMAGE_HEIGHT;
                imageWidth = MAX_IMAGE_HEIGHT * this.aspect_ratio_num;
            }
            pillarBarWidth = (MAX_IMAGE_WIDTH - imageWidth) / 2;
            this.seekImage.move({
                x: 291 + pillarBarWidth,
                y: 166,
                z: this.z + 1,
                width: imageWidth,
                height: imageHeight
            });

            // Update the seek filler.
            imageWidth = 386;
            imageHeight = 219;
            if (this.aspect_ratio_str === "4x3") {
                seekFillerImage = "images/seek-preview-4-3-blank-back.png";
                imageWidth = 294;
                imageHeight = 219;
            }
            this.seekFiller.move({
                x: 960 / 2 - imageWidth / 2 + 3,
                y: 540 / 2 - imageHeight / 2 + 3,
                z: this.z,
                width: imageWidth,
                height: imageHeight
            });
            this.seekFiller.setURL(seekFillerImage);

            // Update the seek background.
            if (this.aspect_ratio_str === "4x3") {
                seekBackgroundImage = "images/seek-preview-4-3-back.png";
            }
            this.seekBackground.move({
                x: 0,
                y: 0,
                z: this.z + 2,
                width: 960,
                height: 540
            });
            this.seekBackground.setURL(seekBackgroundImage);
            
            this.force_seek_preview_update = false;
        }
    };
    
    this.show = function () {
        this.updatePreviewImagery();
        
        this.playArrow.show();
        this.seekBackground.show();
        this.seekFiller.show();
        this.seekImage.show();
        this.seekCursor.show();
        this.seekLabel.show();
        this.node.view.fireEvent("CONTROL_SHOWN", {target: this.node});
    };
    
    this.updateSeekLabels = function (seekMilliseconds, overrideThrottle) {
        var seekXPosition, now;
        
        this.seekLabel.setText($htv.Utils.formatSecondsAsTimeCode(seekMilliseconds / 1000));
        this.seekLabel.show();
        this.seekCursor.show();
        seekXPosition = 195 - (0.5 * 6) + (621 * seekMilliseconds / 1000 / this.metadata.duration);
        this.seekCursor.move({
            x: seekXPosition,
            y: 440,
            z: this.z + 10,
            width: 6,
            height: 39
        });
        
        this.updatePreviewImagery();
        
        // Throttle image loads for the seek preview images
        // overrideThrottle should be true for seek preview starting, seek preview jumps, and when press-and-hold let go
        now = (new Date()).getTime(); 
        if (overrideThrottle || Math.abs(now - this.lastSeekImageTime) > 300) {
            this.lastSeekImageTime = now;
            this.seekImage.setURL($htv.Constants.Endpoints.iball + "/thumb?id=" + this.metadata.content_id + "&s=" + parseInt(seekMilliseconds * 0.001, 10));
        }
    };

    this.focus = function () {
        
    };
    
    this.unfocus = function () {
        
    };
    
    this.dispose = function () {
        $htv.Platform.deleteItem(this.playArrow);
        $htv.Platform.deleteItem(this.seekBackground);
        $htv.Platform.deleteItem(this.seekFiller);
        $htv.Platform.deleteItem(this.seekImage);
        $htv.Platform.deleteItem(this.seekCursor);
        $htv.Platform.deleteItem(this.seekLabel);
        this.playArrow = null;
        this.seekBackground = null;
        this.seekFiller = null;
        this.seekImage = null;
        this.seekCursor = null;
        this.seekLabel = null;
    };
    
    this.handleEvent = function (eventName, eventData) {
        switch (eventName) {
        case "USER_INPUT":
            this.handleInput(eventData);
            break;
        case "PLAYER_METADATA_RECEIVED":
            this.metadata = eventData.metadata;
            break;
        case "PLAYER_PLAYLIST_RECEIVED":
            if (this.aspect_ratio_str !== eventData.playlist.aspect_ratio) {
                this.aspect_ratio_str = eventData.playlist.aspect_ratio;
                this.aspect_ratio_num = $htv.Utils.getAspectRatio(this.aspect_ratio_str);
                this.force_seek_preview_update = true;
            }
            break;
        default:
            
            break;
        }
    };
    
    this.handleInput = function (eventData) {
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        
        switch (eventData.action) {
        case "MOVE_UP":
           
            break;
        case "MOVE_LEFT":
            
            break;
        case "MOVE_RIGHT":
        
            break;
        case "MOVE_DOWN":
        
            break;
        case "PRESS_OK":
        
            break;

        default:
            
            break;
        }
    };
};


$htv.Controls.PlayerClosedCaptions = function () {
    this.height = 0;
    this.width = 0;
    this.x = 0;
    this.y = 0;
    this.z = 0;
    this.className = "PlayerClosedCaptions";
    this.node = null;
    this.canvas = null;
    // platform ui components

    this.captionTextArea = null;
    this.captionTextShadow = null;
    this.captions = null;
    this.enc_iv = null;
    this.enc_key = null;
    this.enabled = false;
    this.nextCaptionIndex = 0;
    this.vOffset = 0;
    this.lastTextHeight = 0;
    this.lastTimeProgress = 0;
    this.transcriptsURL = null;
    this.isLoading = false;
    this.loadingtranscriptsURL = null;
    
    this.initialize = function (position, target, url, options) {
        this.height = position.height;
        this.width = position.width;
        this.x = position.x;
        this.y = position.y;
        this.z = position.z;
        this.node = target;
        this.vOffset = 0;
        this.lastTextHeight = this.height;
        this.render();
    };
    
    // todo: positioning/scaling by this.position
    this.render = function () {
        if (this.captionTextArea === null) {
            this.captionTextArea = $htv.Platform.createTextArea({
                x: this.x,
                y: this.y + this.vOffset + this.height - this.lastTextHeight,
                z: this.z + 1,
                width: this.width,
                height: this.height
            }, "", this.canvas, {center: true, styleName: $htv.Styles.ClosedCaptions});
        }
        this.captionTextArea.hide();
        if (this.captionTextShadow === null) {
            this.captionTextShadow = $htv.Platform.createTextArea({
                x: this.x + 2,
                y: this.y + this.vOffset + this.height - this.lastTextHeight + 2,
                z: this.z,
                width: this.width,
                height: this.height
            }, "", this.canvas, {center: true, styleName: $htv.Styles.ClosedCaptionsShadow});
        }
        this.captionTextShadow.hide();        
    };
    
    this.hide = function () {
        this.captionTextArea.hide();
        this.captionTextShadow.hide();
        this.node.view.fireEvent("CONTROL_HIDDEN", {target: this.node});
    };
    
    this.show = function () {
        this.captionTextArea.show();
        this.captionTextShadow.show();
        this.node.view.fireEvent("CONTROL_SHOWN", {target: this.node});
    };
    
    this.enable = function () {
        this.enabled = true;
        // if captions not already loaded and a transcripts url exists, load
        // NOTE: deejay only returns a transcripts url if the video metadata has_captions
        if (this.captions === null && !$htv.Utils.stringIsNullOrEmpty(this.transcriptsURL)) {
            this.makeTranscriptsRequest(this.transcriptsURL);
        }
    };
    
    this.disable = function () {
        this.enabled = false;
        this.clearCaptionText();
    };

    this.reposition = function () {
        this.captionTextArea.move({
            x: this.x,
            y: this.y + this.vOffset + this.height - this.lastTextHeight,
            z: this.z + 1,
            width: this.width,
            height: this.height
        });
        this.captionTextShadow.move({
            x: this.x + 2,
            y: this.y + this.vOffset + this.height - this.lastTextHeight + 2,
            z: this.z,
            width: this.width,
            height: this.height
        });
    };
    
    this.setVerticalOffset = function (offset) {
        this.vOffset = offset;
        this.reposition();
    };
    
    this.clearVerticalOffset = function () {
        this.setVerticalOffset(0);
    };
    
    this.makeTranscriptsRequest = function (url) {
        if ($htv.Utils.stringIsNullOrEmpty(url)) {
            
            this.isLoading = false;
        }
        else {
            if (this.isLoading === false || this.loadingtranscriptsURL !== this.transcriptURL) {
                
                this.loadingtranscriptsURL = this.transcriptURL;
                this.isLoading = true;
                $htv.Platform.loadURL(url, this, this.transcriptsRequestResult, {
                    xmlparse: true,
                    errorCallback: this.SMIRequestError
                });
            } else {
                
            }
        }
    };
    
    this.transcriptsRequestResult = function (responseXML, options) {
        
        if (responseXML) {
            this.makeSMIRequest($htv.Platform.evaluateXPathString(responseXML, "transcripts/en"));
        } else {
            this.SMIRequestError("responseXML was undefined or null");
        }
    };
    
    this.makeSMIRequest = function (url) {
        if ($htv.Utils.stringIsNullOrEmpty(url)) {
            
            this.isLoading = false;
        }
        else {
            
            $htv.Platform.loadURL(url, this, this.SMIRequestResult, {
                xmlparse: true,
                errorCallback: this.SMIRequestError
            });
        }
    };
    
    this.SMIRequestResult = function (responseXML, options) {
        
        // todo : check error result
        if (responseXML) {
            this.captions = $htv.Utils.getCaptionData(responseXML);
            this.ensureAscending(this.captions);
            this.node.view.fireEvent("CAPTIONS_INITIALIZED", {});
            this.isLoading = false;
        } else {
            this.SMIRequestError("responseXML was undefined or null");
        }
    };
    
    this.SMIRequestError = function (errorMessage) {
        this.isLoading = false;
        
    };
    
    this.ensureAscending = function (captions) {
        if (captions && captions.length > 0) {
            var j, lastCaptionTime = captions[captions.length - 1].time;
            for (j = captions.length - 2; j >= 0; j--) {
                if (captions[j].time > lastCaptionTime) {
                    
                    captions[j].encrypted = false;
                    captions[j].text = "";
                    continue;
                }
                lastCaptionTime = captions[j].time;
            }
        }
    };
    
    this.handleTimeProgress = function (milliseconds) {
        if (this.enabled && this.captions !== null) {
            if (this.nextCaptionIndex < 0) {
                this.nextCaptionIndex = 0;
            }
            if (this.nextCaptionIndex >= this.captions.length) {
                this.nextCaptionIndex = this.captions.length - 1;
            }
            
            if (Math.abs(milliseconds - this.lastTimeProgress) > 5000) {
                
                var targetCaptionIndex = this.nextCaptionIndex;
                if (milliseconds < this.lastTimeProgress) {
                    
                    while (this.captions[targetCaptionIndex].time > milliseconds) {
                        if (targetCaptionIndex === 0) {
                            break;
                        }
                        targetCaptionIndex--;
                    }
                } else {
                    
                    while (this.captions[targetCaptionIndex].time < milliseconds) {
                        if (targetCaptionIndex === this.captions.length - 1) {
                            break;
                        }
                        targetCaptionIndex++;
                    }
                    targetCaptionIndex--;
                }
                
                this.nextCaptionIndex = targetCaptionIndex;
            }
            try {
                while (this.nextCaptionIndex < this.captions.length - 1 &&
                this.captions[this.nextCaptionIndex].time < milliseconds) {
                
                    this.showCaption(this.captions[this.nextCaptionIndex]);
                    this.nextCaptionIndex++;
                }
            } catch (e) {
                
            }
            this.lastTimeProgress = milliseconds;
        }
    };
    
    /*jslint regexp: false */
    this.showCaption = function (caption) {
        var text = "";
        describe(caption);
        try {
            // Decrypt caption, saving the result
            if (caption.encrypted) {
                caption.text = this.decryptCaptionText(caption.text);
                caption.encrypted = false;
            }
            text = caption.text;
            // Convert <BR/> to \n
            text = text.replace(/<br\s*\/\s*>/gi, "\n");
            // Misc conversions
            text = text.split("&amp;").join("&").split("&quot;").join("\"").split("&apos;").join("'");
            // Strip remaining tags
            text = text.replace(/<\S[^><]*>/g, "");
            // If no unicode support, strip unicode tokens 
            if ($htv.Platform.properties.has_unicode === false) {
                text = text.replace(/&\S*;/g, " ");
            }
            
        } 
        catch (e) {
            
            describe(e);
            text = "";
        }
        // Hiding to prevent text flicker on Samsung
        this.captionTextArea.hide();
        this.captionTextShadow.hide();
        this.captionTextArea.setText(text);
        this.captionTextShadow.setText(text);
        this.lastTextHeight = this.captionTextArea.getTextDimensions().textHeight;
        this.reposition();
        this.captionTextArea.show();
        this.captionTextShadow.show();
    };
    /*jslint regexp: true */
    /*jslint bitwise: false */
    this.decryptCaptionText = function (captionText) {
        var key, iv, ct, result, i;
        if (this.enc_iv === null) {
            key = $htv.Libs.Crypto.util.hexToBytes("625298045c1db17fe3489ba7f1eba2f208b3d2df041443a72585038e24fc610b");
            for (i = 0; i < key.length; i++) {
                key[i] = key[i] ^ 42;
            }
            iv = "V@6i`q6@FTjdwtui";
            iv = $htv.Libs.Crypto.charenc.UTF8.stringToBytes(iv);
            for (i = 0; i < iv.length; i++) {
                iv[i] = iv[i] ^ 1;
            }
            this.enc_key = $htv.Libs.Crypto.util.bytesToHex(key);
            this.enc_iv = $htv.Libs.Crypto.util.bytesToHex(iv);
        }
        result = $htv.Platform.decryptAES(captionText, this.enc_key, this.enc_iv);
        return $htv.Libs.Crypto.charenc.UTF8.bytesToString(result);
    };
    /*jslint bitwise: true */
    this.focus = function () {
        
    };
    
    this.unfocus = function () {
        
    };
    
    this.dispose = function () {
        $htv.Platform.deleteItem(this.captionTextArea);
        $htv.Platform.deleteItem(this.captionTextShadow);
        this.captionTextArea = null;
        this.captionTextShadow = null;
        this.captions = null;
        this.transcriptsURL = null;
    };
    
    this.clearCaptionText = function () {
        this.captionTextArea.setText("");
        this.captionTextShadow.setText("");
    };
    
    this.handleEvent = function (eventName, eventData) {
        switch (eventName) {
        case "USER_INPUT":
            this.handleInput(eventData);
            break;
        case "PLAYER_PLAYLIST_RECEIVED":
            // clear previous video caption
            this.clearCaptionText();
            
            // if this is a new video and captions exist, try to load the captions
            if (this.transcriptsURL !== eventData.playlist.transcripts) {
                // null the captions to indicate not yet loaded
                this.captions = null;
                
                this.transcriptsURL = eventData.playlist.transcripts;
                
            }
            
            if (this.enabled === true) {
                this.enable();
            }
            break;
        case "PLAYER_TIME_PROGRESS":
            this.handleTimeProgress(eventData.milliseconds);
            break;
        case "PLAYER_ADBREAK_PLAYING":
            this.clearCaptionText();
            break;
        case "PLAYER_PLAYBACK_FINISHED":
            this.clearCaptionText();
            break;
        default:
            
            break;
        }
    };
    
    this.handleInput = function (eventData) {
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        
        switch (eventData.action) {
        case "MOVE_UP":
           
            break;
        case "MOVE_LEFT":
            
            break;
        case "MOVE_RIGHT":
        
            break;
        case "MOVE_DOWN":
        
            break;
        case "PRESS_OK":
        
            break;

        default:
            
            break;
        }
    };
};

$htv.Controls.PlayerQualityPopup = function () {
    this.height = 0;
    this.width = 0;
    this.x = 0;
    this.y = 0;
    this.z = 0;
    this.className = "PlayerQualityPopup";
    this.node = null;
    this.canvas = null;
    this.activeIndex = 0;
    this.background = null;
    this.buttons = [];
    this.text = null;
    this.bitrates = [];
    this.autoswitchAvailable = false;
    
    this.initialize = function (position, target, url, options) {
        this.height = position.height;
        this.width = position.width;
        this.x = position.x;
        this.y = position.y;
        this.z = position.z;
        this.node = target;
        this.activeIndex = 0;
        if (options && options.hasOwnProperty("autoswitch")) {
            this.autoswitchAvailable = options.autoswitch;
        }
        this.render();
    };
    
    // todo: positioning/scaling by this.position
    this.render = function () {
        if (this.background === null) {
            this.background = $htv.Platform.createImage({
                x: 0,
                y: 0,
                z: this.z,
                width: 960,
                height: 540
            }, "images/player_quality_back.png", this.canvas);
        }
        
        if (this.text === null) {
            this.text = $htv.Platform.createLabel({
                x: 376,
                y: 185,
                z: this.z + 1,
                width: 208,
                height: 30
            }, "Video Quality", this.canvas, { styleName: $htv.Styles.VideoQualityTitle });
        }
    };
  

    var PREFERRED_BITRATES = [3200, 2000, 1000, 650, 2500, 1500];
    this.setButtons = function (allBitrates, currentBitrate) {
        var i, yPosition, button, buttonText, bitrate, brStr, fStr;
        yPosition = 225;
        i = 0;

        this.bitrates = [];
        if (currentBitrate !== -1) {
            this.bitrates.push(currentBitrate);
        }

        //pick 3 more bitrates, choosing the most preferred first
        while ((this.bitrates.length < 4) && (i < PREFERRED_BITRATES.length)) {
            if ((allBitrates.indexOf(PREFERRED_BITRATES[i]) >= 0) && (PREFERRED_BITRATES[i] !== currentBitrate)) {
                this.bitrates.push(PREFERRED_BITRATES[i]);
            }
            i += 1;
        }
        this.bitrates.sort(function (a, b) {
            return b - a;
        });
        if (this.autoswitchAvailable === true) {
            this.bitrates.splice(0, 0, -1);
            if (this.bitrates.length > 4) {
                this.bitrates.pop();
            }
        }

        for (i = 0; i < this.bitrates.length; i++) {
            if (i < this.buttons.length) {
                button = this.buttons[i];
            } else {
                button = $htv.ControlPool.getObject("ButtonControl");
                this.buttons.push(button);
            }
            
            bitrate = this.bitrates[i];
            if (bitrate === -1) {
                buttonText = "Auto";
            } else if (bitrate >= 1000) {
                bitrate /= 1000.0;
                
                // Number.toFixed does not exist in AS.
                brStr = bitrate.toString();
                fStr = brStr.substr(0, brStr.indexOf('.') + 2);
                
                buttonText = ((bitrate === 1) ? "SD" : "HD") + " (" + fStr + " Mb/s)";
            } else {
                buttonText = "SD (" + bitrate + " kb/s)";
            }
            
            button.initialize({
                x: 420,
                y: yPosition,
                z: this.z + 1,
                width: 120,
                height: 30
            }, null, null, {
                text: buttonText,
                focused_style: $htv.Styles.VideoQualityPopupButtonFocused,
                unfocused_style: $htv.Styles.VideoQualityPopupButtonUnfocused
            });
            if (this.bitrates[i] === currentBitrate) {
                this.activeIndex = i;
                button.focus();
            }
            button.hide();
            
            yPosition += 35;
        }
        while (this.buttons.length > this.bitrates.length) {
            this.buttons.pop().dispose();
        }
    };

    this.updateActiveIndex = function (bitrate) {
        var i = 0;
        while ((i < this.bitrates.length) && (this.bitrates[i] !== bitrate)) {
            i++;
        }
        if (i < this.buttons.length) {
            this.buttons[this.activeIndex].unfocus();
            this.activeIndex = i;
            this.buttons[this.activeIndex].focus();
        }
    };

    this.hide = function () {
        this.background.hide();
        this.text.hide();
        for (var i = 0; i < this.buttons.length; i++) {
            this.buttons[i].hide();
        }
        
        this.node.view.fireEvent("CONTROL_HIDDEN", {target: this.node});
    };
    
    this.show = function () {
        this.background.show();
        this.text.show();
        for (var i = 0; i < this.buttons.length; i++) {
            this.buttons[i].show();
        }
        this.node.view.fireEvent("CONTROL_SHOWN", {target: this.node});
    };
    
    this.focus = function () {
        this.buttons[this.activeIndex].focus();
    };
    
    this.unfocus = function () {
        this.buttons[this.activeIndex].unfocus();
    };
    
    this.dispose = function () {
        $htv.Platform.deleteItem(this.background);
        this.background = null;
        $htv.Platform.deleteItem(this.text);
        this.text = null;
        while (this.buttons.length > 0) {
            this.buttons.pop().dispose();
        }
        this.autoswitchAvailable = false;
    };
    
    this.handleEvent = function (eventName, eventData) {
        if (eventName === "USER_INPUT") {
            this.handleInput(eventData);
        } else {
            
        }
    };
    
    this.handleInput = function (eventData) {
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        
        switch (eventData.action) {
        case "MOVE_UP":
            if (this.activeIndex > 0) {
                this.buttons[this.activeIndex].unfocus();
                this.activeIndex--;
                this.buttons[this.activeIndex].focus();
            }
            break;
        case "MOVE_LEFT":
            break;
        case "MOVE_RIGHT":
            break;
        case "MOVE_DOWN":
            if (this.activeIndex < this.buttons.length - 1) {
                this.buttons[this.activeIndex].unfocus();
                this.activeIndex++;
                this.buttons[this.activeIndex].focus();
            }        
            break;
        case "KEY_RETURN":
            this.node.view.fireEvent("RETURN_KEY_PRESSED", {target: this.node});
            break;
        case "KEY_EXIT": 
            this.node.view.fireEvent("EXIT_KEY_PRESSED", {target: this.node});
            break;
        case "PRESS_OK":
            this.node.view.fireEvent("QUALITY_CHANGE_REQUESTED", {
                quality: this.bitrates[this.activeIndex]
            });
            break;
        default:
            
            break;
        }
    };
};

$htv.Controls.VolumeIndicator = function () {
    this.height = 0;
    this.width = 0;
    this.x = 0;
    this.y = 0;
    this.z = 0;
    this.node = null;
    this.className = "VolumeIndicator";
    this.visible = true;
    this.indicatorBackgroundPosition = null;
    this.indicatorBackground = null;
    this.volumeBarPosition = null;
    this.volumeBar = null;
    this.volumeBarSliverPosition = null;
    this.volumeBarSliver = null;
    this.volumeIconPosition = null;
    this.volumeIcon = null;
    this.canvas = null;
    this.initialized = false;
    
    this.previousVolumeIcon = null;
    this.previousVolumeLevel = null;
    
    this.peekTimer = $htv.Platform.createTimer(0, null, null);
    this.peekTime = -1;
    
    this.PEEK_DURATION = 2000;
    this.VOLUME_CONTROL_X_POSITION = 960 - 105;
    this.VOLUME_CONTROL_Y_POSITION = 540 - 295;
    this.VOLUME_ICON_WIDTH = 19;
    this.VOLUME_ICON_HEIGHT = 12;
    this.VOLUME_BACKGROUND_WIDTH = 34;
    this.VOLUME_BACKGROUND_HEIGHT = 170;
    this.HEIGHT_OF_ICON_BOX = 24;
    
    this.initialize = function (position, target, url, options) {
        this.height = position.height;
        this.width = position.width;
        this.x = position.x;
        this.y = position.y;
        this.z = position.z;
        this.node = target;
        this.indicatorBackgroundPosition = {
            x: this.VOLUME_CONTROL_X_POSITION,
            y: this.VOLUME_CONTROL_Y_POSITION,
            z: this.z + 20,
            width: this.VOLUME_BACKGROUND_WIDTH,
            height: this.VOLUME_BACKGROUND_HEIGHT
        };
        this.volumeBarPosition = {
            x: 0,
            y: 0,
            z: this.z + 21,
            width: 0,
            height: 0
        };
        this.volumeBarSliverPosition = {
            x: 0,
            y: 0,
            z: this.z + 21,
            width: 0,
            height: 0
        };
        this.volumeIconPosition = {
            x: this.VOLUME_CONTROL_X_POSITION + this.VOLUME_BACKGROUND_WIDTH / 2 - this.VOLUME_ICON_WIDTH / 2,
            y: this.VOLUME_CONTROL_Y_POSITION + this.VOLUME_BACKGROUND_HEIGHT - this.HEIGHT_OF_ICON_BOX / 2 - this.VOLUME_ICON_HEIGHT / 2,
            z: this.z + 21,
            width: this.VOLUME_ICON_WIDTH,
            height: this.VOLUME_ICON_HEIGHT
        };
        if (this.initialized === false) { //  there can only be one
            if (options.hasOwnProperty("canvas")) {
                this.canvas = options.canvas;
            }
            
            this.indicatorBackground = $htv.Platform.createImage(this.indicatorBackgroundPosition, "images/volume-back.png", this.canvas);
            this.volumeBar = $htv.Platform.createBox(this.volumeBarPosition, "VolumeIndicatorFilled", this.canvas);
            this.volumeBarSliver = $htv.Platform.createImage(this.volumeBarSliverPosition, "images/volume-fill.jpg", this.canvas);
            this.volumeIcon = $htv.Platform.createImage(this.volumeIconPosition, "images/volume-icon.png", this.canvas);
            this.indicatorBackground.hide();
            this.volumeBar.hide();
            this.volumeBarSliver.hide();
            this.volumeIcon.hide();
            
            this.updateVolumeIndicator();
            
            $htv.Controller.addEventListener("VOLUME_CHANGED", this);
            
            this.initialized = true;
        }
    };
    
    this.dispose = function () {
        $htv.Platform.deleteItem(this.indicatorBackground);
        this.indicatorBackground = null;
        $htv.Platform.deleteItem(this.volumeBar);
        this.volumeBar = null;
        $htv.Platform.deleteItem(this.volumeBarSliver);
        this.volumeBarSliver = null;
        $htv.Platform.deleteItem(this.volumeIcon);
        this.volumeIcon = null;
        this.volumeBarSliverPosition = null;
        this.volumeIconPosition = null;
        this.volumeBarPosition = null;
        this.indicatorBackgroundPosition = null;
        this.initialized = false;
        this.previousVolumeIcon = null;
        this.previousVolumeLevel = null;
    };
    
    this.focus = function () {
    
    };
    
    this.unfocus = function () {
    
    };
    
    this.hide = function () {
        this.visible = false;
        this.indicatorBackground.hide();
        this.volumeBar.hide();
        this.volumeBarSliver.hide();
        this.volumeIcon.hide();
    };
    
    this.show = function () {
        this.visible = true;
        this.indicatorBackground.show();
        this.volumeBar.show();
        this.volumeBarSliver.show();
        this.volumeIcon.show();
    };
    
    this.peek = function (duration) {
        var now, hideTime;
        this.show();
        if (duration === null || duration === undefined) {
            duration = $htv.Constants.CONTROLS_PEEK_DURATION;
        }
        now = (new Date()).getTime();
        hideTime = now + duration;
        this.peekTime = Math.max(hideTime, this.peekTime);
        
        this.peekTimer.setCallback(this, this.peekTimerExpired);
        this.peekTimer.setInterval((this.peekTime - now));
        this.peekTimer.start();
    };
    
    this.peekTimerExpired = function () {
        this.peekTimer.stop();
        this.hide();
    };
    
    this.updateVolumeIndicator = function () {
        var height, isMuted, volumeIcon, volumeIconArray, volumeLevel;
        
        isMuted = $htv.Platform.isMuted();
        volumeLevel = $htv.Platform.getVolume();
        
        if (this.previousVolumeLevel === null || this.previousVolumeLevel !== volumeLevel) {
            height = (this.VOLUME_BACKGROUND_HEIGHT - this.HEIGHT_OF_ICON_BOX - 2) * volumeLevel;
            this.volumeBar.move({
                x: this.VOLUME_CONTROL_X_POSITION + 2,
                y: this.VOLUME_CONTROL_Y_POSITION + (this.VOLUME_BACKGROUND_HEIGHT - this.HEIGHT_OF_ICON_BOX - height),
                z: this.z + 21,
                width: 30,
                height: height
            });
            if (this.previousVolumeLevel === null || (this.previousVolumeLevel >= 1 && volumeLevel < 1) || (this.previousVolumeLevel < 1 && volumeLevel <= 1)) {
                this.volumeBarSliver.move({
                    x: this.VOLUME_CONTROL_X_POSITION + 2,
                    y: this.VOLUME_CONTROL_Y_POSITION + (this.VOLUME_BACKGROUND_HEIGHT - this.HEIGHT_OF_ICON_BOX) - 1,
                    z: this.z + 21,
                    width: 30,
                    height: (height < 1) ? 0 : 1
                });
            }
        }
        
        if (isMuted === true) {
            volumeIcon = 0;
        } else if (volumeLevel === 0) {
            volumeIcon = 1;
        } else if (volumeLevel < 0.33) {
            volumeIcon = 2;
        } else if (volumeLevel < 0.67) {
            volumeIcon = 3;
        } else {
            volumeIcon = 4;
        }
        
        if (this.previousVolumeIcon === null || this.previousVolumeIcon !== volumeIcon) {
            volumeIconArray = [];
            volumeIconArray[0] = "images/volume-icon-mute.png";
            volumeIconArray[1] = "images/volume-icon.png";
            volumeIconArray[2] = "images/volume-icon-1.png";
            volumeIconArray[3] = "images/volume-icon-2.png";
            volumeIconArray[4] = "images/volume-icon-3.png";
            this.volumeIcon.setURL(volumeIconArray[volumeIcon]);
        }
        
        this.previousVolumeIcon = volumeIcon;
        this.previousVolumeLevel = volumeLevel;
    };
    
    this.handleEvent = function (eventName, eventData) {
        if (eventName === "VOLUME_CHANGED") {
            this.peek(this.PEEK_DURATION);
            this.updateVolumeIndicator();
        } else {
            
            describe(eventData);
        }
    };
};
