var InfoHover = {
  init: function() {
    InfoHover.observeLinks();
    var body = $$('body').first();
    if (body) Element.observe(body, 'mouseout', InfoHover.out);
  },

  observeLinks: function() {
    $$('a.info_hover').each(function(el) {
      if (!el.hasClassName('observing')) {
        Element.observe(el, 'mouseover', InfoHover.over);
        el.addClassName('observing');
      }
    });
  },

  currentTimeout: null,
  currentTarget: null,
  currentBounds: {},
  showThumbnails: false,
  urlBase: "/info.php",

  over: function(ev) {
    var el = Event.element(ev);
    if (!el) return false;

    /* find the target element */
    if (!el.hasClassName('info_hover')) {
      el = el.up('.info_hover');
      if (!el) return false;
    }

    var showThumbnails = el.hasClassName('show-thumb');

    /* use the thumb if there's one in our children */
    var img = el.down('img.thumbnail');
    if (img) el = img;

    /* quit if we've already shown it */
    if (InfoHover.currentTarget == el) return;
    InfoHover.currentTarget = el;

    /* update the bounding box once the mouse
    * moves out of the box hide it. */
    InfoHover.currentBounds = InfoHover.getBounds(el);

    clearTimeout(InfoHover.currentTimeout);
    InfoHover.currentTimeout = null;
    InfoHover.showThumbnails = showThumbnails;
    InfoHover.currentTimeout = setTimeout(function() {
      InfoHover.load();
    }, 700);

    return false;
  },

  getBounds: function(el) {
    var bounds = {};

    var xy = Position.cumulativeOffset(el);
    bounds.left = xy[0];
    bounds.top = xy[1];

    var dim = el.getDimensions();
    bounds.width = dim.width;
    bounds.height = dim.height;

    return bounds;
  },

  cache: {},
  load: function() {
    var url = InfoHover.parseUrl();
    if (!url) return;

    var cache = InfoHover.cache;
    if (cache[url]) {
      InfoHover.show(cache[url]);
    }
    else {
      new Ajax.Request(url, {
        method: 'get',
        onSuccess: function(trans) {
          var obj = eval('(' + trans.responseText + ')');
          InfoHover.cache[url] = obj;
          InfoHover.show(obj);
        }
      });
    }
  },

  out: function(ev) {
    var el = Event.element(ev);

    var bounds = InfoHover.currentBounds;
    var y = Event.pointerY(ev);
    var x = Event.pointerX(ev);

    var hide =
      y < bounds.top                 ||
      y > bounds.top + bounds.height ||
      x < bounds.left                ||
      x > bounds.left + bounds.width;

    if (hide) {
      InfoHover.currentBounds = {};
      InfoHover.currentTarget = null;
      clearTimeout(InfoHover.currentTimeout);
      InfoHover.currentTimeout = null;
      new Effect.Fade($('info_hover'), {
        duration: 0.3,
        afterFinish: InfoHover.showWindowedControls
      });
    }

    return false;
  },

  parseUrl: function() {
    var a = InfoHover.currentTarget;

    if (a.tagName != 'A') {
      var el = a.up('a');
      if (!el) el = a.down('a');
      if (el) a = el;
      else return null;
    }

    var path = a.href ? a.href.split('http://') : [];

    if (path.length > 1) {
      path = path[1];
    }
    else {
      path = a.href;
    }

    if (!path || path.blank()) return null;

    var s = path.split('/watch/');
    if (s.length <= 1) {
      s = path.split('/hd/');
    }
    if (s.length <= 1) {
      s = path.split('/superbowl/');
    }

    // watch, hd, superbowl -> Videos
    if (s.length > 1) {
      return [InfoHover.urlBase, '?type=video&id=', s[1].split('/')[0]].join('');
    }
    // profiles -> Users
    else if (path.split('/profiles/').length > 1) {
      return [InfoHover.urlBase, '?type=user&id=', path.split('/')[2].split('?')[0]].join('');
    }
    // Else -> Shows
    else {
      return [InfoHover.urlBase, '?type=show&id=', path.split('/')[1].split('?')[0]].join('');
    }

    return null;
  },

  update: function(data) {
    var hover_div = $$('div#info_hover').first();
    if (!hover_div) return;
    
    var content = hover_div.down('div.content');
    
    // Remove the hover types.
    hover_div.removeClassName('type_show');
    hover_div.removeClassName('type_video');
    hover_div.removeClassName('type_user');
    
    // Update the size of the content box accordingly too.
    if (data.show_name) {
      hover_div.addClassName('type_video');
      var updated_html = InfoHover.update_video(data);
    }
    else if (data.display_name) {
      hover_div.addClassName('type_user');
      var updated_html = InfoHover.update_user(data);
    }
    else {
      hover_div.addClassName('type_show');
      var updated_html = InfoHover.update_show(data);
    }

    content.update(updated_html);
  },
  
  update_video: function(data) {
    var html = "";
    var esc = InfoHover.cleanEscape;
    
    if (InfoHover.showThumbnails) {
      html += '<img class="thumb" src="';
      html += data.thumbnail_url;
      html += '" border="0" width="145" height="80" />';
    }

    if (data.show_name == data.title) {
      html += '<b>' + esc(data.show_name) + '</b><br/>';
    }
    else {
      html += '<b>' + esc(data.show_name) + ':</b> ';
      html += esc(data.title) + "<br/>";
    }

    var hasSeasonOrDuration = false;
    if (data.season_number > 0 && data.episode_number > 0) {
      html += 'Season ' + data.season_number + ', ';
      html += 'Ep. ' + data.episode_number + ' ';
      hasSeasonOrDuration = true;
    }
    else if (data.programming_type) {
      html += esc(data.programming_type) + ' ';
      hasSeasonOrDuration = true;
    }

    var dur = parseInt(data.duration);
    if (dur > 0) {
      var hms = [
        Math.floor(dur / 3600),
        Math.floor(dur / 60),
        dur % 60
      ];
      hms[1] -= hms[0] * 60;
      if (hms[1] < 10) hms[1] = '0' + hms[1];
      if (hms[2] < 10) hms[2] = '0' + hms[2];
      if (hms[0] == 0) hms.shift();
      html += '(' + hms.join(':') + ')';
      hasSeasonOrDuration = true;
    }

    if (hasSeasonOrDuration) {
      html += '<br/>';

      if (data.air_date) {
        var label = 'Air date: ';
        if(data.programming_type && data.programming_type == 'Trailer') {
          label = 'In theaters ';
        }
        html += label + esc(data.air_date) + ' &nbsp;|&nbsp; ';
      }
    }

    html += 'Rated: ' + esc(data.content_rating);

    if (data.has_captions) {
      html += ' &nbsp;|&nbsp; ';
      html += '<img class="cc" src="/images/icon-cc-gray.png" border="0" width="17" height="12" />';
    }
    html += '<br/>';

    html += 'Avg. user rating: ' + InfoHover.starRating(data.rating);
    html += '<br/>';

    html += '<div class="line"><span></span></div>';

    html += '<p>' + data.description.stripTags() + '</p>';
    
    if(data.stats.valid && data.programming_type == "Trailer") {
      html += '<div class="line"><span></span></div>';
      html += '<table class="demographics"><tr style="padding-bottom: 4px;">'
      html += '<td width="40%">Demographics:</td>'
      html += '<td class="centered" width="30%">Under 25</td>'
      html += '<td class="centered" width="30%">Over 25</td>'
      html += '</td></tr>'
      html += '<tr><td class="indent" width="40%">Women</td>'
      html += '<td class="centered" width="30%">' + InfoHover.starRating(data.stats.female_young_rating)
      html += '<td class="centered" width="30%">' + InfoHover.starRating(data.stats.female_old_rating)
      html += '</td></tr>'
      html += '<tr><td class="indent" width="40%">Men</td>'
      html += '<td class="centered" width="30%">' + InfoHover.starRating(data.stats.male_young_rating)
      html += '<td class="centered" width="30%">' + InfoHover.starRating(data.stats.male_old_rating)
      html += '</td></tr></table>'
    }
    
    return html;
  },
  
  update_show: function(data) {
    var html = "";
    var esc = InfoHover.cleanEscape;
    
    if (InfoHover.showThumbnails) {
      html += '<img class="thumb" src="';
      html += data.thumbnail_url;
      html += '" border="0" width="145" height="80" />';
    }
    html += '<b>' + esc(data.name) + '</b><br/>';
    html += 'Channel: ' + esc(data.channel) + '<br/>';

    if (data.film_date) {
      html += 'Premiere Date: ' + esc(data.film_date) + '<br/>';
    }

    if (!InfoHover.showThumbnails)
      html += '<div class="line"><span></span></div>';

    html += '<p>' + esc(data.description) + '</p>';
  
    return html;
  },
  
  update_user: function(data) {
    var html = "";
    var esc = InfoHover.cleanEscape;
    
    html += '<b>' + esc(data.display_name) + '</b><br/>';
    if (data.location) {
      html += esc(data.location);
    }
    html += '<hr/><div style="float: left;"><img class="avatar" src="';
    html += esc(data.avatar_url);
    html += '"/></div><div style="float: left; font-size: 10px;">';
    html += data.friends_count;
    html += ' friends<br/>';
    html += data.viewed_videos_count;
    html += ' videos watched<br/>';
    html += data.votes_count;
    html += ' ratings<br/>';
    html += data.reviews_count;
    html += ' reviews<br/>';
    html += data.posts_count;
    html += ' discussions<br/>';
    html += '</div><br style="clear:both;"/>';
    
    return html;
  },

  cleanEscape: function(s) {
    return s ? s.escapeHTML() : "";
  },

  starRating: function(n) {
    var stars = "";
    n = parseFloat(n);

    var type;
    $R(1, 5).each(function(rating) {
      type = rating <= Math.floor(n) ? 'full' : (rating == Math.round(n) ? 'half' : 'empty');
      stars += '<img src="';
      stars += '/images/rating_' + type + '.gif';
      stars += '" height="11" width="11" border="0" alt="Rating star" />';
    });

    return stars;
  },

  TAIL_WIDTH: 22,
  TAIL_HEIGHT: 23,
  TAIL_OFFSET: 2,

  show: function(data) {
    var hover = $('info_hover');

    if (hover && hover.style.display == 'none') {
      var ih = InfoHover;
      InfoHover.update(data);
      var dim = hover.getDimensions();
      var bounds = InfoHover.currentBounds;
      var viewport = Element.viewportOffset(InfoHover.currentTarget);

      var loc = InfoHover.determineTailLocation(
        dim,
        InfoHover.currentBounds,
        viewport
      );

      hover.style.left = loc.x + 'px';
      hover.style.top = loc.y + 'px';

      InfoHover.removeTailClassNames(hover);
      hover.addClassName(loc.className);

      InfoHover.hideWindowedControls();
      new Effect.Appear(hover, { duration: 0.4 });
    }
  },

  removeTailClassNames: function(el) {
    el.removeClassName('top-right');
    el.removeClassName('mid-right');
    el.removeClassName('bottom-right');
    el.removeClassName('top-left');
    el.removeClassName('mid-left');
    el.removeClassName('bottom-left');
  },

  determineTailLocation: function(hoverDim, target, viewport) {
    var docViewport = document.viewport.getDimensions();

    var offset = InfoHover.TAIL_OFFSET;
    hoverDim.width += InfoHover.TAIL_WIDTH;

    var lr = "right";
    var x = target.left + target.width + offset;

    if (viewport.left + target.width + hoverDim.width > docViewport.width) {
      lr = "left";
      x = target.left - hoverDim.width - offset;
    }

    var tmb = "mid";
    var y = target.top + target.height / 2 - hoverDim.height / 2;

    if (viewport.top + target.height / 2 - hoverDim.height / 2 + hoverDim.height > docViewport.height) {
      tmb = "bottom";
      y = target.top - hoverDim.height;
    }
    else if (viewport.top + target.height / 2 - hoverDim.height / 2 < 0) {
      tmb = "top";
      y = target.top + target.height;
    }

    var loc = [x, y, lr, tmb];
    loc.x = x;
    loc.y = y;
    loc.horiz = lr;
    loc.vert = tmb;
    loc.className = [loc.vert, loc.horiz].join('-');
    return loc;
  },

  showWindowedControls: function() {
    if (!Prototype.Browser.IE) return;
    $$('select').each(function(el) { el.style.visibility = 'visible'; });
  },

  hideWindowedControls: function() {
    if (!Prototype.Browser.IE) return;
    $$('select').each(function(el) { el.style.visibility = 'hidden'; });
  }
};

Ajax.Responders.register({
  onComplete: InfoHover.observeLinks
});

Event.observe(window, 'load', InfoHover.init);
