/*

Here, I'm trying to build a set of utilities for The MoFaT on
zetaboards

*/

// Create the namespace
var com;
if (!com) com = {};
if (!com.TheMoFaT) com.TheMoFaT = {};


com.TheMoFaT.hasher = {};
(function( ns ) {
    var alertYou = 0;
    var tdc = undefined;
    var last_hasher = undefined;
    
    function hashOf( txt ) {
	var txtlen = txt.length;
	var txti;
	var ret = 0;
	for( txti=0 ; txti < txt.length ; txti++ ) {
	    if ( txt.charCodeAt(txti) >= 48 ) {
		ret = ( ret + (txt.charCodeAt(txti) - 48) ) % 100;
	    }
	}
	return ret + 1;
    }
    
    function traverse( item ) {
	if ( item.tagName != "TD" ) { return; }
	if ( item.className == tdc ) {
	    last_hasher = " hasher" + hashOf(item.innerHTML);
	    item.className = item.className + last_hasher;
	    return;
	}
	if (
	    (item.className == "c_sig" || item.className == "c_nosig") &&
	    last_hasher
	) {
	    item.className = item.className + last_hasher;
	}
    }
    
    function init( my_tdc ) {
	alertYou = 0;
	tdc = my_tdc;
    }

    // Public methods of hasher
    ns.traverse = traverse;
    ns.init = init;
    
    return ns;
})(com.TheMoFaT.hasher);

// shuffle is a class that boosts some particular table cells into
// div's and adds them to a particular other cell.
// This is done by the traverse function.
// The table cells that get boosted are those that show the main index page's
// board totals for viewers, Topics, and Replies.
// Before boosting, we also put the original contents of the parent cell
// into a new DIV, within that cell.
// Cells to boost are identified by their CSS className
com.TheMoFaT.shuffle = {};
(function( ns ) {

    // divify()
    // Move all child elements of a given parent into a new DIV.
    // The new DIV has the same CSS class as the original parent.
    // Returns the new DIV
    function divify( todiv ){
	var div = document.createElement("div");
	div.className = todiv.className;
	while( todiv.hasChildNodes() ) {
	    div.appendChild( todiv.firstChild );
	}
	return div;
    } // divify()

    var tdgrandparent_class;
    var tdparent_class;
    var tdchild_class;
    var grandParentElem = null;
    var parentElem = null;
    var parentChild1 = null;
//    var childs = 0;

    var diag_rowid = "";
    
    // traverse()
    // Intended to be called by the com.TheMoFaT.enhance traverse loop.
    // Three kinds of elements are being identified:
    // child: one of the TDs to be shuffled (viewers, Topics, Replies)
    // parent: new destination of child, which was originally the TD holding
    // the last topic
    // grandparent: the TD that will be holding the last topic, which will be
    // shuffled from the parent
    function traverse( item ) {
if ( item.tagName == "TR" && item.id != '' ) { diag_rowid = item.id; }
    	if ( item.tagName != "TD" ) { return; }
	
	if ( item.className.indexOf(tdgrandparent_class) >= 0 ) {
	    // Found a grandparent element
	    grandParentElem = item;

	    // Put all the initial contents of the grandparent
	    // into a new DIV within the grandparent
	    grandParentElem.appendChild( divify(item) );
//	    childs = 0;
	    return;
	}
	if ( grandParentElem && item.className.indexOf(tdparent_class) >= 0 ) {
	    // Found a parent element
	    parentElem = item;

	    // Put all the initial contents of the parent
	    // into a new DIV within the parent
	    parentElem.appendChild( parentChild1 = divify(item) );
	    
	    // At this point, it may seem that we could shuffle the parent's 
	    // contents into the grandparent. Unfortunately, that seems to
	    // mess with the traversal order. Save it for later
	    return;
	}
	if ( parentElem && item.className.indexOf(tdchild_class) >= 0 ) {
	    // Shuffle the item to its destination
	    parentElem.appendChild( divify(item) );

	    var itpar = item.parentNode;
	    itpar.removeChild(item);
	    itpar.normalize();
	    // Now check if we've removed all child elements from itpar.
	    // When we have, move the parent's original contents to the
	    // grandparent.
	    //
	    // Problem: having moved all the child elements, itpar is empty.
	    // itpar appears as a black oblong, unless we do something
	    
//	    childs++;

// if ( diag_rowid =="trash" || childs >=3 ) {
// alert( "In clause after nize. Childs:" + childs + " diag_rowid '" + diag_rowid + "' <" + itpar.tagName + "> " + itpar.childNodes.length );
// }

	    if ( itpar.childNodes.length === 1 ) {
		grandParentElem.appendChild( parentChild1 );

		var newtd = document.createElement("td");
		newtd.className = itpar.className;
		itpar.appendChild(newtd);
	    }
	    return;
	}
    }

    
    function init(
	my_tdgrandparent_class, my_tdparent_class, my_tdchild_class
    ) {
	tdgrandparent_class = my_tdgrandparent_class;
    	tdparent_class = my_tdparent_class ;
	tdchild_class = my_tdchild_class;
    }
    
    // Public methods of shuffle
    ns.init = init;
    ns.traverse = traverse;
    
    return ns;
})(com.TheMoFaT.shuffle);

