// The cgi script
var cgiscript = "kanji.cgi";
//var debug = true;
var debug = false;

/* General purpose routines. */

/* Get parameters from a URL. For example, if the URL is
index.html?r=10, given "r" as "name" this returns "10". */

function gup (name)
{
    name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
    var regexS = "[\\?&]"+name+"=([^&#]*)";
    var regex = new RegExp( regexS );
    var results = regex.exec( window.location.href );
    if( results == null )
	return "";
    else
	return results[1];
}

/* Switch on the debugging flag if the URL contains "debug=" plus
anything. */

function check_debug ()
{
    if (gup ("debug")) {
        debug = true;
    }
}

/* Remove all the child elements from element "o". */

function clear (o)
{
    while (o.firstChild)
        o.removeChild(o.firstChild);
}

function getbyid (id)
{
    var element = document.getElementById (id);
    if (! element) {
	alert ("Could not find element with id "+id);
	exit;
    }
    return element;
}

function parse_json (json)
{
    var result;
    try {
        result = eval ('(' + json + ')');
    }
    catch (err) {
        if (debug)
            alert ("Parsing of " + json + " failed.");
    }
    return result;
}

function createXmlHttp ()
{
    xmlhttp = false;

    try {
	xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
	try {
	    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
	} catch (E) {
	    xmlhttp = false;
	}
    }
    if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
	xmlhttp = new XMLHttpRequest();
    }
    return xmlhttp;
}

/* Send "sendmessage" to the server asynchronously, and call
"callback" back when the server responds with success. */

function sendit (sendmessage, callback)
{
    if (debug) alert ("Sending `"+sendmessage+"'");
    if (! this.xmlhttp)
        this.xmlhttp = createXmlHttp ();
    if (! this.xmlhttp)
        return;
    // Abort partially loaded requests
    if (this.xmlhttp.readyState == 1 ||
	this.xmlhttp.readyState == 2 ||
        this.xmlhttp.readyState == 3) {
	this.xmlhttp.abort (); 
    }
    this.xmlhttp.open ("POST", cgiscript, true);
    var self = this;
    this.xmlhttp.onreadystatechange = function() {
	if (self.xmlhttp.readyState == 4) {
            if (self.xmlhttp.status == 200) {
	        if (debug)
                    alert("Calling back\n" + self.xmlhttp.responseText);
	        callback (self.xmlhttp.responseText);
            } else {
                if (debug) 
                    alert("Call to '" + cgiscript + "'failed " +
                          " with status "+self.xmlhttp.status);
            }
        }
    }
    this.xmlhttp.send (sendmessage);
}

// Create a node (an html element).

function create_node (type,parent)
{
    if (!type) {
	alert ("No type given to create_node");
	exit;
    }	
    if (!parent) {
	alert ("No parent given to create_node");
	exit;
    }	
    var new_node = document.createElement (type);
    if (!new_node) {
	alert ("Creation of node of type '"+type+"' failed.");
	exit;
    }
    parent.appendChild (new_node);
    return new_node;
}

function create_text_node (type,parent,text)
{
    var new_node = create_node (type,parent);
    var text_node = document.createTextNode (text);
    if (!text_node) {
	alert ("Creation of text node with text '"+text+"' failed.");
	exit;
    }
    new_node.appendChild(text_node);
    return new_node;
}

function append_text (parent,text)
{
    var text_node = document.createTextNode (text);
    if (!text_node) {
	alert ("Creation of text node with text '"+text+"' failed.");
	exit;
    }
    parent.appendChild(text_node);
}

/* Functions and variables related to the display of the table of
kanji, which is common to both the multiradical and the four corner
part. */

// Number of columns in the table of results
var results_table_columns = 10;
// Maximum number of kanji to display
var max_kanji=100;
// Where the list starts from.
var global_offset;
var global_kanji;
var global_n_kanji;

function godown()
{
    global_offset += max_kanji;
    show_kanji_offset ();
}

function goup()
{
    global_offset -= max_kanji;
    show_kanji_offset ();
}

function clear_found_kanji ()
{
    var found_kanji_element = getbyid ("found_kanji");
    clear (found_kanji_element);
    return found_kanji_element;
}

function clear_down_button ()
{
    var downbuttondiv = getbyid ("down_button");
    clear (downbuttondiv);
    return downbuttondiv;
}

function clear_up_button ()
{
    var upbuttondiv = getbyid ("up_button");
    clear (upbuttondiv);
    return upbuttondiv;
}

