﻿Type.registerNamespace("TitanTV");

// Constructor
TitanTV.GridPopUp = function(element)
{
  TitanTV.GridPopUp.initializeBase(this, [element]);

  this._key = 'grid';
  this._gridDisplayId = null;
  this._srcUrl = null;

  this._autoHideTimeout = null;
  this._autoHideDelay = 500;
  this._autoOpenTimeout = null;
  this._toolTipTimeout = null;
  this._currentGridTarget = null;
  this._currentGridTargetData = null;
  this._gridDisplay = null;

  this._hPlacement = null;
  this._vPlacement = null;
  this._xPosition = null;
  this._yPosition = null;

  this._uiElementsBound = false;

  this._shadowElement = null;

  this._contentElement = null;
  this._barElement = null;
  this._titleElement = null;
  this._channelElement = null;
  this._timeElement = null;
  this._detailElement = null;
  this._arrowUpperLeftElement = null;
  this._arrowUpperRightElement = null;
  this._arrowLowerLeftElement = null;
  this._arrowLowerRightElement = null;
  this._tvRatingElement = null;
  this._mpaaRatingElement = null;
  this._starRatingElement = null;
  this._videoFormatElement = null;
  this._audioFormatElement = null;
  this._closedCaptionElement = null;
  this._toolTipElement = null;
  this._adElement = null;
  this._moreBoxElement = null;
  this._infoLinkElement = null;
  this._airingsLinkElement = null;

  // Menu Buttons
  this._detailButtonElement = null;
  this._reminderButtonElement = null;
  this._watchButtonElement = null;
  this._recordButtonElement = null;
  this._burnToDVDButtonElement = null;
  this._remoteScheduleButtonElement = null;
  this._addToCalendarButtonElement = null;
  this._addFavoriteButtonElement = null;
  this._removeFavoriteButtonElement = null;

  // Public methods
  this.show = null;
  this.hide = null;
  this.configureMenu = null;
  this.reposition = null;
  this.populateDetails = null;
  this.populateDetailsCallback = null;
  this.showToolTip = null;
  this.hideToolTip = null;
  this.addFavorite = null;
  this.removeFavorite = null;
  this.toggleFavoriteCallback = null;

  // Private methods

  // Delegates
  this._hoverDelegate = null;
  this._unhoverDelegate = null;

  // Flags turning buttons on/off
  this._detailsFlag = 1;
  this._watchFlag = 2;
  this._recordFlag = 4;
  this._burnToDVDFlag = 8;
  this._remoteScheduleFlag = 16;
  this._reminderFlag = 32;

  this._inPast = -1;
  this._inProgress = 0;
  this._inFuture = 1;
}

