// JavaScript Document
// (ch) = Christopher Holland - christopher@librarything.com or chris@concepthouse.com
if (!LibraryThing) {
	var LibraryThing = {}; //new function() {};
}


// LibraryThing functions
{
	LibraryThing.version = '1.0';
	LibraryThing.gCookieName = 'LTUnifiedCookie';
	
	LibraryThing.K = function(x) { return x; };
	LibraryThing.time = function()
	{
		return parseInt(new Date().getTime().toString().substring(0, 10))
	};
	
	LibraryThing.setCookie = function(c_name, c_value)
	{
		//alert('setting cookie:'+c_name+'='+c_value);
		var cookieObj = LibraryThing.getCookieObject();
		cookieObj[c_name] = c_value;
		LibraryThing.setCookieObject(cookieObj);
	};
	
	LibraryThing.getCookie = function (c_name)
	{
		var cookieObj = LibraryThing.getCookieObject();
		return cookieObj[c_name];
	};
	
	LibraryThing.cookieEvalTest = function (c_name, c_val)
	{
		var blech = new Object;
		blech[c_name] = c_val;
		alert(blech[c_name]);
	};
	
	LibraryThing.getCookieObject =  function () // loads the Unified cookie object in from the document cookie.
	{
		var cookieObject;
		var cookieJSON = '';
		if (document.cookie.length>0)
		{
			c_start=document.cookie.indexOf(LibraryThing.gCookieName + "=");
			if (c_start!=-1)
			{ 
				c_start=c_start + LibraryThing.gCookieName.length+1; 
				c_end=document.cookie.indexOf(";",c_start);
				if (c_end==-1) c_end=document.cookie.length;
				cookieJSON = (document.cookie.substring(c_start,c_end));
				cookieObject = unescape(cookieJSON).evalJSON();
				return cookieObject;
			}
			else
			{
				return new Object;
			}
		}
		else
		{
			return new Object;
		}
	};
	
	LibraryThing.setCookieObject = function (cookieObject)
	{
		var cookieVal = Object.toJSON(cookieObject);
		var expiredays = 365;
		var exdate=new Date();
		exdate.setDate(exdate.getDate()+expiredays);
		document.cookie= LibraryThing.gCookieName + "=" +escape(cookieVal)+
		((expiredays==null) ? "" : ";expires="+exdate.toGMTString())+
		';path=/';
	};
	
	LibraryThing.setCookie = function(c_name, c_value)
	{
		//alert('setting cookie:'+c_name+'='+c_value);
		var cookieObj = LibraryThing.getCookieObject();
		cookieObj[c_name] = c_value;
		LibraryThing.setCookieObject(cookieObj);
	};
	
	LibraryThing.ltGetCookie = function (c_name)
	{
		return LibraryThing.getCookie(c_name);
	};
	
	LibraryThing.ltSetCookie = function (c_name, c_value)
	{
		LibraryThing.setCookie(c_name, c_value);
	};
	
	// deprecated to match other calls
	LibraryThing.killCookie = function (c_name)
	{
		return LibraryThing.ltKillCookie(c_name);
	};
	
	LibraryThing.ltKillCookie = function (c_name)
	{
		var cookieObj = LibraryThing.getCookieObject();
		delete cookieObj[c_name];
		LibraryThing.setCookieObject(cookieObj);
		
	};
	
	LibraryThing.addValueToCookie = function (c_name, value)
	{
		var cookieObj = LibraryThing.getCookieObject();
		var theCookie = cookieObj[c_name];
		theCookie.push(value);
		LibraryThing.setCookieObject(LT_array_unique(theCookie));
	};
	
	LibraryThing.removeValueFromCookie = function (c_name, value)
	{
		var cookieObj = LibraryThing.getCookieObject();
		var theCookie = cookieObj[c_name];
		var theindex = LT_in_array(value, theCookie)
		theCookie.splice(1, theindex);
		LibraryThing.setCookieObject(theCookie);
	};
	
	LibraryThing.setLocalTimeOffset = function()
	{
		var ldate = new Date();
		var offset = ldate.getTimezoneOffset() * -1;
		var lstring = ldate.toLocaleString();
		LibraryThing.ltSetCookie('localTimeOffset', offset);
	};
	
	LibraryThing.returnFalse = function()
	{
		return false;
	};
	
	
	LibraryThing.setSessionData = function(key, value, sync)
	{
		var url = '/ajax_setSessionData.php';
		var params = {
			key: key,
			value: value
		};
		var response = function(t) {
			//var rt = t.responseText;
		};
		
		if (sync)
		{
			basic_ajax_sync(url, params, response);
		}
		else
		{
			basic_ajax(url, params, response);
		}
	}

	
	// This function isn't finished...just stubbed out.
	LibraryThing.getSessionData = function(key) 
	{
		var url = '/ajax_getSessionData.php';
		var params = {
			key: key
		};
		var response = function(t) {
			var rt = t.responseText;
		};
		basic_ajax(url, params, response);	
	}
	
	
	LibraryThing.deferedJS = function(url)
	{
		var scriptElem = document.createElement('script');
		scriptElem.src = url;
		document.getElementsByTagName('head')[0].appendChild(scriptElem);
	}
	
} // end LibraryThing members

