//  HULU CONFIDENTIAL MATERIAL. DO NOT DISTRIBUTE.
//  Copyright (C) 2009-2010 Hulu, LLC
//  All Rights Reserved
/**
 *
 * htvControls3.js
 *
 * Defines controls used by the thumbnail carousels.
 */

/*jslint maxerr: 1000, nomen: false, evil: false, immed: true, plusplus: false */
/*global LOG, describe */
var $htv;

$htv.Controls.BaseThumbnailCarousel = function () {
    this.className = "BaseThumbnailCarousel";
    this.node = null;
    this.height = 0;
    this.width = 0;
    this.x = 0;
    this.y = 0;
    this.z = 0;
    // todo: alphabetize for clarity?
    this.items = null;
    this.displayItems = null;
    this.displayPositions = null;
    this.displayPositionsUnfocused = null;
    this.reflectionItems = null;
    this.reflectionPositions = null;
    this.reflectionPositionsUnfocused = null;
    this.dataWaiting = false;
    this.visible = false; // for purposes of avoiding image artifacts
    this.carousel_item_type = "";
    this.canvas = null;
    this.activeIndex = 0;
    this.add_cb = false;
    this.login_required = false;
    this.recommended_required = false;
    this.hasFocus = false;
    this.itemFields = ['title', 'cmtype'];
    this.startAtEnd = false;
    this.show_id = 0;
    this.show_canonical_name = "";
    this.carouselLabelPosition = null;
    this.carouselLabel = null;
    this.loadingLabelPosition = null;
    this.loadingLabel = null;
    this.showImage = null;
    this.last_show_thumb_id = 0;
    this.leftBracket = null;
    this.rightBracket = null;
    this.delayedStartTimer = null;
    this.delayedJumpTimer = null;
    this.url = null;
    this.downArrow = null;
    this.initialized = false;
    this.include_show_title = false;
    this.show_actual_total = false;
    this.companyBugUrl = "";
    this.companyBug = null;
    this.countLabelPosition = null;
    this.show_name = "";
    this.selectedItemIndex = 0;
    this.disable_down_override = false;
    this.use_related_title = false;
    this.video_title = "";
    this.package_id = null;
    this.SELECTED_WIDTH = 300;
    this.SELECTED_HEIGHT = this.SELECTED_WIDTH * 9 / 16;
    this.UNSELECTED_WIDTH = 145;
    this.UNSELECTED_HEIGHT = 80; // NOTE: technically not 145 * 9 / 16
    this.REFLECTION_WIDTH = 145;
    this.REFLECTION_HEIGHT = 35;
    this.SELECTED_REFLECTION_WIDTH = 300;
    this.SELECTED_REFLECTION_HEIGHT = 72;
    this.REFLECTION_ALPHA_TOP = 0.2;
    this.TWDUR_MOVE = 400;
};

