// meshCloud.js: utilities for building tag clouds on pages without content, such as Mesh Home pages.
// Requires ThoughtMesh.js.
// V1.5, modified by Jon to work with public author homes.
/*__________ Constants. __________*/
thoughtMesh.desiredMaxTagsInt = 50 ; // Empirically derived.
thoughtMesh.maxToMinTagFrequencyRatioForIE = 5 ; // Empirically derived for F*CKING IE!!! May need to be changed. Ends up 7 for ThoughtMesh home.
/*__________ Initialization __________*/
function loadMeshCloud (argObj) {
	primaryGroup = (typeof argObj.primaryGroup == "undefined")? 0 : argObj.primaryGroup ;
	// Used for creating tag clouds of global mesh. Stripped down variant of loadMesh.
	/*________________________ Check browser compatibility.________________________*/
	// Check for browser compliance. If stale browser, go to old browser page. (Safari works for the most part, as is explained in the stale browser page.)
	if ( browsers.ns4 || browsers.ie4 || browsers.ie5 || browsers.ie6) { // Explicit numbers is more future-proof.
		if ( !confirm("Your browser doesn't appear to support all ThoughtMesh features.\n\nClick Cancel to learn more, or\n\nOK to proceed anyway.") ) {
			document.location="recommended_thoughtmesh_browsers.html";
		}
	}
	// Assume Telamon, assume online.
	/*__________ Load telamon parameters __________*/
	thoughtMesh.id = ( typeof argObj.documentId == "undefined" )?  "[No document id specified!]" : argObj.documentId ; // Document, not author id.
	thoughtMesh.isAuthorMesh = (typeof argObj.isAuthorMesh == "undefined")? false : argObj.isAuthorMesh ; // Usually a document Mesh.
	thoughtMesh.authorId = (typeof argObj.authorId == "undefined")? "[No author id specified!]" : argObj.authorId ; // Only used for author home.
	thoughtMesh.authorWritten = (typeof argObj.authorWritten == "undefined")? "[No author name specified!]" : argObj.authorWritten ; // Only used for author home.
	thoughtMesh.outsideLexiasUrl = 'http://vectors.usc.edu/thoughtmesh/json/outsideLexias.json.php' ;
	thoughtMesh.outsideLexiasUrl = encodeURI(thoughtMesh.outsideLexiasUrl) ; // NEC? JB says no.
	/*________________________ Initialize tags.________________________*/
	thoughtMesh.hasLexiasHere = false ;
	thoughtMesh.method = "telamon" ;
	telamon.offline = false ;
	/*__________ Initialize submeshes, tags, and tab. __________*/
	// FOLLOWING REPLACES: telamon.get( thoughtMesh.outsideLexiasUrl, {documentid: thoughtMesh.id }, "outsideLexiasFun(); initializeSubmeshes() ; registerMeshTags() ; respondToTab( document.getElementById('tab-out') )") ;
	outsideLexiasFun();
	if (thoughtMesh.isAuthorMesh) {
		initializeAuthorMesh() ;
	}
	else {
		initializeSubmeshes() ;
	}
	registerMeshTags() ;
	respondToTab( document.getElementById('tab-out') ) ;
}
function registerMeshTags() {
	debug("'registerMeshTags'")
	// Add tag properties to dynamic menu. Version of registerTags where data comes from JSON instead of HTML. Leaves out inline navigation.
	thoughtMesh.selectedTags = [] ; // Used after clicking on a tag, this is a manager of objects with integer index and tag name properties.
	thoughtMesh.numberOfLexiasByTag = {} ; // In loadMesh, this object contains arrays; here it comes from JSON and returns just integers.
	thoughtMesh.numberOfDocumentsByTag = {} ; // Specific to registerMeshTags; comes from JSON and returns just integers.
	thoughtMesh.uniqueTags = [] ;
	thoughtMesh.visibleTags = [] ; // Used for setting optimum number of visible tags.
	/*__________ Loop through all items in JSON, registering tags. __________*/
	// Pull tags with no lexias out of the array first.
	numTaggedWith.zeros(false) ;
	// tag is "art", "Bill Clinton", etc.
	// numTaggedWith.lexias["art"] is integer number of lexias tagged with "art".
	// numTaggedWith.documents["art"] is integer number of documents tagged with "art".
	debugObject("numTaggedWith.lexias");// DEBUGGING.
	for (var tag in numTaggedWith.lexias) {
		if (typeof tag == "string") { // UPGRADE: nec?
			thoughtMesh.uniqueTags.push( tag ) ;
			// UPGRADE: Are these additional constructions REDUNDANT?
			thoughtMesh.numberOfLexiasByTag[ tag ] = numTaggedWith.lexias[ tag ] ;
			thoughtMesh.numberOfDocumentsByTag[ tag ] = (typeof numTaggedWith.documents[ tag ] == "undefined")? 0 : numTaggedWith.documents[ tag ] ;
		}
	}; // End loop through items.
	// First sort unique tags by frequency to get max and min values for normalizing tag size.
	thoughtMesh.uniqueTags.sort( sortMeshTagsNumerically ) ;
	thoughtMesh.tagFrequencyMin = 0;
	thoughtMesh.tagFrequencyMax = 0;
	if (typeof(thoughtMesh.numberOfLexiasByTag[ thoughtMesh.uniqueTags[0] ]) != 'undefined') {
	  thoughtMesh.tagFrequencyMin = thoughtMesh.numberOfLexiasByTag[ thoughtMesh.uniqueTags[0] ];
	  thoughtMesh.tagFrequencyMax = thoughtMesh.numberOfLexiasByTag[  thoughtMesh.uniqueTags[ thoughtMesh.uniqueTags.length-1 ]  ] ;
	}
	// Set a value that helps user show fewer or more tags once page has loaded.
	thoughtMesh.minimumVisibleTagFrequency = thoughtMesh.tagFrequencyMin ;
	debug("thoughtMesh.tagFrequencyMin")
	debug("thoughtMesh.tagFrequencyMax")
	debugArray("thoughtMesh.uniqueTags")
 	if ( browsers.ie ) { // F*cking IE borks spacing unless you do this.
		// debug( "thoughtMesh.tagFrequencyMax", 3)
		// debug(" thoughtMesh.maxToMinTagFrequencyRatioForIE", 3)
		// _ratio = thoughtMesh.tagFrequencyMax / thoughtMesh.maxToMinTagFrequencyRatioForIE; debug("_ratio", 3)
		// _ceil = Math.ceil(_ratio); debug("_ceil", 3)
		thoughtMesh.minimumVisibleTagFrequencyForIE = Math.ceil( thoughtMesh.tagFrequencyMax / thoughtMesh.maxToMinTagFrequencyRatioForIE ) ; // Empirically derived--may need future adjustment.
		// debug( "thoughtMesh.minimumVisibleTagFrequencyForIE", 3 )
		if ( thoughtMesh.minimumVisibleTagFrequencyForIE < 2 ) {
			thoughtMesh.minimumVisibleTagFrequencyForIE = 2 ;
		}
		for (var tagCounter = thoughtMesh.uniqueTags.length - 1; tagCounter >= 0; tagCounter--){
			if (  thoughtMesh.numberOfLexiasByTag[ thoughtMesh.uniqueTags[tagCounter] ] < thoughtMesh.minimumVisibleTagFrequencyForIE ) {
				thoughtMesh.uniqueTags.splice( tagCounter, 1 ) ;
			}
		};
	}
	// Now sort unique tags alphabetically (default).
	thoughtMesh.uniqueTags.sort( sortAlphabeticallyWithoutCase ) ;
	// Now add tags to cloud.
	debugArray("thoughtMesh.uniqueTags")
	for (var tagCounter=0; tagCounter < thoughtMesh.uniqueTags.length; tagCounter++) {
		var thisTagLexiaFrequency = thoughtMesh.numberOfLexiasByTag[ thoughtMesh.uniqueTags[tagCounter] ] ;
		var thisTagDocumentFrequency = thoughtMesh.numberOfDocumentsByTag[ thoughtMesh.uniqueTags[tagCounter] ] ;
		if ( thisTagDocumentFrequency > 0 ) { // Strip out of the JSON any tags with 0 documents--eg, tags that have been removed or documents that have been unpublished.
			var thisCloudTag = new CloudTag({
				containerEle: document.getElementById("home-cloud"), // UPGRADE: pass this as variable.
				tag: thoughtMesh.uniqueTags[tagCounter],
				frequency: thisTagLexiaFrequency,
				size: setTagSize( {
					frequency:thisTagLexiaFrequency,
					minimum:thoughtMesh.tagFrequencyMin,
					maximum:thoughtMesh.tagFrequencyMax
				}),
				documentsFrequency: thisTagDocumentFrequency
			}) ;
			thoughtMesh.tagObjs.push( thisCloudTag ) ;
			// Enable recovery of cloudTagObj from its name, for use in style highlighting--eg, thoughtMesh.tagObjs.getObjectByTag["technology"].
			thoughtMesh.tagObjs.getObjectByTag[ thoughtMesh.uniqueTags[tagCounter] ] = thisCloudTag ;
			// Assume all tags are visible on load, then adjust below.
			thoughtMesh.visibleTags.push( thisCloudTag ) ;
		}
	}
	debugArray("thoughtMesh.tagObjs")
	if ( ! browsers.ie ) {
		setCloudScope() ;
		setMinimumVisibleTagFrequency() ;
	}
}
function setMinimumVisibleTagFrequency () {
	// Called on load. thoughtMesh.desiredMaxTagsInt is a constant set when this script is loaded.
	while ( thoughtMesh.visibleTags.length > thoughtMesh.desiredMaxTagsInt ) {
		changeCloudScope("wantFewer") ;
	}
}
/*__________ Respond to user actions. __________*/
function setCloudScope () {
	// Hides or shows more clouds depending on the value of minimumVisibleTagFrequency.
	// This function is called on load and after each change of scope made by the user.
	if ( thoughtMesh.minimumVisibleTagFrequency > thoughtMesh.tagFrequencyMin ) {
		document.getElementById("thoughtmesh-scope-more-link").style.color = "black" ;
	}
	else {
		document.getElementById("thoughtmesh-scope-more-link").style.color = "rgb(70%,70%,70%)" ; /*lighter dimgray*/
	}
	if ( thoughtMesh.minimumVisibleTagFrequency < thoughtMesh.tagFrequencyMax ) {
		document.getElementById("thoughtmesh-scope-fewer-link").style.color = "black" ;
	}
	else {
		document.getElementById("thoughtmesh-scope-fewer-link").style.color = "rgb(70%,70%,70%)" ; /*lighter dimgray*/
	}
}
function changeCloudScope (argObj) {
	// Increase or decrease the number of tags shown based on frequency.
	if (argObj == "wantMore") {
		if ( thoughtMesh.minimumVisibleTagFrequency > thoughtMesh.tagFrequencyMin ) {
			thoughtMesh.minimumVisibleTagFrequency-- ;
			setCloudScope()
		}
	}
	if (argObj == "wantFewer") { // User wants to see fewer tags.
		if ( thoughtMesh.minimumVisibleTagFrequency < thoughtMesh.tagFrequencyMax ) {
			thoughtMesh.minimumVisibleTagFrequency++ ;
			setCloudScope()
		}
	}
	thoughtMesh.visibleTags = [] ;
	for (var tagCounter=0; tagCounter < thoughtMesh.tagObjs.length; tagCounter++) {
		if (thoughtMesh.tagObjs[ tagCounter ].frequency < thoughtMesh.minimumVisibleTagFrequency) {
			thoughtMesh.tagObjs[ tagCounter ].tagBox.style.display = "none" ;
		}
		else {
			thoughtMesh.tagObjs[ tagCounter ].tagBox.style.display = "inline" ;
			thoughtMesh.visibleTags.push(thoughtMesh.tagObjs[tagCounter]) ; // Used for determining optimum set on load.
		}
	}
}
/*__________ Utilities __________*/
function sortMeshTagsNumerically(a,b) {
	return thoughtMesh.numberOfLexiasByTag[ a ] - thoughtMesh.numberOfLexiasByTag[ b ] ;
}