function clear_kanji_list()
{
    clear_found_kanji ();
    clear_down_button ();
    clear_up_button ();
}

function overflow_button (silly_remaining)
{
    var remaining =  global_n_kanji - max_kanji - global_offset;
    if (global_offset == 0 && remaining <= 0)
	return;
    var downbuttondiv = clear_down_button ();
    if (!silly_remaining && remaining > 0) {
	downbutton = create_text_node ("a", downbuttondiv,
                                       "▼"+remaining+" more");
	downbutton.onclick=godown;
    }
    var upbuttondiv = clear_up_button ();
    if (global_offset != 0) {
	upbutton = create_text_node ("a", upbuttondiv,
                                     "▲"+global_offset+" more");
	upbutton.onclick=goup;
    } else {
        if (!silly_remaining && remaining > 0) {
	    upbutton = create_text_node ("a", upbuttondiv, "▲ 0 more");
	    upbutton.className= "deadupbutton";
        }
    }
}

function get_cookie (cookie_string)
{
    if (!document.cookie)
        return;
    var c_start=document.cookie.indexOf (cookie_string);
    if (c_start == -1)
        return;
    c_start += cookie_string.length;
    var c_end = document.cookie.indexOf (";", c_start);
    if (c_end == -1)
        c_end = document.cookie.length;
    var cookie = document.cookie.substring (c_start, c_end);
    return cookie;
}

function set_cookie (value)
{
    var date_now = new Date();
    var one_year_later = new Date (date_now.getTime() + 31536000000);
    var expiry_date = one_year_later.toGMTString();
    document.cookie = value + ';expires=' + expiry_date + ';';
}

var link_cookie_string = "link=";

/* Set the user's link preference. */

function set_link_preference (link)
{
    if (debug)
        alert ("Linking to "+ link);
    set_cookie (link_cookie_string + link);
}

function get_link_preference ()
{
    return get_cookie (link_cookie_string);
}

var window_cookie_string = "newwindow=";

function set_window_preference ()
{
    var newwindow = getbyid ("nwc");
    var value;
    if (newwindow.checked) {
        value = 1;
    } else {
        value = 0;
    }
    if (debug)
        alert ("Setting new window to "+value);
    set_cookie (window_cookie_string + value);
}

function get_window_preference ()
{
    var nwindow = get_cookie (window_cookie_string);
    if (debug)
        alert ("Open a new window: "+nwindow);
    return nwindow;
}

function wwwjdic_href (kanji)
{
    var href = "http://www.csse.monash.edu.au/~jwb/cgi-bin/wwwjdic.cgi?1MMJ"
        + encodeURI (kanji);
    return href;
}

/* Given a kanji "kanji", make a link with the kanji as its text and a
link to WWWJDIC as its href, and attach the link to "parent". */

function create_link (parent, kanji)
{
    var link_preference = get_link_preference ();
    var href;
    // Switch to false to prevent any links being made.
    var make_link = true;
    if (link_preference) {
        switch (link_preference) {

        case "wwwjdic-aus":
            href = "http://www.csse.monash.edu.au/~jwb/cgi-bin/wwwjdic.cgi?1MMJ" + encodeURI (kanji);
            break;

        case "wwwjdic-can":
            href = "http://ryouko.imsb.nrc.ca/cgi-bin/wwwjdic?1MMJ" + encodeURI (kanji);
            break;

        case "wwwjdic-eur":
            href = "http://jp.msmobiles.com/cgi-bin/wwwjdic?1MMJ" + encodeURI (kanji);
            break;

        case "wwwjdic-jap":
            href = "http://www.aa.tufs.ac.jp/~jwb/cgi-bin/wwwjdic.cgi?1MMJ" + encodeURI (kanji);
            break;

        case "wwwjdic-swe":
            href = "http://wwwjdic.sys5.se/cgi-bin/wwwjdic.cgi?1MMJ" + encodeURI (kanji);
            break;

        case "wwwjdic-usa":
            href = "http://www.edrdg.org/cgi-bin/wwwjdic/wwwjdic?1MMJ" + encodeURI (kanji);
            break;

        case "jisho-org":
            href = "http://jisho.org/kanji/details/" + encodeURI (kanji);
            break;

        case "tangorin":
            href = "http://tangorin.com/kanji/" + encodeURI (kanji);
            break;

        case "no-link":
            make_link = false;
            break;
        default:
            href = wwwjdic_href (kanji);
            break;
        }
    } else {
        href = wwwjdic_href (kanji);
    }
    if (make_link) {
        var anchor = create_text_node ("a", parent, kanji);
        anchor.href = href;
        if (get_window_preference() == "1") {
            anchor.onclick = function () {
                window.open (this.href);
                return false;
            }
        }
    } else {
        append_text (parent, kanji);
        parent.className = "unlinked_kanji";
    }
}

