
/*

DISCLAIMER: THESE JAVASCRIPT FUNCTIONS ARE SUPPLIED 'AS IS', WITH 
NO WARRANTY EXPRESSED OR IMPLIED. YOU USE THEM AT YOUR OWN RISK. 
PAUL STEPHENS DOES NOT ACCEPT ANY LIABILITY FOR 
ANY LOSS OR DAMAGE RESULTING FROM THEIR USE, HOWEVER CAUSED. 

Paul Stephens' cookie-handling object library

Version 2.1
2.0 - Introduces field names
2.1 - Fixes bug where undefined embedded fields[] elements weren't written to disk

www.paulspages.co.uk 

TO USE THIS LIBRARY, INSERT ITS CONTENTS IN THE <HEAD> SECTION 
OF YOUR WEB PAGE SOURCE, BEFORE ANY OTHER JAVASCRIPT ROUTINES.

(C) Paul Stephens, 2001-2003. Feel free to use this code, but please leave this comment block in. This code must not be sold, either alone or as part of an application, without the consent of the author.

*/

function cookieObject(name, expires, accessPath) {
	var i
	var j
	this.name = name
	this.fieldSeparator = "#"
	this.found = false
	this.expires = expires
	this.accessPath = accessPath
	this.rawValue = ""
	this.fields = new Array()
	this.fieldnames = new Array() 
	if (arguments.length > 3) { // field name(s) specified
	  j = 0
	  for (i = 3; i < arguments.length; i++) {
	    this.fieldnames[j] = arguments[i]    
	    j++
	  }
	  this.fields.length = this.fieldnames.length 
	}
	this.read = ucRead
	
	this.write = ucWrite
	
	this.remove = ucDelete
	this.get = ucFieldGet
	this.put = ucFieldPut
	this.namepos = ucNamePos
	this.read()
}
	


function ucFieldGet(fieldname) {
	var i = this.namepos(fieldname)
	if (i >=0) {
	  return this.fields[i]
	} else {
	  return "BadFieldName!"
	}
}



function ucFieldPut (fieldname, fieldval) {
	var i = this.namepos(fieldname)
	if (i >=0) {
	  this.fields[i] = fieldval
	  return true
	} else {
	  return false
	}
}



function ucNamePos(fieldname) {
	var i 
	for (i = 0; i < this.fieldnames.length; i++) {
	  if (fieldname == this.fieldnames[i]) {
	    return i
	  }
	}
	return -1
}



function ucWrite() {      
	  var cookietext = this.name + "=" 
	
	// concatenate array elements into cookie string
	
	// Special case - single-field cookie, so write without # terminator
	if (this.fields.length == 1) {
	  cookietext += escape(this.fields[0])
	  } else { // multi-field cookie
	    for (i= 0; i < this.fields.length; i++) {
	      cookietext += escape(this.fields[i]) + this.fieldSeparator }
	  }
	
	
	// Set expiry parameter, if specified
	    if (this.expires != null) {  
	      if (typeof(this.expires) == "number") { // Expiry period in days specified  
	        var today=new Date()     
	        var expiredate = new Date()      
	        expiredate.setTime(today.getTime() + 1000*60*60*24*this.expires)
	        cookietext += "; expires=" + expiredate.toGMTString()
	      } else { // assume it's a date object
	        cookietext +=  "; expires=" + this.expires.toGMTString()
	      } // end of typeof(this.expires) if
	    } // end of this.expires != null if 
	   
	// add path, if specified
	   if (this.accessPath != null) {
	   cookietext += "; PATH="+this.accessPath }
	
	// write cookie
	   // alert("writing "+cookietext)
	   document.cookie = cookietext 
	   return null  
}



function ucRead() {
	  var search = this.name + "="                       
	  var CookieString = document.cookie            
	  this.rawValue = null
	  this.found = false     
	  if (CookieString.length > 0) {                
	    offset = CookieString.indexOf(search)       
	    if (offset != -1) {                         
	      offset += search.length                   
	      end = CookieString.indexOf(";", offset)   
	      if (end == -1) {  // cookie is last item in the string, so no terminator                        
	       end = CookieString.length }              
	      this.rawValue = CookieString.substring(offset, end)                                   
	      this.found = true 
	      } 
	    }
	   
	if (this.rawValue != null) { // unpack into fields
	
	  var sl = this.rawValue.length
	  var startidx = 0
	  var endidx = 0
	  var i = 0
	
	// Special case - single-field cookies written by other functions,
	// so without a '#' terminator
	
	if (this.rawValue.substr(sl-1, 1) != this.fieldSeparator) {
	  this.fields[0] = unescape(this.rawValue)
	  } else { // separate fields
	
	  do  
	  {
	   endidx = this.rawValue.indexOf(this.fieldSeparator, startidx)
	   if (endidx !=-1) {
	     this.fields[i] = unescape(this.rawValue.substring(startidx, endidx))
	     i++
	     startidx = endidx + 1}
	  }
	  while (endidx !=-1 & endidx != (this.rawValue.length -1));
	}
	} // end of unpack into fields if block
	  return this.found
} // end of function



function ucDelete() {
	  this.expires = -10
	  this.write()
	  return this.read()
}



/*
*********** IT'S OK TO REMOVE THE CODE BELOW HERE IF YOUR PAGE 
DOESN'T USE cookieList() OBJECTS OR THE findCookieObject() FUNCTION.
*/



function findCookieObject(cName, cObjArray) {
	/* 
	This function finds a named cookie among the objects
	pointed to by a cookieList array (see below).
	
	Parameters are the cookie name to search for (a string), and an array created with 
	the new cookieList() constructor (see below)
	
	NOTE - if you're only dealing with a specific, named cookie, then it's
	more efficient to ceate a single cookieObject directly with that name,
	and check its .found property to see if it already exists on this client.
	
	This function is for when you've created an all-cookies array anyway,
	and now want to check whether a specific cookie is present.
	
	It returns a pointer to the cookieObject if found, or null if not found.
	*/
	
	var cpointer = null, i
	for (i in cObjArray) {
	  if (cName == cObjArray[i].name) {
	    cpointer = cObjArray[i]
	  }
	}
	return cpointer
}



function cookieList() {
	/* 
	This constructor function creates a cookieObject object (see below) 
	for each cookie in document.cookie,
	and returns an array of pointers to the objects.
	
	You can use it to load all the cookies available to a page, then walk through them.
	
	Example usage:
	
	cookList = new cookieList()
	for (i in cookList) {
	 document.write(cookList[i].name + " " + cookList[i].fields[0] + "
	")
	}
	
	*/
	
	var i = 0
	var rawstring
	var offset = 0
	var start
	var newname
	cpointers = new Array()
	rawstring = document.cookie
	if (rawstring.length > 0) {
	  do {
	   start = rawstring.indexOf("=", offset)
	   if (start != -1) { // another cookie found in string
	     // get cookie string up to end of current cookie name
	     newname = rawstring.substring(0, start) 
	     if (offset > 0) { 
	       // if not first cookie in string, remove previous cookie data from substring
	       // subsequent cookie names have a space before them (just a little browser foible!)
	       newname = newname.substring(newname.lastIndexOf(";")+2, start)
	     }     
	     cpointers[i] = new cookieObject(newname)
	     offset = start + 1
	     i++
	   }
	  } while (start != -1)
	} // end rawstring.length > 0
	return cpointers
} //end function



