/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de>                                */
/* This work has been released under the CC0 1.0 Universal license!           */
/******************************************************************************/

using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;

using com.muldersoft.slunkcrypt.gui.utils;

namespace com.muldersoft.slunkcrypt.gui.process
{
    public static class PasswordGen
    {
        private static readonly TimeSpan TIMEOUT = TimeSpan.FromSeconds(180);

        private const string COMMAND_PASSWRD = "-p";

        // =============================================================================
        // Exception classes
        // =============================================================================

        public class GenerationFailedException : IOException
        {
            public GenerationFailedException(string message) : base(message)
            {
            }
        }

        // =============================================================================
        // Public methods
        // =============================================================================

        public static async Task<string> GeneratePassword(int length)
        {
            if (length <= 0)
            {
                throw new ArgumentOutOfRangeException("Password length must be a positive value!");
            }
            using (FileStream executableFile = ExecutableHelper.GetExecutableFile())
            {
                string[] arguments = new string[] { COMMAND_PASSWRD, string.Format("{0:D}", length) };
                Tuple<int, string[]> result = await ProcessRunner.ExecAsnyc(executableFile.Name, arguments, null, null, ProcessPriorityClass.BelowNormal, TIMEOUT);
                if (result.Item1 == 0)
                {
                    foreach (string password in result.Item2)
                    {
                        if ((password.Length >= length) && (!IsWeakPassword(password)))
                        {
                            return password;
                        }
                    }
                }
                throw new GenerationFailedException("Failed to generate password string!");
            }
        }

        public static bool IsWeakPassword(string password)
        {
            int flags = 0;
            if (!string.IsNullOrEmpty(password))
            {
                foreach (char c in password)
                {
                    if (char.IsLetter(c))
                    {
                        flags |= char.IsUpper(c) ? 0x2 : 0x1;
                    }
                    else
                    {
                        flags |= char.IsDigit(c) ? 0x8 : 0x4;
                    }
                }
            }
            return (flags != 0xF);
        }
    }
}