/** 
* cookie script for interfaces needing to set & read multiple values
* cookie script based on O'reilly Definitive javascript. 
* modified to remember cookie set info, assignment of key/vals and store with same method, assignment
* of multiple key/val pairs, true/false tests for cookie
*/

/**
*getCookie and store vals in object
*remember name, daysToLive, path, domain, secure 
*/
function CookieManager(name, daysToLive, path, domain, secure) {
    
    //confirm can read/set cookie
    if(!CookieManager.enabled()){return;}
    this.$name = name;  
    this.$daysToLive = daysToLive || false;
    this.$path = path || false;
    this.$domain = domain || false;
    this.$secure = secure || false;
    this.getCookie();
} 

CookieManager.prototype.getCookie = function() {
    var allcookies, cookies, cookie, cookieval;
    allcookies = document.cookie;
    if(allcookies === "") {return;}
    // check for name in string of all cookies
    cookies = allcookies.split(';');
    cookie = null;
    
    for(var i = 0; i < cookies.length; i++) {
        if (cookies[i].match(this.$name + "=")){
            cookie = cookies[i];
            //ie adds white space before each cookie
            cookie = cookie.replace(/^\s/, '');
            this.$exists = true;
            break;
        }
    }
    // if no matching cookie, quit now
    if (cookie === null) {
        //or error message
        this.$exists = false;
        return;
    }
    //remove leading &
    cookieval = cookie.substring(this.$name.length+1);
    //for newly initialised cookie
    if(!cookieval.match('&')){return;}
    
    var a = cookieval.split('&');    // array of name/value pairs
    
    //
    for(var j=1; j < a.length; j++) { // break each pair into an array
        a[j] = a[j].split(':');
        //set the names and values as properties of this Cookie object
        this[a[j][0]] = decodeURIComponent(a[j][1]);
        
    }
 };

/**
*daysToLive, path, domain, secure are assigned when the cookie object is instantiated
*arguments - 0, 1, or 2 arguments
*0 arguments =  write cookie with already stored values
*1 argument = obj of key value pairs to store
*2 arguments = a single key value pair
*all key val pairs  inc. object properties, values should be strings
*/
CookieManager.prototype.setCookie = function() {
    var args, key, value, obj;
    
    args = arguments.length;    
        if(args === 2){
            key = arguments[0];
            value = arguments[1];
            //check if key/val pair
            if(key && (key !== '') && (typeof key === 'string') && value && (value !== '')){
                this[key] = value;
            }
            else{
                throw "Invalid arguments. Expected pairs of key value strings";
            }
        }
    
        else if(args ===1){
             obj= arguments[0];
            //check if Object
            if(obj.constructor !== Object){
                throw "Invalid argument. Expected Object containing properties and values, not a " + arguments[0].constructor;
            }
            for(var i in obj){
                this[i] = obj[i];
            }
        }
        //check if too many arguments
        else if(args > 2){ 
            throw "Too many arguments. Multiple key value pairs must be handled via an object";
        }

        //store the cookie
        document.cookie = this.toString();
    
};

/**
 * Generate a string representation for the cookie. This can be
 * use to set document.cookie.
 */
CookieManager.prototype.toString = function() {
    //construct cookie from Cookie object properties
    var cookie, expires, cookieval;

    cookieval = "";
    
    for (var prop in this) {
        // Ignore properties with names that begin with '$' and also methods
        if ((prop.charAt(0) === '$') || ((typeof this[prop]) === 'function')){ 
            continue;
        }
        cookieval += '&' + prop + ':' + encodeURIComponent(this[prop]);
    }

    cookieString = this.$name + '=' + cookieval; 

    //expires = deprecated, but max-age not supported by ie
    if (this.$daysToLive) { 
        var date = new Date();
        date.setTime(date.getTime()+(this.$daysToLive*24*60*60*1000));
        expires = "; expires=" + date.toGMTString();
    } else {
        expires = "";
    }
    cookieString += expires;

    if (this.$path) {  cookieString += "; path=" + this.$path;}
    if (this.$domain){ cookieString += "; domain=" + this.$domain;}
    if (this.$secure){ cookieString += "; secure";}

    return cookieString;
}

/**
 * delete properties of the Object, and remove the cookie
 * removing a cookie requires the same (path, domain, secure) values passed to setCookie().
 */
CookieManager.prototype.remove = function() {
    // Delete the properties of the Cookie object
    for(var prop in this) {
        if (prop.charAt(0) !== '$' && typeof this[prop] !== 'function'){ 
            delete this[prop];
        }
    }
    //note, the stored persistent time is overwritten
    //could write value directly rather than store
    this.$daysToLive = -1;
    this.setCookie( );
};

//read the value of a key
CookieManager.prototype.readKey = function(key){
    if(key){
        return this[key];
    }
};

// remove subkey
CookieManager.prototype.removeKey = function() {
    for(var i=0; i< arguments.length; i++){
        key = arguments[i];
        if((key !== '') && (typeof key === 'string')){
            if(this[key]){
                delete this[key];
            }
        }
    }
    
    this.setCookie();
};

/**
 * static method attempts to determine whether cookies are enabled.
 * It returns true if they appear to be enabled and false otherwise.
 * A return value of true does not guarantee that cookies actually persist.
 * Nonpersistent session cookies may still work even if this method 
 * returns false. 
 */
CookieManager.enabled = function() {
    // Use navigator.cookieEnabled if this browser defines it
    if (navigator.cookieEnabled !== undefined) {
         return navigator.cookieEnabled;
      }

    // If we've already cached a value, use that value
    if (CookieManager.enabled.cache !== undefined) {
        return CookieManager.enabled.cache;
      }

    // Otherwise, create a test cookie with a lifetime
    document.cookie = "testcookie=test";
   
    // Now see if that cookie was saved
    var cookies = document.cookie;
    if (cookies.indexOf("testcookie=test") === -1) {
        return CookieManager.enabled.cache = false;
    }
    else {
        // delete test cookie
        document.cookie = "testcookie=test; expires=Thu, 01-Jan-1970 00:00:01 GMT";
        return CookieManager.enabled.cache = true;
    }
};

//alt to checking for value, scope for confusion? ie. value from object not cookie
CookieManager.prototype.exists = function(key){
    if(key in this){ return true;}
    else {return false;}
};

/**
* strings, to serialise into a set of keyvals for saving sets of information, ie. nested subkeys.
*/
CookieManager.prototype.keySet = function(){
    var setVal='', key;
    for(var i=0; i< arguments.length; i++){
        key = arguments[i];
        if((key !== '') && (typeof key === 'string')){
            if(this[key]){
                setVal += '@' + key + '-' + this[key];
            }
        }
    }

    return setVal;
};

/**
* diagnostic - return cookie properties as string
*/
CookieManager.prototype.cookieVals = function(){
    var cookieProps='';
    for(var i in this){
        if((typeof this[i]) !== 'function'){
           cookieProps += i + '=' + this[i] + '\n';
        }
    }
    return cookieProps;
}

/**
* generic event function
*/
function addEvent(obj,evt,fn){
    if(obj.addEventListener){
        obj.addEventListener(evt, fn, false);
    }
    else if(obj.attachEvent){
        obj.attachEvent('on' + evt,fn);
    }
}

var cookieManagerLoaded=true;