// String functions
// TODO: An existance check should be placed on these declarations

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}

function removeSpaces(string) {
	var tstring = "";
	string = '' + string;
	splitstring = string.split(" ");
	for(i = 0; i < splitstring.length; i++) {
	  if (splitstring[i].length>0) {
	    tstring += splitstring[i];
	  }
	}
	return tstring;
}

// Cookie functions
function getCookie(c_name) {
	if (document.cookie.length>0) {
	  c_start=document.cookie.indexOf(c_name + "=");
	  if (c_start!=-1) {
	    c_start=c_start + c_name.length+1;
	    c_end=document.cookie.indexOf(";",c_start);
	    if (c_end==-1) c_end=document.cookie.length;
	    return unescape(document.cookie.substring(c_start,c_end));
	    }
	  }
	return "";
}

function setCookie(c_name,value,expiredays) {
	var exdate=new Date();
	exdate.setDate(exdate.getDate()+expiredays);
	document.cookie=c_name+ "=" +escape(value)+
	((expiredays==null) ? "" : ";expires="+exdate.toGMTString());
}

function cookiesTurnedOn() {
	document.cookie = "cookies=true";
	var has_cookies = (document.cookie) ? "true" : "false";
	return has_cookies;
}

// Toggle functions

// setTogglesFromCookies()
// Description:
//   Function to loop through div tabs and determine whether to toggle them
//   based on a cookie value.  The cookie is set dynamically based on the value
//   of the tab's innerHTML
// Arguments:
//   STR parent_id
// Usage:
//   Call this in <body onload="">:
//     setTogglesFromCookies('content-what-recent');
//   Syntax in div tab:
//     <div class="toggler" onclick="toggleDisplay( this, 'toggleNext' ); setCookie(removeSpaces(this.innerHTML.trim()),((this.nextSibling.nextSibling.style.display=='none')?0:1),5);">

