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

VW article renderer.

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

Insert article contents into an empty div:
	<div id="article_contents"></div>

* Generates: id="article_toc_component"

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

// *. Vars

var Vwa = function(user_custom_vwa) {
    /// CUSTOMIZABLE VARIABLES
    this.ignored_sections_reobjects = [ ] ;
    this.lang = "en";
    this.article_title_escaped = "Main_Page";
    this.main_page_titles_escaped = [ "Main_Page", "%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8" ] ;
    this.abstract_section_title = "Abstract";
    this.show_all_article_message = "all";
    this.section_nav_next_alt = "Go to tne next section";
    this.insert_toc_p = true;
    this.insert_slidebox_p = true;
    this.show_inlink_tooltip_p = true;

    /// Vars less likely be changed
    this.article_div_id = "article_contents";
    this.captioned_image_min_width = 85 ;
    // this.captioned_image_max_width = 210 ;
    this.captioned_image_max_width = 220 ;
    this.section_fold_threshold = 15;
    this.in_other_languages_max_entries = 12;

    /// RE
    this.ref_re = new RegExp( "<a href=\"#cite_note-[^\"]+?\" title=\"\">.+?</a>", "gi");
    // this.split_sections_re = new RegExp( "(<h[2-6]> *(?:<span *class=\"editsection.+?</span>)? *<span *class=\"mw-headline\">) *(.+?) *(</span></h[2-6]>)", "ig"); /// jump://~/docs/tmp/snippets/20080607_174325 - '\n<p><a name="Techniques" id="Techniques"></a></p>\n'
    this.split_sections_re = new RegExp( "(?:<p><a name=\".*?\" id=\".*?\"></a></p>\r?\n?)?(<h[2-6]> *(?:<span *class=\"editsection.+?</span>)? *<span *class=\"mw-headline\">) *(.+?) *(</span></h[2-6]>)", "ig"); /// jump://~/docs/tmp/snippets/20080607_174325 - '\n<p><a name="Techniques" id="Techniques"></a></p>\n'
    this.section_level_re = new RegExp( "^<h([2-6])>", "i");
    this.internal_query_link_re = new RegExp( "(<a +href=\"/w/.+?\"[^>]*?>)(.+?)(</a>)", "ig");    /// query links like /w/index.php?title=Humanism:_A_New_Religion&action=edit&redlink=1
    this.inlink_non_ns0_re = new RegExp( "(<a +href=\"/wiki/(?:[^:_\">]+?:.+?)\"[^>]*?>)(.+?)(</a>)", "ig");
    // this.inlink_ns0_re = new RegExp( "(<a +href=\")/wiki/(.+?)(\"[^>]*?)>(.+?)(</a>)", "ig");
    this.inlink_ns0_re = new RegExp( "(<a +href=\")/wiki/(.+?)(?:#.+?)?(\"[^>]*?)>(.+?)(</a>)", "ig");    /// no pound
    this.citation_needed_re = new RegExp( "\\[<i>citation needed</i>\\]", "ig");
    this.simple_image_re = new RegExp( "<img\\s+.+?>", "i");
    this.section_toc_id_re = new RegExp( "[0-9]+$");
    this.non_captioned_images_re = new RegExp( '<img\\s+alt=""\\s+src="([^\"]+?)"\\s+[^>]*?\\bwidth="([0-9]+)"\\s+height="([0-9]+)"', "ig" );    /// [src, width, height] - Examples: jump://~/docs/tmp/snippets/20080614_003504
    /// 2008-12-24 - Newer-style captioned_images_re. captioned_images_re now also captured non captioned images.  - not used any more
    // this.captioned_images_re = new RegExp( '<img\\s+alt="([^\"]*?)"\\s+src="([^\"]+?)"\\s+[^>]*?\\bwidth="([0-9]+)"\\s+height="([0-9]+)"', "ig" );    /// [alt, src, width, height] - Examples: jump://~/docs/tmp/snippets/20080614_003504

    this.simple_a_tag_re = new RegExp( "<a\\s.+?>(.+?)</a>", "gi");    /// used to remove links from each section title
    // this.thumb_image_fname_re = new RegExp( '/(?:[0-9]+px-)?(.+)$', "i");    /// used to remove '200px-' in 200px-filename
    this.thumb_image_fname_re = new RegExp( '/(?:[0-9]+px-)(.+)$', "i");    /// used to detect '200px-' in 200px-filename
    this.redirect_page_title_re = new RegExp( '^<ol>\\s<li>REDIRECT\\s*<a href="/wiki/(.+?)"[^>]*?>' , "i");
    this.languages = [ ['en', 'English'], ['ja', '日本語'], ['de', 'Deutsch'], ['fr', 'Français'], ['pl', 'Polski'], ['it', 'Italiano'], ['nl', 'Nederlands'], ['pt', 'Português'], ['es', 'Español'], ['ru', 'Русский'], ['sv', 'Svenska'], ['zh', '中文'], ['no', 'Norsk (Bokmål)'], ['fi', 'Suomi'], ['ca', 'Català'], ['uk', 'Українська'], ['vo', 'Volapük'], ['tr', 'Türkçe'], ['ro', 'Română'], ['cs', 'Čeština'], ['hu', 'Magyar'], ['eo', 'Esperanto'], ['sk', 'Slovenčina'], ['da', 'Dansk'], ['id', 'Bahasa Indonesia'], ['ko', '한국어'], ['lt', 'Lietuvių'], ['sr', 'Српски / Srpski'], ['sl', 'Slovenščina'], ['bg', 'Български'], ['vi', 'Tiếng Việt'] ] ; /// ['he', 'עברית'], ['ar', 'العربية'], ['et', 'Eesti'], ['ht', 'Krèyol ayisyen'], ['hr', 'Hrvatski'], ['fa', 'فارسی'], ['new', 'नेपाल भाषा'], ['te', 'తెలుగు'], ['nn', 'Nynorsk'], ['gl', 'Galego'], ['th', 'ไทย'], ['el', 'Ελληνικά'], ['simple', 'Simple English'], ['ceb', 'Sinugboanong Binisaya'], ['ms', 'Bahasa Melayu'], ['eu', 'Euskara'], ['bs', 'Bosanski'], ['lb', 'Lëtzebuergesch'], ['ka', 'ქართული'], ['bpy', 'ইমার ঠার/বিষ্ণুপ্রিয়া মণিপুরী'], ['is', 'Íslenska'], ['la', 'Latina'], ['hi', 'हिन्दी'], ['sq', 'Shqip'], ['br', 'Brezhoneg'], ['mr', 'मराठी'], ['az', 'Azərbaycan'], ['mk', 'Македонски'], ['sh', 'Srpskohrvatski / Српскохрватски'], ['cy', 'Cymraeg'], ['tl', 'Tagalog'], ['bn', 'বাংলা'], ['lv', 'Latviešu'], ['pms', 'Piemontèis'], ['io', 'Ido'], ['ta', 'தமிழ்'], ['oc', 'Occitan'], ['jv', 'Basa Jawa'], ['su', 'Basa Sunda'], ['be', 'Беларуская'], ['nds', 'Plattdüütsch'], ['nap', 'Nnapulitano'], ['scn', 'Sicilianu'], ['be-x-old', 'Беларуская (тарашкевіца)'], ['ku', 'Kurdî / كوردی'], ['ast', 'Asturianu'], ['af', 'Afrikaans'], ['wa', 'Walon'], ['an', 'Aragonés'] ] ;

    for (var p in user_custom_vwa)
        this[p] = user_custom_vwa[p];
    this.in_english_message = (this.lang == 'ja') ? '[<strong>英語だと</strong>: <strong>$1</strong>]' : '[<strong>In English</strong>: $1]' ;    /// this is to be decided AFTER correct this.lang is set.
    
    /// Store
    this.langlinks = null ;
    this.article_html = '' ;
    this.section_index = 0;
    this.captioned_image_index = 0;
    this.article_sections = [ ] ;    /// [ (section_title, section_level, section_content)_1:n ]
    this.captioned_images = [ ] ; /// [ (caption, src, width, height)_1:n ]
    this.intro_first_imageinfo = null ; /// Will be: [ caption, src, width, height ]
} ;