//LibraryThing.setLocalTimeOffset();

// Find a DOM object based on its ID.
// cross-browser as much as possible (ch)
function LT_findObj(objectId)
{
if(document.getElementById && document.getElementById(objectId))
	{
	// W3C DOM
	return document.getElementById(objectId);
	} 
else if (document.all && document.all(objectId))
	{
	// MSIE 4 DOM
	return document.all(objectId);
	} 
else if (document.layers && document.layers[objectId])
	{
	// NN 4 DOM.. note: this won't find nested layers
	return document.layers[objectId];
	}
return false;
} // getStyleObject

// Makes a perfect copy of an object (ch)
// usage: newObject = new cloneObject(originalObject);
function cloneObject (obj)
{
for (i in obj)
	{
	//if (typeof obj[i] == 'object') {
	//	this[i] = new cloneObject(obj[i]);
	//}
	//else
	this[i] = obj[i];

	//debug('cloning attribute: '+i);
	}
}

// Get the OBJECT which triggered the javascript event, if possible (ch)
function eventTrigger (e) {
    if (!e)
        e = event;
	if (!e)
		e = window.event;
	if (e.target) // W3C
		return e.target;
	if (e.srcElement)  //IE 
		return e.srcElement;
	else 
		return 0;
}
// cross-browser event validator
// Returns the current EVENT if possible.
function validEvent (e) {
		if (!e)
        	e = event;
		if (!e)
			e = window.event;
		if (e == null)
			return null;
		return e;
}

function validateEvent(e) { return validEvent(e); }

// Does nothing. Nice for certain occasions. (ch)
function nilEvent() {
	return;
}

/* 	sets class...can't get any more basic than that. 
 	It was doing more stuff...hence the need for a function. I'm not really crazy. (ch)
*/
function LT_changeClass(object, className)
{
	object.className = className;
}

// ========================================
// Prints to the Firebug console in Firefox. VERY useful to have.
function printfire(text) {
	console.log(text);
	/*
   	if (document.createEvent)
   	{
      printfire.args =  arguments;
      var ev = document.createEvent("Events");
      ev.initEvent("printfire", false, true );
      dispatchEvent(ev);
   	}
   	*/
}



// ==========================================
// Cookie Functions
var expireDate= new Date(2050, 10, 23);
function cookieVal(cookieName)
{
thisCookie = document.cookie.split("; ")
for (i=0; i<thisCookie.length; i++)
    {
    if (cookieName == thisCookie[i].split("=")[0])
        {
        return thisCookie[i].split("=")[1]
        }
    }
return 0;
}
function setCookie(cookieName,cookieContent,transientBoolean)
{
	var expireDate= new Date(2050, 10, 23);
	if (transientBoolean)
    	document.cookie = cookieName+"="+cookieContent;
	else
    	document.cookie = cookieName+"="+cookieContent+";expires="+expireDate.toGMTString()+";path=/";
}

function getCookie(name) { return cookieVal(name); }
function mouseX(evt) {
	if (evt.pageX) return evt.pageX;
	else if (evt.clientX)
	return evt.clientX + (document.documentElement.scrollLeft ?
	document.documentElement.scrollLeft :
	document.body.scrollLeft);
	else return null;
}

function getCookieAjax(name)
{
	var uid = LT_GetRandomID(5);
	var url = "/ajax_getCookie.php";
	var params = {
		c: name,
		uid: uid
	};
	var responseFunction = function(t) 
	{
		return t.responseText;
	};
	
	basic_ajax(url,params,responseFunction);
}

function setCookieAjax(name, value)
{
	var uid = LT_GetRandomID(5);
	var url = "/ajax_setCookie.php";
	var params = {
		cookiename: name,
		value: value,
		uid: uid
	};
	var responseFunction = function(t) 
	{
		return t.responseText;
	};
	
	basic_ajax_sync(url,params,responseFunction);
}


