using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
// The following two namespaces are for the AssemblyResolve stuff
using System.Reflection;
using System.IO;

using EA.GameTalk;
using EA.GameTalkMessages;

namespace EA.FileTalk
{
	public partial class FileTalkService : ServiceBase
	{
		private FileServer mFileServer;

#if(DEBUG)
		private static LogManager sLogManager = new LogManager();
		public static LogManager LogManager
		{ get { return sLogManager; }}
#endif
		public static void ShutDownLogger()
		{
#if(DEBUG)
			Trace.Listeners.Remove(sLogManager); 
			sLogManager.Close();
#endif
		}

		public FileTalkService()
		{
			InitializeComponent();
			Trace.WriteLine("Started FileTalkServer " + Assembly.GetExecutingAssembly().GetName().Version.ToString());
		}

		protected override void OnStart(string[] args)
		{
			mFileServer = new FileServer();
			mFileServer.StartServer();
		}

		protected override void OnStop()
		{
			Trace.WriteLine("Shutting down FileTalkServer");
			mFileServer.StopServer();
			ShutDownLogger();
		}

		/// <summary>
		/// This is strictly a debugging method - outputs a list of manifest resource names
		/// </summary>
		/// <param name="assembly"></param>
		private static void DebugAssembly(Assembly assembly)
		{
			string[] manifestResourceNames = assembly.GetManifestResourceNames();
			for (int i = 0; i < manifestResourceNames.Length; i++)
			{
				Trace.WriteLine("name: " + manifestResourceNames[i]);
			}
		}

		private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			try
			{
				// Get DLL base name = assembly (full) name up to first comma.
				string desired = args.Name.Substring(0, args.Name.IndexOf(','));
				string desiredWithCommaDelimiter = args.Name.Substring(0, args.Name.IndexOf(',') + 1);
				// First see if we've already loaded a version of this assembly.
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				for (int i = 0; i < assemblies.Length; i++)
				{
					if (assemblies[i].FullName.StartsWith(desiredWithCommaDelimiter))
					{
						return assemblies[i];
					}
				}

				if ((string.Compare(desired, "GameTalk") != 0) ||
					(string.Compare(desired, "GameTalkMessages") != 0) ||
					(string.Compare(desired, "FileTalkMessages") != 0))
				{
					// Now try and load DLL embedded as a resource.
					Assembly mainAssembly = System.Reflection.Assembly.GetExecutingAssembly();
					//DebugAssembly(mainAssembly);
					Stream stream = mainAssembly.GetManifestResourceStream("EA.FileTalk.Assemblies." + desired + ".dll");
					if (stream != null)
					{
						byte[] bytes = new byte[stream.Length];
						stream.Read(bytes, 0, (int)stream.Length);
						stream.Close();

						return Assembly.Load(bytes);
					}
				}
			}
			catch (Exception exception)
			{
				Trace.WriteLine("CurrentDomain_AssemblyResolve: Exception: " + exception.Message + Environment.NewLine + exception.StackTrace);
			}

			// No dice.
			return null;
		}

		private static void HandleCommandLineArguments(string[] args)
		{
			bool runningAsApp = false;
			if (args.Length > 0)
			{
				if (args[0] == EA.GameTalkMessages.Configuration.RunServerAsAppCommandLineArgs)
				{
					EA.GameTalkMessages.RegistrySettings.SetRegistryKeyAreaToCurrentUser();
					// We will run this as an application to facilitate debugging
					try
					{
						// Putting the following assignment before Run - because Run won't complete (until process dies)
						runningAsApp = true;
						System.Windows.Forms.Application.Run(new FileTalkConsole());
					}
					catch (Exception e)
					{
						Trace.WriteLine("Main: Exception: " + e.Message + Environment.NewLine + e.StackTrace);
						// Could try handling this - but whatever
						throw e;
					}
				}
			}

			if (!runningAsApp)
			{
				ServiceBase[] ServicesToRun;

				// More than one user Service may run within the same process. To add
				// another service to this process, change the following line to
				// create a second service object. For example,
				//
				//   ServicesToRun = new ServiceBase[] {new Service1(), new MySecondUserService()};
				//
				ServicesToRun = new ServiceBase[] { new FileTalkService() };

				ServiceBase.Run(ServicesToRun);
			}
		}

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		static void Main(string[] commandLineArgs)
		{
#if(DEBUG)
			// Useful for debugging - allows us to look at log file if issue arises
			Trace.Listeners.Add(FileTalkService.LogManager);
#endif
			AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

			// Critical you don't invoke any GameTalkMessages methods in this method - as it will result in an immediate crash because .NET won't let the assumbly resolve (above) be registered
			HandleCommandLineArguments(commandLineArgs);
		}
	}
}