// *. Fun

Vwa.prototype.is_legal_section_title = function(section_title) {
    for (var i = 0; i < this.ignored_sections_reobjects.length; i++) {
        if (this.ignored_sections_reobjects[i].test(section_title))
            return false;
    }
    return true;
}

Vwa.prototype.do_initial_article_cleanup = function(html, show_inlink_tooltip_p, lang) {
    var html = html.replace(this.ref_re, "")  /// Reference removal
    .replace(this.internal_query_link_re, "$2")    /// remove query links like /w/index.php?title=Humanism:_A_New_Religion&action=edit&redlink=1
    .replace(this.inlink_non_ns0_re, "$2")    /// remove links to non-ns0 pages.
    .replace(this.citation_needed_re, "");  /// remove [citation needed] string. this distrusts you while reading.
    var additional_inlink_params = '';
    if (!lang)
        var lang = this.lang
    if (show_inlink_tooltip_p)
        additional_inlink_params = " class=\"inlink\" onclick=\"tkTooltipEnable = false;\" onmouseover=\"ajax_showTooltip('http://"+lang+ ".wikipedia.org/w/api.php?action=parse&page=$2&prop=text&format=json&callback=?',this,vwa.postprocess_tooltip_data);return false\" onmouseout=\"ajax_hideTooltip()\"";
    return html.replace(this.inlink_ns0_re, "$1"+"/"+lang+"/$2$3"+ additional_inlink_params +">$4$5");    /// after non-ns0 link normalization, do ns0 link normalization. Just remove '/wiki/' in link.
}
Vwa.prototype.process_fresh_article_html = function(html) {
    /// Sequence: jump://~/docs/tmp/snippets/20080609_155535
    /// Pre-processing
    this.article_html = this.do_initial_article_cleanup(html, this.show_inlink_tooltip_p) ;
    
    /// Illegal section removal and section info construction.
    var section_info_list = [ ];
    var L = this.article_html.split(this.split_sections_re);    /// [ upto_first_match, \1, \2, \3, from_end_of_previous_\3_to_next_match, \1, \2, \3, ..., from_end_of_previous_\3_to_eos ]    /// length= 4*n_matches + 1
    // alert(L.length);
    var intro_part = L.shift();
    intro_part = "<div id=\"vw_abstract_section\">" + intro_part + "</div>";
    section_info_list.push( [ this.abstract_section_title, 2,  intro_part ] ) ;
    for (var i = 0; i < (L.length/4); i++) {
        var j = i*4;
        var head = L[j], section_title = L[j+1], tail = L[j+2], section_content = L[j+3];
        if (string_contains(section_title, '<'))    /// !!TODO: this is rather a dangerous & non-unique criterion. employment different method.
            section_title = $(section_title).text();    /// strip away html to get plaintext
        // var head = L[j], section_title = $.text(L[j+1]), tail = L[j+2], section_content = L[j+3];
        // ignore all sections that are not so useful
        if (this.is_legal_section_title(section_title))
            section_info_list.push([ section_title , 
                                    Number(head.match( this.section_level_re )[1]) ,
                                    [head, section_title, tail, section_content].join( "" ) ]) ;    /// Prev: jump://~/docs/tmp/snippets/20080613_153901
    }

    /// Non-captioned image mining in INTRO (abstract) part because the first
    /// pic tend to be important even if it doesnt have caption. If any, Append
    /// on top.
    var K = intro_part.split(this.non_captioned_images_re);
    K.shift();
    for (var i = 0; i < (K.length/4); i++) {
        var j = i*4;
        var src = K[j], width = Number(K[j+1]), height = Number(K[j+2]);
        if (width >= this.captioned_image_min_width) {
            this.intro_first_imageinfo = ["", src, width, height];
            break;
        }
    }

/* 
    /// if the first image is in intro part, then avoid displaying the same image at first.
    if ( (this.captioned_images.length >= 1) && string_contains(intro_part, this.captioned_images[0][1]) ) {
        if (this.captioned_images.length > 1)
            this.captioned_images.push( this.captioned_images.shift() ) ;
        else    /// dont even show it if it the only one image contained in intro part.
            this.captioned_images = [ ];
    }
*/    
    return section_info_list;    /// article_sections
}

