using System;
using System.IO;
using System.Diagnostics;
using System.Collections;
using System.Security.Cryptography;

namespace BfEngine
{
	public static class Utils
	{
		public static int ExecuteProcess(StringView executable, StringView commandLine)
		{
			Log.Info("Executing: {0} {1}", executable, commandLine);
			var process = scope SpawnedProcess();
			var processStartInfo = scope ProcessStartInfo();
			processStartInfo.SetFileName(executable);
			processStartInfo.SetArguments(commandLine);
			switch (process.Start(processStartInfo)) {
			case .Ok:
				break;
			case .Err:
				return -1;
			}
			process.WaitFor();
			return process.ExitCode;
		}

		public static bool ReadBinaryFile(StringView filename, out uint8[] data)
		{
			data = null;
			var file = scope FileStream();
			switch (file.Open(filename, FileAccess.Read)) {
			case .Ok:
				break;
			case .Err:
				return false;
			}
			data = new uint8[file.Length];
			file.TryRead(Span<uint8>(data));
			file.Close();
			return true;
		}

		public static DateTime GetLatestTimestamp(params StringView[] args)
		{
			var bestDateTime = DateTime();
			for (var arg in args)
			{
				switch (File.GetLastWriteTimeUtc(arg)) {
				case .Ok(let dt):
					if (dt > bestDateTime)
					{
						bestDateTime = dt;
					}
					break;
				default:
				}
			}
			return bestDateTime;
		}

		public static void NormalizePath(String path)
		{
			path.Replace("\\", "/");
			path.Replace("//", "/");
		}

		public static void FindFiles(StringView path, StringView what, ref List<String> foundFiles)
		{
			var searchPath = scope String();
			var fileName = scope String();
			searchPath.AppendF("{}/{}", path, what);
			var files = Directory.Enumerate(searchPath, .Directories | .Files);
			for (var file in files)
			{
				fileName.Clear();
				file.GetFilePath(fileName);
				if (file.IsDirectory)
				{
					FindFiles(fileName, what, ref foundFiles);
				} else
				{
					var foundFileName = new String(fileName);
					Utils.NormalizePath(foundFileName);
					foundFiles.Add(foundFileName);
				}
			}
		}

		public static void SHA256ToString(SHA256Hash hash, String s)
		{
			for (var h in hash.mHash)
			{
				s.AppendF("{0:X}", h);
			}
		}

	}
}
