/*
 * Simple class handling cookie storing and reading for name, value (string, string) pairs
 *
 * To use:
 * construct a cookie object with options object containing at least name and path.  (can also set
 * expires (num days from today).
 *
 * then set keys to values with set(key, value) -- automatically updates cookie.
 * also supports removing a value and explicitly clearing a cookie.
 */

"use strict";

/*globals window, document, $, jQuery */

var Cookie = (function () {

	//static constants:
	//note these two chars will change when URI encoded (currently used below), so we should be safe
	var pairDelimiter = '@',
		keyValueDelimiter = ':',
		cookies = {};

	//static methods:
	function escapeCookieValue(val) {
		return encodeURIComponent(val);
	}

	function unescapeCookieValue(val) {
		return decodeURIComponent(val);
	}

	//class ctor:
	return function (opts) {
		var cookieRegEx,
			options,
			cookieData = {},
			predefined;

		if (!opts || !opts.name || !opts.path) {
			throw 'invalid name and path for cookie';
		}

		predefined = cookies[opts.name]; 
		if (predefined) {
			predefined.setPath(opts.path);
			return predefined;
		}

		options = jQuery.extend({
			expires: 3
		}, opts);


		options.expires *= 86400000; //num days * num milliseconds in a day
		cookieRegEx = new RegExp(options.name + '=(.*?)(?:;|$)');

		function write() {
			var date = new Date(), tokens = [], prop, first = true, cookieString;
			date.setTime(date.getTime() + options.expires);
			for (prop in cookieData) {
				if (Object.hasOwnProperty.call(cookieData, prop)) {
                    if (!first) {
                        tokens.push(pairDelimiter);
                    }
				}
				tokens.push(escapeCookieValue(prop));
				tokens.push(keyValueDelimiter);
				tokens.push(escapeCookieValue(cookieData[prop]));
				first = false;
			}
			cookieString = options.name + "=" + tokens.join('') + "; expires=" + date.toGMTString() + "; path=" + options.path;
			//console.log('cookieString:', cookieString)
			document.cookie = cookieString;
			//console.log('document.cookie', document.cookie);
		}

		function read() {
			var cookie = (document.cookie.match(cookieRegEx) || [])[1], pairs, i, pair;
			if (cookie) {
				pairs = cookie.split(pairDelimiter);
				for (i = 0; i < pairs.length;) {
					pair = pairs[i].split(keyValueDelimiter);
					cookieData[unescapeCookieValue(pair[0])] = unescapeCookieValue(pair[1]);
				    i = i + 1;
                }
				return true;
			}
			return false;
		}

		function clear() {
			document.cookie = options.name + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=' + options.path;
			//console.log('cleared', options.name +'=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=' + options.path, document.cookie);
		}

		function set(name, val) {
			if (name) {
				cookieData[name] = val;
				//console.log(cookieData);
				write();
			}
		}

		function get(name) {
			return cookieData[name];
		}

		function remove(name) {
			var prop;
			if (name) {
				delete cookieData[name];
				for (prop in cookieData) {
					if (Object.hasOwnProperty.call(cookieData, prop)) {
						write(); //rewrite the cookie, there's still some properties left
						return;
					}
				}
				clear(); //no properties were found (this was the last), so clear the cookie
			}
		}
		function setPath(path) {
			if (path !== options.path) {
				options.path = path;
				write();
			}
		}

		read();

		return (cookies[options.name] = {
			clear: clear,
			set: set,
			get: get,
			remove: remove,
			read: read,
			setPath: setPath
		});
	};
}());