// Taps:Javascript

//
// PropertyHandler Object
//

// Constructor
function PropertyHandler(target) {
	this.targetObj = getObj(target);
	if (!this.targetObj) {return false;}

  // Initialize data
  this.synchronizeData();
}

// Object methods
PropertyHandler.prototype.synchronizeData = function() {
  if (this.className == this.targetObj.className) {return;}

  this.className = this.targetObj.className;
  this.classList = this.targetObj.className.split(/\s+/);
  this.classSet = new Array();
  this.propertySet = new Array();

  for (var i=0; i<this.classList.length; i++) {
    var pair = this.classList[i].split(/-/);

    if (pair.length <= 1) {
      // Not a valid property name-value pair.  Store with default of "".
      this.classSet[this.classList[i]] = true;
      continue;
    }
    
    var propertyName = pair[0];
    var propertyValue = pair[1];
    
    this.propertySet[propertyName] = propertyValue;
  }
}

// Returns an array of arrays, that is a set of property value lists.
PropertyHandler.prototype.getProperty = function(name) {
  this.synchronizeData();
  return this.propertySet[name];
}


PropertyHandler.prototype.hasClass = function(name) {
  this.synchronizeData();
  return this.classSet[name];
}



//
// Object Management and Retrieval Functions
//

function getObjById(name) {
	if (document.getElementById) {
		return document.getElementById(name);
	}
	else if (document.all) {
		return document.all[name];
	}
	else if (document.layers) {
		return document.layers[name];
	}

	return false;
}

function getObj(target) {
	if (!target) {return target;}

	if (typeof(target) == "string") {
		return getObjById(target);
	}
	else {
    return target;
  }
}

function getObjectsByTag(tagList) {
  if (typeof(tagList) != 'array') {
    tagList = new Array(tagList);
  }

  var outputList = new Array(0);

  for (var i=0; i < tagList.length; i++) {
    var nodeList = document.getElementsByTagName(tagList[i]);
    for (x=0; x<nodeList.length; x++) {
      outputList.push(nodeList[x]);
    }
  }

  return outputList;
}

function getObjectsByTagAndClass(tagList, classList) {
  var objectList = getObjectsByTag(tagList);
  return getObjectsFromListByClass(objectList, classList);
}

function getObjectsFromListByClass(objectList, classList) {
  // Convert input to arrays if need be
  if ((typeof(classList) != 'array') && (typeof(classList) != 'object')) {
    classList = new Array(classList);
  }

  var classTestPassed;
  var outputList = new Array();

  // Test each object to see if it has all of the classes
  for (var i=0; i < objectList.length; i++) {
    classTestPassed = true;

    // Pass through the list looking for missing classes
    for (var x=0; x < classList.length; x++) {
      if (!hasClass(objectList[i], classList[x])) {
        classTestPassed = false;
        break;
      }
    }

    // Include the object in the output if it has all of the classes
    if (classTestPassed) {
      outputList.push(objectList[i]);
    }
  }

  return outputList;
}


function hasTag(target, targetTag) {
	var targetObj = getObj(target);
	if (!targetObj) {return false;}

	var objectTag = targetObj.nodeName.toLowerCase().replace("#", "");
	if (objectTag.indexOf(targetTag.toLowerCase()) != -1) {
		return true;
	}
	else {
		return false;
	}
}



//
// CSS Class Management Functions
//

// Note that this will also match class 'red' against an object having class 'blahred'
// A regex or some other alternative should probably be put in this fuction to
// make it match class names more strictly
function hasClass(target, targetClass) {
	var targetObj = getObj(target);
	if (!targetObj) {return false;}

  var re = new RegExp("\\b" + targetClass + "\\b");

	if (targetObj.className.match(re)) {
		return true;
	}
	else {
		return false;
	}
}

function addClass(target, targetClass) {
	var targetObj = getObj(target);
	if (!targetObj) {return false;}

	if (targetObj.className.indexOf(targetClass) == -1) {
		if (targetObj.className) {
			targetObj.className = targetObj.className + " " + targetClass;	// Append if existing list
		}
		else {
			targetObj.className = targetClass;	// Set if nothing is existing
		}
	}
}

function removeClass(target, targetClass) {
	var targetObj = getObj(target);
	if (!targetObj) {return false;}

	var re = new RegExp("\\b" + targetClass + "\\b", "g");
  targetObj.className = targetObj.className.replace(re, "");
}

function setClass(target, newClassName) {
	var targetObj = getObj(target);
	if (!targetObj) {return false;}

	targetObj.className = newClassName;
	return false;
}

function toggleClass(target, class_a, class_b) {
	var targetObj = getObj(target);
	if (!targetObj) {return false;}

	if (hasClass(targetObj, class_a)) {
		removeClass(targetObj, class_a);
		addClass(targetObj, class_b);
	}
	else {
		removeClass(targetObj, class_b);
		addClass(targetObj, class_a);
	}
	return false;
}


//
// Display Functions
//