TitanTV.GridPopUp.prototype =
{
  // property accessors.

  get_key: function() { return this._key; },
  set_key: function(value) { this._key = value; },

  get_gridDisplayId: function() { return this._gridDisplayId; },
  set_gridDisplayId: function(value) { this._gridDisplayId = value; },

  get_srcUrl: function() { return this._srcUrl; },
  set_srcUrl: function(value) { this._srcUrl = value; },

  get_autoOpenTimeout: function() { return this._autoOpenTimeout; },
  set_autoOpenTimeout: function(value) { this._autoOpenTimeout = value; },

  get_gridDisplay: function()
  {
    if (this._gridDisplay === null || !this._gridDisplay.doCommand)
      this._gridDisplay = $find(this._gridDisplayId);

    return this._gridDisplay;
  },

  initialize: function()
  {
    var element = this.get_element();

    // Save the menu object to the static collection
    if (this.get_key()) TitanTV.GridPopUp.PopUpCollection[this.get_key()] = this;

    if (this.show === null) this.show = Function.createDelegate(this, this._show);
    if (this.hide === null) this.hide = Function.createDelegate(this, this._hide);
    if (this.reposition === null) this.reposition = Function.createDelegate(this, this._reposition);
    if (this.configureMenu === null) this.configureMenu = Function.createDelegate(this, this._configureMenu);
    if (this.populateDetails === null) this.populateDetails = Function.createDelegate(this, this._populateDetails);
    if (this.populateDetailsCallback === null) this.populateDetailsCallback = Function.createDelegate(this, this._populateDetailsCallback);
    if (this.showToolTip === null) this.showToolTip = Function.createDelegate(this, this._showToolTip);
    if (this.hideToolTip === null) this.hideToolTip = Function.createDelegate(this, this._hideToolTip);
    if (this.addFavorite === null) this.addFavorite = Function.createDelegate(this, this._addFavorite);
    if (this.removeFavorite === null) this.removeFavorite = Function.createDelegate(this, this._removeFavorite);
    if (this.toggleFavoriteCallback === null) this.toggleFavoriteCallback = Function.createDelegate(this, this._toggleFavoriteCallback);

    if (this._hoverDelegate === null) this._hoverDelegate = Function.createDelegate(this, this._hoverHandler);
    Sys.UI.DomEvent.addHandler(element, 'mouseover', this._hoverDelegate);

    if (this._unhoverDelegate === null) this._unhoverDelegate = Function.createDelegate(this, this._unhoverHandler);
    Sys.UI.DomEvent.addHandler(element, 'mouseout', this._unhoverDelegate);

    TitanTV.GridPopUp.callBaseMethod(this, 'initialize');

    Sys.Debug.trace('Initialize: ' + element.id);
  },

  // Release resources before control is disposed.
  dispose: function()
  {
    var element = this.get_element();

    if (this.hide) delete this.hide;
    if (this.show) delete this.show;
    if (this.reposition) delete this.reposition;
    if (this.configureMenu) delete this.configureMenu;
    if (this.populateDetails) delete this.populateDetails;
    if (this.populateDetailsCallback) delete this.populateDetailsCallback;
    if (this.showToolTip) delete this.showToolTip;
    if (this.hideToolTip) delete this.hideToolTip;
    if (this.addFavorite) delete this.addFavorite;
    if (this.removeFavorite) delete this.removeFavorite;
    if (this.toggleFavoriteCallback) delete this.toggleFavoriteCallback;

    if (this._hoverDelegate)
    {
      //if (this._currentGridTarget != null) $removeHandler(this._currentGridTarget, 'mouseover', this._hoverDelegate);
      $removeHandler(element, 'mouseover', this._hoverDelegate);
      delete this._hoverDelegate;
    }

    if (this._unhoverDelegate)
    {
      //if (this._currentGridTarget != null) $removeHandler(this._currentGridTarget, 'mouseout', this._unhoverDelegate);
      $removeHandler(element, 'mouseout', this._unhoverDelegate);
      delete this._unhoverDelegate;
    }

    if (this._detailButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._detailButtonElement);
    if (this._watchButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._watchButtonElement);
    if (this._recordButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._recordButtonElement);
    if (this._burnToDVDButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._burnToDVDButtonElement);
    if (this._remoteScheduleButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._remoteScheduleButtonElement);
    if (this._reminderButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._reminderButtonElement);
    if (this._addToCalendarButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._addToCalendarButtonElement);
    if (this._addFavoriteButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._addFavoriteButtonElement);
    if (this._removeFavoriteButtonElement != null) Sys.UI.DomEvent.clearHandlers(this._removeFavoriteButtonElement);

    TitanTV.GridPopUp.callBaseMethod(this, 'dispose');

    Sys.Debug.trace('Dispose: ' + element.id);
  },

  _bindUIElements: function()
  {
    if (this._uiElementsBound) return;

    var element = this.get_element();

    this._contentElement = $get('content', element);
    this._barElement = $get('bar', element);
    this._arrowUpperLeftElement = $get('arrowUL', element);
    this._arrowUpperRightElement = $get('arrowUR', element);
    this._arrowLowerLeftElement = $get('arrowLL', element);
    this._arrowLowerRightElement = $get('arrowLR', element);

    this._timeElement = $get('time', element);
    this._channelElement = $get('channel', element);
    this._titleElement = $get('title', element);
    this._detailElement = $get('detail', element);

    this._tvRatingElement = $get('tvRating', element);
    this._mpaaRatingElement = $get('mpaaRating', element);
    this._starRatingElement = $get('starRating', element);
    this._videoFormatElement = $get('videoFormat', element);
    this._audioFormatElement = $get('audioFormat', element);
    this._closedCaptionElement = $get('closedCaption', element);

    this._detailButtonElement = $get('details', element);
    this._watchButtonElement = $get('watch', element);
    this._recordButtonElement = $get('record', element);
    this._burnToDVDButtonElement = $get('dvd', element);
    this._remoteScheduleButtonElement = $get('remoteSchedule', element);
    this._reminderButtonElement = $get('reminder', element);
    this._addToCalendarButtonElement = $get('calendar', element);
    this._addFavoriteButtonElement = $get('addFavorite', element);
    this._removeFavoriteButtonElement = $get('removeFavorite', element);

    this._moreBoxElement = $get('moreBox', element);
    this._infoLinkElement = $get('infoLink', element);
    this._airingsLinkElement = $get('airingsLink', element);

    this._toolTipElement = $get('toolTip', element);

    this._adElement = $get('ad', element);

    // Shadow
    this._shadowElement = $get('shadow', element);

    this._uiElementsBound = true;
  },

  // Show Cell Menu
  _show: function(sender, isClick)
  {
    var element = this.get_element();

    // Make sure we don't call hide or double open
    clearTimeout(this._autoHideTimeout);
    clearTimeout(this._autoOpenTimeout);

    // Ensure the UI is bound.
    this._bindUIElements();

    // A second click on the same cell hides the menu
    if (this._currentGridTarget === sender && element.style.display == 'block')
    {
      if (isClick) this.hide();
      return;
    }

    // Wire up temporary event over/out handlers
    if (this._currentGridTarget)
    {
      $removeHandler(this._currentGridTarget, 'mouseover', this._hoverDelegate);
      $removeHandler(this._currentGridTarget, 'mouseout', this._unhoverDelegate);
    }

    this._currentGridTarget = sender;
    this._currentGridTargetData = Sys.Serialization.JavaScriptSerializer.deserialize(sender.getAttribute("data"));

    $addHandler(this._currentGridTarget, 'mouseover', this._hoverDelegate);
    $addHandler(this._currentGridTarget, 'mouseout', this._unhoverDelegate);

    // Need to have the element visible for resizing;

    element.style.top = '-1000px';
    element.style.display = 'block';

    // Get the Title
    var gridTitleNode = $get('tn', sender);
    if (gridTitleNode) this._titleElement.innerHTML = gridTitleNode.innerHTML;

    this._timeElement.innerHTML = "&nbsp;"
    this._channelElement.innerHTML = "&nbsp;"

    this._detailElement.innerHTML = "";

    this._adElement.innerHTML = "";

    this._tvRatingElement.style.display = 'none';
    this._mpaaRatingElement.style.display = 'none';
    this._starRatingElement.style.display = 'none';
    this._videoFormatElement.style.display = 'none';
    this._audioFormatElement.style.display = 'none';
    this._closedCaptionElement.style.display = 'none';

    this.configureMenu();
    this.reposition(true);
    this.populateDetails();
  },

  _hide: function()
  {
    var element = this.get_element();
    element.style.display = 'none';
  },

  _reposition: function(calculatePlacements)
  {
    var element = this.get_element();

    // Find the grid contrould
    var grid = this.get_gridDisplay();

    // Get the bounds of the grid cell
    var gridBounds = Sys.UI.DomElement.getBounds(grid.get_element());
    var gridElementBounds = Sys.UI.DomElement.getBounds(this._currentGridTarget);
    var elementBounds = Sys.UI.DomElement.getBounds(element);

    var verticalScrollPosition = TitanTV.GridPopUp.GetVerticalScroll();

    if (calculatePlacements)
    {
      this._hPlacement = 'right';
      this._vPlacement = 'bottom';

      // Calculate the x position
      this._xPosition = gridElementBounds.x - 5;
      if ((this._xPosition + elementBounds.width) > (gridBounds.x + gridBounds.width))
      {
        this._xPosition = (gridElementBounds.x + gridElementBounds.width) - elementBounds.width + 5;

        // We don't want to allow the popup to go off the screen to the left
        if (this._xPosition < gridBounds.x)
          this._xPosition = gridBounds.x + 5;

        this._hPlacement = 'left';
      }

      // Calculate the y position;
      this._yPosition = gridElementBounds.y + gridElementBounds.height + 10;
      if ((this._yPosition + elementBounds.height) > (verticalScrollPosition + TitanTV.GridPopUp.GetViewPortHeight()))
      {
        this._yPosition = gridElementBounds.y - elementBounds.height - 10;
        this._vPlacement = 'top';
      }
    }
    else
    {
      // the Y position always needs to be calculated if we are using top placement
      if (this._vPlacement == 'top')
        this._yPosition = gridElementBounds.y - elementBounds.height - 10;
    }


    var showPointer = true;
    if (this._yPosition <= verticalScrollPosition)
    {
      this._yPosition = verticalScrollPosition + 5;
      showPointer = false;
    }


    // Move the bar to the top or bottom depending on the placement;
    if (this._vPlacement == 'top')
    {
      element.insertBefore(this._contentElement, this._barElement);
      var placementClass = this._contentElement.getAttribute('topPlacementClass');
      if (placementClass) this._contentElement.className = placementClass;

      var barPlacementClass = this._barElement.getAttribute('bottomPlacementClass');
      if (barPlacementClass) this._barElement.className = barPlacementClass;
    }
    else
    {
      element.insertBefore(this._barElement, this._contentElement);
      var placementClass = this._contentElement.getAttribute('bottomPlacementClass');
      if (placementClass) this._contentElement.className = placementClass;

      var barPlacementClass = this._barElement.getAttribute('topPlacementClass');
      if (barPlacementClass) this._barElement.className = barPlacementClass;
    }

    // Reposition the Element
    Sys.UI.DomElement.setLocation(element, this._xPosition, this._yPosition);


    // Size & Show The Shadow
    if (this._shadowElement)
    {
      this._shadowElement.style.height = elementBounds.height + 'px';
      this._shadowElement.style.display = 'block';
    }

    // Hide all arrow objects;
    this._arrowUpperLeftElement.style.display = 'none';
    this._arrowUpperRightElement.style.display = 'none';
    this._arrowLowerLeftElement.style.display = 'none';
    this._arrowLowerRightElement.style.display = 'none';

    // Calculate the Arrow's x position;
    var minX = Math.max(gridElementBounds.x, this._xPosition);
    var maxX = Math.min(gridElementBounds.x + gridElementBounds.width, this._xPosition + elementBounds.width);
    var startX = gridElementBounds.x - this._xPosition + Math.floor((maxX - minX) / 2);


    // Figure out which arrow element we need to work with;

    if (!showPointer)
    {
      this._arrowUpperLeftElement.style.display = 'none';
      this._arrowUpperRightElement.style.display = 'none';
      this._arrowLowerLeftElement.style.display = 'none';
      this._arrowLowerRightElement.style.display = 'none';
    }
    else if (this._hPlacement != 'left' && this._vPlacement != 'top')
    {
      this._arrowUpperLeftElement.style.display = 'block';
      Sys.UI.DomElement.setLocation(this._arrowUpperLeftElement, startX, -26);
    }
    else if (this._hPlacement == 'left' && this._vPlacement == 'top')
    {
      this._arrowLowerRightElement.style.display = 'block';
      Sys.UI.DomElement.setLocation(this._arrowLowerRightElement, startX - 34, elementBounds.height - 6);
    }
    else if (this._hPlacement == 'left' && this._vPlacement != 'top')
    {
      this._arrowUpperRightElement.style.display = 'block';
      Sys.UI.DomElement.setLocation(this._arrowUpperRightElement, startX - 34, -26);
    }
    else
    {
      this._arrowLowerLeftElement.style.display = 'block';
      Sys.UI.DomElement.setLocation(this._arrowLowerLeftElement, startX, elementBounds.height - 6);
    }
  },

  _configureMenu: function()
  {
    // Configure the menu buttons
    if (this._currentGridTargetData === null) return;

    var gridClient = this.get_gridDisplay();

    var commandFlags = this._currentGridTargetData.Flags;
    var rowIndex = this._currentGridTargetData.Row;
    var scheduleId = this._currentGridTargetData.SID;
    var status = this._currentGridTargetData.Status;
    var isFavorite = Sys.UI.DomElement.containsCssClass(this._currentGridTarget, "gFav");

    // Details
    if (this._detailButtonElement != null)
    {
      this._detailButtonElement.style.display = (commandFlags & this._detailsFlag) ? "inline" : "none";
      $clearHandlers(this._detailButtonElement);
      $addHandler(this._detailButtonElement, 'click', function(e) { gridClient.openDetails(e, rowIndex, scheduleId, status, false); });
      $addHandler(this._detailButtonElement, 'click', this.hide);

      $addHandler(this._detailButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._detailButtonElement, 'mouseout', this.hideToolTip);
    }

    // Reminder
    if (this._reminderButtonElement != null)
    {
      this._reminderButtonElement.style.display = (commandFlags & this._reminderFlag) ? "inline" : "none";
      Sys.UI.DomEvent.clearHandlers(this._reminderButtonElement);
      Sys.UI.DomEvent.addHandler(this._reminderButtonElement, 'click', function(e) { gridClient.executePVRCommand(e, rowIndex, scheduleId, 'REMINDER'); })
      Sys.UI.DomEvent.addHandler(this._reminderButtonElement, 'click', this.hide);

      $addHandler(this._reminderButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._reminderButtonElement, 'mouseout', this.hideToolTip);
    }

    // Watch
    if (this._watchButtonElement != null)
    {
      this._watchButtonElement.style.display = ((commandFlags & this._watchFlag) && status == this._inProgress) ? "inline" : "none";
      Sys.UI.DomEvent.clearHandlers(this._watchButtonElement);
      Sys.UI.DomEvent.addHandler(this._watchButtonElement, 'click', function(e) { gridClient.executePVRCommand(e, rowIndex, scheduleId, 'W'); })
      Sys.UI.DomEvent.addHandler(this._watchButtonElement, 'click', this.hide);

      $addHandler(this._watchButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._watchButtonElement, 'mouseout', this.hideToolTip);
    }

    // Record
    if (this._recordButtonElement != null)
    {
      this._recordButtonElement.style.display = ((commandFlags & this._recordFlag) && (status == this._inProgress || status == this._inFuture)) ? "inline" : "none";
      Sys.UI.DomEvent.clearHandlers(this._recordButtonElement);
      Sys.UI.DomEvent.addHandler(this._recordButtonElement, 'click', function(e) { gridClient.executePVRCommand(e, rowIndex, scheduleId, 'R'); })
      Sys.UI.DomEvent.addHandler(this._recordButtonElement, 'click', this.hide);

      $addHandler(this._recordButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._recordButtonElement, 'mouseout', this.hideToolTip);
    }

    // Burn to DVD
    if (this._burnToDVDButtonElement != null)
    {
      this._burnToDVDButtonElement.style.display = ((commandFlags & this._burnToDVDFlag) && (status == this._inProgress || status == this._inFuture)) ? "inline" : "none";
      Sys.UI.DomEvent.clearHandlers(this._burnToDVDButtonElement);
      Sys.UI.DomEvent.addHandler(this._burnToDVDButtonElement, 'click', function(e) { gridClient.executePVRCommand(e, rowIndex, scheduleId, 'DVD'); })
      Sys.UI.DomEvent.addHandler(this._burnToDVDButtonElement, 'click', this.hide);

      $addHandler(this._burnToDVDButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._burnToDVDButtonElement, 'mouseout', this.hideToolTip);
    }

    // Remote Schedule
    if (this._remoteScheduleButtonElement != null)
    {
      this._remoteScheduleButtonElement.style.display = ((commandFlags & this._remoteScheduleFlag) && (status == this._inProgress || status == this._inFuture)) ? "inline" : "none";
      Sys.UI.DomEvent.clearHandlers(this._remoteScheduleButtonElement);
      Sys.UI.DomEvent.addHandler(this._remoteScheduleButtonElement, 'click', function(e) { gridClient.executePVRCommand(e, rowIndex, scheduleId, 'REMOTESCHEDULE'); })
      Sys.UI.DomEvent.addHandler(this._remoteScheduleButtonElement, 'click', this.hide);

      $addHandler(this._remoteScheduleButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._remoteScheduleButtonElement, 'mouseout', this.hideToolTip);
    }

    // Add to Calendar
    if (this._addToCalendarButtonElement != null)
    {
      this._addToCalendarButtonElement.style.display = (status == this._inFuture) ? "inline" : "none";
      Sys.UI.DomEvent.clearHandlers(this._addToCalendarButtonElement);
      Sys.UI.DomEvent.addHandler(this._addToCalendarButtonElement, 'click', function(e) { gridClient.executePVRCommand(e, rowIndex, scheduleId, 'ICAL'); })
      Sys.UI.DomEvent.addHandler(this._addToCalendarButtonElement, 'click', this.hide);

      $addHandler(this._addToCalendarButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._addToCalendarButtonElement, 'mouseout', this.hideToolTip);
    }

    // Add Favorite
    if (this._addFavoriteButtonElement != null)
    {
      this._addFavoriteButtonElement.style.display = !isFavorite ? "inline" : "none";
      Sys.UI.DomEvent.clearHandlers(this._addFavoriteButtonElement);
      Sys.UI.DomEvent.addHandler(this._addFavoriteButtonElement, 'click', this.addFavorite)
      Sys.UI.DomEvent.addHandler(this._addFavoriteButtonElement, 'click', this.hide);

      $addHandler(this._addFavoriteButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._addFavoriteButtonElement, 'mouseout', this.hideToolTip);
    }

    // Remove Favorite
    if (this._removeFavoriteButtonElement != null)
    {
      this._removeFavoriteButtonElement.style.display = isFavorite ? "inline" : "none";
      Sys.UI.DomEvent.clearHandlers(this._removeFavoriteButtonElement);
      Sys.UI.DomEvent.addHandler(this._removeFavoriteButtonElement, 'click', this.removeFavorite)
      Sys.UI.DomEvent.addHandler(this._removeFavoriteButtonElement, 'click', this.hide);

      $addHandler(this._removeFavoriteButtonElement, 'mouseover', this.showToolTip);
      $addHandler(this._removeFavoriteButtonElement, 'mouseout', this.hideToolTip);
    }

  },

  _populateDetails: function()
  {
    if (this._currentGridTargetData === null) return;

    var grid = this.get_gridDisplay();

    var stationData = grid.getStationData(this._currentGridTargetData.Row);

    var serviceStationData = new WebApp.Services.StationData();

    serviceStationData.Channel = stationData.dc;
    serviceStationData.StationId = stationData.sid;
    serviceStationData.PsipId = stationData.pid;
    serviceStationData.Callsign = stationData.cs;
    serviceStationData.ContentType = stationData.pt;
    serviceStationData.Major = stationData.maj;
    serviceStationData.Minor = stationData.min;
    serviceStationData.HDCapable = stationData.hd;

    var context = { "ScheduleId": this._currentGridTargetData.SID };

    WebApp.Services.GridDetailService.GetDetails(context.ScheduleId, serviceStationData, grid.get_context(), this.get_srcUrl(), this.populateDetailsCallback, null, context);
  },

  _populateDetailsCallback: function(result, context, methodName)
  {
    if (!this._detailElement || !result || !context || context.ScheduleId != this._currentGridTargetData.SID)
      return;

    if ((result.InfoLink && this._infoLinkElement) || (result.AiringsLink && this._airingsLinkElement))
    {
      if (this._moreBoxElement)
        this._moreBoxElement.style.display = 'block';

      if (this._infoLinkElement)
        this._infoLinkElement.setAttribute("href", result.InfoLink);

      if (this._airingsLinkElement)
        this._airingsLinkElement.setAttribute("href", result.AiringsLink);
    }
    else if (this._moreBoxElement)
    {
      this._moreBoxElement.style.display = 'none';
    }

    this._adElement.innerHTML = result.Markup;

    if (this._timeElement) this._timeElement.innerHTML = result.Time + " " + result.Duration;
    if (this._channelElement) this._channelElement.innerHTML = this._getChannelInfo();

    var detailHTML = "";

    if (result.EpisodeTitle) detailHTML += "<div class='gpEpisodeTitle'>\"" + result.EpisodeTitle + "\"</div>";
    if (result.Part) detailHTML += "<div class='gpPart'>" + result.Part + "</div>";
    if (result.ProgramAttributes) detailHTML += "<div class='gpAttributes'>" + result.ProgramAttributes + "</div>";
    if (result.Description) detailHTML += "<div class='gpDescription'>" + result.Description + "</div>";
    if (result.Cast) detailHTML += "<div class='gpCast'><span class='gpCastTitle'>Credits:</span> " + result.Cast + "</div>";

    this._detailElement.innerHTML = detailHTML;

    // TV Rating
    var tvRating = (result.TVRating === null) ? "" : result.TVRating.trimStart().toLowerCase();

    if (tvRating.startsWith('tvg'))
    {
      this._tvRatingElement.style.display = "block";
      this._tvRatingElement.className = "gpIcon gpIconTVG";
      this._tvRatingElement.setAttribute("title", result.TVRating);
    }
    else if (tvRating.startsWith('tvyv'))
    {
      this._tvRatingElement.style.display = "block";
      this._tvRatingElement.className = "gpIcon gpIconTVYV";
      this._tvRatingElement.setAttribute("title", result.TVRating);
    }
    else if (tvRating.startsWith('tvy'))
    {
      this._tvRatingElement.style.display = "block";
      this._tvRatingElement.className = "gpIcon gpIconTVY";
      this._tvRatingElement.setAttribute("title", result.TVRating);
    }
    else if (tvRating.startsWith('tv14'))
    {
      this._tvRatingElement.style.display = "block";
      this._tvRatingElement.className = "gpIcon gpIconTV14";
      this._tvRatingElement.setAttribute("title", result.TVRating);
    }
    else if (tvRating.startsWith('tvpg'))
    {
      this._tvRatingElement.style.display = "block";
      this._tvRatingElement.className = "gpIcon gpIconTVPG";
      this._tvRatingElement.setAttribute("title", result.TVRating);
    }
    else if (tvRating.startsWith('tvma'))
    {
      this._tvRatingElement.style.display = "block";
      this._tvRatingElement.className = "gpIcon gpIconTVMA";
      this._tvRatingElement.setAttribute("title", result.TVRating);
    }

    // MPAA Rating
    var mpaaRating = (result.MPAARating === null) ? "" : result.MPAARating.trimStart().toLowerCase();

    if (mpaaRating.startsWith('g'))
    {
      this._mpaaRatingElement.style.display = "block";
      this._mpaaRatingElement.className = "gpIcon gpIconG";
      this._mpaaRatingElement.setAttribute("title", result.MPAARating);
    }
    else if (mpaaRating.startsWith('pg-13'))
    {
      this._mpaaRatingElement.style.display = "block";
      this._mpaaRatingElement.className = "gpIcon gpIconPG13";
      this._mpaaRatingElement.setAttribute("title", result.MPAARating);
    }
    else if (mpaaRating.startsWith('pg'))
    {
      this._mpaaRatingElement.style.display = "block";
      this._mpaaRatingElement.className = "gpIcon gpIconPG";
      this._mpaaRatingElement.setAttribute("title", result.MPAARating);
    }
    else if (mpaaRating.startsWith('r'))
    {
      this._mpaaRatingElement.style.display = "block";
      this._mpaaRatingElement.className = "gpIcon gpIconR";
      this._mpaaRatingElement.setAttribute("title", result.MPAARating);
    }
    else if (mpaaRating.startsWith('nc-17'))
    {
      this._tvRatingElement.style.display = "block";
      this._tvRatingElement.className = "gpIcon gpIconNC17";
      this._tvRatingElement.setAttribute("title", result.MPAARating);
    }

    // Star Rating
    var starRating = (result.StarRating === null) ? "" : result.StarRating.trimStart();
    switch (starRating)
    {
      case "+":
        this._starRatingElement.style.display = "block";
        this._starRatingElement.className = "gpIcon gpIcon05Star";
        this._starRatingElement.setAttribute("title", "1/2 Star");
        break;
      case "*":
        this._starRatingElement.style.display = "block";
        this._starRatingElement.className = "gpIcon gpIcon10Star";
        this._starRatingElement.setAttribute("title", "1 Star");
        break;
      case "*+":
        this._starRatingElement.style.display = "block";
        this._starRatingElement.className = "gpIcon gpIcon15Star";
        this._starRatingElement.setAttribute("title", "1 1/2 Stars");
        break;
      case "**":
        this._starRatingElement.style.display = "block";
        this._starRatingElement.className = "gpIcon gpIcon20Star";
        this._starRatingElement.setAttribute("title", "2 Stars");
        break;
      case "**+":
        this._starRatingElement.style.display = "block";
        this._starRatingElement.className = "gpIcon gpIcon25Star";
        this._starRatingElement.setAttribute("title", "2 1/2 Stars");
        break;
      case "***":
        this._starRatingElement.style.display = "block";
        this._starRatingElement.className = "gpIcon gpIcon30Star";
        this._starRatingElement.setAttribute("title", "3 Stars");
        break;
      case "***+":
        this._starRatingElement.style.display = "block";
        this._starRatingElement.className = "gpIcon gpIcon35Star";
        this._starRatingElement.setAttribute("title", "3 1/2 Stars");
        break;
      case "****":
        this._starRatingElement.style.display = "block";
        this._starRatingElement.className = "gpIcon gpIcon40Star";
        this._starRatingElement.setAttribute("title", "4 Stars");
        break;
    }

    // Video Format
    if (result.VideoFormat && result.VideoFormat.startsWith("HDTV"))
    {
      this._videoFormatElement.style.display = "block";
      this._videoFormatElement.setAttribute("title", result.VideoFormat);

      if (result.VideoFormat.indexOf("1080i") >= 0) this._videoFormatElement.className = "gpIcon gpIcon1080i";
      else if (result.VideoFormat.indexOf("1080p") >= 0) this._videoFormatElement.className = "gpIcon gpIcon1080p";
      else if (result.VideoFormat.indexOf("720") >= 0) this._videoFormatElement.className = "gpIcon gpIcon720p";
      else this._videoFormatElement.className = "gpIcon gpIconHDTV";
    }

    // Audio Format
    switch (result.AudioFormat)
    {
      case "Stereo":
        this._audioFormatElement.style.display = "block";
        this._audioFormatElement.className = "gpIcon gpIconStereo";
        this._audioFormatElement.setAttribute("title", result.AudioFormat);
        break;
      case "Dolby Stereo":
      case "Dolby Surround":
        this._audioFormatElement.style.display = "block";
        this._audioFormatElement.className = "gpIcon gpIconDolby";
        this._audioFormatElement.setAttribute("title", result.AudioFormat);
        break;
      case "Dolby Digital":
        this._audioFormatElement.style.display = "block";
        this._audioFormatElement.className = "gpIcon gpIconDolbyDigital";
        this._audioFormatElement.setAttribute("title", result.AudioFormat);
        break;
    }

    // Closed Caption
    if (result.IsClosedCaption) this._closedCaptionElement.style.display = 'block';

    this.reposition(false);
  },

  _addFavorite: function()
  {
    if (this._currentGridTarget === null) return;

    var context = { "ScheduleId": this._currentGridTargetData.SID };

    WebApp.Services.GridDetailService.ToggleFavorite(context.ScheduleId, false, this.toggleFavoriteCallback, null, context);
  },

  _removeFavorite: function()
  {
    if (this._currentGridTarget === null) return;

    var context = { "ScheduleId": this._currentGridTargetData.SID };

    WebApp.Services.GridDetailService.ToggleFavorite(context.ScheduleId, true, this.toggleFavoriteCallback, null, context);
  },

  _toggleFavoriteCallback: function(result, context, methodName)
  {
    if (result && result.Error)
    {
      alert("Error: " + result.Error);
      return;
    }

    if (!result || !result.Title) return;

    var grid = this.get_gridDisplay();

    if (!grid) return;

    if (result.Added)
      grid.toggleFavorite(result.Title, false)
    else if (result.Removed)
      grid.toggleFavorite(result.Title, true);
  },

  _showToolTip: function(e)
  {
    clearTimeout(this._toolTipTimeout);
    this._toolTipElement.innerHTML = e.target.getAttribute("title");
  },

  _hideToolTip: function()
  {
    this._toolTipElement.innerHTML = "";
  },

  _hoverHandler: function(event)
  {
    clearTimeout(this._autoHideTimeout);
  },

  _unhoverHandler: function(event)
  {
    this._autoHideTimeout = setTimeout(this.hide, this._autoHideDelay);
  },

  _getChannelInfo: function()
  {
    var grid = this.get_gridDisplay();
    var rowData = grid.getStationData(this._currentGridTargetData.Row);

    if (!rowData) return null;

    if (rowData.maj > 0 && rowData.min > 0)
      return String.format("{0} - {1}.{2}", rowData.cs, rowData.maj, rowData.min);
    else
      return String.format("{0} - {1}", rowData.cs, rowData.dc);
  }
}