Vwa.prototype.get_imageinfo_list = function() {    /// Returns list of [caption, src, width, height] - this must be executed after article content is actually inserted.
    var imageinfo_list = [ ];     /// [ [caption1, src1, width1, height1], [caption2, src2, width2, height2], ...  ]
    var e = $( '.thumbinner:has(.thumbimage):has(.thumbcaption)' ) ;
    e.each(function() {
        var t = $(this);
        var img = t.find('.thumbimage')[0] ;
        var caption = t.find('.thumbcaption').text();
        caption = htmlspecialchars(strip(caption), true);
        imageinfo_list.push([caption, img.src, img.width, img.height]);    /// note that on stupid IE5.5+, both img.width and img.height  become 0.
    });

    /// Prepend, if not defined, the intro image.
    if (this.intro_first_imageinfo) {
        var intro_src = this.intro_first_imageinfo[1];
        if (!find_elem(function(e) { return e[1] == intro_src; }, imageinfo_list) )    /// if the intro image is not already inserted 
            imageinfo_list = [ this.intro_first_imageinfo ].concat( imageinfo_list );    /// prepend the intro image 
            // imageinfo_list = imageinfo_list.concat( [ this.intro_first_imageinfo ] );    /// !!append the intro image at the end instead of top
    }
    return imageinfo_list;
}

Vwa.prototype.thumburl2orig = function(thumburl) {
    /// http://upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Bkdraft.jpg/300px-Bkdraft.jpg
    /// del /thumb
    /// del [0-9]+px-
    /// → http://upload.wikimedia.org/wikipedia/commons/b/b3/Bkdraft.jpg/Bkdraft.jpg
    if (this.thumb_image_fname_re.test(thumburl)) {    /// If it is like '/300px-Bkdraft.jpg', but not on '/Bkdraft.jpg'
        var pt = rfind(thumburl, '/');
        if (pt > -1)    /// if this doesnt succeed, something is wrong.
            thumburl = thumburl.substring(0, pt);
    }
    // return thumburl.replace( '/thumb/', '/' ).replace(this.thumb_image_fname_re, "/$1") ;
    return thumburl.replace( '/thumb/', '/' );
}

