// -*- coding: utf-8 -*-
/**
Copyright (c) 2008, 2009 T. Hoshi  All rights reserved.

vw video renderer by using youtube api

Assumptions:
* jquery.js is loaded
* there is an empty div id="..." in the current html

[!file-evolution-number: 594]
*/

/**
DOCUMENTATION.
     Youtube - Important feed elements ~/docs/tmp/snippets/20080618_220516

`#youtube-video-1' : main video div id. jump://~/www/mysite/vw.py#        <div id="youtube-video-1" style="display: inline;"></div>
`#youtube-video-2' : thumb video div id. jump://~/www/mysite/vw.py#        <div id="youtube-video-1" style="display: inline;"></div>

Youtube-API.
   Entry-structure.
     d = data;
     d.feed.entry[0].title.$t
     d.feed.entry[0].content.$t
     d.feed.entry[0].id.$t
     d.feed.entry[0].link[0].href
     d.feed.entry[0].media$group.media$content[0].url
     data.feed.openSearch$totalResults.$t     // total hits
     entries[0].media$group.media$thumbnail[0].url    /// thumbnail url
     d.feed.entry[0].media$thumbnail[0].{url,height,width,time}    /// thumbnail structure

Experimental-requests.
    http://gdata.youtube.com/feeds/api/videos?vq=tkykhs&start-index=1&max-results=5&orderby=relevance&alt=json-in-script
    http://gdata.youtube.com/feeds/api/videos?vq=Main%20Page&start-index=1&max-results=1&orderby=relevance&alt=json-in-script

SEE.
  Youtube Player parameters http://code.google.com/apis/youtube/player_parameters.html
  Youtube API and Data feed reference guide http://code.google.com/apis/youtube/2.0/reference.html

TODO:
* uncomment other fixIEUnfocus() and make it faster.

*/

var Vwv = function(user_custom_vwv) {
    this.debug = false;
    this.lang = 'en';
    this.orderby = 'relevance';    /// TODO. embed value of this var.
    
    /// main video div
    this.target_id = 'youtube-videos-component' ;
    this.video_query_escaped = "video%20query" ;
    this.video_component_title = 'Videos on “' +htmlspecialchars(unescape(this.video_query_escaped))+ '”' ;
    this.fullscreen_message = "Full screen" ;
    this.max_displayed_videos = 5;    /// 1 main video + 4 thumbnails
    // this.video_width = 300;
    // this.video_height = 250;
    this.video_width = 312;
    this.video_height = 260;
    this.thumb_width = 130;    /// 96
    this.thumb_height = 97;    /// 72
    this.max_description_length = 222;
    this.max_title_length = 55;

    // -------------------------------------------------------------------------
    for (var p in user_custom_vwv)
        this[p] = user_custom_vwv[p];
    
    /// INTERNAL VARIABLES

    /// main video div
    this.start_index = 1;
    this.url = 'http://gdata.youtube.com/feeds/api/videos?vq='+this.video_query_escaped+'&start-index='+this.start_index+'&max-results='+this.max_displayed_videos+'&lr='+this.lang+'&orderby='+this.orderby+'&format=5&alt=json-in-script&callback=?' ;    /// Honban
    // this.url = 'http://gdata.youtube.com/feeds/api/videos?vq=tkykhs%20key&start-index='+this.start_index+'&max-results='+this.max_displayed_videos+'&lr='+this.lang+'&orderby='+this.orderby+'&format=5&alt=json-in-script&callback=?' ;   /// Test
    this.total_videos = 0 ;    /// data.feed.openSearch$totalResults.$t
    this.video_data = null;    /// data

    /// right video div
    this.rtarget_id = 'right-youtube-video-component' ;
    this.rvideo_width = 230;
    // this.rvideo_height = 172;
    this.rvideo_height = 192;
    this.rmax_title_length = 60;
    this.rstart_index = 1;
    /// For main pages, show the VisWiki (visualwikipedia) video. TODO: Move this control to vw.py
    if (this.lang=='en' && this.video_query_escaped=='Main%20Page')
        this.rvideo_query_escaped = "%22" + escape('Visual Wikipedia for knowledge lovers') + "%22" ;
    else
        this.rvideo_query_escaped = "%22" + this.video_query_escaped + "%22" ;    /// quoted this.video_query_escaped
    this.rfullscreen_message = this.fullscreen_message ;
    this.rurl = 'http://gdata.youtube.com/feeds/api/videos?vq='+this.rvideo_query_escaped+'&start-index='+this.rstart_index+'&max-results=1&lr='+this.lang+'&orderby='+this.orderby+'&format=5&alt=json-in-script&callback=?' ;    /// Honban
    // this.rurl = 'http://gdata.youtube.com/feeds/api/videos?vq=tkykhs&start-index='+this.rstart_index+'&max-results=1&lr='+this.lang+'&orderby='+this.orderby+'&format=5&alt=json-in-script&callback=?' ;    /// test
    this.rtotal_videos = 0 ;    /// data.feed.openSearch$totalResults.$t
    this.rvideo_data = null;    /// data
}

