using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace BepInEx
{
	/// 
	/// Generic helper properties and methods.
	/// 
	public static class Utility
	{
		/// 
		/// Combines multiple paths together, as the specific method is not available in .NET 3.5.
		/// 
		/// The multiple paths to combine together.
		/// A combined path.
		public static string CombinePaths(params string[] parts) => parts.Aggregate(Path.Combine);
		/// 
		/// Tries to parse a bool, with a default value if unable to parse.
		/// 
		/// The string to parse
		/// The value to return if parsing is unsuccessful.
		/// Boolean value of input if able to be parsed, otherwise default value.
		public static bool SafeParseBool(string input, bool defaultValue = false)
		{
			return bool.TryParse(input, out bool result) ? result : defaultValue;
		}
		/// 
		/// Converts a file path into a UnityEngine.WWW format.
		/// 
		/// The file path to convert.
		/// A converted file path.
		public static string ConvertToWWWFormat(string path)
		{
			return $"file://{path.Replace('\\', '/')}";
		}
		/// 
		/// Indicates whether a specified string is null, empty, or consists only of white-space characters.
		/// 
		/// The string to test.
		/// True if the value parameter is null or empty, or if value consists exclusively of white-space characters.
		public static bool IsNullOrWhiteSpace(this string self)
		{
			return self == null || self.Trim().Length == 0;
		}
		public static IEnumerable TopologicalSort(IEnumerable nodes, Func> dependencySelector)
		{
			List sorted_list = new List();
			HashSet visited = new HashSet();
			HashSet sorted = new HashSet();
			foreach (TNode input in nodes)
			{
				Stack currentStack = new Stack();
				if (!Visit(input, currentStack))
				{
					throw new Exception("Cyclic Dependency:\r\n" + currentStack
																   .Select(x => $" - {x}") //append dashes
																   .Aggregate((a, b) => $"{a}\r\n{b}")); //add new lines inbetween
				}
			}
			return sorted_list;
			bool Visit(TNode node, Stack stack)
			{
				if (visited.Contains(node))
				{
					if (!sorted.Contains(node))
					{
						return false;
					}
				}
				else
				{
					visited.Add(node);
					stack.Push(node);
					foreach (var dep in dependencySelector(node))
						if (!Visit(dep, stack))
							return false;
					sorted.Add(node);
					sorted_list.Add(node);
					stack.Pop();
				}
				return true;
			}
		}
		/// 
		/// Try to resolve and load the given assembly DLL.
		/// 
		/// Name of the assembly, of the type .
		/// Directory to search the assembly from.
		/// The loaded assembly.
		/// True, if the assembly was found and loaded. Otherwise, false.
		public static bool TryResolveDllAssembly(AssemblyName assemblyName, string directory, out Assembly assembly)
		{
			assembly = null;
			var potentialDirectories = new List { directory };
			potentialDirectories.AddRange(Directory.GetDirectories(directory, "*", SearchOption.AllDirectories));
			foreach (string subDirectory in potentialDirectories)
			{
				string path = Path.Combine(subDirectory, $"{assemblyName.Name}.dll");
				if (!File.Exists(path))
					continue;
				try
				{
					assembly = Assembly.LoadFile(path);
				}
				catch (Exception)
				{
					continue;
				}
				return true;
			}
			return false;
		}
	}
}