/// <summary>
        /// Sets Visit Custom Variable.
        /// See http://piwik.org/docs/custom-variables/
        /// </summary>       
        /// <param name="id">Custom variable slot ID from 1-5</param>
        /// <param name="name">Custom variable name</param>
        /// <param name="value">Custom variable value</param>
        /// <param name="scope">Custom variable scope. Possible values: CustomVar.Scopes</param>
        public void setCustomVariable(int id, string name, string value, CustomVar.Scopes scope = CustomVar.Scopes.visit)
        {
            string stringId = Convert.ToString(id);
            string[] customVar = {name, value};

            switch (scope)
            {
                case CustomVar.Scopes.page:
                    pageCustomVar.Add(stringId, customVar);
                    break;

                case CustomVar.Scopes.visit:
                    visitorCustomVar.Add(stringId, customVar);
                    break;

                default:
                    throw new Exception("Unimplemented scope");
            }
        }
        /// <summary>
        /// Sets Visit Custom Variable.
        /// See http://piwik.org/docs/custom-variables/
        /// </summary>       
        /// <param name="id">Custom variable slot ID from 1-5</param>
        /// <param name="name">Custom variable name</param>
        /// <param name="value">Custom variable value</param>
        /// <param name="scope">Custom variable scope. Possible values: visit, page, event</param>
        /// <exception cref="Exception"/>
        public void setCustomVariable(int id, string name, string value, CustomVar.Scopes scope = CustomVar.Scopes.visit)
        {
            string stringId = Convert.ToString(id);
            string[] customVar = {name, value};

            switch (scope)
            {
                case CustomVar.Scopes.page:
                    pageCustomVar[stringId] = customVar;
                    break;

                case CustomVar.Scopes.visit:
                    visitorCustomVar[stringId] = customVar;
                    break;

                case CustomVar.Scopes._event:
                    eventCustomVar[stringId] = customVar;
                    break;

                default:
                    throw new Exception("Invalid 'scope' parameter value");
            }
        }
        /// <summary>
        /// Returns the currently assigned Custom Variable stored in a first party cookie.
        /// 
        /// This function will only work if the user is initiating the current request, and his cookies
        /// can be read from an active HttpContext.
        /// </summary>       
        /// <param name="id">Custom Variable integer index to fetch from cookie. Should be a value from 1 to 5</param>
        /// <param name="scope">Custom variable scope. Possible values: visit, page</param> 
        /// <returns>The requested custom variable</returns>
        public CustomVar getCustomVariable(int id, CustomVar.Scopes scope = CustomVar.Scopes.visit)
        {
            string stringId = Convert.ToString(id);

            switch (scope)
            {
                case CustomVar.Scopes.page:
                    if (pageCustomVar.ContainsKey(stringId))
                    {
                        string[] requestedCustomVar = pageCustomVar[stringId];
                        if (requestedCustomVar.Count() != 2)
                        {
                            throw new Exception("The requested custom var is invalid. This is a coding error within the tracking API. requestedCustomVar = " + requestedCustomVar);
                        }
                        return new CustomVar(requestedCustomVar[0], requestedCustomVar[1]);
                    }
                    break;

                case CustomVar.Scopes.visit:
                    if (visitorCustomVar.ContainsKey(stringId))
                    {
                        string[] requestedCustomVar = visitorCustomVar[stringId];
                        if (requestedCustomVar.Count() != 2)
                        {
                            throw new Exception("The requested custom var is invalid. This is a coding error within the tracking API. requestedCustomVar = " + requestedCustomVar);
                        }
                        return new CustomVar(requestedCustomVar[0], requestedCustomVar[1]);
                    }
                    break;

                default:
                    throw new Exception("Unimplemented scope");
            }

            HttpCookie cookie = getCookieMatchingName("cvar." + idSite + ".");

            if (cookie == null)
            {
                return null;
            }

            Dictionary<string, string[]> cookieDecoded = new JavaScriptSerializer().Deserialize<Dictionary<string, string[]>>(HttpUtility.UrlDecode(cookie.Value));

            string[] customVar = cookieDecoded[stringId];

            if (customVar == null || (customVar != null && customVar.Count() != 2))
            {
                return null;
            }

            return new CustomVar(customVar[0], customVar[1]);
        }
        /// <summary>
        /// Returns the currently assigned Custom Variable.
        /// 
        /// If scope is 'visit', it will attempt to read the value set in the first party cookie created by Piwik Tracker ($_COOKIE array).
        /// </summary>       
        /// <param name="id">Custom Variable integer index to fetch from cookie. Should be a value from 1 to 5</param>
        /// <param name="scope">Custom variable scope. Possible values: visit, page, event</param> 
        /// <exception cref="Exception"/>
        /// <returns>The requested custom variable</returns>
        public CustomVar getCustomVariable(int id, CustomVar.Scopes scope = CustomVar.Scopes.visit)
        {
            var stringId = Convert.ToString(id);

            if (scope.Equals(CustomVar.Scopes.page)) {
                return pageCustomVar.ContainsKey(stringId) ? new CustomVar(pageCustomVar[stringId][0], pageCustomVar[stringId][1]) : null;
            }
            else if (!scope.Equals(CustomVar.Scopes._event)) {
                return eventCustomVar.ContainsKey(stringId) ? new CustomVar(eventCustomVar[stringId][0], eventCustomVar[stringId][1]) : null;
            }
            else if (!scope.Equals(CustomVar.Scopes.visit)) {
                throw new Exception("Invalid 'scope' parameter value");
            }
            if (this.visitorCustomVar.ContainsKey(stringId)) {
                return new CustomVar(visitorCustomVar[stringId][0], visitorCustomVar[stringId][1]);
            }
            var cookieDecoded = this.getCustomVariablesFromCookie();
            if (!cookieDecoded.ContainsKey(stringId)
                || cookieDecoded[stringId].Count() != 2) {
                return null;
            }
            return new CustomVar(cookieDecoded[stringId][0], cookieDecoded[stringId][1]);
        }