$htv.Controls.BaseThumbnailCarousel.prototype._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.visible = true; // true when initialized
    this.displayItems = [null, null, null, null, null, null, null];
    this.displayPositions = new Array(this.displayItems.length);
    this.displayPositionsUnfocused = new Array(this.displayItems.length);
    this.reflectionItems = [null, null, null, null, null, null, null];
    this.reflectionPositions = new Array(this.reflectionItems.length);
    this.reflectionPositionsUnfocused = new Array(this.reflectionItems.length);
    
    this.dataWaiting = false;
    this.hasFocus = false;
    this.login_required = false;
    this.recommended_required = false;
    this.activeIndex = 0;
    this.startAtEnd = false;
    this.show_id = 0;
    this.show_name = "";
    this.show_canonical_name = "";
    this.last_show_thumb_id = 0;
    this.initialized = false;
    this.include_show_title = false;
    this.show_actual_total = false;
    this.disable_down_override = false;
    this.video_title = "";
    this.use_related_title = false;
    this.add_cb = false;
    this.package_id = null;

    if (options.hasOwnProperty("canvas")) {
        this.canvas = options.canvas;
    }
    if (options.hasOwnProperty("carousel_name") && !$htv.Utils.stringIsNullOrEmpty(options.carousel_name)) {
        this.carousel_name = options.carousel_name;
    }
    if (options.hasOwnProperty("carousel_item_type") && typeof(options.carousel_item_type) !== "undefined" && !$htv.Utils.stringIsNullOrEmpty(options.carousel_item_type)) {
        this.carousel_item_type = options.carousel_item_type;
    }
    if (options.hasOwnProperty("login_required") && (options.login_required === true || parseInt(options.login_required, 10) === 1)) {
        this.login_required = true;
    }
    if (options.hasOwnProperty("add_cb") && (parseInt(options.add_cb, 10) === 1)) {
        this.add_cb = true;
    }
    if (options.hasOwnProperty("recommended_required") && (options.recommended_required === true || parseInt(options.recommended_required, 10) === 1)) {
        this.recommended_required = true;
    }
    if (options.hasOwnProperty("include_show_title") && (options.include_show_title === true || parseInt(options.include_show_title, 10) === 1)) {
        this.include_show_title = true;
    }
    if (options.hasOwnProperty("show_actual_total") && (options.show_actual_total === true)) {
        this.show_actual_total = true;
    }
    if (options.hasOwnProperty("disable_down_override") && (options.disable_down_override === true)) {
        this.disable_down_override = true;
    }
    if (options.hasOwnProperty("start_at_end")) {
        this.startAtEnd = (options.start_at_end === true);
    }
    if (options.hasOwnProperty("show_canonical_name") && options.show_canonical_name !== undefined) {
        this.show_canonical_name = options.show_canonical_name;
    }
    // are these checks redundant?
    if (options.hasOwnProperty("show_id") && options.show_id) {
        this.show_id = parseInt(options.show_id, 10);
    }
    if (options.hasOwnProperty("show_name") && options.show_name) {
        this.show_name = options.show_name;
    }
    if (options.hasOwnProperty("video_title") && options.video_title) {
        this.video_title = options.video_title;
    }
    if (options.hasOwnProperty("use_related_title") && (options.use_related_title || parseInt(options.use_related_title, 10) === 1)) {
        this.use_related_title = true;
    }
    if (options.hasOwnProperty("package_id") && options.package_id !== undefined) {
        this.package_id = options.package_id;
    }    
    /*jslint onevar: false */
    var i, numItems, selectedMargin, unselectedMargin, centerY;
    numItems = 7;
    selectedMargin = 48;
    unselectedMargin = 22;
    centerY = this.y;
    
    this.selectedItemIndex = 3;
    /*jslint onevar: true */
    this.displayPositions = [];
    for (i = 0; i < 7; i++) {
        if (i < this.selectedItemIndex) {
            this.displayPositions[i] = {
                x: this.x + this.width / 2 - this.SELECTED_WIDTH / 2 - selectedMargin -
                (this.selectedItemIndex - i) * this.UNSELECTED_WIDTH -
                (this.selectedItemIndex - i - 1) * unselectedMargin,
                y: centerY - this.UNSELECTED_HEIGHT / 2,
                z: this.z,
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        } else if (i === this.selectedItemIndex) {
            this.displayPositions[i] = {
                x: this.x + this.width / 2 - this.SELECTED_WIDTH / 2,
                y: centerY - this.SELECTED_HEIGHT / 2,
                z: this.z,
                width: this.SELECTED_WIDTH,
                height: this.SELECTED_HEIGHT
            };
        } else { // if (i > this.selectedItemIndex)
            this.displayPositions[i] = {
                x: this.x + this.width / 2 + this.SELECTED_WIDTH / 2 + selectedMargin +
                (i - this.selectedItemIndex - 1) * (this.UNSELECTED_WIDTH + unselectedMargin),
                y: centerY - this.UNSELECTED_HEIGHT / 2,
                z: this.z,
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        }
    }
    this.displayPositionsUnfocused = [];
    for (i = 0; i < 7; i++) {
        if (i < this.selectedItemIndex) {
            this.displayPositionsUnfocused[i] = {
                x: this.x + this.width / 2 - this.UNSELECTED_WIDTH / 2 - unselectedMargin -
                (this.selectedItemIndex - i) * this.UNSELECTED_WIDTH -
                (this.selectedItemIndex - i - 1) * unselectedMargin,
                y: centerY - this.UNSELECTED_HEIGHT / 2,
                z: this.z,
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        } else if (i === this.selectedItemIndex) {
            this.displayPositionsUnfocused[i] = {
                x: this.x + this.width / 2 - this.UNSELECTED_WIDTH / 2,
                y: centerY - this.UNSELECTED_HEIGHT / 2,
                z: this.z,
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        } else { // if (i > this.selectedItemIndex)
            this.displayPositionsUnfocused[i] = {
                x: this.x + this.width / 2 + this.UNSELECTED_WIDTH / 2 + unselectedMargin +
                (i - this.selectedItemIndex - 1) * (this.UNSELECTED_WIDTH + unselectedMargin),
                y: centerY - this.UNSELECTED_HEIGHT / 2,
                z: this.z,
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        }
    }
    
    this.reflectionPositions = [];
    for (i = 0; i < 7; i++) {
        if (i < this.selectedItemIndex) {
            this.reflectionPositions[i] = {
                x: this.x + this.width / 2 - this.SELECTED_WIDTH / 2 - selectedMargin -
                (this.selectedItemIndex - i) * this.UNSELECTED_WIDTH -
                (this.selectedItemIndex - i - 1) * unselectedMargin,
                y: centerY + this.UNSELECTED_HEIGHT / 2 + 10,
                z: this.z,
                width: this.REFLECTION_WIDTH,
                height: this.REFLECTION_HEIGHT
            };
        } else if (i === this.selectedItemIndex) {
            if ($htv.Platform.properties.has_animations) {
                this.reflectionPositions[i] = {
                    x: this.x + this.width / 2 - this.SELECTED_WIDTH / 2,
                    y: centerY + this.SELECTED_HEIGHT / 2 + 10,
                    z: this.z,
                    width: this.SELECTED_REFLECTION_WIDTH,
                    height: this.SELECTED_REFLECTION_HEIGHT
                };
            } else {
                this.reflectionPositions[i] = {
                    x: -1000,
                    y: -1000,
                    z: this.z,
                    width: this.REFLECTION_WIDTH,
                    height: this.REFLECTION_HEIGHT
                };
            }
        } else { // if (i > this.selectedItemIndex)
            this.reflectionPositions[i] = {
                x: this.x + this.width / 2 + this.SELECTED_WIDTH / 2 + selectedMargin +
                (i - this.selectedItemIndex - 1) * (this.UNSELECTED_WIDTH + unselectedMargin),
                y: centerY + this.UNSELECTED_HEIGHT / 2 + 10,
                z: this.z,
                width: this.REFLECTION_WIDTH,
                height: this.REFLECTION_HEIGHT
            };
        }
    }
    this.reflectionPositionsUnfocused = [];
    for (i = 0; i < 7; i++) {
        if (i < this.selectedItemIndex) {
            this.reflectionPositionsUnfocused[i] = {
                x: this.x + this.width / 2 - this.UNSELECTED_WIDTH / 2 - unselectedMargin -
                (this.selectedItemIndex - i) * this.UNSELECTED_WIDTH -
                (this.selectedItemIndex - i - 1) * unselectedMargin,
                y: centerY + this.UNSELECTED_HEIGHT / 2 + 10,
                z: this.z,
                width: this.REFLECTION_WIDTH,
                height: this.REFLECTION_HEIGHT
            };
        } else if (i === this.selectedItemIndex) {
            this.reflectionPositionsUnfocused[i] = {
                x: this.x + this.width / 2 - this.UNSELECTED_WIDTH / 2,
                y: centerY + this.UNSELECTED_HEIGHT / 2 + 10,
                z: this.z,
                width: this.REFLECTION_WIDTH,
                height: this.REFLECTION_HEIGHT
            };
        } else { // if (i > this.selectedItemIndex)
            this.reflectionPositionsUnfocused[i] = {
                x: this.x + this.width / 2 + this.UNSELECTED_WIDTH / 2 + unselectedMargin +
                (i - this.selectedItemIndex - 1) * (this.UNSELECTED_WIDTH + unselectedMargin),
                y: centerY + this.UNSELECTED_HEIGHT / 2 + 10,
                z: this.z,
                width: this.REFLECTION_WIDTH,
                height: this.REFLECTION_HEIGHT
            };
        }
    }
    
    this.countLabelPosition = {
        x: this.x,
        y: this.displayPositionsUnfocused[0].y - 80,
        z: this.z,
        width: this.width,
        height: 40
    };
    this.carouselLabelPosition = {
        x: this.x,
        y: this.countLabelPosition.y - 28,
        z: this.z,
        width: this.width,
        height: 30
    };
    this.loadingLabelPosition = {
        x: this.x,
        y: this.y + 10,
        z: this.z,
        width: this.width,
        height: 30
    };

    this.carouselLabel = $htv.Platform.createLabel(this.carouselLabelPosition, this.carousel_name, this.canvas, {styleName: $htv.Styles.CarouselTitleUnfocused});
    this.carouselLabel.hide();
    
    // Recreated in _updateShowLogo
    this.showImage = $htv.Platform.createImage({
        x: -100,
        y: -100,
        z: this.z,
        width: 0,
        height: 0
    }, null, this.canvas);
    this.showImage.hide();
    this.loadingLabel = $htv.Platform.createLabel(this.loadingLabelPosition, "Loading...", this.canvas, {styleName: $htv.Styles.CarouselThumbnailSubtitleCentered});
    this.loadingLabel.show();
    
    this.companyBug = $htv.Platform.createImage({
        x: 0,
        y: 0,
        z: this.z + 1,
        width: 41,
        height: 18
    }, null, this.canvas);
    this.companyBug.hide();
    
    if (this.show_id > 0) {
        this.countLabelPosition = {
            x: this.x,
            y: this.displayPositionsUnfocused[0].y - 35,
            z: this.z,
            width: this.width,
            height: 90
        };
        
        this._updateShowLogo(this.show_id);
        this.showImage.show();
    } else {
        this.carouselLabel.show();
    }
    if (this.use_related_title === true) {
        this.showImage.hide();
        this.carouselLabel.hide();
        this.countLabelPosition.y -= 30;
    }
    this.countLabel = $htv.Platform.createLabel(this.countLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselCount});
    
    this.leftBracket = $htv.Platform.createImage({
        x: this.displayPositions[this.selectedItemIndex].x - 26,
        y: this.displayPositions[this.selectedItemIndex].y,
        z: this.z + 1,
        width: 17,
        height: 169
    }, "images/bracket_large_left.png", this.canvas);
    this.leftBracket.hide();
    this.rightBracket = $htv.Platform.createImage({
        x: this.displayPositions[this.selectedItemIndex].x + this.displayPositions[this.selectedItemIndex].width + 11,
        y: this.displayPositions[this.selectedItemIndex].y,
        z: this.z + 1,
        width: 17,
        height: 169
    }, "images/bracket_large_right.png", this.canvas);
    this.rightBracket.hide();
    this.downArrow = $htv.Platform.createImage({
        x: this.displayPositions[this.selectedItemIndex].x + this.displayPositions[this.selectedItemIndex].width / 2 - 21 / 2,
        y: 520,
        z: this.z,
        width: 21,
        height: 8
    }, "images/down-arrow.png", this.canvas);
    this.downArrow.hide();
    
    // data source
    if (options.items) {
        this.items = options.items;
    }
    else {
        this.items = $htv.Utils.createTwinkieCollection(this.itemFields);
        
        // the data source requires a login token (recommendations, queue)
        if (this.login_required && url.indexOf("user_id=") === url.length - 8) {
            
            url = url + $htv.Profile.getUserToken();
        }
        if (this.add_cb) {
            
            url = url + "&cb=" +  Math.random().toString();
        }
        if (this.recommended_required) {
            
            // Change show_id/video_id to r_id
            url = url.replace(/show_id=([0-9]+)/, "r_id=$1");
            url = url.replace(/video_id=([0-9]+)/, "r_id=$1");
            // Add the user id and page size
            url = url +
                "&r_user_id=" + $htv.Profile.getUserToken() +
                "&r_items_per_page=" + $htv.Constants.DEFAULT_PAGE_SIZE +
                "&r_package_id=2&r_device_id=2";
        }
        
        if (this.package_id !== null) {
            this.url = $htv.Utils.applyGlobalContext(url, this.package_id);
        }
        else {
            this.url = $htv.Utils.applyGlobalContext(url);
        }
    }

    // populate the collection, delaying if requested
    if (options.hasOwnProperty("delayed_initialize") && options.delayed_initialize) {
        this.dataWaiting = true;
        this.loadingLabel.show();
        this.delayedStartTimer = $htv.Platform.createTimer(600, this, this._delayedInitialize);
        this.delayedStartTimer.start();
    }
    else {
        this._delayedInitialize();
    }
};

$htv.Controls.BaseThumbnailCarousel.prototype._delayedInitialize = function () {
    if (this.delayedStartTimer !== null) {
        this.delayedStartTimer.stop();
        this.delayedStartTimer = null;
    }
    if (this.visible === true) {
        this.node.view.fireEvent("INITIALIZE_STARTED", {
            target: this.node
        });
        this.items.initialize(this.url, this, this.initializeResult, {
            callback: this.initializeResult,
            receiver: this
        });
    } else {
        
    }
};

$htv.Controls.BaseThumbnailCarousel.prototype._initializeResult = function () {
    this.dataWaiting = false;
    if (this.visible === true) {
        this.countLabel.setText(this._generateCountLabelText());
        if (this.use_related_title === false) {
            this.carouselLabel.setText(this.carousel_name);
        }
        if (this.initialized === false && this.startAtEnd === true) {
            if (this.items.getLength() === 0) {
                // defer render.
                // TODO: why is this getting called by another VTC?
                return;
            }
            this.activeIndex = this.items.getLength() - 1;
        }
        this.loadingLabel.hide();
        
        this.initialized = true;
        this.node.view.fireEvent("INITIALIZE_COMPLETE", {
            target: this.node
        });
    } else {
        
    }
};

$htv.Controls.BaseThumbnailCarousel.prototype._generateCountLabelText = function () {
    var clText = "";
    
    if (this.use_related_title === true) {
        if (this.carousel_item_type === "shows" || this.carousel_item_type === "movies") {
            clText = "People who watched " + this.show_name;
        } else {
            clText = "People who watched " + this.show_name + ": " + this.video_title;
        }
        clText += " also watched these " + this.carousel_item_type;
    } else {
        clText = (this.items.getLength() > 100 ? "100+" : this.items.getLength()) + " " + this.carousel_item_type;
    }
    return clText;
};

$htv.Controls.BaseThumbnailCarousel.prototype._updateShowLogo = function (show_id) {
    this.last_show_thumb_id = show_id;
    var url = $htv.Utils.getURLForShowLogo(this.last_show_thumb_id, {
        width: 220,
        height: 80,
        maintain_ratio: true,
        format: "png"
    });
    
    // Recreate image since no loaded callback exists 
    $htv.Platform.deleteItem(this.showImage);
    this.showImage = $htv.Platform.createImage({
        x: this.x + this.width / 2 - 110,
        y: this.displayPositionsUnfocused[0].y - 64 - 80,
        z: this.z,
        width: 220,
        height: 80
    }, url, this.canvas);
};

$htv.Controls.BaseThumbnailCarousel.prototype._focus = function () {
    var i;
    if (this.hasFocus === false) {
        this.hasFocus = true;
        for (i = 0; i < this.displayItems.length; i++) {
            if (this.displayItems[i] !== null) {
                this.displayItems[i].move(this.displayPositions[i], this.TWDUR_MOVE);
            }
        }
        for (i = 0; i < this.reflectionItems.length; i++) {
            if (this.reflectionItems[i] !== null) {
                this.reflectionItems[i].move(this.reflectionPositions[i], this.TWDUR_MOVE);
            }
        }
    }
    if (this.initialized === true) {
        this.showImage.hide();
        this.carouselLabel.hide();
        this.countLabel.hide();
        this.leftBracket.show();
        this.rightBracket.show();
        if (this.disable_down_override === false) {
            this.downArrow.show();
        }
        if (!$htv.Utils.stringIsNullOrEmpty(this.companyBugUrl)) {
            this.companyBug.show();
        }
    } else {
        if (this.use_related_title === false) {
            if (!$htv.Utils.stringIsNullOrEmpty(this.show_canonical_name)) {
                this.showImage.show();
            } else {
                this.carouselLabel.show();
            }
        }
        this.countLabel.show();
        this.companyBug.hide();
    }
    $htv.Platform.updateSpotlight(this.x + this.width / 2, this.y + this.height / 2 - 100);
};
    
$htv.Controls.BaseThumbnailCarousel.prototype._unfocus = function () {
    var i;
    if (this.hasFocus === true) {
        this.hasFocus = false;
        for (i = 0; i < this.displayItems.length; i++) {
            if (this.displayItems[i] !== null) {
                this.displayItems[i].move(this.displayPositionsUnfocused[i], this.TWDUR_MOVE);
            }
        }
        for (i = 0; i < this.reflectionItems.length; i++) {
            if (this.reflectionItems[i] !== null) {
                this.reflectionItems[i].move(this.reflectionPositionsUnfocused[i], this.TWDUR_MOVE);
            }
        }
    }
    
    if (this.use_related_title === false) {
        if (this.show_canonical_name !== "") {
            this.showImage.show();
        } else {
            this.showImage.hide();
            this.carouselLabel.show();
        }
    } else {
        this.showImage.hide();
        this.carouselLabel.hide();
    }
    this.countLabel.show();
    this.leftBracket.hide();
    this.rightBracket.hide();
    this.downArrow.hide();
    this.companyBug.hide();
};
    
$htv.Controls.BaseThumbnailCarousel.prototype._hide = function () {
    var i;
    this.visible = false;
    if (this.delayedStartTimer !== null) {
        // is this safe?  cancel delayed load
        this.delayedStartTimer.stop();
        this.delayedStartTimer = null;
    }
    
    for (i = 0; i < this.displayItems.length; i++) {
        if (this.displayItems[i] !== null) {
            this.displayItems[i].hide();
        }
    }
    for (i = 0; i < this.reflectionItems.length; i++) {
        if (this.reflectionItems[i] !== null) {
            this.reflectionItems[i].hide();
        }
    }
    this.carouselLabel.hide();
    this.showImage.hide();
    this.countLabel.hide();
    this.leftBracket.hide();
    this.rightBracket.hide();
    this.downArrow.hide();
    this.companyBug.hide();
    this.loadingLabel.hide();
};
    
$htv.Controls.BaseThumbnailCarousel.prototype._show = function () {
    var i;
    this.visible = true;
    for (i = 0; i < this.displayItems.length; i++) {
        if (this.displayItems[i] !== null) {
            this.displayItems[i].show();
        }
    }
    for (i = 0; i < this.reflectionItems.length; i++) {
        if (this.reflectionItems[i] !== null) {
            this.reflectionItems[i].show();
        }
    }
    if (this.hasFocus) {
        this.carouselLabel.hide();
        this.showImage.hide();
        this.downArrow.show();
        if (!$htv.Utils.stringIsNullOrEmpty(this.companyBugUrl)) {
            this.companyBug.show();
        }
    } else {
        if (this.use_related_title === false) {
            if (!$htv.Utils.stringIsNullOrEmpty(this.show_canonical_name)) {
                this.showImage.show();
            } else {
                this.carouselLabel.show();
            }
        }
        this.countLabel.show();
        this.companyBug.hide();
    }
};

$htv.Controls.BaseThumbnailCarousel.prototype._dispose = function () {
    var i;
    this.activeIndex = 0;
    this.add_cb = false;
    this.login_required = false;
    this.visible = false;
    this.displayPositions = new Array(this.displayItems.length);
    for (i = 0; i < this.displayItems.length; i++) {
        $htv.Platform.deleteItem(this.displayItems[i]);
    }
    for (i = 0; i < this.reflectionItems.length; i++) {
        $htv.Platform.deleteItem(this.reflectionItems[i]);
    }
    $htv.Platform.deleteItem(this.showImage);
    $htv.Platform.deleteItem(this.carouselLabel);
    $htv.Platform.deleteItem(this.countLabel);
    $htv.Platform.deleteItem(this.leftBracket);
    $htv.Platform.deleteItem(this.rightBracket);
    $htv.Platform.deleteItem(this.downArrow);
    $htv.Platform.deleteItem(this.companyBug);
    $htv.Platform.deleteItem(this.loadingLabel);
    if (this.delayedStartTimer !== null) {
        this.delayedStartTimer.stop();
        this.delayedStartTimer = null;
    }
    if (this.delayedJumpTimer !== null) {
        this.delayedJumpTimer.stop();
        this.delayedJumpTimer = null;
    }
    this.items = null;
    this.itemFields = ['title', 'cmtype'];
    this.url = null;
    this.displayItems = null;
    this.displayPositions = null;
    this.displayPositionsUnfocused = null;
    this.reflectionItems = null;
    this.reflectionPositions = null;
    this.reflectionPositionsUnfocused = null;
    this.showImage = null;
    this.carouselLabel = null;
    this.countLabel = null;
    this.leftBracket = null;
    this.rightBracket = null;
    this.downArrow = null;
    this.companyBug = null;
    this.loadingLabel = null;
    this.show_name = "";
    this.selectedItemIndex = 0;
    this.disable_down_override = false;
    this.use_related_title = false;
    this.video_title = "";
    this.carousel_item_type = "";
    this.show_actual_total = false;
    this.countLabelPosition = null;
    this.loadingLabelPosition = null;
    this.carouselLabelPosition = null;
    this.package_id = null;
};

$htv.Controls.BaseThumbnailCarousel.prototype._render = function () {
    var index, i, item, loadingurl;
    if (this.visible === true) {
        for (i = 0; i < this.displayItems.length; i++) {
            index = i + this.activeIndex - this.selectedItemIndex;
            if (index >= 0 && index < this.items.getLength()) {
                if (i === this.selectedItemIndex && this.hasFocus) {
                    loadingurl = "images/thumb-loading-lg.png";
                } else {
                    loadingurl = "images/thumb-loading-sm.png";
                }
                if (this.displayItems[i] === null) {
                    this.displayItems[i] = $htv.Platform.createImage(this.displayPositions[i], loadingurl, this.canvas, {
                        styleName: $htv.Styles.CarouselThumbnail
                    });
                } else {
                    this.displayItems[i].setURL(loadingurl);
                    this.displayItems[i].show();
                }
                
                if ($htv.Platform.properties.has_reflections === true) {
                    if (this.reflectionItems[i] === null) {
                        this.reflectionItems[i] = $htv.Platform.createReflection(this.reflectionPositions[i], this.displayItems[i], this.canvas, {
                            source_height: this.UNSELECTED_HEIGHT,
                            alpha_top: 0.2
                        });
                    } else {
                        this.reflectionItems[i].show();
                    }
                } else {
                    if (this.reflectionItems[i] === null) {
                        this.reflectionItems[i] = $htv.Platform.createImage(this.reflectionPositions[i], "images/thumb-reflection-loading.png", this.canvas);
                    } else {
                        this.reflectionItems[i].setURL("images/thumb-reflection-loading.png");
                        this.reflectionItems[i].show();
                    }
                }
                
                
                if (this.dataWaiting === false) {
                    this.loadingLabel.hide();
                    item = this.items.getItemAt(index).item;
                    if (item !== null) {
                        this.displayItems[i].setURL(this.itemRenderer(item, i === this.selectedItemIndex));
                        if ($htv.Platform.properties.has_reflections !== true) {
                            this.reflectionItems[i].setURL(this.itemRenderer(item, false, true));
                        }
                    } else {
                        this.dataWaiting = true;
                        this.loadingLabel.show();
                    }
                }
                
                if (this.hasFocus === true) {
                    this.displayItems[i].move(this.displayPositions[i], this.TWDUR_MOVE);
                    this.reflectionItems[i].move(this.reflectionPositions[i], this.TWDUR_MOVE);
                } else {
                    this.displayItems[i].move(this.displayPositionsUnfocused[i], this.TWDUR_MOVE);
                    this.reflectionItems[i].move(this.reflectionPositionsUnfocused[i], this.TWDUR_MOVE);
                }
            } else {
                this.displayItems[i] = null;
                this.reflectionItems[i] = null;
            }
        }
    } else {
        
    }
};

$htv.Controls.BaseThumbnailCarousel.prototype._jumpToIndex = function (index, options) {
    var i;
    if (this.delayedJumpTimer !== null) {
        this.delayedJumpTimer.stop();
        this.delayedJumpTimer = null;
    }
    
    this.activeIndex = index;
    for (i = 0; i < this.displayItems.length; i++) {
        if (this.displayItems[i] !== null) {
            $htv.Platform.deleteItem(this.displayItems[i]);
            this.displayItems[i] = null;
        }
    }
    for (i = 0; i < this.reflectionItems.length; i++) {
        if (this.reflectionItems[i] !== null) {
            $htv.Platform.deleteItem(this.reflectionItems[i]);
            this.reflectionItems[i] = null;
        }
    }
    
    this.loadingLabel.show();
    if (options && options.hasOwnProperty("delayed_jump") && options.delayed_jump) {
        this.delayedJumpTimer = $htv.Platform.createTimer(600, this, this._delayedJumpToIndex);
        this.delayedJumpTimer.start();
    }
    else {
        this._delayedJumpToIndex();
    }
};

$htv.Controls.BaseThumbnailCarousel.prototype._delayedJumpToIndex = function () {
    if (this.delayedJumpTimer !== null) {
        this.delayedJumpTimer.stop();
        this.delayedJumpTimer = null;
    }
    this.loadingLabel.hide();

    this.render();
};

$htv.Controls.BaseThumbnailCarousel.prototype._getDataSource = function () {
    return this.items;
};

$htv.Controls.BaseThumbnailCarousel.prototype._handleMoveRight = function () {
    var i, index, item, loadingurl;
    
    if (this.activeIndex < this.items.getLength() - 1) {
        this.activeIndex++;
        if (this.displayItems[0] !== null) {
            $htv.Platform.deleteItem(this.displayItems[0]);
            this.displayItems[0] = null;
        }
        if (this.reflectionItems[0] !== null) {
            $htv.Platform.deleteItem(this.reflectionItems[0]);
            this.reflectionItems[0] = null;
        }
        
        for (i = 1; i < this.displayItems.length; i++) {
            if (this.displayItems[i] !== null) {
                index = this.activeIndex - this.selectedItemIndex + i - 1;
                item = this.items.getItemAt(index).item;
                if (item !== null) {
                    this.displayItems[i].setURL(this.itemRenderer(item, i - 1 === this.selectedItemIndex));
                }
                this.displayItems[i].move(this.displayPositions[i - 1], this.TWDUR_MOVE);
            }
            this.displayItems[i - 1] = this.displayItems[i];
        }
        for (i = 1; i < this.reflectionItems.length; i++) {
            if (this.reflectionItems[i] !== null) {
                this.reflectionItems[i].move(this.reflectionPositions[i - 1], this.TWDUR_MOVE);
            }
            this.reflectionItems[i - 1] = this.reflectionItems[i];
        }
        
        // todo? what is this
        index = this.activeIndex + this.selectedItemIndex;
        if (index >= 0 && index < this.items.getLength()) {
            if (i === this.selectedItemIndex && this.hasFocus) {
                loadingurl = "images/thumb-loading-lg.png";
            }
            else {
                loadingurl = "images/thumb-loading-sm.png";                    
            }
            this.displayItems[this.displayItems.length - 1] = $htv.Platform.createImage(this.displayPositions[this.displayItems.length - 1], loadingurl, this.canvas, {styleName: $htv.Styles.CarouselThumbnail});
            if ($htv.Platform.properties.has_reflections === true) {
                this.reflectionItems[this.reflectionItems.length - 1] = $htv.Platform.createReflection(this.reflectionPositions[this.displayItems.length - 1], this.displayItems[this.displayItems.length - 1], this.canvas, {
                    source_height: this.UNSELECTED_HEIGHT,
                    alpha_top: 0.2
                });
            } else {
                this.reflectionItems[this.reflectionItems.length - 1] = $htv.Platform.createImage(this.reflectionPositions[this.displayItems.length - 1], "images/thumb-reflection-loading.png", this.canvas);
            }
            
            if (this.dataWaiting === false && this.items.getItemAt(index).item !== null) {
                item = this.items.getItemAt(index).item;
                if (item !== null) {
                    this.displayItems[this.displayItems.length - 1].setURL(this.itemRenderer(item, false));
                    if ($htv.Platform.properties.has_reflections !== true) {
                        this.reflectionItems[this.reflectionItems.length - 1].setURL(this.itemRenderer(item, false, true));
                    }
                }
            }
        }
        else {
            this.displayItems[this.displayItems.length - 1] = null;
            this.reflectionItems[this.reflectionItems.length - 1] = null;
        }
    } else {
        if (this.items.getLength() === 1 || $htv.Controller.isKeyHeld()) {
            return; // doesn't need to do anything.
        }
        this._jumpToIndex(0);
    }
    
    this.node.view.fireEvent("CAROUSEL_SELECTION_CHANGED", {
        canonical_name: this.items.getItemAt(this.activeIndex).item.canonical_name,
        collation_name: this.items.getItemAt(this.activeIndex).item.collation_name,
        collation_title:  this.items.getItemAt(this.activeIndex).item.collation_title,
        target: this.node
    });
};


$htv.Controls.BaseThumbnailCarousel.prototype.__handleMoveDown = function () {
    this.node.view.fireEvent("LOSING_FOCUS", {
        nav_dir: "down",
        item: this.items.getItemAt(this.activeIndex).item,
        target: this.node
    });
};

$htv.Controls.BaseThumbnailCarousel.prototype._handleMoveDown = function () {
    this.__handleMoveDown();
};

$htv.Controls.BaseThumbnailCarousel.prototype._handleMoveLeft = function () {
    var i, index, item, loadingurl;
    
    if (this.activeIndex > 0) {
        this.activeIndex--;
        if (this.displayItems[this.displayItems.length - 1] !== null) {
            $htv.Platform.deleteItem(this.displayItems[this.displayItems.length - 1]);
            this.displayItems[this.displayItems.length - 1] = null;
        }
        if (this.reflectionItems[this.reflectionItems.length - 1] !== null) {
            $htv.Platform.deleteItem(this.reflectionItems[this.reflectionItems.length - 1]);
            this.reflectionItems[this.reflectionItems.length - 1] = null;
        }
        
        for (i = this.displayItems.length - 1; i >= 1; i--) {
            if (this.displayItems[i - 1] !== null) {
                index = this.activeIndex - this.selectedItemIndex + i;
                item = this.items.getItemAt(index).item;
                if (item !== null) {
                    this.displayItems[i - 1].setURL(this.itemRenderer(item, i === this.selectedItemIndex));
                }
                this.displayItems[i - 1].move(this.displayPositions[i], this.TWDUR_MOVE);
            }
            this.displayItems[i] = this.displayItems[i - 1];
        }
        for (i = this.reflectionItems.length - 1; i >= 1; i--) {
            if (this.reflectionItems[i - 1] !== null) {
                this.reflectionItems[i - 1].move(this.reflectionPositions[i], this.TWDUR_MOVE);
            }
            this.reflectionItems[i] = this.reflectionItems[i - 1];
        }
        
        index = this.activeIndex - this.selectedItemIndex;
        if (index >= 0 && index < this.items.getLength()) {
            if (i === this.selectedItemIndex && this.hasFocus) {
                loadingurl = "images/thumb-loading-lg.png";
            }
            else {
                loadingurl = "images/thumb-loading-sm.png";                    
            }
            this.displayItems[0] = $htv.Platform.createImage(this.displayPositions[0], loadingurl, this.canvas, {styleName: $htv.Styles.CarouselThumbnail});
            if ($htv.Platform.properties.has_reflections === true) {
                this.reflectionItems[0] = $htv.Platform.createReflection(this.reflectionPositions[0], this.displayItems[0], this.canvas, {
                    source_height: this.UNSELECTED_HEIGHT,
                    alpha_top: 0.2
                });
            } else {
                this.reflectionItems[0] = $htv.Platform.createImage(this.reflectionPositions[0], "images/thumb-reflection-loading.png", this.canvas);
            }
            if (this.dataWaiting === false && this.items.getItemAt(index).item !== null) {
                item = this.items.getItemAt(index).item;
                if (item !== null) {
                    this.displayItems[0].setURL(this.itemRenderer(item, false));
                    if ($htv.Platform.properties.has_reflections !== true) {
                        this.reflectionItems[0].setURL(this.itemRenderer(item, false, true));
                    }
                }
            }
        }
        else {
            this.displayItems[0] = null;
            this.reflectionItems[0] = null;
        }
    } else {
        if (this.items.getLength() === 1 || $htv.Controller.isKeyHeld()) {
            return; // doesn't need to do anything.
        }
        this._jumpToIndex(this.items.getLength() - 1);
        
    }

    if (this.items.getItemAt(this.activeIndex).item) {
        this.node.view.fireEvent("CAROUSEL_SELECTION_CHANGED", {
            canonical_name: this.items.getItemAt(this.activeIndex).item.canonical_name,
            collation_name: this.items.getItemAt(this.activeIndex).item.collation_name,
            collation_title:  this.items.getItemAt(this.activeIndex).item.collation_title,
            target: this.node
        });
    } else {
        this.node.view.fireEvent("CAROUSEL_SELECTION_CHANGED", {
            canonical_name: "",
            collation_name: "",
            collation_title:  "",
            target: this.node
        });
    }
};

$htv.Controls.BaseThumbnailCarousel.prototype._handleEvent = function (eventName, eventData) {
    if (eventName === "USER_INPUT") {
        this.handleInput(eventData);
    } else {
        
    }
};

$htv.Controls.BaseThumbnailCarousel.prototype._handleInput = function (eventData) {
    switch (eventData.action) {
    case "MOVE_RIGHT":
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        this._handleMoveRight();
        break;
    case "MOVE_LEFT":
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        this._handleMoveLeft();
        break;
    case "MOVE_DOWN":
        if (eventData.is_down) {
            this.downArrow.setURL("images/down-arrow-hover.png");
        } else {
            this.downArrow.setURL("images/down-arrow.png");
            // idea here is: if disable_down, do the losing focus. otherwise, try doing _handleMoveDown
            // which may or may not be overridden, in which case it still might call losing_focus
            if (this.disable_down_override === true) { 
                this.__handleMoveDown();
            }
            else {
                this._handleMoveDown();
            }
        }
        break;
    case "KEY_RETURN":
    case "MOVE_UP":
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        this.node.view.fireEvent("LOSING_FOCUS", {
            nav_dir: "up",
            item: this.items.getItemAt(this.activeIndex).item,
            target: this.node
        });
        break;
    case "PLAY":
    case "PRESS_OK":
        break;
    default:
        
        break;
    }
};

$htv.Controls.CompanyThumbnailCarousel = function () {
    $htv.Controls.BaseThumbnailCarousel.call(this);
    this.className = "CompanyThumbnailCarousel";
    this.carousel_name = "unnamed company carousel";
    this.descriptionTextArea = null;
    this.descriptionTextAreaPosition = null;
    this.companySubtitleLabelPosition = null;
    this.companySubtitleLabel = null;
    this.companyTitleLabelPosition = null;
    this.companyTitleLabel = null;
    this.progressLabelPosition = null;
    this.progressLabel = null;
    
    this.initialize = function (position, target, url, options) {
        
        this.carousel_item_type = "companies";
        this.itemFields = ['canonical_name', 'cmtype', 'items_url', 'name', 'company_id', 'videos_count', 'full_episodes_count', 'clips_count', 'feature_films_count'];
        this._initialize(position, target, url, options);

        this.companySubtitleLabelPosition = {
            x: this.x,
            y: this.displayPositions[3].y - 35,
            z: this.z + 1,
            width: this.width,
            height: 30
        };
        this.companyTitleLabelPosition = {
            x: this.x,
            y: this.companySubtitleLabelPosition.y - 35,
            z: this.z + 1,
            width: this.width,
            height: 34
        };
        this.descriptionTextAreaPosition = {
            x: this.displayPositions[3].x,
            y: this.displayPositions[3].y + this.displayPositions[3].height + 12,
            z: this.z + 1,
            width: this.displayPositions[3].width + 35,
            height: 100
        };
        // NOTE: right-aligned
        this.progressLabelPosition = {
            x: this.x,
            y: this.y + this.height - 60,
            z: this.z + 1,
            width: this.width - 50,
            height: 30
        };
        
        this.companyTitleLabel = $htv.Platform.createLabel(this.companyTitleLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailTitle});
        this.companySubtitleLabel = $htv.Platform.createLabel(this.companySubtitleLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailSubtitleCentered});
        this.descriptionTextArea = $htv.Platform.createTextArea(this.descriptionTextAreaPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailDescription});
        this.progressLabel = $htv.Platform.createLabel(this.progressLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselProgress});

    };
    
    this.initializeResult = function () {
        this._initializeResult();
        this.render();
    };
    
    this.itemRenderer = function (item, focused, reflection) {
        var options;
        if (focused || $htv.Platform.properties.has_animations) {
            options = {
                width: this.SELECTED_WIDTH,
                height: this.SELECTED_HEIGHT
            };
        }
        else {
            options = {
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        }
        
        if (reflection === true) {
            options.format = "png";
            options.reflection_height = this.REFLECTION_HEIGHT;
            options.reflection_alpha_top = this.REFLECTION_ALPHA_TOP;
        }
        
        return $htv.Utils.getURLForCompanyThumb(item.company_id, options);
    };
    
    this.dispose = function () {
        this._dispose();
        $htv.Platform.deleteItem(this.companyTitleLabel);
        $htv.Platform.deleteItem(this.companySubtitleLabel);
        $htv.Platform.deleteItem(this.descriptionTextArea);
        $htv.Platform.deleteItem(this.progressLabel);
        this.companyTitleLabel = null;
        this.companySubtitleLabel = null;
        this.descriptionTextArea = null;
        this.progressLabel = null;
        this.companySubtitleLabelPosition = null;
        this.companyTitleLabelPosition = null;
        this.descriptionTextAreaPosition = null;
        this.progressLabelPosition = null;
    };
    
    this.focus = function () {
        if (this.items.getLength() === 0) {
            this.node.view.fireEvent("LOSING_FOCUS", {
                nav_dir: "up"
            });
            return;
        }
        
        this._focus();
        if (this.initialized === true) {
            this.updateLabels();
            this.companyTitleLabel.show();
            this.companySubtitleLabel.show();
            this.descriptionTextArea.show();
            this.progressLabel.show();
        }
    };
    
    this.unfocus = function () {
        this._unfocus();
        this.companyTitleLabel.hide();
        this.companySubtitleLabel.hide();
        this.descriptionTextArea.hide();
        this.progressLabel.hide();
    };
    
    this.hide = function () {
        this._hide();
        this.companyTitleLabel.hide();
        this.companySubtitleLabel.hide();
        this.descriptionTextArea.hide();
        this.progressLabel.hide();
    };
    
    this.show = function () {
        this._show();
        if (this.hasFocus === false) {
            this.companyTitleLabel.hide();
            this.companySubtitleLabel.hide();
            this.descriptionTextArea.hide();
            this.progressLabel.hide();
        }
        else {
            this.companyTitleLabel.show();
            this.companySubtitleLabel.show();
            this.descriptionTextArea.show();
            this.progressLabel.show();
        }
    };
   
    this.updateLabels = function () {
        var activeItem, totalCount;
        activeItem = this.items.getItemAt(this.activeIndex).item;
        if (activeItem) {
            this.companyTitleLabel.setText(activeItem.name);
            this.companySubtitleLabel.setText(activeItem.videos_count + " video" + (parseInt(activeItem.videos_count, 10) === 1 ? "" : "s"));
        }
        //this.descriptionTextArea.setText(activeItem.description);
        totalCount = this.items.getLength();
        if (totalCount > 100 && !this.show_actual_total) {
            totalCount = "100+";
        }
        this.progressLabel.setText((this.activeIndex + 1) + " of " + totalCount + " " + this.carousel_item_type);  
    };
    
    this._handleMoveDown = function () {
        $htv.Controller.pushView("ContentView", {
            menu_url: this.items.getItemAt(this.activeIndex).item.items_url,
            view_title: this.items.getItemAt(this.activeIndex).item.name,
            show_id: this.items.getItemAt(this.activeIndex).item.show_id,
            show_name: this.items.getItemAt(this.activeIndex).item.title,
            previous_view_title: this.carousel_name
        });
    };

    this.handleInput = function (eventData) {
        this._handleInput(eventData);
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        
        switch (eventData.action) {
        case "MOVE_RIGHT":
            this.updateLabels();
            break;
        case "MOVE_LEFT":
            this.updateLabels();
            break;
        case "PRESS_OK":
            this._handleMoveDown();
            break;
        default:
            
            break;
        }
    };

    this.render = this._render;
    this.jumpToIndex = this._jumpToIndex;
    this.getDataSource = this._getDataSource;
    this.handleEvent = this._handleEvent;
};