// rollover is a class that enhances elements with a rollover change
// This works by allowing there to be a paired element that represents the
// element when rolled over
com.TheMoFaT.rollover = {};
(function( ns ) {

    function swapper( el1, el2 ) {
	return function() {
	    var swapclass = el1.className;
	    el1.setAttribute( "class", el2.className );
	    el2.setAttribute( "class", swapclass );
	    return true;
	}
    }

    var orro_class;
    var ro_class;
    var orroElem = null;
    // traverse gets called on every document element, by
    // the com.TheMoFaT.enhance*.traverse, itself called by 
    // the com.TheMoFaT.enhance initialiser
    function traverse( item ) {
	if ( item.className.indexOf(orro_class) >= 0 ) {
	    orroElem = item;
	}
	else if ( item.className.indexOf(ro_class) >= 0 ) {
	    if ( orroElem ) {
		com.TheMoFaT.enhance.setMouseOver(
		    orroElem, swapper( item, orroElem )
		);
		com.TheMoFaT.enhance.setMouseOut(
		    item, swapper( item, orroElem )
		);
		com.TheMoFaT.enhance.setMouseOver(
		    item, swapper( item, orroElem )
		);
		com.TheMoFaT.enhance.setMouseOut(
		    orroElem, swapper( item, orroElem )
		);
		orroElem = null;
	    }
	}
    }

    
    function init( my_orro_class, my_ro_class ) {
	orro_class = my_orro_class;
	ro_class = my_ro_class;
    }
    
    // Public methods of rollover
    ns.init = init;
    ns.traverse = traverse;
    
    return ns;
})(com.TheMoFaT.rollover);

// analysedURL is a utility class that parses a URL into paths and paramaters
com.TheMoFaT.analysedURL = {};
(function( ns ) {

    // c(URL, optional return object) constructor function
    // Returns an object with the following properties:
    // oURL is the original URL
    // URLpaths is an array of pieces that were between /s in the oURL
    // URLparams is an associative array of ? and & parameters that were in oURL
    // if the return object is specified, the properties are added to it
    // Otherwise a new object is created
    function c(aURL, ret) {
	var URLpaths = [];
	var URLparams = {};
	var oURL = undefined;

	oURL = aURL || "";

	// Divide the whole URL into path components
	URLpaths = oURL.split( '/' );

	// Pop any empty paths off the end
	// Note that http:// contains an empty path, but it's best
	// to leave this in place
	var last_path = URLpaths.length;
	while( URLpaths[--last_path] == "" ) URLpaths.pop();

	// If the last path is arguments, split the arguments into an array...
	var URLpathargs = [];
	var args_start = URLpaths[ last_path ].indexOf('?');
	if ( args_start > -1 ) {
		URLpathargs =
		    URLpaths[ last_path ].substring(args_start + 1).split('&')
		;
	}

	// ... and load the parameters into an "associative array" object
	for( var i=0; i < URLpathargs.length; i++ ) {
	    var pstart = URLpathargs[i].indexOf('=');
	    if ( pstart < 0 ) continue;
	    URLparams[ URLpathargs[i].substring( 0, pstart ) ] =
		URLpathargs[i].substring( pstart + 1 )
	    ;
	}

	if (!ret) ret = {};
	ret.URLpaths = URLpaths;
	ret.URLparams = URLparams;
	ret.oURL = oURL;
	return ret;
    } // c()

    // Public methods
    ns.c = c;

})(com.TheMoFaT.analysedURL);