TitanTV.GridPopUp.registerClass('TitanTV.GridPopUp', Sys.UI.Control);

// Static Properties and Methods

TitanTV.GridPopUp.PopUpCollection = new Object();

TitanTV.GridPopUp.Click = function(sender, key)
{
  var key = null; // need to decode this from the data attribute;

  var popUpObject = TitanTV.GridPopUp.PopUpCollection[key != null ? key : 'grid'];

  if (!popUpObject) return;

  clearTimeout(popUpObject.get_autoOpenTimeout());

  popUpObject.show(sender, true);
}

TitanTV.GridPopUp.Over = function(sender, key)
{
  //sender.style.backgroundColor = "#bbddff";

  var popUpObject = TitanTV.GridPopUp.PopUpCollection[key != null ? key : 'grid'];

  if (!popUpObject) return;

  clearTimeout(popUpObject.get_autoOpenTimeout());
  var f = function() { popUpObject.show(sender, false); };
  popUpObject.set_autoOpenTimeout(setTimeout(f, 2000))
}

TitanTV.GridPopUp.Out = function(sender, key)
{
  //sender.style.backgroundColor = "";

  var popUpObject = TitanTV.GridPopUp.PopUpCollection[key != null ? key : 'grid'];

  if (!popUpObject) return;

  clearTimeout(popUpObject.get_autoOpenTimeout());
}