$htv.Controls.SearchThumbnailCarousel = function () {
    $htv.Controls.BaseThumbnailCarousel.call(this);
    this.className = "SearchThumbnailCarousel";
    this.carousel_name = "unnamed search carousel";
    
    this.stars = null;
    this.ccIcon = null;
    this.videoSubtitlePipe = null;
    this.videoSubtitleContainer = null;
    this.descriptionTextArea = null;
    this.descriptionTextAreaPosition = null;
    this.showGenreRatingLabelPosition = null;
    this.showGenreRatingLabel = null;
    this.videoSubtitleContainerPosition = null;
    this.webOnlyLabel = null;
    this.webOnlyLabelPosition = null;
    this.webOnlyBackgroundBox = null;
    this.webOnlyBackgroundBoxPosition = null;
    this.webOnlyDescriptionText = null;
    
    this.titleLabelPosition = null;
    this.titleLabel = null;
    this.progressLabelPosition = null;
    this.progressLabel = null;
    this.playArrow = null;

    
    this.initialize = function (position, target, url, options) {
        
        this.carousel_item_type = "results";
        this._initialize(position, target, url, options);
        this.stars = null;
        this.webOnlyDescriptionText = "Sorry, we do not have the rights to stream this show to your device. It is available at Hulu.com on your computer web browser.";
        
        this.videoSubtitleContainerPosition = {
            x: this.x,
            y: this.displayPositions[3].y - 35,
            z: this.z + 1,
            width: this.width,
            height: 22
        };
        this.showGenreRatingLabelPosition = {
            x: 0,
            y: 0,
            z: this.z + 1,
            width: this.width,
            height: 22
        };
        this.descriptionTextAreaPosition = {
            x: this.displayPositions[3].x,
            y: this.displayPositions[3].y + this.displayPositions[3].height + 20,
            z: this.z + 1,
            width: this.displayPositions[3].width + 35,
            height: 75
        };
        this.stars = $htv.ControlPool.getObject("RatingStarsControl");
        this.stars.initialize({
                x: 0,
                y: 0,
                z: this.z + 1,
                width: 92,
                height: 16
            }, null, null, { rating: 0 });
        this.stars.hide();
        this.videoSubtitleContainer = $htv.Platform.createContainer(this.videoSubtitleContainerPosition, this.canvas, {spacing: 13, center: true});
        this.videoSubtitlePipe = $htv.Platform.createImage({
            x: 0, 
            y: 0, 
            z: this.z + 1, 
            width: 1, 
            height: 14
        }, "images/small_pipe.png", this.canvas);
        this.videoSubtitlePipe.hide();
        
        this.videoSubtitleContainer.hide();
        
        this.ccIcon = $htv.Platform.createImage({
            x: 0,
            y: 0,
            z: this.z + 1,
            width: 20,
            height: 14
        }, "images/cc-icon.png", this.canvas);
        this.ccIcon.hide();
        
        this.titleLabelPosition = {
            x: this.x,
            y: this.videoSubtitleContainerPosition.y - 35,
            z: this.z + 1,
            width: this.width - 30,
            height: 34
        };
       
        // NOTE: right-aligned
        this.progressLabelPosition = {
            x: this.x,
            y: this.y + this.height - 60,
            z: this.z + 1,
            width: this.width - 50,
            height: 30
        };
        this.playArrow = $htv.Platform.createImage({
            x: this.displayPositions[this.selectedItemIndex].x + this.displayPositions[this.selectedItemIndex].width / 2 - 53 / 2,
            y: this.displayPositions[this.selectedItemIndex].y + this.displayPositions[this.selectedItemIndex].height / 2 - 62 / 2,
            z: this.z + 1,
            width: 53,
            height: 62
        }, "images/play-arrow.png", this.canvas);
        this.playArrow.hide();
        
        this.webOnlyLabelPosition = {
            x: this.displayPositions[this.selectedItemIndex].x + 10,
            y: this.displayPositions[this.selectedItemIndex].y + this.displayPositions[this.selectedItemIndex].height - 25,
            z: this.z + 2,
            width: this.displayPositions[this.selectedItemIndex].width,
            height: 30
        };
        
        this.webOnlyBackgroundBoxPosition = {
            x: this.displayPositions[this.selectedItemIndex].x,
            y: this.displayPositions[this.selectedItemIndex].y + this.displayPositions[this.selectedItemIndex].height - 30,
            z: this.z + 1,
            width: this.displayPositions[this.selectedItemIndex].width,
            height: 30
        };
            
        
        this.titleLabel = $htv.Platform.createLabel(this.titleLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailTitle});
        this.showGenreRatingLabel = $htv.Platform.createLabel(this.showGenreRatingLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailSubtitle});
        this.videoSubtitleContainer.addItem(this.showGenreRatingLabel);
        this.videoSubtitleContainer.addItem(this.videoSubtitlePipe, {padding: {bottom: 1}, absolute_offset: {top: 2}});
        this.videoSubtitleContainer.addItem(this.stars.getContainer(), {padding: {bottom: 2}, absolute_offset: {top: 0}});
        this.descriptionTextArea = $htv.Platform.createTextArea(this.descriptionTextAreaPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailDescription});
        this.progressLabel = $htv.Platform.createLabel(this.progressLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselProgress});
        this.webOnlyLabel = $htv.Platform.createLabel(this.webOnlyLabelPosition, "Web Only", this.canvas, {styleName: $htv.Styles.WebOnlyText});
        this.webOnlyLabel.hide();
        this.webOnlyBackgroundBox = $htv.Platform.createBox(this.webOnlyBackgroundBoxPosition, "CountdownBackground", this.canvas);
        this.webOnlyBackgroundBox.hide();
    };
    
    this.initializeResult = function () {
        this._initializeResult();
        this.render();
    };
    
    this.itemRenderer = function (item, focused, reflection) {
        var options;
        if (focused || $htv.Platform.properties.has_animations) {
            options = {
                width: this.SELECTED_WIDTH,
                height: this.SELECTED_HEIGHT
            };
        }
        else {
            options = {
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        }
        
        if (reflection === true) {
            options.format = "png";
            options.reflection_height = this.REFLECTION_HEIGHT;
            options.reflection_alpha_top = this.REFLECTION_ALPHA_TOP;
        }
            
        if (item.item_type === "show") {
            return $htv.Utils.getURLForShowThumb(item.show_id, options);
        }
        else if (item.item_type === "company") {
            return $htv.Utils.getURLForCompanyThumb(item.company_id, options);
        }
        else if (item.item_type === "video") {
            return $htv.Utils.getURLForVideoThumb(item.content_id, options);
        }
    };
    
    this.dispose = function () {
        this._dispose();  
        $htv.Platform.deleteItem(this.titleLabel);
        $htv.Platform.deleteItem(this.showGenreRatingLabel);
        $htv.Platform.deleteItem(this.videoSubtitlePipe);
        $htv.Platform.deleteItem(this.ccIcon);
        $htv.Platform.deleteItem(this.descriptionTextArea); 
        $htv.Platform.deleteItem(this.videoSubtitleContainer);
        $htv.Platform.deleteItem(this.progressLabel);
        $htv.Platform.deleteItem(this.playArrow);
        $htv.Platform.deleteItem(this.webOnlyLabel);
        $htv.Platform.deleteItem(this.webOnlyBackgroundBox);
        this.stars.dispose();
        this.videoSubtitlePipe = null;
        this.showGenreRatingLabel = null;
        this.descriptionTextArea = null;
        this.videoSubtitleContainer = null;
        this.titleLabelPosition = null;
        this.progressLabelPosition = null;
        this.descriptionTextAreaPosition = null;
        this.showGenreRatingLabelPosition = null;
        this.videoSubtitleContainerPosition = null;
        this.stars = null;
        this.ccIcon = null;
        this.titleLabel = null;
        this.progressLabel = null;
        this.playArrow = null;
        this.webOnlyLabel = null;
        this.webOnlyLabelPosition = null;
        this.webOnlyBackgroundBox = null;
        this.webOnlyBackgroundBoxPosition = null;
        this.webOnlyDescriptionText = null;
    };
    
    this.focus = function () {
        if (this.items.getLength() === 0) {
            this.node.view.fireEvent("LOSING_FOCUS", {
                nav_dir: "up"
            });
            return;
        }
    
        this._focus();
        this.titleLabel.show();
        this.progressLabel.show();
        this.descriptionTextArea.show();
        this.progressLabel.show();
        this.videoSubtitlePipe.show();
        this.showGenreRatingLabel.show();
        this.videoSubtitleContainer.show();
        this.stars.show();
        this.updateLabels();
    };
    
    this.unfocus = function () {
        this._unfocus();
        this.titleLabel.hide();
        this.progressLabel.hide();
        this.playArrow.hide();
        this.videoSubtitlePipe.hide();
        this.showGenreRatingLabel.hide();
        this.descriptionTextArea.hide();
        this.videoSubtitleContainer.hide();
        this.stars.hide();
        this.ccIcon.hide();
        this.webOnlyLabel.hide();
        this.webOnlyBackgroundBox.hide();
    };
    
    this.hide = function () {
        this._hide();
        this.titleLabel.hide();
        this.progressLabel.hide();
        this.playArrow.hide();
        this.videoSubtitlePipe.hide();
        this.showGenreRatingLabel.hide();
        this.descriptionTextArea.hide();
        this.videoSubtitleContainer.hide();
        this.stars.hide();
        this.ccIcon.hide();
        this.webOnlyLabel.hide();
        this.webOnlyBackgroundBox.hide();
    };
    
    this.show = function () {
        this._show();
        if (this.hasFocus === false) {
            this.titleLabel.hide();
            this.progressLabel.hide();
            this.videoSubtitlePipe.hide();
            this.showGenreRatingLabel.hide();
            this.descriptionTextArea.hide();
            this.videoSubtitleContainer.hide();
            this.stars.hide();
            this.webOnlyLabel.hide();
            this.webOnlyBackgroundBox.hide();
        }
        else {
            this.titleLabel.show();
            this.progressLabel.show();
            this.descriptionTextArea.show();
            this.progressLabel.show();
            this.videoSubtitlePipe.show();
            this.showGenreRatingLabel.show();
            this.videoSubtitleContainer.show();
            this.stars.show();
        }
    };
   
    this.updateLabels = function () {
        var activeItem, rating, totalCount;
        activeItem = this.items.getItemAt(this.activeIndex).item;
        if (activeItem === null) {
            this.videoSubtitlePipe.hide();
            this.stars.hide();
            this.webOnlyLabel.hide();
            this.webOnlyBackgroundBox.hide();
        } else if (activeItem.item_type === "company") {
            this.webOnlyLabel.hide();
            this.webOnlyBackgroundBox.hide();
        
            this.titleLabel.setText(activeItem.name);
            // NOTE: search_company API is always returning 0 episodes right now
            //this.subtitleLabel.setText("");//activeItem.full_episodes_count + " episode" + (parseInt(activeItem.full_episodes_count) === 1 ? "" : "s"));
            this.showGenreRatingLabel.hide();
            this.videoSubtitlePipe.hide();
            this.stars.hide();
            this.descriptionTextArea.setText("");
            this.playArrow.hide();
            this.ccIcon.hide();
        } else if (activeItem.item_type === "show") {
            if (activeItem.web_only === true) {
                this.webOnlyLabel.show(500);
                this.webOnlyBackgroundBox.show(2000);
            } else {
                this.webOnlyLabel.hide();
                this.webOnlyBackgroundBox.hide();
            }
            this.showGenreRatingLabel.show();
            this.videoSubtitlePipe.show();
            this.stars.show();
            this.titleLabel.setText(activeItem.title);
            rating = 3.0;
            if (activeItem.positive_votes_count > 10) {
                rating = activeItem.positive_votes_count / activeItem.votes_count;
            }
            
            this.stars.setRating(rating);
            this.showGenreRatingLabel.setText(activeItem.genre);
            if (activeItem.web_only === true) {
                this.descriptionTextArea.setText(this.webOnlyDescriptionText);
            } else {
                this.descriptionTextArea.setText(activeItem.description);
            }
            this.ccIcon.hide();
            this.playArrow.hide();
        } else if (activeItem.item_type === "video") {
            this.webOnlyLabel.hide();
            this.webOnlyBackgroundBox.hide();
            this.showGenreRatingLabel.show();
            this.videoSubtitlePipe.show();
            this.stars.show();
            if (activeItem.has_captions && activeItem.has_captions.toLowerCase() === "true") {
                this.ccIcon.show();
                if (!this.videoSubtitleContainer.containsItem(this.ccIcon)) {
                    this.videoSubtitleContainer.addItem(this.ccIcon, {
                        padding: {
                            bottom: 2
                        },
                        absolute_offset: {
                            top: 1
                        }
                    });
                }
            } else {
                this.webOnlyLabel.hide();
                this.webOnlyBackgroundBox.hide();
                this.ccIcon.hide();
                if (!this.videoSubtitleContainer.containsItem(this.ccIcon)) {
                    this.videoSubtitleContainer.removeItem(this.ccIcon);
                }
            }
            if (this.include_show_title) {
                this.titleLabel.setText(activeItem.show_name + ": " + activeItem.title);
            }
            else {
                this.titleLabel.setText(activeItem.title);
            }
            // TODO: use rating and hascaptions
            this.stars.setRating(activeItem.rating);
            this.showGenreRatingLabel.setText($htv.Utils.formatVideoSubtitle(activeItem));
            this.descriptionTextArea.setText(activeItem.description);
            this.playArrow.show();
        }
        
        totalCount = this.items.getLength();
        if (totalCount > 100 && !this.show_actual_total) {
            totalCount = "100+";
        }
        this.progressLabel.setText((this.activeIndex + 1) + " of " + totalCount + " " + this.carousel_item_type);
    };
    
    this._handleMoveDown = function () {
        var item = this.items.getItemAt(this.activeIndex).item;
        if (item === null) {
            return;
        }
        if (item.item_type === "company") {
            $htv.Controller.pushView("ContentView", {
                menu_url: item.items_url,
                view_title: item.name,
                show_id: item.show_id,
                show_name: item.title,
                previous_view_title: this.carousel_name
            });
        } else if (item.item_type === "show") {
        
            if (item.web_only === true) {
                $htv.Controller.fireEvent("WEBONLY_ITEM_ACTIVATED", {message: item.web_only_message});
            } else if ($htv.Utils.stringIsNullOrEmpty(item.feature_film_content_id)) {
                $htv.Controller.pushView("ContentView", {
                    menu_url: item.items_url,
                    view_title: item.title,
                    show_id: item.show_id,
                    show_name: item.title,
                    show_canonical_name: item.canonical_name,
                    previous_view_title: this.carousel_name
                });
            } else {
                $htv.Controller.pushView("MovieDetailsView", {
                    view_title: item.title,
                    content_id: parseInt(item.feature_film_content_id, 10),
                    show_id: item.show_id,
                    show_name: item.title,
                    video_title: item.title,
                    video_id: parseInt(item.feature_film_id, 10),
                    show_canonical_name: item.canonical_name,
                    previous_view_title: this.carousel_name
                });
            }
        } else if (item.item_type === "video") {
            $htv.Controller.pushView("VideoDetailsView", {
                url: item.items_url,
                view_title: (this.include_show_title ? (item.show_name + ": ") : "") + item.title,
                content_id: item.content_id,
                video_title: item.title,
                video_id: item.video_id,
                show_canonical_name: item.show_canonical_name,
                show_name: item.show_name,
                previous_view_title: this.carousel_name,
                include_show_title: this.include_show_title
            });
        }

    };

    this.handleInput = function (eventData) {
        this._handleInput(eventData);

        
        switch (eventData.action) {
        case "MOVE_RIGHT":
            if (!eventData.is_down || eventData.is_hold) {
                return;
            }
            this.updateLabels();
            break;
        case "MOVE_LEFT":
            if (!eventData.is_down || eventData.is_hold) {
                return;
            }
            this.updateLabels();
            break;
        // NOTE: PLAY and PLAY_PAUSE will be intercepted by Controller._handleInput
        // if player is active. So will only get here if video is not playing.
        case "PLAY":
        case "PLAY_PAUSE":
        case "PRESS_OK":
            var item = this.items.getItemAt(this.activeIndex).item;
            if (item === null) {
                return;
            }
            

            if (item.item_type !== "video") {
                if (eventData.is_down) {
                    this._handleMoveDown();
                }
            } else {
                if ((eventData.action === "PRESS_OK" || eventData.action === "PLAY") && this.items.getItemAt(this.activeIndex).item) {
                    if (eventData.is_down) {
                        this.playArrow.setURL("images/play-arrow-hover.png");
                    } else {
                        this.playArrow.setURL("images/play-arrow.png");
                        
                        $htv.Controller.playVideo(this.items.getItemAt(this.activeIndex).item.content_id, { package_id: this.package_id });
                    }
                }
            }
        
            break;
        default:
            
            break;
        }
    };

    this.render = this._render;
    this.jumpToIndex = this._jumpToIndex;
    this.getDataSource = this._getDataSource;
    this.handleEvent = this._handleEvent;
};