Vwa.prototype.make_langlink_dict = function(L) {    /// L == data.parse.langlinks
    if (!L)  return null;
    var O = Object();
    for (var i=0; i < L.length; i++)
        O[ L[i]['lang'] ] = L[i][ '*' ];
    return O;
}


/// Remove the right component-border-top if it is an excess like this:
///  </home/tk/docs/public_html/image/capture/20080901230651.png>
Vwa.prototype.remove_right_bordertop = function() {
    var c = $('#rightColumn > div')[0];
    if (!c)
        return false;
    if (string_contains(c.className, "component-border-top"))
        $(c).removeClass("component-border-top");
}

// **. section

Vwa.prototype.do_post_cleanup = function(target_element_s, section_index) {    /// like: ('#some-div' , 0) or (null, null)
    var target_element_s = target_element_s ? target_element_s : '#'+this.article_div_id ;
    var section_index = (typeof(section_index) != 'undefined') ? section_index : this.section_index ;
    // var main_page_p = (this.main_page_titles_escaped.indexOf(this.article_title_escaped) > -1) ? true : false;
    var main_page_p = ($.inArray(this.article_title_escaped, this.main_page_titles_escaped) > -1) ? true : false;
    section_index = (main_page_p==true && (target_element_s != '#ajax_tooltip_content')) ? -1 : section_index;    /// if it is the main page, we dont want to remove stuff what we normally do when section_index==0
    
    if (main_page_p && (target_element_s != '#ajax_tooltip_content'))
        var tobe_removed = [
                        target_element_s+"  #mp-topbanner" ,
                        target_element_s+"  #mp-strapline" ,
                        target_element_s+"  #protected-icon" ,
                        target_element_s+"  .editsection", 
                        target_element_s+" .noprint" ,
                        target_element_s+"  #toc"    // Contents
                            ] ;
    else /// post-removal of div components
        var tobe_removed = [
                        target_element_s+"  #protected-icon" ,
                        target_element_s+"  .dablink" ,
                        target_element_s+"  #infoboxCountry",
                        target_element_s+"  .editsection", 
                        target_element_s+"  .toccolours",     //  </home/tk/docs/public_html/image/capture/20080607185909.png>
                        target_element_s+"  .ambox",  // </home/tk/docs/public_html/image/capture/20080607165235.png>
                        target_element_s+"  .navbox",  // </home/tk/docs/public_html/image/capture/20080607183911.png>
                        target_element_s+"  .sisterproject",
                        target_element_s+"  .metadata",
                        target_element_s+"  .Template-Fact",
                        target_element_s+"  #toc"    // Contents
                            ] ;
    $( tobe_removed.join( "," ) ).remove();
    
    if (this.show_inlink_tooltip_p)    /// dont show buitin tooltip
        $( target_element_s+" a" ).attr("title", "");

    /// Special treatment for the first section "Abstract" *in addition to* normal removal
    if (section_index == 0) {
        // if (target_element_s=='#ajax_tooltip_content')
            // alert('adcAfterTextSetFunction');
        var tobe_removed_in_abstract = [
                                        target_element_s+"  .infobox",      //  </home/tk/docs/public_html/image/capture/20080608133141.png>
                                        target_element_s+"  .vcard",
                                        target_element_s+" .noprint" ,
                                        target_element_s+" .tright" ,
                                        target_element_s+" .thumbinner" ,
                                        target_element_s+" .NavFrame" ,
                                        target_element_s+"  .sisterproject",
                                        target_element_s+" img" ,
                                        target_element_s+"  table"      //  </home/tk/docs/public_html/image/capture/20080608133141.png>
                                        ] ;
        // var first_image_match = ($('#'+this.article_div_id)[0].innerHTML).match(this.simple_image_re);
        $( tobe_removed_in_abstract.join( "," ) ).remove();
        // if ( first_image_match && (!this.simple_image_re.test($('#'+this.article_div_id)[0].innerHTML)) ) {
            // var html = "<div class=\"vw-abstract-first-image\">\n"+first_image_match[0]+"\n</div>";
            // $('#'+this.article_div_id).prepend( html );
        // }
    }
}

Vwa.prototype.set_current_by_tagid = function( section_tagid ) {
    var index = section_tagid.match(this.section_toc_id_re)[0];
    if (!index)
        return false;
    this.section_index = Number(index);
    var this_section = this.article_sections[this.section_index][2] ;
    this.set_section(this_section, this.section_index);
}

/// Prev: jump://~/docs/tmp/snippets/20080620_155301
Vwa.prototype.goto_next_section = function( ) {
    this.section_index = (this.section_index+1) % this.article_sections.length ;
    var this_section = this.article_sections[this.section_index][2];
    this.set_section(this_section, this.section_index);
}
Vwa.prototype.goto_prev_section = function( ) {
    this.section_index = (this.section_index - 1) < 0  ?  (this.article_sections.length - 1) : (this.section_index - 1) ;
    var this_section = this.article_sections[this.section_index][2];
    this.set_section(this_section, this.section_index);
}