function setTogglesFromCookies(parent_id) {
	var parent_object = document.getElementById(parent_id);
	if (!parent_object) return;
	var the_options = parent_object.getElementsByTagName('div');
	var the_cookie = '';
	for (var a = 0; a < the_options.length; a++) {
		if (the_options[a].className != 'toggler' && the_options[a].className != 'toggler-open') continue;
		the_cookie = getCookie(removeSpaces(the_options[a].innerHTML.trim()));
		if (the_cookie.length > 0) { // values returned would be "" | 0 | 1
			if (the_options[a].nextSibling.nextSibling.style.display=='block' && the_cookie == 1) continue;
			if (the_options[a].nextSibling.nextSibling.style.display!='block' && the_cookie == 0) continue;
			toggleDisplay(the_options[a], 'toggleNext' );
		}
	}
}

function toggleDisplay (ele, nextVar) {
	// Use nextVar if you want to hide the next div instead of the DOM element clicked on.
	if (typeof nextVar != "undefined") {
		eleToToggle = ele.parentNode.getElementsByTagName('div')[1] ;
	}
	else {
		eleToToggle = ele ;
	}
    if (eleToToggle.style.display!="block") { // Putting this option first prevents misfiring based on no display defined yet.
        eleToToggle.style.display="block";
		ele.className = "toggler-open" ;
    }
    else {
        eleToToggle.style.display="none";
		ele.className = "toggler" ;
    }
}