var silly_amount = 20;

function show_kanji_offset ()
{
    clear_kanji_list ();
    var max = global_kanji.length;
    var remaining = 0;
    // "silly_remaining" is true if the number of characters truncated
    // by the scroll downwards is smaller than "silly_amount", so that
    // it would make more sense to display them rather than truncate.
    var silly_remaining = false;
    if (global_offset + max_kanji < max) {
	max = global_offset + max_kanji;
	remaining = global_kanji.length - max;
	if (remaining < silly_amount) {
	    max = global_kanji.length;
	    silly_remaining = true;
	}
    }
    var displayed_kanji = 0;

    var found_kanji = getbyid ("found_kanji");
    var table = create_node ("table", found_kanji);
    var tbody = create_node ("tbody", table);
    var tr;
    for (var k = global_offset; k < max; k++) {
        if ((k - global_offset) % results_table_columns == 0)
            tr = create_node ("tr", tbody);
        var td = create_node ("td", tr);
        if (global_kanji[k].match(/^\d+$/)) {
            append_text (td, global_kanji[k]);
	    td.className = "number";
        } else {
            create_link (td, global_kanji[k]);
            displayed_kanji++;
	}
    }
    if (k >= max_kanji + global_offset ||
        global_offset > 0) {
	overflow_button (silly_remaining);
    }
}

/* Generic function to show a list of kanjis with overflow. */

function show_kanji_list (n_kanji, kanji)
{
    global_offset  = 0;
    global_kanji   = kanji;
    global_n_kanji = n_kanji;
    show_kanji_offset ();
}

/* Multiradical functions and variables. */

/* Multiradical related variables. */

var n_radicals = 252;
var mr_buttons_selected = 0;
var mr_button_states = new Array ();
var mr_chosens = new Array();

/* Update the buttons of the multiradical selector using the
information got back from the server, "button_states". "button_states"
is a string of length of the number of radical buttons which contains
the letters "I" for "invalid" (the button cannot be pressed), "P" for
possible (the button can be pressed), or "C" for "chosen" (already
chosen) for each button. */

function mr_update_buttons(button_states)
{
    if (! button_states)
	return;
    if (debug) alert (button_states);
    for (i=0;i< n_radicals;i++) {
	var state = button_states.substring(i,i+1);
	var radical_button = getbyid("rad_"+(i+1));

        var className = radical_button.className;
        className = className.replace (/\s*(invalid|choice|chosen)/g, "");
	radical_button.className = className;
	if (state == "I") {
	    radical_button.className += ' invalid';
            mr_button_states[i+1] = -1;
        }
	else if (state == "P") {
            mr_button_states[i+1] = 0;
	    radical_button.className += ' choice';
        }
	else if (state == "C") {
            mr_button_states[i+1] = 1;
	    radical_button.className += ' chosen';
        }
    }
}

function mr_show_kanji_list (data)
{
    var kanji_match = parse_json (data);
    if (! kanji_match) {
	if (debug) alert("Empty return data");
	return;
    }
    var n_kanji = kanji_match.n_results;
    var kanji_list = kanji_match.results.match (/\d+|./g);
    mr_update_buttons(kanji_match.buttons);
    show_kanji_list (n_kanji, kanji_list);
}

/* Set all the buttons back to their initial state. */

function mr_reset_buttons ()
{
    for (var i = 1; i <= n_radicals; i++) {
	var radid = "rad_"+i;
        var className = getbyid(radid).className;
        className = className.replace(/invalid|chosen/g, "choice");
	getbyid(radid).className = className;
	mr_chosens[i]=0;
        mr_button_states[i] = 0;
    }
    mr_buttons_selected = 0;
    clear_kanji_list ();
}

/* Push one of the buttons. The callbacks are set up in
"mr_reset_buttons". */