// Smart cookie handler
// This code is not yet finished. DO NOT USE! (ch)
function SmartCookieHandler() {

	this.setCookie = function (name, value, seconds) {

		if (typeof(seconds) != 'undefined') {
			var date = new Date();
			date.setTime(date.getTime() + (seconds*1000));
			var expires = "; expires=" + date.toGMTString();
		}
		else {
			var expires = "";
		}

		document.cookie = name+"="+value+expires+"; path=/";
	}

	this.getCookie = function (name) {

		name = name + "=";
		var carray = document.cookie.split(';');

		for(var i=0;i < carray.length;i++) {
			var c = carray[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(name) == 0) return c.substring(name.length,c.length);
		}

		return null;
	}

	this.deleteCookie = function (name) {
		this.setCookie(name, "", -1);
	}

}




function mouseY(evt) {
	if (evt.pageY) return evt.pageY;
	else if (evt.clientY)
	return evt.clientY + (document.documentElement.scrollTop ?
	document.documentElement.scrollTop :
	document.body.scrollTop);
	else return null;
}

// =======================================
// Hex to decimal converter
var hD="0123456789ABCDEF";
function d2h(d) {
	var h = hD.substr(d&15,1);
	while(d>15) {d>>=4;h=hD.substr(d&15,1)+h;}
	return h;
}
function h2d(h) {
	return parseInt(h,16);
}
function pad(number,length) {
    var str = '' + number;
    while (str.length < length)
        str = '0' + str;
    return str;
}

// =======================================
// Generate Unique/Random ID for page URLs (ch)
function getRandomNumber(range)
{
	return Math.floor(Math.random() * range);
}

function getRandomChar()
{
	var chars = "0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ";
	return chars.substr( getRandomNumber(62), 1 );
}

function LT_GetRandomID(size)
{
	var str = "";
	for(var i = 0; i < size; i++)
	{
		str += getRandomChar();
	}
	return str;
}

// ======================================
// parses a URLs query string into an associative array with key/value pairs
//    Useful for ripping out certain pairs or making sure there are no duplicates
//    when you add query arguments (ch)
function parseGetVars() {
    var getVars = location.search.substring(1).split("&");
    var returnVars = new Array();
    var i;
    for(i=0; i < getVars.length; i++) {
        var newVar = getVars[i].split("=");
				var myvar = new Array();
				
				myvar['key'] = unescape(newVar[0]);
				myvar['value'] = unescape(newVar[1]);
				returnVars[i] = myvar;
    }
    return returnVars;
}

// =======================================
// Other utils
function LT_preloadImages() { //v3.0
  var d=document; 
	if(d.images)
	{ 
		if(!d.MM_p) 
			d.MM_p=new Array();
    var i,j=d.MM_p.length;
		var a=LT_preloadImages.arguments; 
		for(i=0; i<a.length; i++)
    	if (a[i].indexOf("#")!=0)
			{ 
				d.MM_p[j]=new Image;
				d.MM_p[j++].src=a[i];
			}
	}
	
}

/*
	getElementsByClassName - http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/
    Written by Jonathan Snook, http://www.snook.ca/jonathan
    Add-ons by Robert Nyman, http://www.robertnyman.com

	To get all <a> elements in the document with a “info-links” class.
		getElementsByClassName(document, "a", "info-links");
	To get all div elements within the element named “container”, with a “col” and a “left” class.
		getElementsByClassName(document.getElementById("container"), "div", ["col", "left"]);
*/
function getElementsByClassName(oElm, strTagName, oClassNames) {
	try {
		var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
		var arrReturnElements = new Array();
		var arrRegExpClassNames = new Array();
		if(typeof oClassNames == "object"){
			for(var i=0; i<oClassNames.length; i++){
				arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames[i].replace(/\-/g, "\\-") + "(\\s|$)"));
			}
		}
		else{
			arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames.replace(/\-/g, "\\-") + "(\\s|$)"));
		}
		var oElement;
		var bMatchesAll;
		for(var j=0; j<arrElements.length; j++){
			oElement = arrElements[j];
			bMatchesAll = true;
			for(var k=0; k<arrRegExpClassNames.length; k++){
				if(!arrRegExpClassNames[k].test(oElement.className)){
					bMatchesAll = false;
					break;                      
				}
			}
			if(bMatchesAll){
				arrReturnElements.push(oElement);
			}
		}
		return (arrReturnElements)
    }
    catch(e) {
   		return null;
   	}
}