// shows 5 thumbs, one hidden on each wing.
$htv.Controls.ShowThumbnailCarousel = function () {
    $htv.Controls.BaseThumbnailCarousel.call(this);
    this.className = "ShowThumbnailCarousel";
    this.carousel_name = "unnamed show carousel";
    this.is_queue_carousel = null;
    this.starRatingLabel = null;
    this.stars = null;
    this.starsGenrePipe = null;
    this.starsGenreContainer = null;
    this.descriptionTextArea = null;
    this.descriptionTextAreaPosition = null;
    this.showGenreRatingLabelPosition = null;
    this.showGenreRatingLabel = null;
    this.showTitleLabelPosition = null;
    this.showTitleLabel = null;
    this.progressLabelPosition = null;
    this.progressLabel = null;
    this.updateLabelsTimer = null;
    this.starsGenreContainerPosition = null;
    this.companyBugPipe = null;
    
    this.initialize = function (position, target, url, options) {
        
        this.carousel_item_type = "shows";
        this.is_queue_carousel = false;
        this.updateLabelsTimer = null;
        this.itemFields = ['canonical_name', 'collation_name', 'cmtype', 'items_url', 'title', 'genre', 'show_id', 'description', 'rating', 'feature_film_content_id', 'feature_film_id', 'clips_count', 'total_seasons_count', 'company_name', 'company_id', 'include_company_logo'];
        this._initialize(position, target, url, options);
        
        if (options.hasOwnProperty("is_queue_carousel") && (parseInt(options.is_queue_carousel, 10) === 1)) {
            
            this.is_queue_carousel = true;
        }
        
        this.starsGenreContainerPosition = {
            x: this.x,
            y: this.displayPositions[3].y - 35,
            z: this.z + 1,
            width: this.width,
            height: 22
        };
        
        this.showTitleLabelPosition = {
            x: this.x + 15,
            y: this.starsGenreContainerPosition.y - 35,
            z: this.z + 1,
            width: this.width - 30,
            height: 34
        };
        
        // NOTE: right-aligned
        this.progressLabelPosition = {
            x: this.x,
            y: this.y + this.height - 60,
            z: this.z + 1,
            width: this.width - 50,
            height: 30
        };
        
        this.stars = null;

        this.showGenreRatingLabelPosition = {
            x: 0,
            y: 0,
            z: this.z + 1,
            width: this.width,
            height: 22
        };
        this.descriptionTextAreaPosition = {
            x: this.displayPositions[3].x,
            y: this.displayPositions[3].y + this.displayPositions[3].height + 20,
            z: this.z + 1,
            width: this.displayPositions[3].width + 35,
            height: 75
        };
        this.stars = $htv.ControlPool.getObject("RatingStarsControl");
        this.stars.initialize({
                x: 0,
                y: 0,
                z: this.z + 1,
                width: 92,
                height: 16
            }, null, null, { rating: 0 });
        this.stars.hide();
        this.starsGenreContainer = $htv.Platform.createContainer(this.starsGenreContainerPosition, this.canvas, {spacing: 13, center: true});
        this.starsGenrePipe = $htv.Platform.createImage({
            x: 0, 
            y: 0, 
            z: this.z + 1, 
            width: 1, 
            height: 14
        }, "images/small_pipe.png", this.canvas);
        this.starsGenrePipe.hide();
        this.companyBugPipe = $htv.Platform.createImage({
            x: 0, 
            y: 0, 
            z: this.z + 1, 
            width: 1, 
            height: 14
        }, "images/small_pipe.png", this.canvas);
        this.companyBugPipe.hide();
        
        this.starsGenreContainer.hide();
        this.showTitleLabel = $htv.Platform.createLabel(this.showTitleLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailTitle});
        this.showGenreRatingLabel = $htv.Platform.createLabel(this.showGenreRatingLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailSubtitle});
        this.starsGenreContainer.addItem(this.showGenreRatingLabel);
        this.starsGenreContainer.addItem(this.starsGenrePipe, {padding: {bottom: 1}, absolute_offset: {top: 2}});
        this.starsGenreContainer.addItem(this.stars.getContainer(), {padding: {bottom: 2}, absolute_offset: {top: 0}});
        this.descriptionTextArea = $htv.Platform.createTextArea(this.descriptionTextAreaPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailDescription});
        this.progressLabel = $htv.Platform.createLabel(this.progressLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselProgress});
    };
    
    this.initializeResult = function () {
        this._initializeResult();
        this.render();
    };
    
    this.itemRenderer = function (item, focused, reflection) {
        var options;
        if (focused || $htv.Platform.properties.has_animations) {
            options = {
                width: this.SELECTED_WIDTH,
                height: this.SELECTED_HEIGHT
            };
        }
        else {
            options = {
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        }
        
        if (reflection === true) {
            options.format = "png";
            options.reflection_height = this.REFLECTION_HEIGHT;
            options.reflection_alpha_top = this.REFLECTION_ALPHA_TOP;
        }
        
        return $htv.Utils.getURLForShowThumb(item.show_id, options);
    };
    
    this.dispose = function () {
        this._dispose();  
        $htv.Platform.deleteItem(this.showTitleLabel);
        $htv.Platform.deleteItem(this.showGenreRatingLabel);
        $htv.Platform.deleteItem(this.starsGenrePipe);
        $htv.Platform.deleteItem(this.descriptionTextArea); 
        $htv.Platform.deleteItem(this.progressLabel);
        $htv.Platform.deleteItem(this.starsGenreContainer);
        $htv.Platform.deleteItem(this.companyBugPipe);
        this.stars.dispose();
        this.showTitleLabel = null;
        this.showTitleLabelPosition = null;
        this.starsGenrePipe = null;
        this.showGenreRatingLabel = null;
        this.showGenreRatingLabelPosition = null;
        this.descriptionTextArea = null;
        this.descriptionTextAreaPosition = null;
        this.progressLabel = null;
        this.progressLabelPosition = null;
        this.starsGenreContainer = null;
        this.starsGenreContainerPosition = null;
        this.stars = null;
        this.companyBugPipe = null;
        if (this.updateLabelsTimer !== null) {
            this.updateLabelsTimer.stop();
            this.updateLabelsTimer = null;
        }
    };
    
    this.focus = function () {
        if (this.items.getLength() === 0) {
            this.node.view.fireEvent("LOSING_FOCUS", {
                nav_dir: "up"
            });
            return;
        }
    
        this._focus();
        if (this.initialized === true) {
            this.updateLabels();
            this.showTitleLabel.show();
            this.descriptionTextArea.show();
            this.progressLabel.show();
            this.starsGenrePipe.show();
            this.showGenreRatingLabel.show();
            this.starsGenreContainer.show();
            this.stars.show();
        }
    };
    
    this.unfocus = function () {
        this._unfocus();
        this.showTitleLabel.hide();
        this.progressLabel.hide();
        this.starsGenrePipe.hide();
        this.showGenreRatingLabel.hide();
        this.descriptionTextArea.hide();
        this.starsGenreContainer.hide();
        this.stars.hide();
        this.companyBugPipe.hide();
    };
    
    this.hide = function () {
        this._hide();
        this.showTitleLabel.hide();
        this.progressLabel.hide();
        this.starsGenrePipe.hide();
        this.showGenreRatingLabel.hide();
        this.descriptionTextArea.hide();
        this.starsGenreContainer.hide();
        this.stars.hide();
        this.companyBugPipe.hide();
    };
    
    this.show = function () {
        this._show();
        // hasfocus may not be needed... view should focus active view on restore.
        if (this.hasFocus === false) {
            this.showTitleLabel.hide();
            this.starsGenrePipe.hide();
            this.showGenreRatingLabel.hide();
            this.descriptionTextArea.hide();
            this.progressLabel.hide();
            this.starsGenreContainer.hide();
            this.stars.hide();
        }
        else {
            this.showTitleLabel.show();
            this.starsGenrePipe.show();
            this.showGenreRatingLabel.show();
            this.descriptionTextArea.show();
            this.progressLabel.show();
            this.starsGenreContainer.show();
            this.stars.show();
        }
    };
   
    this.updateLabels = function () {
        var activeItem, totalCount;
        activeItem = this.items.getItemAt(this.activeIndex).item;
        if (!activeItem) {
            return;
        }
        
        this.showTitleLabel.setText(activeItem.title);
        
        totalCount = this.items.getLength();
        if (totalCount > 100 && !this.show_actual_total) {
            totalCount = "100+";
        }
        this.progressLabel.setText((this.activeIndex + 1) + " of " + totalCount + " " + this.carousel_item_type);
        
        if ($htv.Controller.isKeyHeld()) {
            if (this.updateLabelsTimer === null) {
                this.updateLabelsTimer = $htv.Platform.createTimer(400, this, this.updateLabelsDelayed);
            }
            this.updateLabelsTimer.start();
            this.showGenreRatingLabel.hide();
            this.starsGenrePipe.hide();
            this.stars.hide();
            this.descriptionTextArea.hide();
            this.companyBug.hide();
            this.companyBugPipe.hide();
        } else {
            if (this.updateLabelsTimer !== null) {
                this.updateLabelsTimer.stop();
                this.updateLabelsTimer = null;
                
                this.showGenreRatingLabel.show();
                this.starsGenrePipe.show();
                this.stars.show();
                this.descriptionTextArea.show();
            }
            
            this.updateLabelsHelper(activeItem);
        }
    };
    
    this.updateLabelsDelayed = function () {
        if (this.updateLabelsTimer !== null) {
            this.updateLabelsTimer.stop();
            this.updateLabelsTimer = null;
        }
        if (this.visible !== true || this.hasFocus !== true) {
            return;
        }
        
        var activeItem = this.items.getItemAt(this.activeIndex).item;
        if (!activeItem) {
            return;
        }
        this.showGenreRatingLabel.show();
        this.starsGenrePipe.show();
        this.stars.show();
        this.descriptionTextArea.show();
        
        this.updateLabelsHelper(activeItem);
    };
    
    this.updateLabelsHelper = function (item) {
        this.stars.setRating(item.rating);
        this.showGenreRatingLabel.setText(item.genre);
        if (this.is_queue_carousel === true) {
            // we need the final counts, somethind like
            // $htv.Utils.getQueuedShowCounts(updateLabelsAsyncHelper);
            this.descriptionTextArea.setText(item.description);
        }
        else {
            this.descriptionTextArea.setText(item.description);
        }
        
        var newCompanyBugUrl = null;
        if (item.include_company_logo && item.include_company_logo.toLowerCase() === "true") {
            newCompanyBugUrl = $htv.Utils.getURLForCompanyLogo(item.company_id, {
                width: 41,
                height: 18,
                maintain_ratio: true,
                format: "png"
            });
        }
        if ($htv.Utils.stringIsNullOrEmpty(newCompanyBugUrl)) {
            if (this.starsGenreContainer.containsItem(this.companyBug)) {
                this.starsGenreContainer.removeItem(this.companyBug);
            }
            if (this.starsGenreContainer.containsItem(this.companyBugPipe)) {
                this.starsGenreContainer.removeItem(this.companyBugPipe);
            }
            this.companyBug.hide();
            this.companyBugPipe.hide();
        }
        else if (this.companyBugUrl === newCompanyBugUrl) {
            if (!this.starsGenreContainer.containsItem(this.companyBug)) {
                this.starsGenreContainer.addItemAtIndex(this.companyBug, 0, {absolute_offset: {top: 2}});
            }
            this.companyBug.show();
            if (!this.starsGenreContainer.containsItem(this.companyBugPipe)) {
                this.starsGenreContainer.addItemAtIndex(this.companyBugPipe, 1, {padding: {bottom: 1}, absolute_offset: {top: 2}});
            }
            this.companyBugPipe.show();
        }
        else {
            if (this.starsGenreContainer.containsItem(this.companyBug)) {
                this.starsGenreContainer.removeItem(this.companyBug);
            }
            this.companyBugUrl = newCompanyBugUrl;
            $htv.Platform.deleteItem(this.companyBug);
            this.companyBug = $htv.Platform.createImage({
                x: 0,
                y: 0,
                z: this.z + 1,
                width: 41,
                height: 18
            }, this.companyBugUrl, this.canvas);
            this.starsGenreContainer.addItemAtIndex(this.companyBug, 0, {absolute_offset: {top: 2}});
            if (!this.starsGenreContainer.containsItem(this.companyBugPipe)) {
                this.starsGenreContainer.addItemAtIndex(this.companyBugPipe, 1, {padding: {bottom: 1}, absolute_offset: {top: 2}});
            }
            this.companyBugPipe.show();
        }
    };
    
    this.updateLabelsAsyncHelper = function (results) {
        this.descriptionTextArea.setText("");
    }; 
    
    this._handleMoveDown = function () {
        if ($htv.Utils.stringIsNullOrEmpty(this.items.getItemAt(this.activeIndex).item.feature_film_content_id)) {
            $htv.Controller.pushView("ContentView", {
                menu_url: this.items.getItemAt(this.activeIndex).item.items_url,
                view_title: this.items.getItemAt(this.activeIndex).item.title,
                show_id: this.items.getItemAt(this.activeIndex).item.show_id,
                show_name: this.items.getItemAt(this.activeIndex).item.title,
                show_canonical_name: this.items.getItemAt(this.activeIndex).item.canonical_name,
                previous_view_title: this.carousel_name,
                total_seasons_count: this.items.getItemAt(this.activeIndex).item.total_seasons_count
            });
        } else if (this.is_queue_carousel === true) {
            $htv.Controller.pushView("ContentView", {
                menu_url: this.items.getItemAt(this.activeIndex).item.items_url,
                view_title: this.items.getItemAt(this.activeIndex).item.title,
                show_id: this.items.getItemAt(this.activeIndex).item.show_id,
                show_name: this.items.getItemAt(this.activeIndex).item.title,
                show_canonical_name: this.items.getItemAt(this.activeIndex).item.canonical_name,
                previous_view_title: this.carousel_name,
                total_seasons_count: this.items.getItemAt(this.activeIndex).item.total_seasons_count,
                feature_film_video_title: this.items.getItemAt(this.activeIndex).item.title,
                feature_film_content_id: parseInt(this.items.getItemAt(this.activeIndex).item.feature_film_content_id, 10),
                feature_film_video_id: parseInt(this.items.getItemAt(this.activeIndex).item.feature_film_id, 10),
                clips_count: this.items.getItemAt(this.activeIndex).item.clips_count
            });
        } else {
            $htv.Controller.pushView("MovieDetailsView", {
                view_title: this.items.getItemAt(this.activeIndex).item.title,
                content_id: parseInt(this.items.getItemAt(this.activeIndex).item.feature_film_content_id, 10),
                show_id: this.items.getItemAt(this.activeIndex).item.show_id,
                show_name: this.items.getItemAt(this.activeIndex).item.title,
                video_title: this.items.getItemAt(this.activeIndex).item.title,
                video_id: parseInt(this.items.getItemAt(this.activeIndex).item.feature_film_id, 10),
                show_canonical_name: this.items.getItemAt(this.activeIndex).item.canonical_name,
                previous_view_title: this.carousel_name,
                clips_count: this.items.getItemAt(this.activeIndex).item.clips_count
            });
        }
    };

    this.handleInput = function (eventData) {
        this._handleInput(eventData);
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        
        switch (eventData.action) {
        case "MOVE_RIGHT":
            this.updateLabels();
            break;
        case "MOVE_LEFT":
            this.updateLabels();
            break;
        case "PRESS_OK":
            this._handleMoveDown();
            break;
        default:
            
            break;
        }
    };

    this.render = this._render;
    this.jumpToIndex = this._jumpToIndex;
    this.getDataSource = this._getDataSource;
    this.handleEvent = this._handleEvent;
};
    