// gkKeys is a class that enhances the quick reply text edit
// The enhancement is that the user can type Ctrl-B to get bold on or off, and
// similarly for underscore, italic, and strike-out
com.TheMoFaT.gkKeys = {};
(function( ns ) {

    // common sub-class holds the map and event handlers that actually do the work
    common = {};
    (function(ns) {
        var monitor = undefined;
        var cmdmap = null;

        function keyDown(a) {
            if (monitor) monitor.print(
                (a.ctrl ? "Ctrl-" : "") + "" + 
                a.code + "(" + a.selStart + "," + a.selEnd + ',"' +
                a.val.substring(a.selStart,a.selEnd) + '")' +
                a.val
            );
            var cmdind = 1*(a.code); // Multiply by 1 forces this to be a number
    
            // If the ctrl key was not being held down, OR
            // if we don't do anything with the key being pressed,
            // Do nothing
            if ( (!a.ctrl) || (!cmdmap[cmdind]) ) return null;
            
            // Otherwise, what we do depends on whether there is a current selection
            if ( a.selStart === a.selEnd) {
                // No selection so we insert either an on or off code
                // To find out if an on or off is required, look for a sequence of
                // on and off codes in the text so far
                var inson = 0; // We'll start by looking for an "on" code
                var schstr = new String( a.val.substring(0,a.selStart) );
                var schind = 0;
                var nschind = schind;
                while(
                    (nschind = schstr.indexOf(
                        cmdmap[cmdind].onoff[inson], schind
                    )) > -1
                ) {
                    schind = nschind;
                    inson = (inson + 1) % 2; // Toggle between 1 and 0
                }
                var part1 = schstr + cmdmap[cmdind].onoff[inson];
                return {
                    value: part1 + a.val.substring(a.selEnd),
                    sel: {
                        start: part1.length,
                        end: part1.length
                    }
                };
            }
            else {
                // Have a selection, so we wrap it in on/off codes, unless
                // it is already wrapped. In that case we strip them
                var part1 = a.val.substring(0,a.selStart);
                var part2 = new String( a.val.substring(a.selStart,a.selEnd) );
                var oncmd = new String( cmdmap[cmdind].onoff[0] );
                var offcmd = new String( cmdmap[cmdind].onoff[1] );
                if (monitor) monitor.print(
                    "part2 '" + part2 + "' " +
                    "indexofon: " + part2.indexOf( oncmd ) +
                    "suffix '" + part2.substr( part2.length - offcmd.length ) + "'" +
                    "indexofoff: " + part2.indexOf( offcmd, part2.length - offcmd.length )
                );
    
                if (
                    part2.length > oncmd.length + offcmd.length &&
                    part2.indexOf( oncmd ) === 0 &&
                    part2.indexOf( offcmd, part2.length - offcmd.length ) ===
                        (part2.length - offcmd.length)
                ) {
                    part2 = part2.substring(
                        oncmd.length, part2.length - offcmd.length
                    );
                }
                else {
		    // Here is where we would process embedded URLs in
		    // FLASH tags
		    if ( cmdmap[cmdind].func ) {
			part2  = cmdmap[cmdind].func( part2 );
		    }
                    part2 = oncmd + part2 + offcmd;
                }
                return {
                    value: part1 + part2 + a.val.substring(a.selEnd),
                    sel: {
                        start: part1.length,
                        end: part1.length + part2.length
                    }
                };
            }
        }    
    
        function onkeydown(o, e) {
            // Tricks for browser-compatibility
            var a = {};
            if (window.event) {
                a.code = e.keyCode;
            }
            else {
                a.code = e.which;
            }

	    // No actual key pressed, just a shift key
	    if ( a.code < 32 ) return true;

            a.val = new String (o.value);
            a.ctrl = e.ctrlKey;

	    if ( o.selectionStart == undefined ) {
	        // IE crap here
		var or = document.selection.createRange();
		var dr = or.duplicate();
		dr.moveToElementText(o);
		dr.setEndPoint( 'EndToEnd', or );
		a.selStart = dr.text.length - or.text.length;
		a.selEnd = a.selStart + or.text.length;
/*
		    alert( "document.selection\n" +
		    "or \"" + or.text + "\", " +
		    "type \"" + document.selection.type + "\", " +
		    "dr \"" + dr.text + "\"\n" +
		    "a.selStart \"" + a.selStart + "\"\n" +
		    "a.selEnd \"" + a.selEnd + "\""
		    );
*/
	    }
	    else {
		a.selStart = o.selectionStart;
		a.selEnd = o.selectionEnd;
	    }

            var prcval = keyDown(a);
            // If we did nothing with it, propagate the event out to the browser
            if (!prcval) return true;
    
            // Otherwise do whatever and ...
            if (prcval.value) o.value = prcval.value;
            if (prcval.sel) {
		if ( o.selectionStart == undefined ) {
	        // IE crap here
		    var nr = document.selection.createRange();
		    nr.moveToElementText(o);
		    nr.moveStart( "character", prcval.sel.start );
		    nr.moveEnd( "character",
			prcval.sel.end - prcval.value.length
		    );
		    nr.select();
		}
		else {
		    o.selectionStart = prcval.sel.start;
		    o.selectionEnd = prcval.sel.end;
		}
            }
    
            // ... do not propagate the event out to the browser
            return false;
        }
    
	// addSimpMap(c) adds a simple command map,
	// where the tag is the same as the key
        function addSimpMap(c) {
            cmdmap[ c.charCodeAt(0) ] = {
                onoff: [ "[" + c + "]", "[/" + c + "]" ],
		func: null
            };
        }

	// addMap(key, cmd, func) adds a command map,
	// where the command is not the same as the key pressed
	// The "off" tag is the "on" tag with a slash prefix
	// func is an optional function that will be run on the text to which
	// the cmd tags are being applied.
        function addMap(key, cmd, func) {
            cmdmap[ key.charCodeAt(0) ] = {
                onoff: [ "[" + cmd + "]", "[/" + cmd + "]" ],
		func: func
            };
        }

	// processFlash(URL)
	// Helper for munging URL's to which FLASH tags are being applied
	function processFlash(URL) {
	    var taggedURL = com.TheMoFaT.analysedURL.c( URL );
	    var chkind = 0;
	    if ( taggedURL.URLpaths[chkind] == "http:" ) chkind++;
	    while( taggedURL.URLpaths[chkind] == '' ) chkind++;
	    var domain = taggedURL.URLpaths[chkind++];
	    if (  domain == "youtu.be" ) {
		return "http://www.youtube.com/watch?v=" + taggedURL.URLpaths[chkind];
	    }
	    return URL;
	}

        function init(monobj) {
            monitor = monobj;
            
            cmdmap = new Array();
	        // Add simple maps for emphasis tags
            addSimpMap( "b"); addSimpMap( "B"); // Bold
            addSimpMap( "i"); addSimpMap( "I"); // Italic
            addSimpMap( "u"); addSimpMap( "U"); // Underscore
            addSimpMap( "s"); addSimpMap( "S"); // Strikethrough
	    
	        // Add maps for other tags
    	    //
    	    // Reedus, here is where you can add more maps, should you wish
    	    // Sorry lover, you have to have an addMap for upper and lower case
    	    //
    	    // [FLASH] For youtube video etc.
    	    addMap( "f", "flash", processFlash );
	    addMap( "F", "FLASH", processFlash );
    	    addMap( "l", "flash", null ); addMap( "L", "FLASH", null );
    	    //
    	    // [IMG] For images
    	    addMap( "g", "img", null ); addMap( "G", "IMG", null );
    	    //
    	    // [SPOILER] For spoiler
    	    addMap( "p", "spoiler", null ); addMap( "P", "SPOILER", null );
    	    addMap( "e", "spoiler", null ); addMap( "E", "SPOILER", null );
        }

        // Public functions of the common sub-class
        ns.onkeydown = onkeydown;
        ns.init = init;

        return ns;
    })(common);

    // c() constructor function
    // Creates a toggle control next to the textarea to be enhanced
    // Clicking the toggle enables and disables the enhanced key-handling
    function c(textarea_name, on_text, off_text, toggler_class, initial) {
        var attEv;
	var ret = {};
        ret.textarea = document.getElementsByName(textarea_name)[0];
        ret.state = !initial; // Negated since we will emulate a toggle later
        
        function toggleClick() {
            ret.state = !ret.state;
            ret.toggle_text.nodeValue = (ret.state ? on_text : off_text);
	    return false;
        }

        ret.toggler = document.createElement("button");
        ret.toggle_text = document.createTextNode( "" );
        ret.toggler.appendChild( ret.toggle_text );
	com.TheMoFaT.enhance.setClick( ret.toggler, toggleClick );
        toggleClick();
	if (toggler_class) ret.toggler.setAttribute( "class", toggler_class );
//        ret.textarea.parentNode.insertBefore( ret.toggler, ret.textarea );
        ret.textarea.parentNode.appendChild( ret.toggler );

        function textareaKeyDown(event) {
            // ret.textarea.value = ret.textarea.value + " tkp(" + ret.state + ")";
            if (ret.state) return common.onkeydown(ret.textarea, event);
            return true;
        }
	com.TheMoFaT.enhance.setKeyDown( ret.textarea, textareaKeyDown );
        
        return ret;
    } // c()

    function init(monobj) {
        common.init(monobj);
    }
    
    // Public methods of gkKeys
    ns.init = init;
    ns.c = c;

    return ns;
})(com.TheMoFaT.gkKeys);