function setDisplay(target, newDisplay) {
	var targetObj = getObj(target);
	if (!targetObj) {return false;}

	if (targetObj.style.display.toLowerCase() != newDisplay.toLowerCase()) {
		targetObj.style.display = newDisplay;
	}
}

function isDisplayed(target, displayState) {
	var targetObj = getObj(target);
	if (!targetObj || !displayState) return;

	if (targetObj.style.display.toLowerCase() == displayState.toLowerCase()) {
		return true;
	}
	return false;
}

function displayGroupMember(target) {
	var targetObj = getObj(target);
	if (!targetObj) {return false;}

  var ph = new PropertyHandler(targetObj);
  var tag = targetObj.nodeName.toLowerCase();
  var group = "group-" + ph.getProperty("group");

	modifyGroup(tag, group, setDisplay, "none", targetObj.id);
	setDisplay(targetObj, "block");
}



// Note: Group is just any provided classname.
function modifyGroup(tag, group, modifyFunc, modifyFuncParam, exceptionId) {
  var groupList = getObjectsByTagAndClass(tag, group);

	// Set the exception id to something that will never match if one wasn't provided
	if (!exceptionId) {exceptionId=0;}

  for (var i=0; i<groupList.length; i++) {
    if (groupList[i].id != exceptionId) {
      modifyFunc(groupList[i], modifyFuncParam);
    }
  }
}



//
// Common Tree Modification Functions
//

/*
function changeStyleSet(targetClass, newClass, rootObj) {
	if (!rootObj) {return;}	// Should fall back to the document root
	modifyRelatives(rootObj, targetClass, changeStyle, newClass, 2);
}
*/



//
// Anchor Navigation
//

function parseAnchor(target) {
	// Strip out a hash and anything before it
	var hashindex = target.indexOf("#");
	if (hashindex != -1) {
		target = target.substring(hashindex+1);
	}
	return target;
}


function locateAnchor(target) {
	return getObj(parseAnchor(target));
}


// Takes an anchor name (with or without adddress/# in front) that is resolved to an id.
function displayAnchor(source) {
	var sourceObj;

	// Display just the provided source if one was given
  if (source) {
    sourceObj = locateAnchor(source);
  	if (sourceObj) {
    	displayGroupMember(sourceObj);
    }
    return false;
  }

	// If a source wasn't explicity provided then look for defaults and display them
	var defaultNavList = getObjectsByTagAndClass('div', 'navDefault');
	for (var i=0; i<defaultNavList.length; i++) {
    displayGroupMember(defaultNavList[i]);
	}

	// Look for a hash anchor and display it if found
	sourceObj = locateAnchor(location.hash);
	if (sourceObj) {
  	displayGroupMember(sourceObj);
  }

  // Make sure the location is set to the top of the page
  if (location.hash)
  {
    location.hash = "";
  }

	return false;
}


function removeNavGroupState(navGroup) {
  var groupList = getObjectsByTagAndClass('a', 'navGroup-' + navGroup);
  for (var i=0; i<groupList.length; i++) {
    removeClass(groupList[i], "navState-isActive");
  }
}

function processNavLink(linkObj) {
  var ph = new PropertyHandler(linkObj);

  if (!ph.hasClass("navLink")) {
    // Not a nav link
    return true;
  }

  var navState = ph.getProperty("navState");
  var navGroup = ph.getProperty("navGroup");
  var navChildGroup = ph.getProperty("navChildGroup");
  var resetContent = ph.getProperty("resetContent");

  if (navState == "isActive") {
    // Already displayed
    return false;
  }

  if (navGroup) {
    removeNavGroupState(navGroup);
  }

  if (navChildGroup) {
    removeNavGroupState(navChildGroup);
  }

  if (resetContent) {
    var targetClassList = new Array("group-" + resetContent, "navDefault");
    var groupDefaults = getObjectsByTagAndClass('div', targetClassList);
    for (var i=0; i<groupDefaults.length; i++) {
      displayGroupMember(groupDefaults[i]);
    }
  }

  // Mark the link as active
  addClass(linkObj, "navState-isActive");

  // Display the content
  displayAnchor(linkObj.href);

  return false;
}

function processNavSelectBox(boxObj) {
  if (!isDisplayed(locateAnchor(boxObj.value), "block")) {
  	displayAnchor(boxObj.value);
  	return 1;
  }
}


function initNavigation() {
  var anchorList = getObjectsByTagAndClass('a', 'navLink');
  var selectList = getObjectsByTagAndClass('select', 'navSelectBox');

  // Assign an onclick function to all of the jumplinks
	for (var i=0; i<anchorList.length; i++) {
  	anchorList[i].onclick = function() {return processNavLink(this);};
	}

  // Assign an onclick function to all of the jumpboxes
	for (var i=0; i<selectList.length; i++) {
  	selectList[i].onclick = function() {return processNavSelectBox(this);};
	}
}


function processOnLoad() {
	initNavigation();
	displayAnchor();
}


window.onload = function() { processOnLoad(); };