if (window.innerWidth) // All But IE
{
  TitanTV.GridPopUp.GetViewPortWidth = function() { return window.innerWidth; };
  TitanTV.GridPopUp.GetViewPortHeight = function() { return window.innerHeight; };
  TitanTV.GridPopUp.GetHorizontalScroll = function() { return window.pageXOffset; };
  TitanTV.GridPopUp.GetVerticalScroll = function() { return window.pageYOffset; };
}
else if (document.documentElement && document.documentElement.clientWidth) // IE6 with DOCTYPE
{
  TitanTV.GridPopUp.GetViewPortWidth = function() { return document.documentElement.clientWidth; };
  TitanTV.GridPopUp.GetViewPortHeight = function() { return document.documentElement.clientHeight; };
  TitanTV.GridPopUp.GetHorizontalScroll = function() { return document.documentElement.scrollLeft; };
  TitanTV.GridPopUp.GetVerticalScroll = function() { return document.documentElement.scrollTop; };
}
else if (document.body.clientWidth) // IE4, 5, 6 Without DOCTYPE
{
  TitanTV.GridPopUp.GetViewPortWidth = function() { return document.body.clientWidth; };
  TitanTV.GridPopUp.GetViewPortHeight = function() { return document.body.clientHeight; };
  TitanTV.GridPopUp.GetHorizontalScroll = function() { return document.body.scrollLeft; };
  TitanTV.GridPopUp.GetVerticalScroll = function() { return document.body.scrollTop; };
}

// Since this script is not loaded by System.Web.Handlers.ScriptResourceHandler
// invoke Sys.Application.notifyScriptLoaded to notify ScriptManager 
// that this is the end of the script.
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();