﻿using System;
using System.Collections.Generic;

namespace NetChris.Security.Cryptography
{
    /// <summary>
    /// Factory for <see cref="IPasswordHasher"/>.
    /// </summary>
    public static class PasswordHashing
    {
        private static readonly IDictionary<string, IPasswordHasher> RegisteredPasswordHashers
            = new Dictionary<string, IPasswordHasher>();

        /// <summary>
        /// Gets the password hasher for the given <paramref name="algorithmIdentifier">algorithm identifier</paramref>.
        /// </summary>
        /// <param name="algorithmIdentifier">The algorithm identifier.</param>
        /// <returns>IPasswordHasher.</returns>
        /// <exception cref="NotSupportedException"><paramref name="algorithmIdentifier"/> is not a recognized algorithm identifier.</exception>
        public static IPasswordHasher GetPasswordHasher(string algorithmIdentifier)
        {
            if (RegisteredPasswordHashers.ContainsKey(algorithmIdentifier))
            {
                return RegisteredPasswordHashers[algorithmIdentifier];
            }

            throw new NotSupportedException("\"" + algorithmIdentifier + "\" is not a recognized algorithm identifier.");
        }

        // *** To change the current standard password hasher:
        // 1. change _currentStandardPasswordHasher
        // 2. Make sure that the previous standard hasher is registered with _registeredPasswordHashers in the static constructor
        // ReSharper disable once InconsistentNaming
        private static readonly IPasswordHasher _currentStandardPasswordHasher =
            new Pbkdf2PasswordHasher20160319();

        static PasswordHashing()
        {
            RegisteredPasswordHashers[_currentStandardPasswordHasher.AlgorithmIdentifier] = _currentStandardPasswordHasher;
        }

        /// <summary>
        /// The current standard password hasher algorithm identifier
        /// </summary>
        /// <remarks>
        /// This is used primarily to check for whether a stored password hash is using
        /// the 'current standard' algorithm.
        /// </remarks>
        public readonly static string CurrentStandardPasswordHasherAlgorithmIdentifier =
            _currentStandardPasswordHasher.AlgorithmIdentifier;

        /// <summary>
        /// Gets the current standard <see cref="IPasswordHasher">password hasher</see>.
        /// </summary>
        /// <value>The current standard.</value>
        public static IPasswordHasher CurrentStandardHasher
        {
            get
            {
                return _currentStandardPasswordHasher;
            }
        }
    }
}