Vwa.prototype.set_section = function(section_html, section_index, show_all_p) {
    if (this.insert_toc_p) {    /// unlink the current section title in toc.
        $( '#article_toc_component span[class*=vw-selected-section-title]' ).removeClass( 'vw-selected-section-title' );    /// '*=' means 'contains'
        $( '#article-section-id-'+section_index ).addClass( 'vw-selected-section-title' );
    }
    // var has_next = ( (section_index < (this.article_sections.length-1)) && true) || false ;
    $('#'+this.article_div_id).empty();
    $('#'+this.article_div_id).append(section_html);
    
    if (!show_all_p) {
        this.do_post_cleanup( );
    }
    else {
        if (this.show_inlink_tooltip_p)    /// dont show buitin tooltip
            $( '#'+this.article_div_id+" a" ).attr("title", "");
    }
    
    /// append nav buttons if not showing all
    if (!show_all_p) {
        var nav_part = this.render_sections_nav_buttons( ) ;
        if (section_index == 0)
            $( '#'+this.article_div_id).prepend('<div style="padding-top: 7px; padding-bottom: 1px;">' + nav_part + '</div>');
        else
            $( '#'+this.article_div_id + ' .mw-headline:first' ).prepend(nav_part);
    }
    
    /// toc navigation handling - disabled for now since right toc is disabled.
/*
    for (var i=section_index; i >= 0; i--) {
        var level = this.article_sections[i][1] ;
        var pn_buttonp = (this.article_sections.length >= this.section_fold_threshold && (i+1) < this.article_sections.length && level == 2) ? (level < this.article_sections[i+1][1]) : false ;
        if (pn_buttonp) {
            $( '#article_toc_component .n-box' ).each( function(i) { vwa.toggle_section_pn(this); } );    /// close all [-] first!
            this.toggle_section_pn($('#toc-pn-'+level+'-'+i)[0], true) ;    /// then open it (if closed)!
        }
        if (level == 2) 
            break ;
    }
*/

}

Vwa.prototype.article_show_all = function( ) {
    // this.set_section( '<div id="vw_entire_article">' + this.article_html + '</div>' , 0, true);
    var all_html_filtered  =  mapconcat(function(e) { return e[2]; } , this.article_sections, "\n\n") ;
    this.set_section( '<div id="vw_entire_article">' + all_html_filtered + '</div>' , 0, true);
    this.do_post_cleanup('#vw_entire_article', -1);
}

Vwa.prototype.toggle_section_title = function( e ) {    /// assumption: e.id='expander-anchor-20' or the like
    var target_elem = $(e).parent().next()[0];
    
    var top_div = $(e).parent().parent();
    /// CASE: Open
    if (top_div.hasClass('expander-open')) {
        top_div.removeClass('expander-open').addClass('expander-closed');
        $(target_elem).slideUp("slow");
    }
    else {      /// CASE: Folded
        top_div.removeClass('expander-closed').addClass('expander-open');
        $(target_elem).slideDown("slow");
    }
}

Vwa.prototype.article_show_all_folded = function( ) {    /// except first intro part
    var toggle_code = 'vwa.toggle_section_title(this)' ;
    // var L = [ "<div id=\"vw_entire_article\">\n" ];
    var cutoff_level = 3 ;
    var N = this.article_sections.length;
    var L = [ this.article_sections[0][2], "<div id=\"vw_entire_article\">\n" ];
    // for (var i=0; i < N; ++i) {
    for (var i=1; i < N; ++i) {
        var title = this.article_sections[i][0], level = this.article_sections[i][1], content = this.article_sections[i][2] ;
        if (level < cutoff_level) {
            // var s = ((i == 0) ? '' : '</div></div>' ) +
            var s = ((i == 1) ? '' : '</div></div>' ) +
            '<div id="expander-' + i + '" class="expander expander-closed">' +
            '<h2 class="expander-header"><a id="expander-anchor-' + i +
            '" class="expander-anchor" href="javascript:void(0)" onclick="'+ toggle_code + '" title="Open">' +
            title + '</a></h2>' +
            '<div id="expander-content-'+i+'" class="expander-content" style="display: none;">';
            L.push(s);
            L.push(this.format_folded_section_content( content )) ;
        }
        else {
            L.push(content);
        }
    }
    if (N > 1)
        L.push("\n</div></div>");    /// end of level 2 expander
    L.push("\n</div>");    /// end of vw_entire_article
    
    var all_html_filtered  =   L.join("\n");
    // this.set_section( all_html_filtered , 0, true);
    this.set_section( all_html_filtered , 0, true);
    this.do_post_cleanup('#vw_abstract_section', 0);    /// first "intro" part.
    this.do_post_cleanup('#vw_entire_article', -1);    /// rest
    $('.expander-content > h2').remove();    /// remove h2 titles (because they are already there!)
}

