// Created with MonoDevelop
//
//    Copyright (C) 2019 Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using Hiperscan.Unix;


namespace Hiperscan.Common.Checksum
{
    public abstract class BaseChecksum
    {
        public enum HashType 
        { 
            MD5, 
            SHA512, 
            SHA256, 
            SHA384, 
            SHA1 
        }

        protected BaseChecksum(HashType type, string salt = null, string api_key_hash = null, string api_key = null)
        {
            this.CurrentHashAlogrithm = BaseChecksum.GetAlgorithm(type);
            this.Salt = salt;
            this.Init(api_key_hash, api_key);
        }

        public abstract string ComputeHash();
        public abstract bool Verifiy();

        private void Init(string api_key_hash,  string api_key)
        {
            if (string.IsNullOrEmpty(api_key_hash) == true && string.IsNullOrEmpty(api_key) == true)
                return;

            if (string.IsNullOrEmpty(api_key_hash) == true)
                throw new ArgumentException(Catalog.GetString("The hash value for API key must not empty"));

            if (string.IsNullOrEmpty(api_key) == true)
                throw new ArgumentException(Catalog.GetString("The value for API key must not empty"));

            string hash = BitConverter.ToString(this.CurrentHashAlogrithm.ComputeHash(Encoding.ASCII.GetBytes(api_key)));

            if (api_key_hash != hash)
                throw new ArgumentException(Catalog.GetString("Cannot generate checksum: Invalid API key."));
        }


        protected List<byte> GenerateSalt()
        {
            List<byte> buf = new List<byte>();

            if (string.IsNullOrEmpty(this.Salt) == false)
                buf.AddRange(Encoding.ASCII.GetBytes(this.Salt));

            return buf;
        }

        private static HashAlgorithm GetAlgorithm(HashType type)
        {
            HashAlgorithm algorithm = null;

            switch (type)
            {
                case HashType.MD5:
                    algorithm = MD5.Create();
                    break;

                case HashType.SHA1:
                    algorithm = SHA1.Create();
                    break;

                case HashType.SHA256:
                    algorithm = SHA256.Create();
                    break;

                case HashType.SHA384:
                    algorithm = SHA384.Create();
                    break;

                case HashType.SHA512:
                    algorithm = SHA512.Create();
                    break;
            }

            return algorithm;
        }

        public static string GeneerateApiKeyHash(HashType type, string api_key)
        {
            HashAlgorithm algorithm = BaseChecksum.GetAlgorithm(type);
            return BitConverter.ToString(algorithm.ComputeHash(Encoding.ASCII.GetBytes(api_key)));
        }

        public HashAlgorithm CurrentHashAlogrithm { get; set; }
        private string Salt                       { get; set; }
    }
}