// *. Functions <youtube-videos-component>

// **. Rendering

// Vwv.prototype.fullscreen = function(video_id) {    /// youtube inline video in (pseudo) full-screen mode.
//     window.open("http://www.youtube.com/v/"+video_id+"&rel=0", "FullScreenVideo","toolbar=no,width="+screen.availWidth+",height="+(screen.availHeight - 50).toString()+",status=no,resizable=yes,scrollbars=no,top=0");
//     document.location.reload();
// }
Vwv.prototype.fullscreen = function(video_url) {    /// youtube inline video in (pseudo) full-screen mode.
    /// video_url is of the form: "http://www.youtube.com/v/"+video_id+"&rel=0"
    var w = window.open(video_url, "FullScreenVideo","toolbar=no,width="+screen.availWidth+",height="+(screen.availHeight - 50).toString()+",status=no,resizable=yes,scrollbars=no,top=0");
    // w.document.title = "Video";
    // document.location.reload();
}

Vwv.prototype.render_nav_buttons = function() {    /// render prev/next video buttons
    // var next_p = ((this.total_videos - this.start_index) < this.max_displayed_videos) ? false : true;
    if (this.total_videos <= this.max_displayed_videos)
        return ''
    var n = Math.ceil( this.start_index / this.max_displayed_videos ) ;
    var total = Math.ceil( this.total_videos / this.max_displayed_videos ) ;
    var html =  '<div id="youtube-videos-nav" style="display: inline; float: right; font-size: 85%; color: #000; margin-right: 25px;">\
    <span id="youtube-videos-nav-status"><strong>'+n+'</strong> / <strong>'+total+'</strong></span>&#xA0;\
    <img width="21" height="15" border="0" src="/media/vw/prev_video.gif" style="cursor: pointer;" onmouseout="this.src=\'/media/vw/prev_video.gif\'" onmouseover="this.src=\'/media/vw/prev_video_on.gif\'" onclick="vwv.goto_prev_video()"/>\
    <img width="21" height="15" border="0" src="/media/vw/next_video.gif" style="cursor: pointer;" onmouseout="this.src=\'/media/vw/next_video.gif\'" onmouseover="this.src=\'/media/vw/next_video_on.gif\'" onclick="vwv.goto_next_video()"/>\
  </div>' ;
    return html;
}