Vwa.prototype.format_folded_section_content = function( content ) {
    $('.expander-content > h2').remove();    /// remove h2 titles (because they are already there!)
    return content;
}


// **. slide

Vwa.prototype.set_captioned_image = function(captioned_image_index) {
    /// update "2 of 5"
    var status = '<strong>'+(captioned_image_index+1)+'</strong> / <strong>'+this.captioned_images.length+'</strong>' ;
    $('#slidebox-status').empty();
    $('#slidebox-status').append(status);
    
    var html = this.render_slide_content_sub(captioned_image_index);
    $('#slidebox-content').empty();
    $('#slidebox-content').append(html);
}
Vwa.prototype.goto_prev_slide = function( ) {
    var total = this.captioned_images.length;
    if (total <= 0)
        return false;
    this.captioned_image_index = ((this.captioned_image_index-1) < 0) ? (total-1) : (this.captioned_image_index-1) ;
    this.set_captioned_image(this.captioned_image_index);
}
Vwa.prototype.goto_next_slide = function( ) {
    var total = this.captioned_images.length;
    if (total <= 0) 
        return false;
    this.captioned_image_index = (this.captioned_image_index+1) % total;
    this.set_captioned_image(this.captioned_image_index);
}

// **. tooltip

Vwa.prototype.postprocess_tooltip_data = function( html ) {
    // var html = vwa.do_initial_article_cleanup(html, false, 'en');
    var html = vwa.do_initial_article_cleanup(html, false, vwa.lang);
    var intro_part = html.split(vwa.split_sections_re).shift();
    return intro_part;
}

var adcAfterTextSetFunction = function() {    /// used by /var/www/media/vw/tk-tooltip.js
    vwa.do_post_cleanup( '#ajax_tooltip_content', 0 );    /// get abstract only
}

// **. renderers

Vwa.prototype.render_sections_nav_buttons = function() { /// render prev/next buttons for article sections
    var total = this.article_sections.length ;
    if (total < 2)
        return '' 
    var n = this.section_index + 1;
    /// Prev: jump://~/docs/tmp/snippets/20080620_163527
    var html =  '<div id="article-sections-nav" style="display: inline; float: right; font-size: 10px; margin-left: 5px; color: #000; padding-bottom:1px;">\
    &#xA0;&#xA0;\
    <img width="21" height="15" border="0" src="/media/vw/prev_section.gif" style="cursor: pointer;" onmouseout="this.src=\'/media/vw/prev_section.gif\'" onmouseover="this.src=\'/media/vw/prev_section_on.gif\'" onclick="vwa.goto_prev_section()"/>\
    <img width="21" height="15" border="0" src="/media/vw/next_section.gif" style="cursor: pointer;" onmouseout="this.src=\'/media/vw/next_section.gif\'" onmouseover="this.src=\'/media/vw/next_section_on.gif\'" onclick="vwa.goto_next_section()"/>\
    &nbsp;<a href="javascript:void(0)" onclick="vwa.article_show_all()" style="font-size: 11px; text-decoration: none !important; font-weight: normal; border-bottom: 0px !important; color:#4a4aff;">['+ this.show_all_article_message +']</a>\
  </div>' ;
    return html;
}

/// Orig: jump://~/docs/tmp/snippets/20080620_195123
Vwa.prototype.render_article_toc_component = function( ) {
    // if (this.article_sections.length <= 1)    /// dont show if it's abstract-only article
        // return '' ;
    var L = [ "<div id=\"article_toc_component\"><ul>\n" ];
    // var prev_level = this.article_sections[0][1] ;
    var cutoff_level = 3 ;
    var N = this.article_sections.length;
    for (var i=0; i < N; i++) {
        var title = this.article_sections[i][0], level = this.article_sections[i][1] ;
        // var pn_buttonp = ((i+1) < N && level >= 2) ? (level < this.article_sections[i+1][1]) : false ;
        var pn_buttonp = (N >= this.section_fold_threshold && (i+1) < N && level == 2) ? (level < this.article_sections[i+1][1]) : false ;
        
        var s = '<li id="toc-li-' + i + '" class="article-section-level-' + level + ( ((N >= this.section_fold_threshold) && (level >= cutoff_level)) ? ' hidden' : '' ) + '">' +
        (pn_buttonp ?  ('<a href="javascript:void(0)" ' + 'id="toc-pn-' + level + '-' + i + '" class="p-box" onclick="vwa.toggle_section_pn(this)"></a>')  : '' ) +
        '<span '+ 'class="vw-toc-section-title" id="article-section-id-' + i + '" ' +
        // (pn_buttonp ? 'onclick="vwa.toggle_section_pn($(\'#toc-pn-'+level+'-'+i+'\')[0], true); vwa.set_current_by_tagid(this.id); false">' : 'onclick="vwa.set_current_by_tagid(this.id); false">' ) +
         'onclick="vwa.set_current_by_tagid(this.id)">'  +
        title.replace( this.simple_a_tag_re, "$1" ) + '</span></li>' ;
        
        L.push(s);
    }
    L.push("\n</ul></div>");
    return L.join("\n");
}