// enhanceWarn is a class to enhance the zetaboards warning page
com.TheMoFaT.enhanceWarn = {};
(function( ns ) {

    function init(docURL) {
	// Only thing to do here is:
	// Generate a [url] back to the original post, and
	// Append that to the warning message text
	// I use the 'single' page for the destination of the [url]
	// Example: http://s4.zetaboards.com/GamingKlutz/single/?p=8085671&t=7944098
	// But how to generate the URL of the single page? Now read on...

	// Before doing anything else,
	// Check we can find the warning reason text area (wrta)
	// Later, we'll append to its value
	// If we can't find it, we won't do anything
	// It has id=txt_warnreason
	var wrta = document.getElementById("txt_warnreason");
	if (!wrta) return;

	// First load the referrer into an analysed URL object
	var refURL = com.TheMoFaT.analysedURL.c( document.referrer );
	var warnURL = null;

	// Note.
	// We only want to use the referrer if it seems to be in this site
	// So all the below check the 3rd part of the path

	// Simplest is if the warning was clicked on a "single" page
	// In that case, the referring URL is all we need
	if (
		refURL.URLpaths[4] == "single" &&
		refURL.URLpaths[3] == docURL.URLpaths[3]
	) {
		warnURL = refURL.oURL;
	}
	    
	// But if the warning was clicked on a "topic" page...
	// We need the topic ID, from the referrer URL, and
	// The post ID, which is in the URL parameters
	if (
		refURL.URLpaths[4] == "topic" &&
		refURL.URLpaths[3] == docURL.URLpaths[3]
	) {
	    // Example: http://s4.zetaboards.com/GamingKlutz/single/?p=8085671&t=7944098
	    warnURL =
		docURL.URLpaths.slice(0,4).join('/') + '/' +
		'single/?p=' + docURL.URLparams['pid'] +
		'&t=' + refURL.URLpaths[5]
	    ;
	}

	if ( warnURL ) {
	    // alert( 'gktools found wrta "' + wrta.value + '"' );
	    wrta.value = wrta.value +
		"[url=" + warnURL + "]Link to post[/url]\n"
	    ;
	}
    } // init()

    ns.init = init;
})(com.TheMoFaT.enhanceWarn);

