using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

using Microsoft.Win32;

namespace EA.GameTalkMessages
{
	/// <summary>
	/// One of the biggest challenges for this class was when MS produced 64 bit platforms AND decided to virtualize access to the Registry.  Specifically even though if you run the following code:
	/// TcpServer.DebugLog("1. " + RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"Software\Electronic Arts Inc.\GameTalkServer\") + " " + RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"Software\Electronic Arts Inc.\GameTalkServer\").GetSubKeyNames().Length);
	/// TcpServer.DebugLog("2. " + RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(@"Software\Electronic Arts Inc.\GameTalkServer\") + " " + RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(@"Software\Electronic Arts Inc.\GameTalkServer\").GetSubKeyNames().Length);
	/// 
	/// You'll see the exact same path for the key - in actual fact - the second one is looking at LocalMachine\Software\Wow6432Node\Electronic Arts Inc.\
	/// The same thing does not happen with the CurrentUser user area of the Registry
	/// </summary>
	public class RegistrySettings
	{
		/// <summary>
		/// Will this work just as well whether it ends with a back-slash "\" or not?
		/// </summary>
		private const string mGameTalkServerConfigKeyStr = @"Software\Electronic Arts Inc.\GameTalkServer\";

		private static RegistryKey mRegistryKey = Registry.LocalMachine;

		private static RegistryKey Get32BitKey()
		{
			RegistryKey regKey = mRegistryKey;
			try
			{
				if (mRegistryKey == Registry.LocalMachine)
					regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
				else //if (mRegistryKey == Registry.CurrentUser)
					regKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32);
			}
			catch (Exception exception)
			{
				Trace.WriteLine("Exception: " + exception.Message + Environment.NewLine + exception.StackTrace);
			}
			return regKey;
		}

		public static RegistryKey RegistryKeyArea
		{
			get
			{
				RegistryKey regKey = mRegistryKey;
				try
				{
					if (Environment.Is64BitOperatingSystem)
					{
						if (mRegistryKey == Registry.LocalMachine)
							regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
						else //if (mRegistryKey == Registry.CurrentUser)
							regKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
					}
					else
					{
						regKey = Get32BitKey();
					}
				}
				catch (Exception exception)
				{
					Trace.WriteLine("Exception: " + exception.Message + Environment.NewLine + exception.StackTrace);
				}

				return regKey;
			}
		}

		public static void SetRegistryKeyAreaToCurrentUser()
		{
			mRegistryKey = Registry.CurrentUser;
		}

		public static bool RunningAsApp()
		{
			if (mRegistryKey == Registry.CurrentUser)
				return true;
			else
				return false;
		}

		/// <summary>
		/// Use with caution as this will entirely delete a registry key if user passes in null value
		/// </summary>
		/// <param name="keyName"></param>
		/// <param name="keyValue"></param>
		/// <returns></returns>
		public static bool SetValue(string keyName, object keyValue)
		{
			RegistryKey key = null;
			try
			{
				key = RegistrySettings.RegistryKeyArea.CreateSubKey(mGameTalkServerConfigKeyStr);
				if (key != null)
				{
					if (keyValue != null)
						key.SetValue(keyName, keyValue);
					else
						key.DeleteValue(keyName);

					return true;
				}
			}
			catch
			{
			}
			finally
			{
				if (key != null)
					key.Close();
			}
			return false;
		}

		public static bool SetValueIn32Bit(string keyName, object keyValue)
		{
			RegistryKey key = null;
			try
			{
				key = Get32BitKey().CreateSubKey(mGameTalkServerConfigKeyStr);
				if (key != null)
				{
					if (keyValue != null)
						key.SetValue(keyName, keyValue);
					else
						key.DeleteValue(keyName);

					return true;
				}
			}
			catch
			{
			}
			finally
			{
				if (key != null)
					key.Close();
			}
			return false;
		}

		public static bool SetValueInUserRegion(string keyName, object keyValue)
		{
			RegistryKey key = null;
			try
			{
				key = Registry.CurrentUser.CreateSubKey(mGameTalkServerConfigKeyStr);
				if (key != null)
				{
					if (keyValue != null)
						key.SetValue(keyName, keyValue);
					else
						key.DeleteValue(keyName);

					return true;
				}
			}
			catch
			{
			}
			finally
			{
				if (key != null)
					key.Close();
			}
			return false;
		}

		public static object GetValue(string keyStr)
		{
			object keyValue = null;
			RegistryKey key = null;
			try
			{
				key = RegistrySettings.RegistryKeyArea.OpenSubKey(mGameTalkServerConfigKeyStr);
				if (key != null)
					keyValue = key.GetValue(keyStr);
			}
			catch
			{
			}
			finally
			{
				if (key != null)
					key.Close();
			}
			return keyValue;
		}

		public static bool SetByte(string keyName, byte byteValue)
		{
			byte[] byteArray = new byte[1];
			byteArray[0] = byteValue;
			return SetValue(keyName, byteArray);
		}