Vwa.prototype.toggle_section_pn = function(e, keep_open_p) {
    
    var n = 'toc-pn-'.length ;
    var level_secid_pair = map(function(a) { return Number(a) } , e.id.substring(n).split( '-' ) ) ;
    
    if (e.className == 'p-box' ) {
/*
        if (keep_closed_p)
            return false;

        /// close any [-] above the point
        for (var i=0; i < level_secid_pair[1]; i++) {
            var target = $('#toc-li-'+i) ;
            var target_level = Number(target[0].className.split( ' ' )[0].substring('article-section-level-'.length)) ;
            if (target_level > level_secid_pair[0] )
                target.addClass( 'hidden' );
            else
                break ;
        }
*/
        /// open this.
        for (var i=(1+level_secid_pair[1]); i < this.article_sections.length; i++) {
            var target = $('#toc-li-'+i) ;
            if (string_contains(target[0].className, 'hidden' ))
                target.removeClass( 'hidden' ) ;
            else
                break ;
        }
        e.className = 'n-box' ;
    }
    else if (e.className == 'n-box' ) {
        if (keep_open_p)
            return false;
        for (var i=(1+level_secid_pair[1]); i < this.article_sections.length; i++) {
            var target = $('#toc-li-'+i) ;
            // var target_level = Number(target[0].id.substring(n).split( '-' )[0]) ;
            var target_level = Number(target[0].className.split( ' ' )[0].substring('article-section-level-'.length)) ;
            if (target_level > level_secid_pair[0] )
                target.addClass( 'hidden' );
            else
                break ;
        }
        e.className = 'p-box' ;
    }
}

Vwa.prototype.render_slide_content_sub = function(captioned_image_index) {
    var this_captioned_image = this.captioned_images[captioned_image_index];
    var alt = this_captioned_image[0], src = this_captioned_image[1], width = this_captioned_image[2], height = this_captioned_image[3] ;
    var original_src = this.thumburl2orig(src) ;

    if (width == 0) {     /// this is for stupid IE5.5+
        return '\
  <a href="' + original_src + '" target="_blank">\
    <img style="width: expression(this.width > '+this.captioned_image_max_width+' ? '+this.captioned_image_max_width+': true); max-width: '+this.captioned_image_max_width+';" id="slidebox-image-'+captioned_image_index+'"  border="0" class="thumbimage" src="'+src+'" alt="'+alt+'" />\
  </a>\
    <div class="thumbcaption">\
      '+alt+'\
    </div>' ;
    }

    var r = width / this.captioned_image_max_width ;
    if (r > 1.0) {
        width = this.captioned_image_max_width ;
        height = Math.floor( height / r );
    }
    var html = '\
  <a href="' + original_src + '" target="_blank">\
    <img id="slidebox-image-'+captioned_image_index+'" width="'+width+'" height="'+height+'" border="0" class="thumbimage" src="'+src+'" alt="'+alt+'" />\
  </a>\
    <div class="thumbcaption">\
      '+alt+'\
    </div>' ;
    return html;
}

Vwa.prototype.render_slidebox_component = function() {    /// image slidebox - this must be executed AFTER article content is inserted (or appended)
    this.captioned_images = this.get_imageinfo_list();    /// !!set captioned_images only after article content is set.
    var total = this.captioned_images.length;
    if (total < 1)
        return ''
    var n = this.captioned_image_index+1 ;
    var slideboxController = (total == 1) ? ' ' : '<div id="slideboxController" style="text-align: center; margin-bottom: 5px;">\
    <span style="font-size:90%; color:#444;" id="slidebox-status"><strong>'+n+'</strong> / <strong>'+total+'</strong></span>&#xA0;\
    <img width="21" height="15" border="0" src="/media/vw/prev_slide.gif" style="cursor: pointer;" onmouseout="this.src=\'/media/vw/prev_slide.gif\'" onmouseover="this.src=\'/media/vw/prev_slide_on.gif\'" onclick="vwa.goto_prev_slide()"/>\
    <img width="21" height="15" border="0" src="/media/vw/next_slide.gif" style="cursor: pointer;" onmouseout="this.src=\'/media/vw/next_slide.gif\'" onmouseover="this.src=\'/media/vw/next_slide_on.gif\'" onclick="vwa.goto_next_slide()"/>\
  </div>' ;
    
    var component = '<div id="slidebox">\
  ' + slideboxController + '\
  <div id="slidebox-content" class="thumbinner">\
    '+ this.render_slide_content_sub(this.captioned_image_index) +'\
  </div>\
\
</div>    <!-- id="slidebox" -->';
    return component;
}