// enhanceTopic is a class to enhance the zetaboards topic pages
com.TheMoFaT.enhanceTopic = {};
(function( ns ) {
    var postToggle = undefined;

    function traverse( item ) {
	com.TheMoFaT.rollover.traverse( item );
    }

    function traverse_hash( item ) {
	com.TheMoFaT.rollover.traverse( item );
	com.TheMoFaT.hasher.traverse( item );
    }

    function init( toggler_class ) {
    	// Only thing to do here is:
	// Enhance the fast reply text entry with Ctrl key recognition
	// The feature can be toggled on and off
	com.TheMoFaT.gkKeys.init();
	com.TheMoFaT.hasher.init("c_post");
	postToggle = com.TheMoFaT.gkKeys.c(
	    "post", "Ctrl on", "Ctrl off", toggler_class, true
	);
	com.TheMoFaT.rollover.init( "_orro", "_ro" );
	var d = new Date();
	if ( (
	    d.getMonth() == 3 && d.getDate() <= 3
	) ||
	    com.TheMoFaT.enhance.getTesting()
	) {
	    return traverse_hash;
	}
	else {
	    return traverse;
	}
    } // init()

    ns.init = init;
})(com.TheMoFaT.enhanceTopic);

// enhanceIndex is a class to enhance the zetaboards index page
com.TheMoFaT.enhanceIndex = {};
(function( ns ) {

    function traverse( item ) {
	com.TheMoFaT.rollover.traverse( item );
    }

    function traverse_shuffle( item ) {
	com.TheMoFaT.rollover.traverse( item );
	com.TheMoFaT.shuffle.traverse( item );
    }

    function init() {
	com.TheMoFaT.rollover.init( "_orro", "_ro" );
	com.TheMoFaT.shuffle.init( "c_forum", "c_last", "c_info-" );
	if ( com.TheMoFaT.enhance.getTheme() != "MoFaT" ) {
	    return traverse_shuffle;
	}
	else {
	    return traverse;
	}
    } // init()

    ns.init = init;
})(com.TheMoFaT.enhanceIndex);

