using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Win32;

/*
 Copyright (c) 2014, LoreSoft
 This class was taken from https://github.com/loresoft/msbuildtasks/ and is licensed under BSD-2 license
*/
internal static class ToolPathUtil
{
	public static bool SafeFileExists(string path, string toolName)
	{
		return SafeFileExists(Path.Combine(path, toolName));
	}

	public static bool SafeFileExists(string file)
	{
		Console.WriteLine(String.Format("Testing {0}", file));
		try { return File.Exists(file); }
		catch { } // eat exception

		return false;
	}

	public static string MakeToolName(string name)
	{
		return (Environment.OSVersion.Platform == PlatformID.Unix) ?
			name : name + ".exe";
	}

	public static string FindInRegistry(string toolName)
	{
		try
		{
			RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + toolName, false);
			if (key != null)
			{
				string possiblePath = key.GetValue(null) as string;
				if (SafeFileExists(possiblePath))
					return Path.GetDirectoryName(possiblePath);
			}
		}
		catch (System.Security.SecurityException) { }

		return null;
	}

	public static string FindInPath(string toolName)
	{
		string pathEnvironmentVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
		string[] paths = pathEnvironmentVariable.Split(new[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
		foreach (string path in paths)
		{
			if (SafeFileExists(path, toolName))
			{
				return path;
			}
		}

		return null;
	}

	public static string FindInProgramFiles(string toolName, params string[] commonLocations)
	{
		foreach (string location in commonLocations)
		{
			string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), location);
			if (SafeFileExists(path, toolName))
			{
				return path;
			}
		}

		return null;
	}

	public static string FindInLocalPath(string toolName, string localPath)
	{
		if (localPath == null)
			return null;

		string path = new DirectoryInfo(localPath).FullName;
		if (SafeFileExists(localPath, toolName))
		{
			return path;
		}

		return null;
	}
}

public class GetToolPath : Microsoft.Build.Utilities.Task
{
	public virtual string ToolName { get; set; }
	public virtual string LocalPath { get; set; }
	public virtual string ToolPath { get; set; }
	public virtual bool Success { get; set; }

	public override bool Execute()
	{
		this.ToolPath = null;
		this.Success = false;
		string tool = ToolPathUtil.MakeToolName(ToolName);

		string toolDir =
					ToolPathUtil.FindInPath(tool) ??
					ToolPathUtil.FindInRegistry(tool) ??
					ToolPathUtil.FindInProgramFiles(tool, tool) ??
					ToolPathUtil.FindInProgramFiles(tool, Path.Combine(tool, "bin")) ??
					ToolPathUtil.FindInLocalPath(tool, LocalPath);


		if (toolDir == null)
		{
			throw new Exception(String.Format("Could not find {0}. Looked in PATH locations and various common folders inside Program Files as well as LocalPath.", tool));
		}

		Console.WriteLine("Found {0} at {1}", tool, toolDir);
		ToolPath = Path.Combine(toolDir, tool);
		Success = true;
		return Success;
	}
}