/*
 * HandyToc: Javascript table-of-contents
 *
 * Now uses JQuery, sort of.
 */

/* Init */
var HandyToc = new Object();

function TagDetail () {
    this.name = '';
    this.num = '';
    this.value = '';
    this.level = '';
}

HandyToc.setup = function(args) {
    this.toc_start_at = 1;
    this.levels = 6;
    this.ignoreh1 = true;
    this.ignore_first_h1 = true;
    this.ignore_only_one = true;
    this.look_in_id = '';
    this.set_args(args);
    this.make_a_toc();
}

HandyToc.set_args = function(args) {
    if (typeof args.start != "undefined") {
	this.toc_start_at = args.start;
    }
    if (typeof args.levels != "undefined") {
	this.levels = args.levels;
    }
    if (typeof args.ignoreh1 != "undefined") {
	this.ignoreh1 = args.ignoreh1;
    }
    if (typeof args.ignore_first_h1 != "undefined") {
	this.ignore_first_h1 = args.ignore_first_h1;
    }
    if (typeof args.ignore_only_one != "undefined") {
	this.ignore_only_one = args.ignore_only_one;
    }
    if (typeof args.look_in_id != "undefined") {
	this.look_in_id = args.look_in_id;
    }
}

HandyToc.make_a_toc = function() {

    var toc_container = $("#htoc");
    if (!toc_container) {
	// if there's no container for the ToC, then forget it.
	return;
    }
    var look_inside;
    if (this.look_in_id)
    {
	look_inside = $("#" + this.look_in_id);
    }
    if (!look_inside)
    {
	look_inside = $("body");
    }

    // If there's only one h1 tag and we want to ignore sole h1 tags,
    // or if there's no h1 tags, then start the ToC at level 2
    var h1_tags = $("h1", look_inside);
    var h1_count = h1_tags.length;
    if (this.toc_start_at == 1
	&& ((this.ignoreh1 && h1_count == 1)
	    || h1_count == 0 )
       )
    {
	this.toc_start_at = 2;
    }

    this.toc_tag_array = Array();

    //Build a list of the header tags
    var i=0;
    for(var h=this.toc_start_at; h<(this.toc_start_at + this.levels); h++){
	this.toc_tag_array[i] = 'H'+h;
	i++;
    }
    var toc_tag_list = this.toc_tag_array.join(',');

    // find the matching headers
    var header_tags = $(toc_tag_list, look_inside);

    // ignore the first H1?
    if (this.ignore_first_h1
	&& header_tags.length > 0
	&& header_tags[0].tagName == 'H1')
    {
	header_tags = header_tags.slice(1);
    }

    // are there enough tags left to make a TOC?
    if (header_tags.length == 0
	|| (this.ignore_only_one && header_tags.length == 1))
    {
	$(toc_container).addClass("hide");
    }
    else
    {
	this.tag_num = 0;
	this.tag_detail = new Array(1);
	this.get_header_details(header_tags);
	this.toc_build(toc_container);
    }

} //HandyToc.make_a_toc

HandyToc.get_header_details = function(tags) {

    // The list of tags will only include matching headers
    // go through the given list of tags
    for(var ti=0; ti < tags.length; ti++)
    {
	this.current_level = this.toc_tag_array.find_pos(tags[ti].tagName);

	// make or find a unique anchor for the section header
	var link_id = 'tocLink'+this.tag_num;
	if (!tags[ti].id)
	{
	    tags[ti].id = link_id;
	}
	else
	{
	    link_id = tags[ti].id;
	}

	// collect some details about the section that we can use to build the ToC with
	this.tag_detail[this.tag_num] = new TagDetail();
	this.tag_detail[this.tag_num].name = tags[ti].tagName;
	this.tag_detail[this.tag_num].link_id = link_id;
	this.tag_detail[this.tag_num].num = this.tag_num;
	this.tag_detail[this.tag_num].level = this.current_level;

	//this.tag_detail[this.tag_num].value = getInnerText(tags[ti],1);
	this.tag_detail[this.tag_num].value = $(tags[ti]).text();

	this.tag_num++; // used to keep track of how many headers we have found. 
    }
} //HandyToc.get_header_details

HandyToc.toc_build = function (toc){

    var lastLevelNum = -1;
    var currentLevelNum = 0;
    var currentParent = toc;
    var lastObject = currentParent;
    var this_detail;

    for(var i = 0; i < this.tag_detail.length; i++) {
	this_detail = this.tag_detail[i];

	currentLevelNum = this_detail.level;

	// created a nested unordered list..
	if(currentLevelNum > lastLevelNum){
	    var levelDiff = currentLevelNum - lastLevelNum;
	    for(ldi=0;ldi<levelDiff;ldi++){
		if (ldi > 0)
		{
		    var liNode = document.createElement("li");
		    currentParent.appendChild(liNode);
		    currentParent = liNode;
		    liNode.className = "HTOCspacer";
		    lastObject = liNode;
		}
		var ulNode = document.createElement("ul");
		if (currentParent.lastChild
		    && currentParent.lastChild.nodeName == 'LI')
		{
		    currentParent.lastChild.appendChild(ulNode);
		}
		else
		{
		    $(currentParent).append(ulNode);
		}
		currentParent = ulNode;
	    }
	}
	//move back up the DOM to the right level
	if(currentLevelNum < lastLevelNum){
	    var levelDiff = lastLevelNum - currentLevelNum;
	    for(ldi=0;ldi<levelDiff;ldi++){
		currentParent = currentParent.parentNode;
		if (currentParent.nodeName == 'LI')
		{
		    currentParent = currentParent.parentNode;
		}
	    }
	}

	//add the new ToC entry
	var liNode = this.toc_build_entry(this_detail);
	currentParent.appendChild(liNode);

	//keep track of where we are
	lastLevelNum = currentLevelNum;
	lastObject = liNode;
    }

} // HandyToc.toc_build


HandyToc.toc_build_entry = function (details){

    var liNode = document.createElement("li");
    var a_node = document.createElement("a");
    var tNode = document.createTextNode(details.value);

    // className is the same as the tag, ie: H1, H2, etc.
    liNode.className = details.name;
    a_node.className = details.name;

    //embed a link in the LI so we can jump to the correct section
    a_node.href = '#'+details.link_id;
    a_node.appendChild(tNode);
    liNode.appendChild(a_node);

    return liNode;

} //HandyToc.toc_build_entry

/************************
 HELPER FUNCTIONS
*************************/

if(Array.prototype.find_pos){
    Array.prototype.find_pos= null;
}
if(!Array.prototype.find_pos) {
    function ArrayFind(value){
	var index = -1;
	for(var i=0; i<this.length;i++){
	    if(this[i] == value){
		index = i;
		break;
	    }
	}
	return index;
    }
    Array.prototype.find_pos = ArrayFind;
} 