// enhanceMsg is a class to enhance the zetaboards message page
com.TheMoFaT.enhanceMsg = {};
(function( ns ) {

    function traverse( item ) {
	com.TheMoFaT.rollover.traverse( item );
    }

    function init() {
	com.TheMoFaT.rollover.init( "_orro", "_ro" );
	return traverse;
    } // init()

    ns.init = init;
})(com.TheMoFaT.enhanceMsg);

// enhanceForum is a class to enhance the zetaboards forum page
com.TheMoFaT.enhanceForum = {};
(function( ns ) {

    function traverse( item ) {
	com.TheMoFaT.rollover.traverse( item );
    }

    function init() {
	com.TheMoFaT.rollover.init( "_orro", "_ro" );
	return traverse;
    } // init()

    ns.init = init;
})(com.TheMoFaT.enhanceForum);

// enhance is the class that identifies the type of page, and then
// invokes the appropriate enhancements for the page
// The enhancements are in separate classes so that there is an opportunity
// for optimisation by hiving them off into separate script files that are only
// loaded on the pages that require them
com.TheMoFaT.enhance = {};
(function( ns ) {
    var version; // Set at the end of the file
    
    var theme = '';
    function getTheme() {return theme;}
    
    var testing;
    function getTesting() { return testing;}
    
    // Stupid browser compatibility crap starts here
    var browserHasAtt = false;
    function setMouseOver( element, handler ) {
        if (browserHasAtt) {
	    element.attachEvent( "onmouseover", handler);
	}
	else {
	    element.onmouseover = handler;
	}
    } // setMouseOver()
    function setMouseOut( element, handler ) {
        if (browserHasAtt) {
	    element.attachEvent( "onmouseout", handler);
	}
	else {
	    element.onmouseout = handler;
	}
    } // setMouseOut()
    function setKeyDown( element, handler ) {
        if (browserHasAtt) {
	    element.attachEvent( "onkeydown", handler);
	}
	else {
	    element.onkeydown = handler;
	}
    } // setKeyDown()
    function setClick( element, handler ) {
        if (browserHasAtt) {
	    element.attachEvent( "onclick", handler);
	}
	else {
	    element.onclick = handler;
	}
    } // setClick()
    // End of stupid browser compatibility crap

    function init() {
	// Find a place to show this script's version number
	var versHolder = document.getElementById("foot_themechooser");
	var docURL = com.TheMoFaT.analysedURL.c( document.URL );
	if ( !versHolder ) versHolder = document.body;
	// Sneak in the browser compatibility detection crap
	if ( versHolder.attachEvent ) browserHasAtt = true;
	var span = document.createElement("span");
	span.appendChild( document.createTextNode(version) );
	versHolder.appendChild( span );

	// Get the theme from the "setskin" control
	var setskin = document.getElementsByName("setskin")[0];
	var setskinopt = setskin.options[setskin.selectedIndex];
	theme = setskinopt.text;
	
	testing = (docURL.URLpaths[0] == "file:");
	var traverse = null;

	if ( testing ) {
	// This means the script is not running on an internet page,
	// but on a file locally, in other words in some kind of test lab
	    com.TheMoFaT.enhanceTopic.init("btn_normal");
//	    traverse = com.TheMoFaT.enhanceIndex.init();
	}
	else {
	    // Warning page
	    // Has a URL like http://s4.zetaboards.com/GamingKlutz/warn/ ...
	    // ... ?level=add&mid=3084031&pid=8085672
	    if ( docURL.URLpaths[4] == "warn" )
		traverse = com.TheMoFaT.enhanceWarn.init(docURL);
    
	    // Topic page
	    // Has a URL like http://s6.zetaboards.com/MoFaT/topic/ ...
	    if ( docURL.URLpaths[4] == "topic" )
		traverse = com.TheMoFaT.enhanceTopic.init("btn_normal");

	    // Forum page
	    // Has a URL like http://s6.zetaboards.com/MoFaT/index/
	    if ( docURL.URLpaths[4] == "index" )
		traverse = com.TheMoFaT.enhanceIndex.init();
    
	    // Message page
	    // Has a URL like http://s6.zetaboards.com/MoFaT/msg/ ...
	    if ( docURL.URLpaths[4] == "msg" )
		traverse = com.TheMoFaT.enhanceMsg.init();

	    // Message page
	    // Has a URL like http://s6.zetaboards.com/MoFaT/msg/ ...
	    if ( docURL.URLpaths[4] == "forum" )
		traverse = com.TheMoFaT.enhanceForum.init();
	}
	
	if (traverse) {
	    var arr = document.body.getElementsByTagName("*");
	    var arrlen = arr.length;

	    for( var i = 0; i < arrlen; i++ ) { traverse( arr[i] ); }
	}
    } // init()

    // Public methods
    ns.getTheme = getTheme;
    ns.getTesting = getTesting;
    ns.setClick = setClick;
    ns.setKeyDown = setKeyDown;
    ns.setMouseOver = setMouseOver;
    ns.setMouseOut = setMouseOut;
    ns.init = init;
    
    // Version identifier, is at the end of the file so that it is easy to find
    version = "com.TheMoFaT 3.4.2";
})(com.TheMoFaT.enhance);

com.TheMoFaT.enhance.init();

