/** var cookie = pulp.cookie.getInstance; */
pulp.Modules.cookie = 'cookie';

(function() {

  /**
   * @class  Object-oriented interface for getting and setting cookie values
   * @name pulp.cookie
   * @extends pulp.cls.Base
   * @requires pulp.base
   * @requires pulp.cls
   * @example
   *   var cookie = pulp.cookie.getInstance;
   *   var myCookie = cookie('fruit');
   *   myCookie.set('apples,oranges,bananas');
   *   // ...
   *   myCookie.set('mango,kiwi');
   *   // ..
   *   myCookie.get();
   */
  var cookie = pulp.cookie = pulp.cls.create(/** @lends pulp.cookie# */{
    /**
     * Return an object representing a cookie
     * @param {String} name  The name of the cookie
     * @param {String} [options]  expires, path, domain, secure 
     * @param {Number} [options.expires=30]  The number of days after which the browser should discard the cookie
     * @param {String} [options.path]  The url path to which to restrict the cookie access
     * @param {String} [options.domain]  The url domain to which to restrict the cookie access
     * @param {Boolean} [options.secure=false]  If true, require https
     * @constructor
     */
    initialize: function(name, options) {
      this.raw = name;
      options = options || {};
      this.options = {};
      this.setExpires(options.expires || 30);
      if (options.path) {
        this.setPath(options.path);
      }
      if (options.domain) {
        this.setDomain(options.domain);
      }
      this.setSecure(options.secure);

      cookie._cache[name] = this;
    },
    
    /**
     * Determine if a cookie has been set before (even if it is currently an empty string)
     * @return {Boolean}
     */
    isset: function() {
      return document.cookie.indexOf(this.raw + '=') > -1;
    },
    
    /**
     * Get the cookie as a string (if not set, return an empty string)
     * @return {String}
     */
    get: function() {
      var start = document.cookie.indexOf(this.raw + '=');
      
      if (start > -1) {
        var len = start + this.raw.length + 1;
        var end = document.cookie.indexOf(";", len);
        if (end == -1) {
          end = document.cookie.length;
        }
        return unescape(document.cookie.substring(len, end));
        
      } else {
        return '';
      }
    },
    
    /**
     * Set the cookie value to the given string
     * @param {String} value  The cookie value
     * @return {Boolean}  True if set properly and not expired
     */
    set: function(value) {
      document.cookie = this.raw + "=" + escape(value) +
        ";expires=" + this.options.expires +
        (this.options.path ? ";path=" + this.options.path : "") +
        (this.options.domain ? ";domain=" + this.options.domain : "") +
        (this.options.secure ? ";secure" : "");
      return this;
    },
    
    /**
     * Remove the cookie by marking it expired
     * @return {pulp.cookie}
     * @chainable
     */
    unset: function() {
      if (this.isset()) {
        document.cookie = this.raw + "=" +
        (this.options.path ? ";path=" + this.options.path : "") +
        (this.options.domain ? ";domain=" + this.options.domain : "" ) +
        ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
      }
      return this;
    },
    
    /**
     * Set the expires date
     *
     * @param {Number} [expires=30]  The number of days after which the browser should discard the cookie
     * @return this
     */
    setExpires: function(expires) {
      this.options.expires = new Date(new Date().getTime() + (expires * 1000 * 60 * 60 * 24)).toGMTString();
      return this;
    },
    
    /**
     * Set the path
     *
     * @param {String} [options.path]  The url path to which to restrict the cookie access
     * @return this
     */    
    setPath: function(path) {
      this.options.path = path;
      return this;
    },
    
    /**
     * Set the domain
     *
     * @param {String} domain  The url domain to which to restrict the cookie access
     * @return this
     */    
    setDomain: function(domain) {
      this.options.domain = domain;
      return this;
    },
    
    /**
     * Set the cookie's secure status
     *
     * @param {Boolean} [secure=false]  If true, require https
     * @return this
     */    
    setSecure: function(secure) {
      this.options.secure = !!secure;
      return this;
    },
    
    /**
     * Append a string to the current cookie value
     * @param {String} value  The string to append to the cookie value
     * @return {Boolean}  True if setting was successful 
     */
    append: function(value) {
      return this.set(this.get() + value);
    }
  });

  cookie.extend(/** @scope pulp.cookie */{
    /**
     * Internal store of pulp.cookie objects
     * @type {Object}
     */
    _cache: {},
    /**
     * Return an object representing a cookie
     * @param {String} name  The name of the cookie
     * @param {String} [options]  expires, path, domain, secure 
     * @param {String} [options.expires=30]  The number of days after which the browser should discard the cookie
     * @param {String} [options.path]  The url path to which to restrict the cookie access
     * @param {String} [options.domain]  The url domain to which to restrict the cookie access
     * @param {Boolean} [options.secure=false]  If true, require https
     * @return {pulp.cookie}
     */
    getInstance: function(name, options){
      return cookie._cache[name] || new cookie(name, options);
    }
  });

})();