function mr_push_button (radical_id)
{
    if (debug)
        alert ("You have pressed button with id "+radical_id);
    if (mr_button_states[radical_id] == -1) {
        /* Button is an unreachable radical, so do nothing. */
        return;
    }
    if (mr_chosens[radical_id] == 1) {
        /* Button is selected, so unselect it. */
        if (debug)
            alert ("turning off "+radical_id);
	mr_chosens[radical_id] = 0;
	mr_buttons_selected--;
    } else {
        /* Button is not selected, so select it. */
        if (debug)
            alert ("turning on "+radical_id);
	mr_chosens[radical_id] = 1;
	mr_buttons_selected++;
    }
    if (mr_buttons_selected)
	mr_get_kanji();
    else
	mr_reset_buttons();
}

/* Send the multiradical information. */

function mr_get_kanji() 
{
    var params = "M ";
    for (radical in mr_chosens)
	if (mr_chosens[radical] == 1)
	    params += radical + " ";
    if (debug)
        alert ("Sending `" + params + "' length: " + params.length);
    clear_found_kanji ();
    sendit (params, mr_show_kanji_list);
}

/* Put the radical selection buttons into their initial state. This is
called by the HTML file to set things up. */

function mr_start_buttons () 
{
    for (var i = 1; i <= n_radicals; i++) {
        var rad_i = getbyid ("rad_"+i);
        (function(i) {
            rad_i.onclick = function () {mr_push_button (i)};
        }(i));
        mr_button_states[i] = 0;
    }
    check_debug ();
}

/* Four-corner specific routines and variables. */

var fc_corner = new Array;
var fc_value = new Array;

/* Number of four-corner corners selected. */

var fc_selected = 0;

/* Given a number from 0 to 49, get the corresponding button as an
HTML element. */

function fc_button (number)
{
    var button_id = "fc" + Math.floor (number / 10) + "v" + (number % 10);
    button = getbyid (button_id);
    return button;
}

/* Four corner add results. */

function fc_addResult (fc_result_json)
{
    if (debug)
        alert ("result is " + fc_result_json);
    var fc_result = parse_json (fc_result_json);
    var buttons = fc_result.buttons;
    var button_states = buttons.split("");
    for (var i = 0; i < 50; i++) {
        var button = fc_button (i);
	if (button_states[i] == "I") {
	    button.className = "invalid";
	} else if (button_states[i] == "P") {
	    button.className = "choice";
	} else if (button_states[i] == "C") {
	    button.className = "chosen";
	}
    }
    var kanji_list = fc_result.results.match (/\d+|./g);

    show_kanji_list (fc_result.n_results, kanji_list);
}

/* Reset all the four corner buttons back to the initial state. */

function fc_reset()
{
    for (var i = 0; i < 50; i++) {
        var button = fc_button (i);
	button.className = "choice";
    }
    fc_selected = 0;
    clear_kanji_list ();
    while (fc_corner.pop());
    while (fc_value.pop());
}

/* Function called as buttons are pressed. */

function fc_choose(a,b) 
{
    var button_id="fc"+a+"v"+b;
    var button = getbyid (button_id);

    var classname = button.className;
    if (classname.match (/chosen/)) {
        /* Deselect the button. */
	for (x in fc_corner) {
	    if (fc_corner[x] == a) {
		fc_corner.splice(x,1);
		fc_value.splice(x,1);
		break;
	    }
	}
	fc_selected--;
    } else if (classname == "choice") {
        /* Select the button. */
	fc_corner.push(a);
	fc_value.push(b);
	fc_selected++;
    } else if (classname == "invalid")
        /* Ignore since the button is invalid. */
	return;
    if (fc_selected) {
        /* Send choices to the server. */
	var r="4 ";
	for (x in fc_corner ) {
	    r += fc_corner[x] + " " + fc_value[x] + "  ";
	}
	sendit (r, fc_addResult);
    } else {
        /* Clear everything up. */
	fc_reset();
    }
}

function fc_start_buttons ()
{
    check_debug ();
}

function change_language ()
{
    var lang_select = getbyid ("lang_select");
    var new_lang = lang_select.value;
//    alert ("change to "+new_lang);
    location.href = new_lang;
}

var obscurestate = 'visible';

function toggleobscure()
{
    var obscure = document.getElementById("obscure");
    if (obscurestate == 'visible')
	obscurestate = 'hidden';
    else if (obscurestate == 'hidden')
	obscurestate = 'visible';
    obscure.style.visibility = obscurestate;    
    var toggler = document.getElementById("toggleobscuretext");
    if (obscurestate == 'visible')
	toggler.innerHTML = trans_hide_obscure;
    else 
	toggler.innerHTML = trans_show_obscure;
}


/*
Local Variables:
mode: javascript
End:
*/