/// Render main video entry (on the left) that will be inserted into #youtube-video-1
// 2008-12-28 - jump://~/docs/tmp/snippets/20081228_050703
Vwv.prototype.render_main_video_entry = function( entry, autoplayp ) {    /// entry is data.feed.entry[0], autoplayp (optional)
    var src = (!entry.media$group.media$content) ? 'foo' : entry.media$group.media$content[0].url;    /// in a rare case, this does happen
    var title = htmlspecialchars(entry.title.$t, true) ;
    // var description = unhtmlspecialchars(entry.content.$t);
    // var description_short = (description.length > this.max_description_length) ?
    // (description.substring(0, this.max_description_length) + "...") : description;
    // description_short = htmlspecialchars(description_short);
    var duration = sec2minutes(entry.media$group.yt$duration.seconds);
    /// SEE: http://code.google.com/apis/youtube/player_parameters.html
    // var other_params_s =  'rel=0&showsearch=0&fs=1&color1=0xc5c5c5&color2=0xdfdfec' ;    /// fs : enable full screen button - doesnt work on smaller pixels
    var other_params_s =  'rel=0&showsearch=0&fs=1&color1=0xc5c5c5&color2=0xdfdfec&showinfo=0&iv_load_policy=3' ;    /// fs : enable full screen button
    if (autoplayp)
        other_params_s += '&autoplay=1' ;
    if (!jQuery.browser.msie)    /// for some reason, IE will not play video if the following param is set.
        other_params_s += '&ap=%2526fmt%3D18' ;     /// this is to enable high quality viewing of video (if any) - &fmt=18
    var s = '\
 <div style="padding-top: 0px; margin-top: 0px;">\
  <object width="'+this.video_width+'" height="'+this.video_height+'">\
    <param name="wmode" value="transparent" />\
    <embed wmode="transparent" src="'+ src + '&' + other_params_s +'" type="application/x-shockwave-flash" width="'+this.video_width+'" height="'+this.video_height+'" allowfullscreen="true"></embed>\
  </object>\
 </div>\
  <div style="padding-top:5px; line-height: 1.2em;">\
    <div>\
      <span style="font-size: 95%; font-weight: bold; color: #222;">' + title + '</span>\
      <span style="font-size: 80%; color:#888;" class="duration-text"> - ' + duration + '</span>\
    </div>\
    <div style="padding-top:3px;"><a style="font-size: 80%; cursor: pointer;" onclick="vwv.fullscreen(\''+ htmlspecialchars(src) +'\')">' + this.fullscreen_message + '</a></div>\
  </div>\
';
    return s;
}

Vwv.prototype.render_video_thumbnail = function( entry, thumb_ordinal ) {    /// Render one thumbnail entry. 
    if (!entry.media$group.media$content)    /// in a rare case, this happens.
        return '<td></td>';

    /// Set variable values
    var thumb_video_url = entry.media$group.media$content[0].url;
    var thumb_video_title = unhtmlspecialchars(entry.title.$t);
    var thumb_video_title_short = (thumb_video_title.length > this.max_title_length) ?
    (thumb_video_title.substring(0, this.max_title_length) + "...") : thumb_video_title;
    // var thumb_video_description = unhtmlspecialchars(entry.content.$t);
    // var thumb_video_description_short = (thumb_video_description.length > this.max_description_length) ?
    // (thumb_video_description.substring(0, this.max_description_length) + "...") : thumb_video_description;
    var thumb_image_url = entry.media$group.media$thumbnail[0].url;
    var thumb_video_duration = sec2minutes(entry.media$group.yt$duration.seconds);
    var thumb_video_rating = '0.0';
    if (entry.gd$rating) 
        thumb_video_rating = entry.gd$rating.average;

    /// Normalize
    thumb_video_title = htmlspecialchars(thumb_video_title);
    thumb_video_title_short = htmlspecialchars(thumb_video_title_short);
    // thumb_video_description = htmlspecialchars(thumb_video_description);
    // thumb_video_description_short = htmlspecialchars(thumb_video_description_short);

    /// Generate td.
    var td = "\
      <td align=\"center\">\
        <div class=\"video-thumb\" style=\"padding-bottom: 8px; padding-right: 5px; padding-left: 5px;\" id=\"video-thumb-" + thumb_ordinal + "\">\
          <div onclick=\"return vwv.place_play_video(" + thumb_ordinal + ")\" style=\"cursor: pointer;\" class=\"thumbnail\">\
            <img  width=\"" + this.thumb_width + "\" height=\"" + this.thumb_height + "\" title=\"" + thumb_video_title + "\" src=\"" + thumb_image_url + "\" class=\"video-thumb-image\"/>\
          </div>\
          <div class=\"title\" style=\"padding-top:5px; font-size:90%; line-height: 1.2em; height: 40px; \">\
            <a class=\"video-thumb-link\" onclick=\"return vwv.place_play_video(" + thumb_ordinal + ")\" title=\"" + thumb_video_title + "\" href=\"javascript:void(0);\">" + thumb_video_title_short + "</a>\
            <span class=\"video-thumb-now-playing hidden\">Now playing ...</span>\
            <span style=\"font-size:80%; color:#888;\" class=\"duration-text\">\
              - " + thumb_video_duration + "\
            </span>\
           <!--  - <span class=\"rating-widget\">" + thumb_video_rating + "</span> -->\
       </div>\
          <div style=\"display: none;\" class=\"full_title\">" + thumb_video_title + "</div>\
          <div style=\"display: none;\" class=\"url\">" + thumb_video_url + "</div>\
       </div>\
       </td>\
";
    return td;
}

