/**
 * author:	Moritz Tuerk
 * contact: moritz <dot> tuerk <at> gmx 'dot' de
 *
 * This javascript library contains a set of functions that
 * implement a dhtml tree menu which can be incorporated in
 * html pages.
 *
 * Copyright (C) 2006  Moritz Tuerk
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

/**
 * This flag indicates if debug information is alerted to the
 * user or not.
 */
var DEBUG=false;

/**
 * This defines the structure of the Menu (the MenuItems are defined here)
 */
var menu = 
	new Array(
		new MenuItem('HOME','itemHome',true,new Array(
			new MenuItem('project page','itemSFProject',false,null,'http://sourceforge.net/projects/cardwizard')
		),'http://cardwizard.sourceforge.net'),
		new MenuItem('GET WIZZARD', 'itemDownload', false, null, 'download.html'),
		new MenuItem('SCREENSHOTS','itemScreenshot',true,new Array(
			new MenuItem('official','itemSCOfficial',true,null,'shots_official.html')
		),null),
		new MenuItem('TEAM','itemTeam',true, new Array(
			new MenuItem('developers','itemTeamDev',false,null,'developers.html')		
		),null),
		new MenuItem('CREDITS','itemCredit',false,null,'credits.html'),
		new MenuItem('CONTACT','itemContact',true,new Array(
			new MenuItem('forum','itemForum',false, null,'http://sourceforge.net/forum/?group_id=158190')
		),'contact.html'),
		new MenuItem('DISCLAIMER','itemDisclaimer',false,null,'disclaimer.html')
	);
	
var init = false;
	
/**
 * user defined object: defines the structure of an menu item.
 * @param itemText (string) conatains the label of the menuItem
 * @param itemId (string) contains the menuItems id
 * @param expanded (boolean) saves if the item is expanded or not
 * @param subMenu (Array) saves an Array containing all subMenu items (type MenuItem)
 * @param ref (string) containing the hyper ref for this element
 */	
function MenuItem(itemText, itemId, expanded, subMenu, ref) {
 	//string
	this.itemText = itemText;
	//string (unique!!!)
	this.itemId = itemId;
	//boolean
	this.expanded = expanded;
	//Array containing MenuItems
	this.subMenu = subMenu;
	//string
	this.ref = ref;
}

/**
 * create the root Menu:
 * This will look for a div element with the id 'tree' and will
 * attach all the menu items as div elements as they are defined
 * in the global var 'menu'
 */
function initMenu() {
	if (init) return;
	
	var level = 0;
	var rootMenuItems = createMenu(menu, level);
	if (rootMenuItems) {
		menuElement = document.getElementById('tree');
	
		for (i = 0; i < rootMenuItems.length; i++) {
			menuElement.appendChild(rootMenuItems[i]);
		} 
	} else if (DEBUG) {
		alert('whoot! root menu is null! that\'s a problem');
	}
	
	init = true;
	
	//the expanded items are saved in the window name
	var expanded = window.name.split(',');
	for (var i = 0; i < expanded.length; i++) {
		expandItem(expanded[i]);		
	}
}

/**
 * this function creates the HTML elements from
 * the MenuItem definitions
 * @param menuDef (Array) saves the Array with the MenuItem Objects
 *        from which the menu should be build
 * @param level (int) saves the level in the tree (is used for indentation,
 *        starts at 0)        
 */
function createMenu(menuDef, level) {
	if (menuDef instanceof Array) {
		var result = new Array(menuDef.length);
		
		for (var i = 0; i < menuDef.length; i++) {
			var newDiv = document.createElement('div');
			newDiv.className = 'treeMenu_menuItemDiv';
			newDiv.id = menuDef[i].itemId;
			
			var newImg = document.createElement('img');
			newImg.className = 'treeMenu_menuItem';
			newImg.onclick = handleClickOpenClose;
			
			if (menuDef[i].subMenu) {
				newImg.style.cursor = 'pointer';
			}
			
			newDiv.appendChild(newImg);
			newDiv.style.marginLeft=''+level*16+'px';
			if (level == 0) {
				newDiv.style.marginTop='4px';
			}
						
			var newImgText = document.createTextNode(menuDef[i].itemText);
			var newHref = document.createElement('a');
			
			newHref.className = 'treeMenu_link';
			newHref.appendChild(newImgText);
			
			if (menuDef[i].ref) {
				newHref.setAttribute('href',menuDef[i].ref);
			}
			
			newDiv.appendChild(newHref);			
			
			if (menuDef[i].subMenu && menuDef[i].expanded) {
				menuDef[i].expanded = true;
			} else {
				menuDef[i].expanded = false;
			}
			
			if (menuDef[i].subMenu) {
				level++;
				newImg.setAttribute('src','../img/bullet.png');
				
				subItems = createMenu(menuDef[i].subMenu, level);
				var disp = 'none';
				
				if (menuDef[i].expanded) {
					disp = 'block';
					newImg.setAttribute('src','../img/bullet_down.png');
				}
				
				for (var j = 0; j < subItems.length; j++) {
					subItems[j].style.display=disp;
					newDiv.appendChild(subItems[j]);
				}
				
				level--;
			} else {
				newImg.setAttribute('src', '../img/bullet_link.png');
			}
			
			result[i] = newDiv;
		}
		return result;
		
	} else if (DEBUG) {
		alert('we got a problem here! Invalid Menu definition found.');
	}
	
	return null;
}