// shows 5 video thumbs plus one hidden on each wing (total 7)
$htv.Controls.VideoThumbnailCarousel = function () {
    $htv.Controls.BaseThumbnailCarousel.call(this);
    // member variables
    this.className = "VideoThumbnailCarousel";
    this.carousel_name = "unnamed video carousel";
    this.videoTitleLabelPosition = null;
    this.videoTitleLabel = null;
    this.progressLabelPosition = null;
    this.progressLabel = null;
    this.dataWaiting = false;
    this.startAtEnd = false;
    this.hasFocus = false;
    
    this.playArrow = null;
    this.availabilityNotes = null;
    this.availabilityNotesContainer = null;
    this.updateLabelsTimer = null;
    this.videoSubtitleContainer = null;
    this.typeDurationLabel = null;
    this.typeDurationPipe = null;
    this.stars = null;
    this.ccIcon = null;
    this.expirationIcon = null;
    this.expirationLabel = null;
    this.hideExpiration = false;
    this.companyBugPipe = null;
    
    // called by object pool to initialize the control's position and data source.
    this.initialize = function (position, target, url, options) {
        var i, layoutInstructions;
        this.itemFields = ['add_cb', 'login_required', 'collation_title', 'thumb_url', 'content_id', 'items_url', 'show_name', 'title', 'season_number', 'episode_number', 'programming_type', 'video_id', 'duration', 'has_captions', 'rating', 'show_id', 'programming_type', 'video_type', 'show_canonical_name', 'company_name', 'company_id', 'plus_living_room_expires_at', 'include_company_logo'];
        this.updateLabelsTimer = null;
        this.carousel_item_type = "videos";
        this._initialize(position, target, url, options);
        
        this.videoTitleLabelPosition = {
            x: this.x + 15,
            y: this.displayPositions[3].y + this.displayPositions[3].height + 20,
            z: this.z + 1,
            width: this.width - 30,
            height: 34
        };
        // NOTE: right-aligned
        this.progressLabelPosition = {
            x: this.x,
            y: this.y + this.height - 60,
            z: this.z + 1,
            width: this.width - 50,
            height: 30
        };
        this.videoSubtitleContainer = $htv.Platform.createContainer({
                x: this.x,
                y: this.displayPositions[3].y + this.displayPositions[3].height + 54,
                z: this.z + 1,
                width: this.width,
                height: 22
            }, this.canvas, {center: true, spacing: 13, edgePadding: 0});
        this.typeDurationLabel = $htv.Platform.createLabel({
            x: 0,
            y: 0,
            z: this.z + 1,
            width: this.width,
            height: 22
        }, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailSubtitle});
        this.typeDurationPipe = $htv.Platform.createImage({
            x: 0, 
            y: 0, 
            z: this.z + 1, 
            width: 1, 
            height: 14
        }, "images/small_pipe.png", this.canvas);
        this.typeDurationPipe.hide();
        this.stars = $htv.ControlPool.getObject("RatingStarsControl");
        this.stars.initialize({
                x: 0,
                y: 0,
                z: this.z + 1,
                width: 92,
                height: 16
            }, null, null, { rating: 0 });
        this.stars.hide();
        // always have the ccIcon around.
        this.ccIcon = $htv.Platform.createImage({
            x: 0,
            y: 0,
            z: this.z + 1,
            width: 20,
            height: 14
        }, "images/cc-icon.png", this.canvas);
        this.ccIcon.hide();
        this.companyBugPipe = $htv.Platform.createImage({
            x: 0, 
            y: 0, 
            z: this.z + 1, 
            width: 1, 
            height: 14
        }, "images/small_pipe.png", this.canvas);
        this.companyBugPipe.hide();
        this.playArrow = $htv.Platform.createImage({
            x: this.displayPositions[this.selectedItemIndex].x + this.displayPositions[this.selectedItemIndex].width / 2 - 53 / 2,
            y: this.displayPositions[this.selectedItemIndex].y + this.displayPositions[this.selectedItemIndex].height / 2 - 62 / 2,
            z: this.z + 1,
            width: 53,
            height: 62
        }, "images/play-arrow.png", this.canvas);
        this.playArrow.hide();
        this.expirationIcon = $htv.Platform.createImage({
            x: this.displayPositions[this.selectedItemIndex].x + 80,
            y: this.displayPositions[this.selectedItemIndex].y + this.displayPositions[this.selectedItemIndex].height + 81,
            z: this.z + 1,
            width: 14,
            height: 14
        }, "images/expiration-icon.png", this.canvas);
        this.expirationIcon.hide();
        this.expirationLabel = $htv.Platform.createLabel({
            x: this.displayPositions[this.selectedItemIndex].x + 100,
            y: this.displayPositions[this.selectedItemIndex].y + this.displayPositions[this.selectedItemIndex].height + 80,
            z: this.z + 1,
            width: this.width,
            height: 22
        }, "Expires in 4 days", this.canvas, {styleName: $htv.Styles.ExpirationText});
        this.expirationLabel.hide();
        /*jslint onevar: false */
        // TODO: reenable availability notes once we have Plus-specific ones
        if (false &&
            options.metadata_item !== null &&
            options.metadata_item !== undefined &&
            !$htv.Utils.stringIsNullOrEmpty(options.metadata_item.availability_notes) &&
            options.include_availability_notes === true) {

            // Availability notes suck: Stargate Atlantis and Outer Limits are the longest
            // Try a few increasing sizes (if necessary) to see if we can get it to fit and look nice
            layoutInstructions = [{
                width: 350,
                height: 130,
                y: this.displayPositionsUnfocused[this.selectedItemIndex].y + this.displayPositionsUnfocused[this.selectedItemIndex].height + 40
            }, {
                width: 500,
                height: 130,
                y: this.displayPositionsUnfocused[this.selectedItemIndex].y + this.displayPositionsUnfocused[this.selectedItemIndex].height + 40                
            }, {
                width: 650,
                height: 130,
                y: this.displayPositionsUnfocused[this.selectedItemIndex].y + this.displayPositionsUnfocused[this.selectedItemIndex].height + 40                
            }, {
                width: 650,
                height: 150,
                y: this.displayPositionsUnfocused[this.selectedItemIndex].y + this.displayPositionsUnfocused[this.selectedItemIndex].height + 20               
            }];

            // Lay out with the first instruction
            i = 0;
            this.availabilityNotes = $htv.Platform.createTextArea({
                x: 0,
                y: 0,
                z: this.z,
                width: layoutInstructions[i].width,
                height: 20 // placeholder height 
            }, "Availability Notes:  " + options.metadata_item.availability_notes, this.canvas, {styleName: $htv.Styles.AvailabilityNotes});
            this.availabilityNotesContainer = $htv.Platform.createContainer({
                x: this.x + this.width / 2 - layoutInstructions[i].width / 2 - 20,
                y: layoutInstructions[i].y,
                z: this.z,
                width: layoutInstructions[i].width + 40,
                height: layoutInstructions[i].height
            }, this.canvas, {center: true, spacing: 0, edgePadding: 0});
            this.availabilityNotesContainer.addItem(this.availabilityNotes);
            
            // If overflowed, try the other instructions
            while (this.availabilityNotesContainer.contentsOverflowed() && (i + 1) < layoutInstructions.length) {
                i++;
                this.availabilityNotes.move({
                    x: 0,
                    y: 0,
                    z: this.z,
                    width: layoutInstructions[i].width,
                    height: 20 // placeholder height 
                });
                this.availabilityNotesContainer.move({
                    x: this.x + this.width / 2 - layoutInstructions[i].width / 2 - 20,
                    y: layoutInstructions[i].y,
                    z: this.z,
                    width: layoutInstructions[i].width + 40,
                    height: layoutInstructions[i].height                 
                });
            }
            /*jslint onevar: true */
        }
        
        this.hideExpiration = (options.hasOwnProperty("hide_expiration") && options.hide_expiration === true);
        
        this.videoSubtitleContainer.addItem(this.typeDurationLabel);
        this.videoSubtitleContainer.addItem(this.typeDurationPipe, {padding: {bottom: 1}, absolute_offset: {top: 2}});
        this.videoSubtitleContainer.addItem(this.stars.getContainer(), {padding: {bottom: 2}, absolute_offset: {top: 0}});
        // Don't add ccIcon until shown in updateLabels (to maintain centering)
        // this.videoSubtitleContainer.addItem(this.ccIcon, {padding: {bottom: 2}});
        this.videoTitleLabel = $htv.Platform.createLabel(this.videoTitleLabelPosition, "", this.canvas, {
            styleName: $htv.Styles.CarouselThumbnailTitle
        });
        this.progressLabel = $htv.Platform.createLabel(this.progressLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselProgress});
    };
    
    this.initializeResult = function () {
        this._initializeResult();
        this.render();
    };
    
    this.itemRenderer = function (item, focused, reflection) {
        var options;
        if (focused || $htv.Platform.properties.has_animations) {
            options = {
                width: this.SELECTED_WIDTH,
                height: this.SELECTED_HEIGHT
            };
        } else {
            options = {
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        }
        
        if (reflection === true) {
            options.format = "png";
            options.reflection_height = this.REFLECTION_HEIGHT;
            options.reflection_alpha_top = this.REFLECTION_ALPHA_TOP;
        }
        
        // todo: fast seek causes a problem.
        return $htv.Utils.getURLForVideoThumb(item.content_id, options);
    };
    
    this.render = function () {

        this._render();
    };
    
    this.jumpToIndex = function (index) {
        this._jumpToIndex(index);
    };
    
    this.getDataSource = this._getDataSource;
    
    // reset state
    this.dispose = function () {
        this._dispose();
        $htv.Platform.deleteItem(this.videoTitleLabel);
        $htv.Platform.deleteItem(this.progressLabel);
        $htv.Platform.deleteItem(this.typeDurationLabel);
        $htv.Platform.deleteItem(this.typeDurationPipe);
        $htv.Platform.deleteItem(this.ccIcon);
        $htv.Platform.deleteItem(this.videoSubtitleContainer);
        $htv.Platform.deleteItem(this.playArrow);
        $htv.Platform.deleteItem(this.expirationIcon);
        $htv.Platform.deleteItem(this.expirationLabel);
        $htv.Platform.deleteItem(this.companyBugPipe);
        if (this.availabilityNotes !== null) {
            $htv.Platform.deleteItem(this.availabilityNotes);
            this.availabilityNotes = null;
        }
        if (this.availabilityNotesContainer !== null) {
            $htv.Platform.deleteItem(this.availabilityNotesContainer);
            this.availabilityNotesContainer = null;
        }
        this.stars.dispose();
        this.playArrow = null;
        this.videoTitleLabel = null;
        this.progressLabel = null;
        this.typeDurationPipe = null;
        this.typeDurationLabel = null;
        this.ccIcon = null;
        this.videoSubtitleContainer = null;
        this.stars = null;
        this.progressLabelPosition = null;
        this.videoTitleLabelPosition = null;
        this.expirationIcon = null;
        this.expirationLabel = null;
        this.companyBugPipe = null;
        if (this.updateLabelsTimer !== null) {
            this.updateLabelsTimer.stop();
            this.updateLabelsTimer = null;
        }
    };
    
    // optionally show and hide overlays, go into a minimized state, etc
    this.focus = function () {
        if (this.items.getLength() === 0) {
            this.node.view.fireEvent("LOSING_FOCUS", {
                nav_dir: "up"
            });
            return;
        }
    
        this._focus();
        if (this.initialized === true) {
            this.updateLabels();
            this.videoTitleLabel.show();
            this.progressLabel.show();
            this.videoSubtitleContainer.show();
            this.stars.show();
            this.typeDurationPipe.show();
            this.typeDurationLabel.show();
            this.playArrow.show();
            if (this.availabilityNotes !== null) {
                this.availabilityNotes.hide();
            }
        }
    };
    
    this.unfocus = function () {
        this._unfocus();
        this.videoTitleLabel.hide();
        this.progressLabel.hide();   
        this.videoSubtitleContainer.hide();
        this.stars.hide();
        this.ccIcon.hide();
        this.typeDurationPipe.hide();
        this.typeDurationLabel.hide();
        this.playArrow.hide();
        this.expirationIcon.hide();
        this.expirationLabel.hide();
        this.companyBugPipe.hide();
        if (this.availabilityNotes !== null) {
            this.availabilityNotes.show();
        }

        if (this.use_related_title === false) {
            // If unfocused show logo is different than thumb's show logo
            var item = this.items.getItemAt(this.activeIndex).item;
            if (item !== null && this.last_show_thumb_id !== this.show_id && this.show_id > 0) {
                this._updateShowLogo(this.show_id);
            }
        }
    };
    
    this.hide = function () {
        this._hide();
        this.videoTitleLabel.hide();
        this.progressLabel.hide();   
        this.videoSubtitleContainer.hide();
        this.stars.hide();
        this.ccIcon.hide();
        this.typeDurationPipe.hide();
        this.typeDurationLabel.hide();        
        this.playArrow.hide();
        this.expirationIcon.hide();
        this.expirationLabel.hide();
        this.companyBugPipe.hide();
        if (this.availabilityNotes !== null) {
            this.availabilityNotes.hide();
        }
    };
    
    this.show = function () {
        this._show();
        if (this.hasFocus === false) {
            this.videoTitleLabel.hide();
            this.progressLabel.hide();   
            this.videoSubtitleContainer.hide();
            this.playArrow.hide();
            if (this.availabilityNotes !== null) {
                this.availabilityNotes.show();
            }
        }
        else {
            this.videoTitleLabel.show();
            this.progressLabel.show();   
            this.videoSubtitleContainer.show();
            this.playArrow.show();
            if (this.availabilityNotes !== null) {
                this.availabilityNotes.hide();
            }
        }
    };
    
    this.handleEvent = this._handleEvent;
    
    this.updateLabels = function () {
        var item, totalCount;
        // update text fields
        if (this.items.getLength() > 0) {
            if (this.dataWaiting === false) {
                item = this.items.getItemAt(this.activeIndex).item;
                if (item !== null) { // todo: there was an item is undefined crash here.
                    if (this.include_show_title) {
                        this.videoTitleLabel.setText(item.show_name + ": " + item.title);
                    }
                    else {
                        this.videoTitleLabel.setText(item.title);
                    }
                    
                    if ($htv.Controller.isKeyHeld()) {
                        if (this.updateLabelsTimer === null) {
                            this.updateLabelsTimer = $htv.Platform.createTimer(400, this, this.updateLabelsDelayed);
                        }
                        this.updateLabelsTimer.start();
                        
                        this.typeDurationLabel.hide();
                        this.typeDurationPipe.hide();
                        this.stars.hide();
                        this.ccIcon.hide();
                        this.showImage.hide();
                        this.companyBug.hide();
                        this.companyBugPipe.hide();
                        this.expirationIcon.hide();
                        this.expirationLabel.hide();
                    }
                    else {
                        if (this.updateLabelsTimer !== null) {
                            this.updateLabelsTimer.stop();
                            this.updateLabelsTimer = null;
                            
                            this.typeDurationLabel.show();
                            this.typeDurationPipe.show();
                            this.stars.show();
                        }
                        
                        this.updateLabelsHelper(item);
                    }
                    
                    this.loadingLabel.hide();
                } else {
                    this.dataWaiting = true;
                    this.loadingLabel.show();
                }
            } else {
                this.videoTitleLabel.setText("");
                this.loadingLabel.hide();
            }
            totalCount = this.items.getLength();
            if (totalCount > 100 && !this.show_actual_total) {
                totalCount = "100+";
            }
            this.progressLabel.setText((this.activeIndex + 1) + " of " + totalCount + " " + this.carousel_item_type);
            
        } else {
            if (this.dataWaiting === true) {
                this.loadingLabel.show();
            }
            else {
                this.videoTitleLabel.setText("No Videos Found.");
                this.loadingLabel.hide();
            }
        }
    };
    
    this.updateLabelsDelayed = function () {
        if (this.updateLabelsTimer !== null) {
            this.updateLabelsTimer.stop();
            this.updateLabelsTimer = null;
        }
        if (this.visible !== true || this.hasFocus !== true) {
            return;
        }
        
        var activeItem = this.items.getItemAt(this.activeIndex).item;
        if (!activeItem) {
            return;
        }
        this.typeDurationLabel.show();
        this.typeDurationPipe.show();
        this.stars.show();
        this.updateLabelsHelper(activeItem);
    };
    
    this.updateLabelsHelper = function (item) {
        var expiresDate, expiresHours, expiresDays, expiresWeeks, newCompanyBugUrl = null;
        if (item.has_captions && item.has_captions.toLowerCase() === "true") {
            this.ccIcon.show();
            if (!this.videoSubtitleContainer.containsItem(this.ccIcon)) {
                this.videoSubtitleContainer.addItem(this.ccIcon, {
                    padding: {
                        bottom: 2
                    },
                    absolute_offset: {
                        top: 1
                    }
                });
            }
        } else {
            this.ccIcon.hide();
            if (this.videoSubtitleContainer.containsItem(this.ccIcon)) {
                this.videoSubtitleContainer.removeItem(this.ccIcon);
            }
        }
        
        // Parse the expiration date and see if it falls within the number of hours for notification
        expiresDate = $htv.Utils.parseDate(item.plus_living_room_expires_at);
        expiresHours = Math.round((expiresDate - (new Date())) / 3600000);
        if (expiresDate &&
            expiresHours > 0 && expiresHours < $htv.Constants.Endpoints.expiration_notice_hours &&
            this.hideExpiration !== true) {
            if (expiresHours >= 168) {
                expiresWeeks = Math.floor(expiresHours / 168);
                this.expirationLabel.setText("Expires in " + expiresWeeks + " week" + (expiresWeeks > 1 ? "s" : ""));
            } else if (expiresHours >= 24) {
                expiresDays = Math.floor(expiresHours / 24);
                this.expirationLabel.setText("Expires in " + expiresDays + " day" + (expiresDays > 1 ? "s" : ""));
            } else {
                this.expirationLabel.setText("Expires in " + expiresHours + " hour" + (expiresHours > 1 ? "s" : ""));
            }
            this.expirationIcon.show();
            this.expirationLabel.show();
        } else {
            this.expirationIcon.hide();
            this.expirationLabel.hide();
        }
        
        this.stars.setRating(item.rating);
        this.typeDurationLabel.setText($htv.Utils.formatVideoSubtitle(item));
        
        if (item.show_id !== this.last_show_thumb_id) {
            this._updateShowLogo(item.show_id);
        }
        this.showImage.show();
        
        if (item.include_company_logo && item.include_company_logo.toLowerCase() === "true") {
            newCompanyBugUrl = $htv.Utils.getURLForCompanyLogo(item.company_id, {
                width: 41,
                height: 18,
                maintain_ratio: true,
                format: "png"
            });
        }
        if ($htv.Utils.stringIsNullOrEmpty(newCompanyBugUrl)) {
            if (this.videoSubtitleContainer.containsItem(this.companyBug)) {
                this.videoSubtitleContainer.removeItem(this.companyBug);
            }
            if (this.videoSubtitleContainer.containsItem(this.companyBugPipe)) {
                this.videoSubtitleContainer.removeItem(this.companyBugPipe);
            }
            this.companyBug.hide();
            this.companyBugPipe.hide();
        }
        else if (this.companyBugUrl === newCompanyBugUrl) {
            if (!this.videoSubtitleContainer.containsItem(this.companyBug)) {
                this.videoSubtitleContainer.addItemAtIndex(this.companyBug, 0, {absolute_offset: {top: 2}});
            }
            this.companyBug.show();
            if (!this.videoSubtitleContainer.containsItem(this.companyBugPipe)) {
                this.videoSubtitleContainer.addItemAtIndex(this.companyBugPipe, 1, {padding: {bottom: 1}, absolute_offset: {top: 2}});
            }
            this.companyBugPipe.show();
        }
        else {
            if (this.videoSubtitleContainer.containsItem(this.companyBug)) {
                this.videoSubtitleContainer.removeItem(this.companyBug);
            }
            this.companyBugUrl = newCompanyBugUrl;
            $htv.Platform.deleteItem(this.companyBug);
            this.companyBug = $htv.Platform.createImage({
                x: 0,
                y: 0,
                z: this.z + 1,
                width: 41,
                height: 18
            }, this.companyBugUrl, this.canvas);
            this.videoSubtitleContainer.addItemAtIndex(this.companyBug, 0, {absolute_offset: {top: 2}});
            
            if (!this.videoSubtitleContainer.containsItem(this.companyBugPipe)) {
                this.videoSubtitleContainer.addItemAtIndex(this.companyBugPipe, 1, {padding: {bottom: 1}, absolute_offset: {top: 2}});
            }
            this.companyBugPipe.show();
        }
    };
    
    this._handleMoveDown = function () {
        var item = this.items.getItemAt(this.activeIndex).item;
        if (!item) { // user exception guard handles this case but not in AS2!
            
            return;
        }
        if (item.video_type === "feature_film") {
            $htv.Controller.pushView("MovieDetailsView", {
                view_title: (this.include_show_title ? (item.show_name + ": ") : "") + item.title,
                content_id: parseInt(item.content_id, 10),
                show_id: parseInt(item.show_id, 10),
                show_name: item.title,
                video_title: item.title,
                video_id: parseInt(item.video_id, 10),
                show_canonical_name: item.show_canonical_name,
                previous_view_title: this.carousel_name
            });
        } else {
            $htv.Controller.pushView("VideoDetailsView", {
                url: item.items_url,
                view_title: (this.include_show_title ? (item.show_name + ": ") : "") + item.title,
                content_id: item.content_id,
                video_title: item.title,
                video_id: item.video_id,
                show_id: parseInt(item.show_id, 10),
                show_name: item.show_name,
                show_canonical_name: item.show_canonical_name,
                previous_view_title: this.carousel_name,
                include_show_title: this.include_show_title
            });
        }
    };
    
    // user input passed in from platform/controller.
    this.handleInput = function (eventData) {
        var i, index, item, thumburl;
        this._handleInput(eventData);

        switch (eventData.action) {
        case "PLAY":
        case "PRESS_OK":
            if (eventData.is_down) {
                this.playArrow.setURL("images/play-arrow-hover.png");
            } else {
                this.playArrow.setURL("images/play-arrow.png");
                if (this.items.getItemAt(this.activeIndex).item) {
                    
                    
                    $htv.Controller.playVideo(this.items.getItemAt(this.activeIndex).item.content_id, 
                    (!$htv.Utils.stringIsNullOrEmpty(this.carousel_name) && this.carousel_name.indexOf("Queued") !== -1) ?
                    { package_id: this.package_id, next_video_type: "queue" } :
                    { package_id: this.package_id });                    
                }
            }
            
            break;
        case "MOVE_RIGHT":
            if (!eventData.is_down || eventData.is_hold) {
                return;
            }
            this.updateLabels();
            break;
        case "MOVE_LEFT": // opposite of move right
            if (!eventData.is_down || eventData.is_hold) {
                return;
            }
            this.updateLabels();
            break;
        default:
            
            break;
        }
    };
};