Vwa.prototype.render_in_english_component = function( ) {
    var page_title = vwa.langlinks.en;
    if (!page_title)
        return '' ;
    page_title = page_title.replace( ' ', '_');
    // var page_title_part = '<a style="color:#557bcb" href="/en/'+ escape(page_title)  +'" class="english-page-title">'+page_title.replace('_', ' ')+'</a>'    /// non-tooltip version.
    var page_title_part = '<a class="inlink" style="color:#153bbb" href="/en/'+ escape(toutf8(page_title))  +'" onmouseover="ajax_showTooltip(\'http://en.wikipedia.org/w/api.php?action=parse&page='+ escape(toutf8(page_title)) +'&prop=text&format=json&callback=?\',this,vwa.postprocess_tooltip_data);return false" onmouseout="ajax_hideTooltip()">'+page_title.replace('_', ' ')+'</a>'    /// tooltip version
    return '<div style="float: left; text-decoration: none; font-size: 100%; color: #b55; margin-bottom: 10px;">' + vwa.in_english_message.replace('$1', page_title_part) + '</div>';
}

Vwa.prototype.render_in_other_languages = function( langlinks ) {
    var L = [ ];
    for (var i=0; i <= Math.min(this.languages.length, this.in_other_languages_max_entries); ++i) {
        var lang = this.languages[i][0] ;
        var title = langlinks[lang];
        if (title) {
            var sharp_index = rfind(title, '#' );
            title = sharp_index > 0 ? title.substring(0, sharp_index) : title;
            L.push(
                   '<li>' + '<a style="color: #060;" href="/' + lang + '/' + escape(toutf8(title.replace(/ /g, '_'))) + '">' +
                   title  + '</a>' +  ' <span style="color: #777; font-size: 90%;">(' + this.languages[i][1] + ')</span>' + '</li>'
                   );
        }
    }
    if (L.length < 1)
        return false;
    return '<ul style="list-style: none; margin:0px; margin-left: 10px;">' + L.join( '\n' ) + '</ul>' ;
}


// *. Execution

var custom_vwa = custom_vwa || { };
var vwa = new Vwa(custom_vwa);    /// Main visual wikipedia article (vwa) object.
$(document).ready(function() {
    if (vwa.lang == 'ja')
        $( '#'+vwa.article_div_id ).css('font-size', '13.5px');

     /// Image url test  jump://~/docs/tmp/snippets/20080607_190203
    $.getJSON(  /// Examples: jump://~/docs/tmp/snippets/20080608_104116
              // "http://"+vwa.lang+".wikipedia.org/w/api.php?action=parse&page="+vwa.article_title_escaped+"&prop=text&format=json&callback=?",
              "http://"+vwa.lang+".wikipedia.org/w/api.php?action=parse&page="+vwa.article_title_escaped+"&prop=text|langlinks&format=json&callback=?",
              function(data) {
                  vwa.article_sections = vwa.process_fresh_article_html(data.parse.text[ "*" ]) ;
/*
                  /// insert TOC [RIGHT]
                  if (vwa.insert_toc_p && $('#article_toc_component').length == 0)
                      $( '#rightColumn' ).prepend( vwa.render_article_toc_component() );
*/
                  /// Insert corresponding titles in other languages. [RIGHT]
                  vwa.langlinks = vwa.make_langlink_dict(data.parse.langlinks);
                  var target = $('#in_other_languages_component');
                  if (target.length > 0  && vwa.langlinks) {
                      var langlinks_html = vwa.render_in_other_languages(vwa.langlinks);
                      if (langlinks_html) {
                          // target.empty();
                          target.append(langlinks_html);
                          target.removeClass( "hidden" ) ;
                      }
                  }

                  /// Insert English link for non-english main lang. [TOP]
                  if (vwa.lang != 'en') {
                      var in_english_component = vwa.render_in_english_component();
                      if (in_english_component) {
                          // $('#in_other_language_version').append(in_english_component);
                          // $('#articleTitle').prepend(in_english_component);
                          $('#title-in-english').prepend(in_english_component);
                      }
                  }

                  /// Remove component-border-top on the right if it is an excess. [RIGHT]
                  vwa.remove_right_bordertop();

                  /// Insert the entire content (folded) [LEFT]
                  vwa.article_show_all_folded();

                  /// Insert image slidebox [RIGHT]
                  if (vwa.insert_slidebox_p && $('#slidebox').length == 0)
                      $( '#rightColumn' ).prepend( vwa.render_slidebox_component() );

/*
                  /// insert the abstract [LEFT]
                  var this_section = vwa.article_sections[vwa.section_index][2];
                  vwa.set_section(this_section, vwa.section_index);
*/
              });
});