		public static byte[] GetBytes(string keyStr)
		{
			object registryValue = GetValue(keyStr);
			if (registryValue is byte[])
				return (byte[])registryValue;

			return null;
		}

		public static int GetInt32(string keyStr)
		{
			object registryValue = GetValue(keyStr);
			if (registryValue is int)
				return (int)registryValue;

			return -1;
		}

		public static string GetString(string keyStr)
		{
			object registryValue = GetValue(keyStr);
			if (registryValue is string)
				return (string)registryValue;

			return null;
		}

		public static Target[] GetRegisteredTargets(int defaultPort)
		{
			List<GameTalkMessages.Target> targets = new List<GameTalkMessages.Target>();
			RegistryKey key = null;
			try
			{
				key = RegistrySettings.RegistryKeyArea.OpenSubKey(mGameTalkServerConfigKeyStr);
				if (key == null)
					return new Target[0];

				string[] subKeyNames = key.GetSubKeyNames();
				foreach (string clientName in subKeyNames)
				{
					RegistryKey subKey = null;
					try
					{
						subKey = key.OpenSubKey(clientName);
						string platform = (string)subKey.GetValue("Platform");
						// Don't try getting the version from registry - the registered target will send its version upon connection
						string dnsName = (string)subKey.GetValue("DnsName");
						string ipAddress = (string)subKey.GetValue("IpAddress");
						bool autoResolve = false;
						try
						{
							autoResolve = Convert.ToBoolean(subKey.GetValue("AutoResolve"));
						}
						catch { }
						int port = -1;
						try
						{
							port = Convert.ToInt32(subKey.GetValue("Port"));
						}
						catch { }
						if (port < 0)
							port = defaultPort;

						targets.Add(new GameTalkMessages.Target(clientName, platform, dnsName, ipAddress, autoResolve, port));
					}
					catch { }
					finally
					{
						if (subKey != null)
							subKey.Close();
					}
				}
			}
			catch
			{
			}
			finally
			{
				if (key != null)
					key.Close();
			}

			return targets.ToArray();
		}

		public static Target GetRegisteredTarget(string targetName, int defaultPort)
		{
			Target target = null;
			RegistryKey key = null;
			try
			{
				key = RegistrySettings.RegistryKeyArea.OpenSubKey(mGameTalkServerConfigKeyStr);
				if (key == null)
					return null;

				string[] subKeyNames = key.GetSubKeyNames();
				foreach (string clientName in subKeyNames)
				{
					if (clientName != targetName)
						continue;

					RegistryKey subKey = null;
					try
					{
						subKey = key.OpenSubKey(clientName);
						string platform = (string)subKey.GetValue("Platform");
						// Don't try getting the version from registry - the registered target will send its version upon connection
						string dnsName = (string)subKey.GetValue("DnsName");
						string ipAddress = (string)subKey.GetValue("IpAddress");
						bool autoResolve = false;
						try
						{
							autoResolve = Convert.ToBoolean(subKey.GetValue("AutoResolve"));
						}
						catch { }
						int port = -1;
						try
						{
							port = Convert.ToInt32(subKey.GetValue("Port"));
						}
						catch { }
						if (port < 0)
							port = defaultPort;

						target = new Target(clientName, platform, dnsName, ipAddress, autoResolve, port);
					}
					catch { }
					finally
					{
						if (subKey != null)
							subKey.Close();
					}
				}
			}
			catch
			{
			}
			finally
			{
				if (key != null)
					key.Close();
			}
			return target;
		}

		public static bool RegisterTarget(Target target)
		{
			// Add to registry
			RegistryKey key = null;
			try
			{
				key = RegistrySettings.RegistryKeyArea.CreateSubKey(mGameTalkServerConfigKeyStr);
				if (key == null)
					return false;

				RegistryKey subKey = null;
				try
				{
					subKey = key.CreateSubKey(target.Name);
					subKey.SetValue("Platform", target.Platform);
					// Don't bother setting the version - we'll be told that when the passive target connects
					subKey.SetValue("DnsName", target.DnsName);
					subKey.SetValue("IpAddress", target.IpAddress);
					subKey.SetValue("Port", target.Port);
					subKey.SetValue("AutoResolve", target.AutoResolveIp);
					return true;
				}
				catch { }
				finally
				{
					if (subKey != null)
						subKey.Close();
				}
			}
			catch { }
			finally
			{
				if (key != null)
					key.Close();
			}
			return false;
		}

		public static string GetXenonDNSName()
		{
			string dnsName = null;
			string xenonKeyName = @"Software\Microsoft\XenonSDK";
			RegistryKey key = Registry.CurrentUser.OpenSubKey(xenonKeyName);
			if (key != null)
				dnsName = (string)key.GetValue("XboxName");
			return dnsName;
		}
	}
}