$htv.Controls.ChannelThumbnailCarousel = function () {
    $htv.Controls.BaseThumbnailCarousel.call(this);
    this.className = "ChannelThumbnailCarousel";
    this.carousel_name = "unnamed channel carousel";
    this.descriptionTextArea = null;
    this.descriptionTextAreaPosition = null;
    this.channelSubtitleLabelPosition = null;
    this.channelSubtitleLabel = null;
    this.channelTitleLabelPosition = null;
    this.channelTitleLabel = null;
    this.progressLabelPosition = null;
    this.progressLabel = null;
    
    this.initialize = function (position, target, url, options) {
        
        this.carousel_item_type = "channels";
        this.itemFields = ['canonical_name', 'cmtype', 'items_url', 'name', 'channel_id', 'videos_count', 'full_episodes_count', 'clips_count', 'feature_films_count'];
        this._initialize(position, target, url, options);

        this.channelSubtitleLabelPosition = {
            x: this.x,
            y: this.displayPositions[3].y - 35,
            z: this.z + 1,
            width: this.width,
            height: 30
        };
        this.channelTitleLabelPosition = {
            x: this.x,
            y: this.channelSubtitleLabelPosition.y - 35,
            z: this.z + 1,
            width: this.width,
            height: 34
        };
        this.descriptionTextAreaPosition = {
            x: this.displayPositions[3].x,
            y: this.displayPositions[3].y + this.displayPositions[3].height + 12,
            z: this.z + 1,
            width: this.displayPositions[3].width + 35,
            height: 100
        };
        // NOTE: right-aligned
        this.progressLabelPosition = {
            x: this.x,
            y: this.y + this.height - 60,
            z: this.z + 1,
            width: this.width - 50,
            height: 30
        };
        
        this.channelTitleLabel = $htv.Platform.createLabel(this.channelTitleLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailTitle});
        this.channelSubtitleLabel = $htv.Platform.createLabel(this.channelSubtitleLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailSubtitleCentered});
        this.descriptionTextArea = $htv.Platform.createTextArea(this.descriptionTextAreaPosition, "", this.canvas, {styleName: $htv.Styles.CarouselThumbnailDescription});
        this.progressLabel = $htv.Platform.createLabel(this.progressLabelPosition, "", this.canvas, {styleName: $htv.Styles.CarouselProgress});

    };
    
    this.initializeResult = function () {
        this._initializeResult();
        this.render();
    };
    
    this.itemRenderer = function (item, focused, reflection) {
        var options;
        if (focused || $htv.Platform.properties.has_animations) {
            options = {
                width: this.SELECTED_WIDTH,
                height: this.SELECTED_HEIGHT
            };
        }
        else {
            options = {
                width: this.UNSELECTED_WIDTH,
                height: this.UNSELECTED_HEIGHT
            };
        }
        
        if (reflection === true) {
            options.format = "png";
            options.reflection_height = this.REFLECTION_HEIGHT;
            options.reflection_alpha_top = this.REFLECTION_ALPHA_TOP;
        }
        
        return $htv.Utils.getURLForChannelThumb(item.canonical_name, options);
    };
    
    this.dispose = function () {
        this._dispose();
        $htv.Platform.deleteItem(this.channelTitleLabel);
        $htv.Platform.deleteItem(this.channelSubtitleLabel);
        $htv.Platform.deleteItem(this.descriptionTextArea);
        $htv.Platform.deleteItem(this.progressLabel);
        this.channelTitleLabel = null;
        this.channelSubtitleLabel = null;
        this.descriptionTextArea = null;
        this.progressLabel = null;
        this.descriptionTextAreaPosition = null;
        this.channelSubtitleLabelPosition = null;
        this.channelTitleLabelPosition = null;
        this.progressLabelPosition = null;
    };
    
    this.focus = function () {
        if (this.items.getLength() === 0) {
            this.node.view.fireEvent("LOSING_FOCUS", {
                nav_dir: "up"
            });
            return;
        }
        
        this._focus();
        if (this.initialized === true) {
            this.updateLabels();
            this.channelTitleLabel.show();
            this.channelSubtitleLabel.show();
            this.descriptionTextArea.show();
            this.progressLabel.show();
        }
    };
    
    this.unfocus = function () {
        this._unfocus();
        this.channelTitleLabel.hide();
        this.channelSubtitleLabel.hide();
        this.descriptionTextArea.hide();
        this.progressLabel.hide();
    };
    
    this.hide = function () {
        this._hide();
        this.channelTitleLabel.hide();
        this.channelSubtitleLabel.hide();
        this.descriptionTextArea.hide();
        this.progressLabel.hide();
    };
    
    this.show = function () {
        this._show();
        if (this.hasFocus === false) {
            this.channelTitleLabel.hide();
            this.channelSubtitleLabel.hide();
            this.descriptionTextArea.hide();
            this.progressLabel.hide();
        }
        else {
            this.channelTitleLabel.show();
            this.channelSubtitleLabel.show();
            this.descriptionTextArea.show();
            this.progressLabel.show();
        }
    };
   
    this.updateLabels = function () {
        var activeItem, totalCount;
        activeItem = this.items.getItemAt(this.activeIndex).item;
        if (activeItem) {
            this.channelTitleLabel.setText(activeItem.name);
            //this.channelSubtitleLabel.setText(activeItem.videos_count + " video" + (parseInt(activeItem.videos_count, 10) === 1 ? "" : "s"));
        }
        totalCount = this.items.getLength();
        if (totalCount > 100 && !this.show_actual_total) {
            totalCount = "100+";
        }
        this.progressLabel.setText((this.activeIndex + 1) + " of " + totalCount + " " + this.carousel_item_type);  
    };
    
    this._handleMoveDown = function () {
        $htv.Controller.pushView("ContentView", {
            menu_url: this.items.getItemAt(this.activeIndex).item.items_url,
            view_title: this.items.getItemAt(this.activeIndex).item.name,
            show_id: this.items.getItemAt(this.activeIndex).item.show_id,
            show_name: this.items.getItemAt(this.activeIndex).item.title,
            previous_view_title: this.carousel_name
        });
    };

    this.handleInput = function (eventData) {
        this._handleInput(eventData);
        if (!eventData.is_down || eventData.is_hold) {
            return;
        }
        
        switch (eventData.action) {
        case "MOVE_RIGHT":
            this.updateLabels();
            break;
        case "MOVE_LEFT":
            this.updateLabels();
            break;
        case "PRESS_OK":
            this._handleMoveDown();
            break;
        default:
            
            break;
        }
    };

    this.render = this._render;
    this.jumpToIndex = this._jumpToIndex;
    this.getDataSource = this._getDataSource;
    this.handleEvent = this._handleEvent;
};

$htv.Controls.CompanyThumbnailCarousel.prototype = new $htv.Controls.BaseThumbnailCarousel();
$htv.Controls.SearchThumbnailCarousel.prototype = new $htv.Controls.BaseThumbnailCarousel();
$htv.Controls.ShowThumbnailCarousel.prototype = new $htv.Controls.BaseThumbnailCarousel();
$htv.Controls.VideoThumbnailCarousel.prototype = new $htv.Controls.BaseThumbnailCarousel();
$htv.Controls.ChannelThumbnailCarousel.prototype = new $htv.Controls.BaseThumbnailCarousel();