/// Render main video entry (on the left) that will be inserted into #youtube-video-1
Vwv.prototype.render_video_thumbnails = function( entries ) {    /// entries is data.feed.entry 
    var tds = [ ];
    for (var n=1; n < this.max_displayed_videos; ++n) {
        var td = (entries[n]) ? this.render_video_thumbnail(entries[n], n) :  '<td></td>' ;
        tds.push(td);
    }
    // var td = this.render_video_thumbnail(entries[0], 1);    /// test
    // var tds = [ td, td, td, td ];
    var s = "\
<table cellspacing=\"0\" cellpadding=\"0\">\
  <tbody>\
	<tr>    <!-- first row -->\
" + tds[0] + "\
" + tds[1] + "\
	</tr>\
	<tr>    <!-- second row -->\
" + tds[2] + "\
" + tds[3] + "\
	</tr>\
  </tbody>\
</table>\
";
    return s;
}

// **. Decoration, control
// 2008-12-28 (22:30)

/// Show #youtube-videos-component and decorate the div with
/// both main video and video thumbnails.
Vwv.prototype.decorate_youtube_video_component = function( data ) {
    /// Info: jump://~/docs/tmp/snippets/20080618_220516
    if (data.feed.entry) {    /// if there was any match at all
        var entries = data.feed.entry ;    /// video entries that matched  query.
        var main_video_id = 'youtube-video-1' ;
        var video_thumbnails_id = 'youtube-video-2' ;
        this.total_videos = Number( data.feed.openSearch$totalResults.$t );    /// number of matched videos 
        $( '#'+this.target_id ).removeClass( 'hidden' ) ;    /// make it visible
        /// navigation arrows
        var e = $( '#'+this.target_id+' > h3' ) ;
        e.empty() ;  
        e.append( this.render_nav_buttons() + this.video_component_title ) ;
        /// main video entry
        var e = $( '#'+main_video_id ) ;
        e.empty( );
        e.append( this.render_main_video_entry(entries[0]) );
        fixIEUnfocus(e.find('embed')[0]);    /// fix ie unfocus on main video
        /// video thumbnails
        var e = $( '#'+video_thumbnails_id ) ;
        e.empty( );
        e.append( this.render_video_thumbnails(entries) );
        
    }
}

Vwv.prototype.place_play_video = function( video_index ) {    /// video_index : index for vwv.video_data
    if (vwv.video_data.feed.entry[video_index]) {
        /// Highlight the thumb currently playing
        // var e = $('.video-thumb-now-playing');
        // e.addClass( 'hidden' );
        // e = $('.video-thumb-link');
        // e.removeClass( 'hidden' );
        // e = $('#video-thumb-'+video_index + " > .video-thumb-link");    /// select
        // e.addClass( 'hidden' );
        // e = $('#video-thumb-'+video_index + " > .video-thumb-now-playing");    /// select
        // e.removeClass( 'hidden' );

        // var e = $('.video-thumb-image');
        // e.removeClass( 'video-thumb-selected' );
        // e = $('#video-thumb-'+video_index + " > .video-thumb-image");    /// select
        // e.addClass( 'video-thumb-selected' );

        /// Main video entry
        var e = $( '#youtube-video-1' ) ;
        e.empty( );
        e.append( this.render_main_video_entry(vwv.video_data.feed.entry[video_index], true) );    /// with autoplay
        fixIEUnfocus(e.find('embed')[0]);    /// fix ie unfocus on main video
    }
}