// Checks to make sure that an ISBN is a valid one using the ISBN checksum algorithm.
// Returns 'goodisbn', 'badisbn', or 'notanisbn'
// We should have it return a boolean eventually, but this is good for now
// It also doesn't check for ISBN-13s correctly yet. (ch)
function isbnCheck(input)
{
	// check if the user enters something that looks even vaguely similar to an ISBN
	regex=/^[0-9]{9,12}[0-9,x]$/i;
	if (regex.exec(input))
	{
		var prod = 0;
		var pieces = input.split('');
		// quick sanity check
		if ((pieces.length != 13) && (pieces.length != 10))
			return 'badisbn';
		// remove the ISBN-13 prefix
		if (pieces.length == 13)
		{
			var prefix = input.substr(0,3);
			if ((prefix == '978') || (prefix == '979') )
				pieces = pieces.slice(3);
			else
				return 'badisbn';
		}
		// now do math to come up with checksum digit
		for(var i = 0; i<pieces.length-1; i++)
		{
				var num = parseInt(pieces[i]);
				prod += (num * (i+1));
		}
		prod = prod % 11;
		var nm = pieces[pieces.length-1];
		if ((nm == 'x') || (nm == 'X'))
					nm = 10;
		prod = prod;
		if (prod == nm)
			return 'goodisbn';
		else
			return 'badisbn';
	}
	return 'notanisbn';
}


function LT_array_unique( array ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com)
    // +      input by: duncan
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Nate
    // *     example 1: array_unique(['Kevin','Kevin','van','Zonneveld','Kevin']);
    // *     returns 1: ['Kevin','van','Zonneveld']
    // *     example 2: array_unique({'a': 'green', 0: 'red', 'b': 'green', 1: 'blue', 2: 'red'});
    // *     returns 2: {'a': 'green', 0: 'red', 1: 'blue'}
    
    var key = '', tmp_arr1 = {}, tmp_arr2 = {};
    var val = '';
    tmp_arr1 = array;
    
  var __array_search = function (needle, haystack, strict) {
        var fkey = '';
      var strict = !!strict;
      for (fkey in haystack) {
          if ((strict && haystack[fkey] === needle) || (!strict && haystack[fkey] == needle) ) {
              return fkey;
          }
      }
      return false;
  }    
  
    for (key in tmp_arr1) {
        val = tmp_arr1[key];
        if (false === __array_search(val, tmp_arr2)) {
            tmp_arr2[key] = val;
        }
        
        delete tmp_arr1[key];
    }
    
    return tmp_arr2;
}

function LT_in_array(needle, haystack, strict) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // *     example 1: in_array('van', ['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: true
 
    var found = false, key, strict = !!strict;
 
    for (key in haystack) {
        if ((strict && haystack[key] === needle) || (!strict && haystack[key] == needle)) {
            found = key;
            break;
        }
    }
 
    return found;
}


// This implements CSS :hover psuedo-elements for IE and Opera, which do not handle them
// Note that this overrides any onmouseover and onmouseout functions that may have
// been applied to the element. Make sure that this is what you want to do.
// initMouseOvers(document, '*', 'ipe', 'ipeHover', 'ipe', false)
// -- Christopher Holland
function initMouseOvers(parentObject, childType, targetClass, mouseOverClass, mouseOutClass, includeAllBrowsers) 
{
	var ievc = function() {
		var version = 999; // we assume a sane browser
		if (navigator.appVersion.indexOf("MSIE") != -1)
		// bah, IE again, lets downgrade version number
		version = parseFloat(navigator.appVersion.split("MSIE")[1]);
		return version;
	};
	var iev = ievc();
	
	if ( ((Prototype.Browser.IE) && (iev < 8)) || (Prototype.Browser.Opera) || (includeAllBrowsers))
	{
		if ( !document.getElementById || !document.getElementsByTagName || !document.body.style ) {
			// If we can't get these things then we might as well give up. We have no hope.
			return;
		}
		//var objects = getElementsByClassName(document, "*", targetClass);
		try {
			var objects = getElementsByClassName(parentObject, childType, targetClass);
			var o, i = objects.length;
			while ( i-- ) 
			{
				o = objects[i];
				o.onmouseover = function() {LT_changeClass(this, mouseOverClass);}
				o.onmouseout = function() {LT_changeClass(this, mouseOutClass);}
			}
		}
		catch(e) {
		
		}
	}
}




// keep in mind that you can't alter the dom for a parent frame in all browsers so do some error checking
function getTopDocument(element)
{
var childElement = element;
var parentElement = childElement.parentNode;
var theTop = null;
if (parentElement !== null)
	{
	return getTopDocument(parentElement);
	}
else
	{
	if (window.parent === window.self)
		{
		return window;
		}
	else
		{
		return window.parent;
		}
	}
return theTop.document;
}
