/* **************************************************************************
 * $Workfile:: menu.js                                                      $
 * **********************************************************************//**
 *
 * Functions and objects to control the display of a common menu on multiple
 * pages of of a website.
 *
 * To use this file the including page must:
 * 1st include it
 *	<script src="theme/menu.js" type="text/javascript"></script>
 * then create a menu variable and write the HTML to the page.
 * for example:
 *	<script type="text/javascript">
 *		var path = "/";
 *		var filename = "index.html";
 *		var nav = InitMenu();
 *		document.write( nav.HTML( path, filename, 1 ) );
 *	</script>
 *
 * The HTML code produced for the menu uses a definition list. It also
 * assigns classes to various parts of the menu to allow formatting via css.
 * The class values assigned are "menuN" where N is a value from 1 for the
 * top level menu, and increasing for submenus on the <dl> element, and
 * "here" for the <dt> element containing the menu item representing the
 * current page. Also note that the menu item representing the current page
 * does not have a link (<a> tag).
 * A sample menu would be:
 *	<dl class="menu1">
 *		<dt class="here">Home</dt>
 *		<dd>
 *			<dl class="menu2">
 *				<dt><a href="oldnews.html">Old News</a></dt>
 *			</dl>
 *		</dd>
 *		<dt><a href="info.html">Guild Charter</a></dt>
 *		<dt><a href="member/members.html">Members</a></dt>
 *		<dt><a href="http://pub52.ezboard.com/bforsakenavengers19241">Norse Forum</a></dt>
 *		<dt><a href="trades/trades.html">Trade Skills</a></dt>
 *		<dt><a href="misc/links.html">Useful Links</a></dt>
 *	</dl>
 *
 * Future enhancements:
 *	o	Allow multiple menus to be created by using an argument to the
 *		InitMenu function.
 *	o	How about allowing a title attribute on a menu item to put on the
 *		anchor element?
 *
 * Created on		May 16, 2002
 * @author			Michael Jay Lippert
 *
 * @version         $Revision:: 4                                           $
 * Last modified by   $Author:: Mjl                                         $
 * Last modified on     $Date:: 4/10/04 7:21p                               $
 *                $NoKeywords::                                             $
 *
 * Copyright (c) 2002 Michael Jay Lippert, All rights reserved.
 *
 * **************************************************************************/

/* **************************************************************************
 * Constants
 ****************************************************************************/

// Constants returned by MenuItem.FindItem()
var	kLocUnknown	= 0;
var	kLocHere	= 1;
var	kLocUnder	= 2;

/* **************************************************************************
 * Page variables
 ****************************************************************************/

/* **************************************************************************
 * InitMenu                                                             *//**
 *
 * InitMenu creates a predefined menu object and returns it.
 *
 * @return	predefined menu object.
 *
 ****************************************************************************/
function InitMenu()
{
	var menu = new Menu();
	var mi;

	mi = menu.Append( new MenuItem( "Home",			"index.xhtml",			"/" ) );
	// This is how to add a submenu:
	//mi.submenu = new Menu();
	//mi.submenu.Append( new MenuItem( "Old News",		"oldnews.html",			"/" ) );

	//mi = menu.Append( new MenuItem( "What's New",				"whatsnew.xhtml",		"/" ) );
	mi = menu.Append( new MenuItem( "We Share a Story",			"we-share-a-story.xhtml", "/" ) );
	mi = menu.Append( new MenuItem( "Storytelling",				"storytelling.xhtml",	"/" ) );
	mi = menu.Append( new MenuItem( "Books",					"books.xhtml",			"/" ) );
	mi = menu.Append( new MenuItem( "Workshops",				"workshops.xhtml",		"/" ) );
	mi = menu.Append( new MenuItem( "Conferences",				"conferences.xhtml",	"/" ) );
	mi = menu.Append( new MenuItem( "Writing Class",			"writingclass.xhtml",	"/" ) );
	mi = menu.Append( new MenuItem( "Show Time!",				"showtime.xhtml",		"/" ) );
	mi = menu.Append( new MenuItem( "About Me",					"meglippertbio.xhtml",	"/" ) );
	mi = menu.Append( new MenuItem( "Awards",					"awards.xhtml",			"/" ) );
	mi = menu.Append( new MenuItem( "Reviews",					"reviews.xhtml",		"/" ) );
	mi = menu.Append( new MenuItem( "StoryPower USA",			"usamap.xhtml",			"/" ) );
	mi = menu.Append( new MenuItem( "Activities",				"activities.xhtml",		"/" ) );
	mi = menu.Append( new MenuItem( "Contact me",				"info@StoryPower.net",	"mailto:" ) );

	return menu;
}

/* **************************************************************************
 * MenuItem                                                             *//**
 *
 * constructor for menu item object
 *
 * A menu item has a display string and a url to execute when the menu item
 * is selected. If the path begins with a '/' then the url is on the current
 * host and the actual path used in the menu will depend on the location
 * of the file currently displayed. Otherwise it is an absolute path that
 * does not depend on the location fo the file being displayed.
 *
 * A menu item may optionally contain a submenu.
 *
 * @param	display		The visible representation of the menu item
 * @param	filename	The filename of the url to execute
 * @param	path		The path to the filename
 *
 ****************************************************************************/