Vwv.prototype.goto_prev_video = function() {
    this.start_index -= this.max_displayed_videos ;
    // this.start_index = (a <= 0)  ?  (this.total_videos + a) : a ;
    if (this.start_index <= 0) {
        this.start_index = 1 ;
        return false;
    }
    this.url = 'http://gdata.youtube.com/feeds/api/videos?vq='+this.video_query_escaped+'&start-index='+this.start_index+'&max-results='+this.max_displayed_videos+'&lr='+this.lang+'&orderby='+this.orderby+'&format=5&alt=json-in-script&callback=?' ;
    $.getJSON( this.url,
              function(data) {
                  vwv.video_data = data;
                  vwv.decorate_youtube_video_component( data ) ;
              });
}

Vwv.prototype.goto_next_video = function() {    /// Ex: jump://~/docs/tmp/snippets/20081226_184316
    var a = this.start_index + this.max_displayed_videos ;
    this.start_index = (a > this.total_videos) ? (a % this.total_videos) : a ;
    this.url = 'http://gdata.youtube.com/feeds/api/videos?vq='+this.video_query_escaped+'&start-index='+this.start_index+'&max-results='+this.max_displayed_videos+'&lr='+this.lang+'&orderby='+this.orderby+'&format=5&alt=json-in-script&callback=?' ;
    $.getJSON( this.url,
              function(data) {
                  vwv.video_data = data;
                  vwv.decorate_youtube_video_component( data ) ;
              });
}

Vwv.prototype.debug_data = function( data ) {    /// Output necessary information.
    var entries = data.feed.entry ;    /// video entries that matched  query.
    if (entries) {    /// if there was any match at all
        var entry = entries[0] ;
        var s = "title: " + entry.title.$t + "\n" + 
        "url: " + entry.media$group.media$content[0].url + "\n" + 
        "description: " + entry.content.$t + "\n" + 
        "duration: " + entry.media$group.yt$duration.seconds + "\n" + 
        "thubnail url: " + entry.media$group.media$thumbnail[0].url + "\n" +
        "thubnail width: " + entry.media$group.media$thumbnail[0].width + "\n" +
        "thubnail height: " + entry.media$group.media$thumbnail[0].height + "\n" +
        '' ;
        if (entry.gd$rating) {
            s +=  "rating: " + entry.gd$rating.average + "\n" + 
            "rating count: " + entry.gd$rating.numRaters + "\n" ;
        }
        alert( s );
    }
}

// *. Functions <right>

/// Render html inside `right-youtube-video-component' (hidden, at the moment on the right, just below slidebox)
Vwv.prototype.render_right_youtube_video = function( entry ) {
    /// nav part
    var nav_bar = (this.rtotal_videos < 2) ? ' ' : '  <div id="right-youtube-videos-nav" style="text-align: center; margin-bottom: 8px;">\
    <span style="font-size:90%; color:#444;" id="right-youtube-videos-nav-status"><strong>'+this.rstart_index+'</strong> / <strong>'+this.rtotal_videos+'</strong></span>&#xA0;\
    <img width="21" height="15" border="0" src="/media/vw/prev_video.gif" style="cursor: pointer;" onmouseout="this.src=\'/media/vw/prev_video.gif\'" onmouseover="this.src=\'/media/vw/prev_video_on.gif\'" onclick="vwv.rgoto_prev_video()"/>\
    <img width="21" height="15" border="0" src="/media/vw/next_video.gif" style="cursor: pointer;" onmouseout="this.src=\'/media/vw/next_video.gif\'" onmouseover="this.src=\'/media/vw/next_video_on.gif\'" onclick="vwv.rgoto_next_video()"/>\
  </div>' ;

    var src = (!entry.media$group.media$content) ? 'foo' : entry.media$group.media$content[0].url;    /// in a rare case, this does happen
    var title = htmlspecialchars(entry.title.$t, true) ;
    // var title_short = (title.length > this.rmax_title_length) ? (title.substring(0, this.rmax_title_length) + "...") : title;
    // title_short = htmlspecialchars(title_short);
    // var duration = sec2minutes(entry.media$group.yt$duration.seconds);
    /// SEE: http://code.google.com/apis/youtube/player_parameters.html
    var other_params_s =  'rel=0&showsearch=0&fs=1&color1=0xc5c5c5&color2=0xdfdfec&showinfo=0&iv_load_policy=3' ;
    if (!jQuery.browser.msie)    /// for some reason, IE will not play video if the following param is set.
        other_params_s += '&ap=%2526fmt%3D18' ;     /// this is to enable high quality viewing of video (if any) - &fmt=18
    var s = '\
' + nav_bar + '\
 <div style="text-align: center;">\
  <object width="'+this.rvideo_width+'" height="'+this.rvideo_height+'">\
    <param name="wmode" value="transparent" />\
    <embed wmode="transparent" src="'+ src + '&' + other_params_s +'" type="application/x-shockwave-flash" width="'+this.rvideo_width+'" height="'+this.rvideo_height+'" allowfullscreen="true"></embed>\
  </object>\
 </div>\
  <div style="text-align: center; padding-top: 2px; line-height: 1.2em;">\
    <span style="font-size: 90%; font-weight: bold; color: #222;">' + title + '</span>\
  </div>\
';
    return s;
}