/**
 * this method handles all click actions on the
 * menu bullets. It expands or collapses the menu items
 * @param (event) e saves the event object fired by the browser
 */
function handleClickOpenClose(e) {
	var event = e;
	
	//the stupid IE does not pass events as argument!
	if (!event) {
		event = window.event;
	}
	
	//stupid browsers have different names for the
	//*SAME* shit! so check 'currentTarget' AND 'srcElement'
	var target = event.currentTarget;
	if (!target) {
		target= event.srcElement;
	}
	
	var divElement = target.parentNode;
	
	menuItem = findItem(menu, divElement.id);
	var expand = !menuItem.expanded && (menuItem.subMenu != null);

	//expand item ?
	if (expand) {
		expandItem(divElement.id);

	//or close it !
	} else {
		closeItem(divElement.id);	
	}
}

/**
 * this method returns the MenuItem Object with
 * the given id from the provided subMenu
 * @param subMenu (Array) saves the subMenu to search trough (contains MenuItem
 *        objects)
 * @param itemId (String) saves the itemId of the MenuItem Object that is
 *        to be returned
 * @returns (MenuItem) the menuItem with the given id or null if not found
 */
function findItem(subMenu, itemId) {
	for (var i = 0; i < subMenu.length; i++) {
		if (subMenu[i].itemId == itemId) {
			return subMenu[i];
		}
		if (subMenu[i].expanded) {
			var tmp = findItem(subMenu[i].subMenu, itemId);
			if (tmp != null) {
				return tmp;
			}
		}
	}
	return null;
}

/**
 * this method is called to expand an closed
 * menu item of the tree menu.
 * @param (String) sItemId saves the item id of the
 *        MenuItem to be expanded
 */
function expandItem(sItemId) {
	var divElement = document.getElementById(sItemId);
	
	if (!divElement) {
		return;
	}
	
	var menuItem = findItem(menu, divElement.id);
	
	menuItem.expanded = true;
	
	DEBUG && alert('EXPAND');
	appendToWindowName(divElement.id);
		
	var subDivs = divElement.getElementsByTagName('div');

	for (i = 0; subDivs && (i < subDivs.length); i++) {
		subDivs[i].style.display='block';
	}

	var imgElement = divElement.getElementsByTagName('img');
	imgElement[0].setAttribute('src','../../img/bullet_down.png');
}

/**
 * this method is called to close an expanded
 * menu item of the tree menu.
 * @param sItemId (String) saves the item id of the item to be
 *        closed
 */
function closeItem(sItemId) {
	var divElement = document.getElementById(sItemId);
	var menuItem = findItem(menu, divElement.id);
	
	menuItem.expanded = false;
	
	DEBUG && alert('CLOSE');
	removeFromWindowName(divElement.id);
		
	var subDivs = divElement.getElementsByTagName('div');
		
	for (i = 0; subDivs && (i < subDivs.length); i++) {
		subDivs[i].style.display='none';
	}
		
	var imgElement = divElement.getElementsByTagName('img');
	//is an expandable node ?
	if (menuItem.subMenu) {
		imgElement[0].setAttribute('src','../../img/bullet.png');
	} else {
		imgElement[0].setAttribute('src','../../img/bullet_link.png');
	}
}

/**
 * this method is called to append the itemId of an newly
 * expanded item to the window.name field. It saves a comma
 * seperated list of all expanded tree items.
 * @param (String) sItemId saves the item Id of the closed MenuItem
 */
function appendToWindowName(sItemId) {
	if (window.name.length == 0) {
		window.name = sItemId;
	} else {
		var expanded = window.name.split(',');
		for (var i = 0; i < expanded.length; i++) {
			//no double ids in the list please!
			if (expanded[i] == sItemId) {
				return;
			}
		}
		window.name = window.name+','+sItemId;
	}
	DEBUG && alert('window.name after append = '+window.name);
}

/**
 * this method is called to remove the itemId of an
 * newly closed Item from the comma seperated list in the
 * window.name field.
 * @param (String) sItemId saves the Id of the Item
 *        to be removed from the expanded list
 */
function removeFromWindowName(sItemId) {
	var expanded = window.name.split(',');
	var newName = '';
	
	for (var i = 0; i < expanded.length; i++) {
		if (expanded[i] != sItemId) {
			//no ',' at the beginning
			if (newName.length > 0) {
				newName = newName + ',' + expanded[i];
			
			} else {
				newName = expanded[i]
			}
		} 
	}
	
	window.name=newName;
	DEBUG && alert('window.name after remove = '+window.name);
}