function MenuItem( display,
				   filename,
				   path )
{
	this.display	= display;
	this.filename	= filename;
	this.path		= path;

	this.submenu	= null;

	// Methods
	this.FindItem = MenuItemFindItem;
	this.CalcURL = MenuItemCalcURL;
}

/* **************************************************************************
 * MenuItemFindItem                                                     *//**
 *
 * MenuItem class method to determine if the given path/filename represents
 * the menu item, or a menu item in a submenu.
 *
 * @param	path		The path to the menu item that is "here".
 * @param	filename	The filename of the menu item to consider "here".
 *
 * @return
 *		kLocHere	if this menu item matches the given path and filename.
 *		kLocUnder	if a menu item of a submenu (or a sub-submenu) matches the
 *					given path and filename.
 *		kLocUnknown	if the given path and filename are not found within this
 *					menu item.
 *
 ****************************************************************************/
function MenuItemFindItem( path, filename )
{
	if ( path == this.path && filename == this.filename )
		return kLocHere;

	if ( this.submenu !== null )
	{
		for ( var i = 0; i < this.submenu.item.length; ++i )
		{
			if ( this.submenu.item[i].FindItem( path, filename ) != kLocUnknown )
				return kLocUnder;
		}
	}

	return kLocUnknown;
}

/* **************************************************************************
 * MenuItemCalcURL                                                      *//**
 *
 * MenuItem class method to calculate the relative URL of the menu item
 * if the current path is basePath.
 *
 * If the path begins with a '/' then the url is on the current
 * host and the relative path needs to be calculated from the given
 * basePath. Otherwise it is an absolute path that
 * does not depend on the location fo the file being displayed.
 *
 * @param	basePath	The base path to calculate the menu items urls
 *						relative to.
 *
 * @return	string containing the relative URL to the menu item if the
 *			current path is basePath.
 *
 ****************************************************************************/
function MenuItemCalcURL( basePath )
{
	// Start by assuming an absolute path
	var calcPath = this.path;

	// If the path actually is relative...
	if ( calcPath.substr( 0, 1 ) == "/" )
	{
		// We're going to do this the easy way, by backing up to the root
		// and then going forward from there. This may not be optimal, but
		// should always work.

		// Each '/' in the basePath after the initial one requires backing
		// up one directory.
		var backupPath = "";
		for ( var i = 1; i < basePath.length; ++i )
		{
			if ( basePath.substr( i, 1 ) == "/" )
				backupPath += "../";
		}

			// prefix path with backupPath.
			calcPath = backupPath + this.path.substr( 1 );
	}

	return calcPath + this.filename;
}


/* **************************************************************************
 * Menu                                                                 *//**
 *
 * constructor for menu object
 *
 ****************************************************************************/
function Menu()
{
	this.item = new Array();

	// Methods
	this.Append = MenuAppend;
	this.HTML = MenuHTML;
}

/* **************************************************************************
 * MenuAppend                                                           *//**
 *
 * Menu class method to append a menu item to the menu.
 *
 * @param	menuitem	The menu item to append
 *
 * @return the menuitem appended.
 *
 ****************************************************************************/
function MenuAppend( menuitem )
{
	this.item.push( menuitem );

	return menuitem;
}

/* **************************************************************************
 * MenuHTML                                                             *//**
 *
 * Menu class method to append a menu item to the menu.
 *
 * @param	basePath	The base path to calculate the menu items urls
 *						relative to.
 * @param	curFilename	The filename of the menu item to consider "here"
 * @param	level		The level of the menu (1 is top level menu, 2 is
 *						submenu of top level menu item, etc)
 *
 * @return string containing the xhtml representation of the menu.
 *
 ****************************************************************************/
function MenuHTML( basePath, curFilename, level )
{
	var	strHTML = "";

	if ( level === undefined )
		level = 1;

	// If the menu has no items we're done.
	if ( this.item.length == 0 )
		return strHTML;

	// Add the definition list with a class specifying the menu level.
	strHTML += '<dl class="menu' + level + '">\n';

	// Iterate through the menu's items and format them in the string.
	var i;
	for ( i = 0; i < this.item.length; ++i )
	{
		var mi = this.item[i];

		// Menu items are displayed in definition terms.
		var relativeLoc = mi.FindItem( basePath, curFilename );
		if ( relativeLoc == kLocHere )
		{
			strHTML += '<dt class="here">';
			strHTML += mi.display;
			strHTML += '</dt>\n';
		}
		else
		{
			strHTML += '<dt>';
			strHTML += '<a href="' + mi.CalcURL( basePath ) + '">' + mi.display + '</a>';
			strHTML += '</dt>\n';
		}

		// Submenus are displayed in definition descriptions.
		if ( mi.submenu !== null && relativeLoc != kLocUnknown )
		{
			strHTML += '<dd>\n';
			strHTML += mi.submenu.HTML( basePath, curFilename, level + 1 );
			strHTML += '</dd>\n';
		}
	}

	// End the definition list
	strHTML += '</dl>\n';

	return strHTML;
}