Vwv.prototype.rgoto_next_video = function() {
    var a = this.rstart_index + 1 ;
    this.rstart_index = (a > this.rtotal_videos) ? 1 : a ;
    this.rurl = 'http://gdata.youtube.com/feeds/api/videos?vq='+this.rvideo_query_escaped+'&start-index='+this.rstart_index+'&max-results=1&lr='+this.lang+'&orderby='+this.orderby+'&format=5&alt=json-in-script&callback=?' ;
    $.getJSON( this.rurl,
              function(data) {
                  vwv.rvideo_data = data;
                  vwv.rdecorate_youtube_video_component( data ) ;
              });
}

Vwv.prototype.rgoto_prev_video = function() {
    this.rstart_index -= 1 ;
    if (this.rstart_index <= 0) {
        this.rstart_index = 1 ;
        return false;
    }
    this.rurl = 'http://gdata.youtube.com/feeds/api/videos?vq='+this.rvideo_query_escaped+'&start-index='+this.rstart_index+'&max-results=1&lr='+this.lang+'&orderby='+this.orderby+'&format=5&alt=json-in-script&callback=?' ;
    $.getJSON( this.rurl,
              function(data) {
                  vwv.rvideo_data = data;
                  vwv.rdecorate_youtube_video_component( data ) ;
              });
}

Vwv.prototype.rdecorate_youtube_video_component = function( data ) {
    if (data.feed.entry) {    /// if there was any match at all
        this.rtotal_videos = Number( data.feed.openSearch$totalResults.$t );    /// number of matched videos 
        var entry = data.feed.entry[0] ;    /// video entries that matched  query.
        var e = $( '#'+this.rtarget_id );
        e.empty( );
        e.removeClass( 'hidden' ) ;    /// make it visible
        e.append( this.render_right_youtube_video(entry) );
        // e.addClass( 'component-border-top' );
        fixIEUnfocus(e.find('embed')[0]);    /// fix ie unfocus on main video
    }
}


// *. Execution

var custom_vwv = custom_vwv || { };
var vwv = new Vwv(custom_vwv);
$(document).ready(function() {

    /// main video
    $.getJSON( vwv.url,  ///  Ex: jump://~/docs/tmp/snippets/20080619_211920
              function(data) {
                  if (vwv.debug)  {  vwv.debug_data(data);  }
                  vwv.video_data = data;
                  vwv.decorate_youtube_video_component( data ) ;
              });

    /// right video
    $.getJSON( vwv.rurl,    /// Ex: jump://~/docs/tmp/snippets/20080619_211920
              function(data) {
                  if (vwv.debug)  {  vwv.debug_data(data);  }
                  vwv.rvideo_data = data;
                  vwv.rdecorate_youtube_video_component( data ) ;
              });
    
});
