/// <summary>
        ///     Gets an <see cref="ICaptchaValue" /> associated with the specified token.
        /// </summary>
        /// <param name="token">The specified token.</param>
        /// <param name="tokenType">The specified token type.</param>
        /// <returns>
        ///     An instance of <see cref="ICaptchaValue" />.
        /// </returns>
        public virtual ICaptchaValue GetValue(string token, TokenType tokenType)
        {
            Validate.ArgumentNotNullOrEmpty(token, "token");
            ICaptchaValue value;

            switch (tokenType)
            {
            case TokenType.Drawing:
                if (DrawingKeys.TryGetValue(token, out value))
                {
                    DrawingKeys.Remove(token);
                }
                break;

            case TokenType.Validation:
                if (ValidateKeys.TryGetValue(token, out value))
                {
                    ValidateKeys.Remove(token);
                }
                break;

            default:
                throw new ArgumentOutOfRangeException("tokenType");
            }
            return(value);
        }
        /// <summary>
        ///     Removes the specified token and <see cref="ICaptchaValue" /> to the storage.
        /// </summary>
        /// <param name="token">The specified token.</param>
        public bool Remove(string token)
        {
            Validate.ArgumentNotNullOrEmpty(token, "token");
            var remove     = DrawingKeys.Remove(token);
            var validation = ValidateKeys.Remove(token);

            return(remove || validation);
        }
        /// <summary>
        ///     Adds the specified token and <see cref="ICaptchaValue" /> to the storage.
        /// </summary>
        /// <param name="captchaPair">
        ///     The specified <see cref="KeyValuePair{TKey,TValue}" />
        /// </param>
        public virtual void Add(KeyValuePair <string, ICaptchaValue> captchaPair)
        {
            Validate.ArgumentNotNull(captchaPair.Value, "captchaPair");
            DrawingKeys.ClearIfNeed(MaxCount);
            ValidateKeys.ClearIfNeed(MaxCount);
            var entry = new KeyTimeEntry <string>(captchaPair.Key);

            DrawingKeys.Add(entry, captchaPair.Value);
            ValidateKeys.Add(entry, captchaPair.Value);
        }
        /// <summary>
        ///     Determines whether the <see cref="IStorageProvider" /> contains a specific token.
        /// </summary>
        /// <param name="token">The specified token.</param>
        /// <param name="tokenType">The specified token type.</param>
        /// <returns>
        ///     <c>True</c> if the value is found in the <see cref="IStorageProvider" />; otherwise <c>false</c>.
        /// </returns>
        public virtual bool IsContains(string token, TokenType tokenType)
        {
            Validate.ArgumentNotNullOrEmpty(token, "token");
            switch (tokenType)
            {
            case TokenType.Drawing:
                return(DrawingKeys.ContainsKey(token));

            case TokenType.Validation:
                return(ValidateKeys.ContainsKey(token));

            default:
                throw new ArgumentOutOfRangeException("tokenType");
            }
        }