// Netflix Bubble Widget, v20100121
// see http://developer.netflix.com/widgets for instructions
// author: Kent Brewster 
// with much help from: Hans Granqvist, John Haren, JR Conlin, Lalitha Shankar, Michael Hart, Mikey Cohen, Navin Prasad, and Priya Poolavari 
// special thanks to: Dave Balmer, Doug Crockford, Dustin Diaz, Hedger Wang, Isaac Schlueter, and Scott Schiller

(function (w, d) {
   var voco = '';
   for (var i = 0; i < 16; i++) { voco += String.fromCharCode(Math.floor(Math.random() * 26) + 97); }
   w[voco] = {};
   var $ = w[voco];
   $.w = w;
   $.d = d;
   $.f = function() { 
      return {   
         p: [],
         init : function(hinc) {
            $.d.b = $.d.getElementsByTagName('BODY')[0]; 
            // get all the script nodes on the page
            var s = $.d.getElementsByTagName('SCRIPT');
            // loop through all script nodes on the page
            for (var i = 0; i < s.length; i++) { 
               if (s[i].src.match(hinc)) { 
                  // found it; read args and go
                  var o = s[i]; 
                  if (!$.d.getElementById('nflx-bub')) {
                     // only build the structure if it's not already here -- there could be lots of Netflix links on this page
                     $.s = $.f.fiat({"div":{"id":"nflx-bub", "style":{"top":"-8675309px"}}});
                     o.parentNode.appendChild($.s);
                     $.f.cura(o);
                  }
                  o.parentNode.removeChild(o);
                  break; 
               } 
            }                       
         },
         // housekeeping
         cura : function(o) {
            $.a = {"k":"5k2ktbs75eru9bpmysaqdumh"};
            var data = $.f.crib(o.getAttribute('settings'));
            for (var f in data) { 
               if (data[f].hasOwnProperty) { 
                  $.a[f] = data[f]; 
               } 
            }                        
            $.a.data = {};            
            $.a.css = "http://jsapi.netflix.com/us/api/w/b/c/bu100.css";
            $.a.delay = 250;
            $.a.domain = /^http:\/\/movi.es\//;
            $.k = {
               "frameName" : "NFLXFRAME",
               "frameHeight":280,
               "frameWidth":480,
               "frameMargin":20,
               "x":40,
               "y":40
            };
            $.f.pono(o); 
            var ave = $.f.acti;
            if(typeof $.w.addEventListener !== 'undefined') {
               $.d.addEventListener('mouseover', ave, false);
            } else if(typeof $.w.attachEvent !== 'undefined') {
               $.d.attachEvent('onmouseover', ave );
            }            
            ave = $.f.klik;
            if(typeof $.w.addEventListener !== 'undefined') {
               $.d.addEventListener('mouseup', ave, false);
            } else if(typeof $.w.attachEvent !== 'undefined') {
               $.d.attachEvent('onmouseup', ave );
            }           
         },
         // launch interrupted: stop timer
         amno : function(){
            $.w.clearTimeout($.a.chro);
         },
         // get data
         acce : function(url) {
            var n = $.f.p.length;
            var scriptId = voco + '.f.p[' + n + ']';
            var req = url + '?expand=@formats,@cast,@directors,@synopsis&output=json&v=2.0&callback=' + scriptId;              
            $.f.p[n] = function(r) { 
               if (r.catalog_title) {                 
                  var id = r.catalog_title.tiny_url.split('/')[3];
                  $.a.data[id] = {};
                  var t = r.catalog_title;
                  var v = {};
                  if (r.meta.links.previews) { v.preview = true; }
                  v.title = t.title.regular;
                  v.queue = t.id;
                  v.web_page = t.web_page;
                  v.box_art = t.box_art.large;
                  v.synopsis = t.synopsis.regular;
                  v.save = true;
                  v.formats = '';
                  if (t.delivery_formats) {
                     if ((t.delivery_formats['Blu-ray'] && t.delivery_formats['Blu-ray'].available_from) || (t.delivery_formats.DVD && t.delivery_formats.DVD.available_from)) {
                        v.add = true;
                        v.save = false;
                     }
                     if (t.delivery_formats.instant && t.delivery_formats.instant.available_from) {
                        v.play = true;
                        v.later = true;
                        v.save = false;
                     }
                     
                     v.formats = '<strong class="' + voco + '">Format:</strong><br />';
                     if (t.delivery_formats.DVD && t.delivery_formats.DVD.available_from) {
                        v.formats += 'DVD';
                     }
                     if (t.delivery_formats['Blu-ray'] && t.delivery_formats['Blu-ray'].available_from) {
                        if (t.delivery_formats.DVD && t.delivery_formats.DVD.available_from) {
                           if (!t.delivery_formats.instant) {
                              v.formats += ' and ';
                           } else {
                              v.formats += ', ';
                           }
                        }
                        v.formats += 'Blu-ray';
                     }
                     if (t.delivery_formats.instant && t.delivery_formats.instant.available_from) {
                        if ((t.delivery_formats.DVD  && t.delivery_formats.DVD.available_from )|| (t.delivery_formats['Blu-ray'] && t.delivery_formats['Blu-ray'].available_from)) {
                           v.formats += ' and ';
                        }
                        v.formats += 'instant';
                     }
                  }                  
                  if (t.cast) { v.cast = $.f.fixArray(t.cast); }
                  if (t.directors) { v.directors = $.f.fixArray(t.directors); }
                  if (t.genres) { v.genres = $.f.fixArray(t.genres); }     
                  if (t.release_year) { v.release_year = t.release_year; }
                  if (t.ratings) { v.ratings = t.ratings; }
                  if (t.runtime) { v.runtime = t.runtime; }
                  $.a.data[id].t = v;
                  $.a.id = id;
                  $.f.aper();
               }
               $.f.abol(voco + '.f.p[' + n + ']');
            };        
            $.d.b.appendChild($.f.fiat({"SCRIPT":{"id":scriptId, "charset":"utf-8", "type":"text/javascript", "src":req}}));
         }, 
         // handle transient API weirdness that sometimes returns an object instead of an array
         fixArray : function(o) {
            var t = [];
            if (typeof o === 'string') {
               t[0] = o;
            }
            if (typeof o === 'object') {
               if (!o[0]) {
                  t[0] = o;                 
               } else {
                  t = o;
               }
            }
            return t;         
         },
         // build our supporting foundation
         pono : function(o) {
            var t = 'netflix_bubble_css';
            if (!$.d.getElementById(t)) {
               var s = $.f.fiat({"link":{"id":t, "type":"text/css", "rel":"stylesheet", "href": $.a.css}});
               $.d.b.appendChild(s);
            }
            $.v = {};
            if ($.d.getElementById('NFLXFRAME')) {
               $.i = $.d.getElementById('NFLXFRAME').parentNode;
            } else {
               $.i = $.f.fiat({"DIV":{"className":"nflx-iframe-container","style":{"display":"none"}}});
               o.parentNode.appendChild($.i);             
               $.i.shadow = $.f.fiat({"DIV":{"className":"nflx-iframe-shadow"}});
               $.i.appendChild($.i.shadow);
            }
         },
         // build the widget
         aper : function() {
            if ($.a.data && $.a.id && $.a.data[$.a.id] && typeof $.a.data[$.a.id].t === 'object' ) {
               var r = $.a.data[$.a.id].t;
               $.s.innerHTML = '';
               // if the widget was called from inside a block, move it up to the body
               if ($.s.parentNode !== $.d.b) {
                  var nu = $.s.cloneNode(true);
                  $.s.parentNode.removeChild($.s);
                  $.s = nu;
                  $.d.b.appendChild($.s);
               }
               $.v.title = $.f.fiat("h4");
               $.v.title.innerHTML = r.title;
               $.s.appendChild($.v.title);
               $.v.info = $.f.fiat("cite");
               if (r.release_year) { $.v.info.innerHTML += r.release_year + ' '; }            
               if (r.ratings) { $.v.info.innerHTML += '<strong class="' + voco + '">' + r.ratings + '</strong> '; }          
               if (r.runtime) { $.v.info.innerHTML += r.runtime / 60 + ' minutes'; }
               $.s.appendChild($.v.info);
               // TODO: quit using tables for markup.  Also drop 40 pounds and quit drinking on school nights....
               var table = $.f.fiat("table");
               $.v.tbody = $.f.fiat("tbody");      
               var br = $.f.fiat("tr");            
               var bda = $.f.fiat({"td":{"className":"k"}});
               $.v.link = $.f.fiat({"a":{"style":{"height":"150px", "width":"110px", "overflow":"hidden"}}});
               $.v.art = $.f.fiat({"img":{"src":null}});
               if (r.web_page) {
                  $.v.art.src = r.box_art;           
                  $.v.link.href = r.web_page; 
               }
               $.v.link.appendChild($.v.art);
               bda.appendChild($.v.link);            
               if (r.add) { 
                   $.v.add = $.f.fiat({"a":{"innerHTML":"Add", "id": voco + "_add_" + $.a.id, "className":"b add"}});
                   bda.appendChild($.v.add);
               }
               if (r.save) { 
                   $.v.save = $.f.fiat({"a":{"innerHTML":"Save", "id": voco + "_save_" + $.a.id, "className":"b save"}});
                   bda.appendChild($.v.save);
               }
               if (r.play) { 
                   $.v.play = $.f.fiat({"a":{"innerHTML":"Play", "id": voco + "_play_" + $.a.id, "className":"b play"}});
                   bda.appendChild($.v.play);
                   $.v.later = $.f.fiat({"a":{"innerHTML":"Add to Instant", "id": voco + "_later_" + $.a.id, "className":"b later"}});
                   bda.appendChild($.v.later);
               }
               if (r.preview) { 
                   $.v.add = $.f.fiat({"a":{"innerHTML":"Preview", "id": voco + "_preview_" + $.a.id, "className":"b preview"}});
                   bda.appendChild($.v.add);
               }           
               br.appendChild(bda);            
               var bdt = $.f.fiat("td");
               $.v.synopsis = $.f.fiat("p");
               $.v.synopsis.innerHTML = r.synopsis.replace(/href/gi, 'class=' + voco + '" href');  
               bdt.appendChild($.v.synopsis);
               if (r.formats) {
                  $.v.formats = $.f.fiat({"p":{"innerHTML":r.formats}});
                  bdt.appendChild($.v.formats);            
               }
               br.appendChild(bdt);            
               $.v.tbody.appendChild(br);
               table.appendChild($.v.tbody);
               $.s.appendChild(table);
               $.s.appendChild($.f.fiat("div"));
               var p = $.f.loco($.a.doMe);
               $.s.style.top = p.y;
               $.s.style.left = p.x;
            }
         },
         // get data
         mani : function() {
            var o = $.a.doMe;   
            $.f.amno();
            var id = o.href.split('/')[3];
            if (typeof $.a.data[id] === 'undefined') {
               $.f.acce(o.href);
            } else {
               $.a.id = id;
               $.f.aper();
            } 
         },
         // attach events
         acti : function(v) {
            var e = v || $.w.event;
            var o = null;
            if (e.target) {
               o = (e.target.nodeType == 3) ? e.target.parentNode : e.target;
            } else {
               o = e.srcElement;
            }
            if (o) {
               if (o.className.match(voco)) {
                  $.f.amno();            
               } else {
                  if (o.href && o.href.match($.a.domain)) {
                     $.a.doMe = o;
                     var ave = $.f.mani;
                     $.a.chro = $.w.setTimeout(ave, $.a.delay);
                  } else {
                     $.a.id = null;
                     $.f.celo();
                  }
               }
            }
         },      
         // obscure the widget
         celo: function() {
            $.f.amno();
            var ave = function() { $.s.style.top = '-8675309px'; };
            $.a.chro = $.w.setTimeout(ave, $.a.delay);
         },
         // find an element
         loco : function(el) {        
            var ww = 0;
            var wh = 0;
            var wx = 0;
            var wy = 0;
            if (!$.w.innerWidth) {
               ww = $.d.b.clientWidth;
               wh = $.d.b.clientHeight;
               wx = $.d.b.scrollLeft;
               wy = $.d.b.scrollTop;
            } else {
               ww = $.w.innerWidth;
               wh = $.w.innerHeight;
               wx = $.w.pageXOffset;
               wy = $.w.pageYOffset;
            }
            var f = el;
            var x = 0;       
            var y = 0;
            do {
               y += f.offsetTop;
               x += f.offsetLeft;
               f = f.offsetParent;
            } while (f.offsetParent);  
            $.s.className = voco;            
            if (x + el.offsetWidth + 390 > ww + wx) {
               $.s.className = voco + ' r';
               x = x - 400;
            } else {
               x = x + el.offsetWidth + 10;
            }  
            y = y - 155 - (el.offsetHeight / 2);
            return ({"x":x + 'px', "y":y + 'px'});
         },
         // listen for clicks
         klik : function(v) {
            var e = v || $.w.event;
            var o = null;
            if (e.target) {
               o = (e.target.nodeType == 3) ? e.target.parentNode : e.target;
            } else {
               o = e.srcElement;
            }
            if (o) {
               if (o.className.match(/ b /)) {
                  var p = o.id.split('_');
                  if (p[0] === voco && p.length === 3) {
                     var a = p[1];
                     var d = p[2];
                     var n = $.a.data[d].t.queue;
                     if (a && d && n) {
                        if (a === 'add' || a === 'save' || a === 'later') {
                           $.f.celo();
                           $.f.exhi(o, a, n);
                        }
                        if (a === 'play') {
                           $.f.celo();
                           $.w.open('http://www.netflix.com/CommunityAPIPlay?devKey=' + $.a.k + '&movieid=' + n + '&nbb=y');
                        }
                        if (a === 'preview') {
                           $.f.celo();
                           $.f.spec(n);
                        }
                     }
                  }
               }
            }
         },   
         // show the queue iframe
         exhi : function(el, action, id) {
            // figure out where to put it
            var ww = 0;
            var wh = 0;
            var wx = 0;
            var wy = 0;
            if (!$.w.innerWidth) {
               ww = $.d.b.clientWidth;
               wh = $.d.b.clientHeight;
               wx = $.d.b.scrollLeft;
               wy = $.d.b.scrollTop;
            } else {
               ww = $.w.innerWidth;
               wh = $.w.innerHeight;
               wx = $.w.pageXOffset;
               wy = $.w.pageYOffset;
            }
            var f = el;
            var x = 0;       
            var y = 0;
            do {
               y += f.offsetTop;
               x += f.offsetLeft;
               f = f.offsetParent;
            } while (f.offsetParent);            
            var tx = x + $.k.x;
            var ty = y + $.k.y;            
            if (tx < wx) {
               tx = wx + $.k.frameMargin;
            } else {
               if (tx + $.k.frameWidth > (ww + wx)) {
                  tx = (wx + ww) - $.k.frameWidth;
               }
            }
            if (ty < wy) {
               ty = wy + $.k.frameMargin;
            } else {
               if (ty + $.k.frameHeight > (wh + wy)) {
                  ty = (wh + wy) - $.k.frameHeight;
               }
            }
            if ($.i.parentNode !== $.d.b) {
               var nu = $.i.cloneNode(true);
               $.i.parentNode.removeChild($.i);
               $.i = nu;
               $.d.b.appendChild($.i);
            }
            if (!$.i.iframe) {
               $.i.iframe = $.f.fiat({"IFRAME":{"className":"nflx-iframe"}});
               $.i.iframe.setAttribute('frameBorder', '0');
               $.i.iframe.scrolling = 'no';
               $.i.iframe.name = $.i.iframe.id = $.k.frameName;
               $.i.appendChild($.i.iframe);
               $.i.x = $.f.fiat({"A":{"className":"nflx-iframe-close","onclick":function() { $.f.occu(); } }});
               $.i.appendChild($.i.x);
            }
            $.i.style.display = 'block';
            $.i.style.top = ty + 'px';
            $.i.style.left = tx + 'px';
            // default: add a disc
            var queue_type = 'disc';
            // or maybe add to instant
            if (action === 'later') { queue_type = 'instant'; }
            // $.a.k = developer key, for affiliate referrals
            $.i.iframe.src = 'http://widgets.netflix.com/addToQueue.jsp?output=json&devKey=' + $.a.k + '&queue_type=' + queue_type + '&movie_id=' + id;
            // show the frame
            $.i.style.display = 'block';
            // start checking for frame close
            $.a.frameChecker = $.w.setInterval($.f.cave, 200);
         },
         // guard the iframe
         cave : function() {
            // there's no school like the old school....
            var f = ( $.d.frames || $.w.frames );
            if (f && f[$.k.frameName] && f[$.k.frameName].frames.length) {
               $.w.clearInterval($.a.frameChecker);
               $.f.occu();
            }
         },
         // hide the iframe -- also called when someone clicks the X button
         occu : function() {
            $.i.style.display = 'none';
            $.i.iframe.src = null;
         },
         // preview 
         spec : function(id) {
            var ave = voco + '.f.prop';
            var req = id.replace(/api/, 'catalog') + '/previews?output=json&callback=' + ave;
            $.f.prop = function(r) { 
               if (r && r.previews && r.previews.preview && r.previews.preview.stream) {
               var s = r.previews.preview.stream;
                  var url = '';
                  var height = 0;
                  var width = 0;
                  for (var i = 0; i < s.length; i++) {
                     if (s[i].category[0].term === 'flv') {
                        url = s[i].link.href;
                        height = s[i].height - 0;
                        width = s[i].width - 0;
                        break;
                     }
                  }            
                  if (!url || !height || !width) { return; }
                  var mt = 0 - (height / 2);
                  var ml  = 0 - (width / 2);
                  var sm = { "407":133, "303":185, "331":166, "311":178, "247":235, "271":210 };
                  var pn = 133;
                  var t = sm[height + ''];
                  if (t) { pn = t; }
                  if ($.w.innerWidth) {
                     // DOM
                     $.i.pglass = $.f.fiat({"DIV":{"style":{"position":"fixed", "top":"0", "left":"0", "height":"100%","width":"100%","opacity":"0.95", "backgroundColor":"#000","zIndex":"8675312"}}});
                     $.i.ui = $.f.fiat({"DIV":{"style":{"position":"fixed","top":"50%","left":"50%","marginLeft":(ml - 2) + 'px',"marginTop":(mt - 32) + 'px', "zIndex":"8675313", "height":height + 32 + 'px',"width":width + 2 + 'px', "backgroundColor":"#ddd", "textAlign":"center" }}});
                  } else {
                     // IE
                     var scrollTop = $.d.documentElement.scrollTop ? $.d.documentElement.scrollTop : $.d.b.scrollTop;
                     $.i.pglass = $.f.fiat({"DIV":{"style":{"position":"absolute", "top":0, "left":0, "height":$.d.b.scrollHeight + 'px',"width":$.d.b.scrollWidth + 'px',"filter":"alpha(opacity=95)","backgroundColor":"#000","zIndex":"8675312"}}});
                     $.i.ui = $.f.fiat({"DIV":{"style":{ "position":"absolute","top":scrollTop  + (($.d.b.clientHeight / 2) - (t/2)) + "px", "left":$.d.b.scrollLeft  + ($.d.b.clientWidth / 2),"marginLeft":(ml - 2) + 'px',"marginTop":(mt - 32) + 'px', "zIndex":"8675313", "height":height + 32 + 'px', "width":width + 2 + 'px', "backgroundColor":"#ddd", "textAlign":"center" }}});                  
                  }
                  $.d.b.appendChild($.i.pglass);
                  $.i.uix = $.f.fiat({"A":{"innerHTML":"close", "onclick": function() { $.f.abol($.i.ui); $.f.abol($.i.pglass); }, "style":{ "display":"block","font":"normal 12px/30px arial, helvetica, sans-serif","height":"30px", "paddingRight":"5px", "margin":"1px 1px 0","background":"#b9090b url(http://jsapi.netflix.com/us/api/images/buttons/n_small.png) 5px 5px no-repeat", "textAlign":"right", "textDecoration":"none", "color":"#fff", "cursor":"pointer" }}});
                  $.i.ui.appendChild($.i.uix);               
                  $.i.player = $.d.createElement('EMBED');
                  $.i.player.src = 'http://screeningcdn.nflximg.com/us/flash/v3Player/' + pn + '.swf?bl=' + encodeURIComponent(url);
                  $.i.player.height = height;
                  $.i.player.width = width;
                  $.i.player.flashvars = 'ptCell=-1';
                  $.i.player.wmode = 'transparent';
                  $.i.player.quality = 'high';
                  $.i.player.bgcolor = '#a00';
                  $.i.player.name = 'flashpcontentObj';
                  $.i.player.id = 'flashpcontentObj';
                  $.i.player.type = 'application/x-shockwave-flash';
                  $.i.ui.appendChild($.i.player);
                  $.d.b.appendChild($.i.ui);
               }
               $.f.abol(voco + '.f.prop');
            };        
            $.d.b.appendChild($.f.fiat({"SCRIPT":{"id":ave, "charset":"utf-8", "type":"text/javascript", "src":req}}));
         },
         // create an element
         fiat: function(o) {
            var el = null;
            var foundClass = false;
            if (typeof o === 'object') {
               for (var t in o) {
                  if (o[t].hasOwnProperty) {
                     try {
                        el = $.d.createElement(t);
                        for (var a in o[t]) {
                           if (typeof o[t][a] === 'string' || typeof o[t][a] === 'function') {
                              try{ 
                                if (a === 'className') { 
                                   o[t][a] = voco + ' ' + o[t][a]; 
                                   foundClass = true;
                                }
                                el[a] = o[t][a]; 
                              } catch (err1) { }
                           } else {
                              if (typeof o[t][a] === 'object') {
                                 for (var v in o[t][a]) {
                                    if (o[t][a][v].hasOwnProperty) {
                                       try { 
                                          el[a][v] = o[t][a][v]; 
                                       } catch (err2) { }
                                    }
                                 }
                              }
                           }
                        }
                     } catch (err3) { }
                     break;
                  }
               }
            } else { 
               if (typeof o === 'string') { 
                  try {
                     el = $.d.createElement(o); 
                  } catch (err4) { }
               } 
            }
            if (typeof el === 'object' && el.tagName) { 
               if (!foundClass) {
                  el.className = voco;
               }
               return el; 
            } else { 
               return false; 
            }
         },
         // remove an element
         abol: function(o) {
            var e = o;
            if (typeof o === 'string') { e = $.d.getElementById(o); }
            if (e && e.parentNode) { e.parentNode.removeChild(e); } 
         },
         // sieve input from a single string into key/value pairs and return an object
         crib : function (input) {
            var args, pairs, i, query, key, value, temp, text;
            args = {};
            // require input to be string, not object
            if (typeof input === 'string') {               
               text = $.w.unescape(input);
               pairs = text.split('&');
               for (i = 0; i < pairs.length; i = i + 1) {
                  query = pairs[i].split('=');
                  key = query[0];
                  value = query[1];
                  // we see a second value for k, so turn it into an array
                  if (typeof args[key] === 'string') {
                     temp = args[key];
                     args[key] = [];
                     args[key][0] = temp;
                  }
                  if (typeof args[key] === 'object' && args[key].length) {
                     // is args[key] an array? add value
                     args[key][args[key].length] = value;
                  } else {
                     // args[key] takes value as a string
                     args[key] = value;
                  }
               }
            }
            return args;
         }
      };
   }();
   var hinc = /^http:\/\/jsapi.netflix.com\/us\/api\/w\/b\/bu100.js/;
   if(typeof $.w.addEventListener !== 'undefined') {
      $.w.addEventListener('load', function() {
         $.f.init(hinc);
      }, false);
   } else if(typeof $.w.attachEvent !== 'undefined') {
      $.w.attachEvent('onload', function() {
         $.f.init(hinc);
      });
   }
})(window, document);
