/* 
 *  	Class.Cookie.js
 * 	
 * 	Utility class for working with cookies.  Stores multiple application-states/properties
 *	in one cookie value using name=value pairs delimited by : and & respectively
 *
 * 	Fernan Fernandez.  Monday, November 26, 2007
 */




/* Constructor:	
 * Cookie( name, document, expires, path, domain, secure ) 
 *
 * Creates a cookie object we can use to save and retrieve application state.  Application
 * state is created by attaching properties to this object, then calling the save() function
 * to commit it to the cookie.
 *
 * If constructor is called with the name of a cookie that already exists, that cookie
 * and all application state associated with it is loaded.
 */

function Cookie( name, document, expires, path, domain, secure )
{
	this.$document  = document;
	this.$name	= name;

	// defaults
	
	// TODO
	// if a cookie already exists with the same name, we should retrieve these attributes
	// for that cookie to prevent us from overwriting and accidentally modifying those values
	// when the save() function is called.
	
	if( expires ) 
		this.$expiration = new Date( (new Date() ).getTime() + expires * 3600000 );
	else
		this.$expiration = null;

	this.$path 	= ( path ) ? path : '/';
	this.$domain	= ( domain ) ? domain : null;
	this.$secure	= ( secure ) ? true   : false;
}

/* Method: save()  
 * 
 * This method is called to convert properties defined for the cookie object into name=value pairs
 * to be stored in the cookie.  Throughout the application, properties can be added dynamically
 * 
 * 	ie. cookieObj.visits = 200;
 *
 * Once all properties or application state has been created with values, calling the Save() method
 * commits them by writing it out to the cookie.
 *
 */

Cookie.prototype.save = function() 
{
	var cookieval = "";

	// Basically, whenever we have a state variable we want to maintain/store, all we have to do
	// is dynamically create a property for the current Cookie object.  When this function is called,
	// it loops through the properties of this object and concatenates them into one big string
	// that we can use to store as a value to our cookie.  Earlier we made a decision to prepend
	// predefined properties with a '$' dollar sign.  This allows us to exclude them into our
	// cookie value string.

	// Lets loop through all the properties of this object, if it's not a predefined property or a method,
	// append it to the cookieval string and store the whole string as a value in our cookie.

	for( var prop in this ) 
	{
		//alert(prop);
		if(  (prop.charAt(0) == '$')  || (  typeof this[ prop ]  == 'function'  )   ) {
			continue;
		}
		if( cookieval != "" ) 
			cookieval += '&';

		cookieval += prop + ':' + escape( this[prop] );
	}

	// Build the actual cookie string

	var cookie = this.$name + '=' + cookieval;


	// build cookie attributes

	if( this.$expiration ) 
		cookie += '; expires=' + this.$expiration.toGMTString();
	if( this.$path )
		cookie += '; path=' + this.$path;
	if( this.$domain )
		cookie += '; domain=' + this.$domain;
	if( this.$secure ) 
		cookie += '; secure=' + this.$secure;

	// Save the cookie
	this.$document.cookie = cookie;
}

/* Method:	load()
 *
 *		Reverses the store() function.  Get the named cookie's value and split
 *		it into our application's name=value states.
 *
 * 		Returns true on success, or false if there is no cookie associated 
 *		with this document.
 */

Cookie.prototype.load = function()
{
	//alert("Cookie.load()");
	var allCookies = this.$document.cookie;

	if( allCookies == '' ) return false;

	// document.cookie contains a semi-colon delimeted list of all cookies associated
	// with this document.
	
	var start = allCookies.indexOf( this.$name + '=' );

	// no cookie of that name
	if( start == -1 ) return false;
	
	// skip up to the value string
	start += this.$name.length + 1;

	// find where the value string ends
	var end = allCookies.indexOf( ';', start );

	// this cookie is last in the list, no need to find separator.
	if( end == -1 ) end = allCookies.length;

	// now extract the value string of this cookie.
	var cookieval = allCookies.substring( start, end );


	/* We now have our cookie's value, now we need to extract our individual state
	 * information which are name=value pairs delimeted by ':' and '&' symbols.  
   	 * First, we use the split() function to split this big string into
	 * name:value pairs through the '&' symbol, then create a two-dimensional array
 	 * separating name from value through the ':' symbol.  Then we populate the
	 * property list of this object using the first index of the 2-d array as the
	 * property name and the second one as it's value.  
	 *
	 * After calling the load function, state variables should be accessible as object
	 * properties like 
	 *			var visits = cookieObj.visits;
	 */

	var a = cookieval.split( '&' );		// 1-d array containing name:value pairs

	for( var i=0; i < a.length; i++ )
	{
		a[i] = a[i].split( ':' );	// 2-d array containing a[0] = name, a[1] = value
	}

	/* Now that we have a hash table of names mapped to values, we need to populate the
	 * current object's property list.  Unescape() to clean cookie values of any illegal characters.
	 */

	for( var i=0; i < a.length; i++ ) 
	{
		this[a[i][0]] = unescape( a[i][1] );
	}

	return true;
}

/* Invalidate cookie */

Cookie.prototype.remove = function() 
{
	var cookie;

	cookie = this.$name + '=';

	if( this.$path ) 
		cookie += '; path=' + this.$path;
	if( this.$domain )
		cookie += '; domain=' + this.$domain;
	
	cookie += '; expires=Fri, 02-Jan-1970 00:00:00 GMT';

	// reset this document cookie
	this.$document.cookie = cookie;
}

// TODO
// Need a method to discover property names that are saved in this cookie.
// Below is a test

Cookie.prototype.getPropertyList = function() 
{
	propertyList = new Array();
	var i = 0;
	for( var prop in this ) 
	{
		if((prop.charAt(0) == '$') || (typeof this[prop] == 'function')) continue;
		propertyList[i++] = prop;
		//alert(prop);
	}
	
	alert("CookieObj Properties: \n" + propertyList.join("\n"));
}

// END Class.Cookie