using System;
using System.IO;
// Issue 10 - Update the code to Net Framework 3.5 - http://code.google.com/p/pandorasbox3/issues/detail?id=10 - Smjert
using System.Collections.Generic;
// Issue 10 - End
using System.Reflection;

namespace BoxServerSetup
{
	/// <summary>
	/// Summary description for Setup.
	/// </summary>
	public class Setup
	{
		public static string RunUOFolder = null;
		public static string BoxFolder = null;
		public static string Spawner = "Spawner";
		// Issue 10 - Update the code to Net Framework 3.5 - http://code.google.com/p/pandorasbox3/issues/detail?id=10 - Smjert
		public static List<string> Log;
		
		public static List<BoxModule> Modules;
		// Issue 10 - End

		private static BoxModule m_Core;

		static Setup()
		{
			// Issue 10 - Update the code to Net Framework 3.5 - http://code.google.com/p/pandorasbox3/issues/detail?id=10 - Smjert
			Modules = new List<BoxModule>();
			// Issue 10 - End

			// CORE FILES
			m_Core = new BoxModule(
				"Core", null,
				"Configuration.cs",
				@"Core\Authentication.cs",
				@"Core\BoxServer.cs",
				@"Core\BoxSpawn.cs",
				@"Core\Errors.cs",
				@"Core\GenericNode.cs",
				@"Core\Login.cs",
				@"Core\Utility.cs",
				@"Core\BuildItem.cs",
				@"Datafiles\BoxData.cs",
				@"Datafiles\Item.cs",
				@"Datafiles\PropsData.cs",
				@"Datafiles\SpawnData.cs" );

			// ITEM BUILDER
			Modules.Add( new BoxModule(
				"Builder", "Provides support for dealing with building structures (moving, deleting, hueing of complex items structures generated by features such as roofing or the area random tiler)",
				@"Modules\Builder\BuilderCore.cs",
				@"Modules\Builder\BuilderMessage.cs",
				@"Modules\Builder\ControlMessages.cs" ) );

			// DATAFILES TRANSFER
			Modules.Add( new BoxModule(
				"Datafile Transfer", "Allows Pandora to remotely retrieve datafiles such as BoxData, PropsData and SpawnData.",
				@"Modules\RetrieveDatafiles\GetDatafile.cs",
				@"Modules\RetrieveDatafiles\ReturnDatafile.cs" ) );

			// RANDOM TILER
			Modules.Add( new BoxModule(
				"Random Tiler", "Allows Pandora to perform random tiling.",
				@"Modules\RandomTiler\RandomBrushMessage.cs",
				@"Modules\RandomTiler\RandomItem.cs",
				@"Modules\RandomTiler\RandomTile.cs" ) );

			// SCRIPT EXPLORER
			Modules.Add( new BoxModule(
				"Script Explorer", "Allows remote users to remotely manage script files. NOTE: This feature requires manual configuration in the file [BoxServer]\\Modules\\ScriptExplorer\\Configuration.cs",
				@"Modules\ScriptExplorer\Configuration.cs",
				@"Modules\ScriptExplorer\CreateFolder.cs",
				@"Modules\ScriptExplorer\DeleteRequest.cs",
				@"Modules\ScriptExplorer\DownloadRequest.cs",
				@"Modules\ScriptExplorer\ExplorerMessage.cs",
				@"Modules\ScriptExplorer\ExplorerRequest.cs",
				@"Modules\ScriptExplorer\FileTransport.cs",
				@"Modules\ScriptExplorer\FolderInfo.cs",
				@"Modules\ScriptExplorer\MoveRequest.cs" ) );

			// SPAWN GROUPS
			Modules.Add( new BoxModule(
				"Spawn Groups", "Allows Pandora's Box to use the Spawn Groups feature",
				@"Modules\SpawnGroups\SpawnMessage.cs" ) );

			// CLIENT LIST
			Modules.Add( new BoxModule(
				"Client List", "Allows remote users to view the player population through Pandora's Box",
				@"Modules\ClientList\ClientListMessage.cs",
				@"Modules\ClientList\ClientListRequest.cs",
				@"Modules\ClientList\ClientCommand.cs" ) );
		}

		public static void PerformInstall( System.Windows.Forms.ProgressBar pBar )
		{
			// Issue 10 - Update the code to Net Framework 3.5 - http://code.google.com/p/pandorasbox3/issues/detail?id=10 - Smjert
			Log = new List<string>();
			// Issue 10 - End
			Log.Add( "Installation log" );
			Log.Add( "" );

			m_Asm = ( typeof( Setup ) ).Assembly;

			// Issue 10 - Update the code to Net Framework 3.5 - http://code.google.com/p/pandorasbox3/issues/detail?id=10 - Smjert
			List<string> files = new List<string>();
			// Issue 10 - End

			files.AddRange( m_Core.Files );

			foreach( BoxModule m in Modules )
				if ( m.Install )
					files.AddRange( m.Files );

			pBar.Minimum = 0;
			pBar.Maximum = files.Count + 4;

			// 1. Copy BoxServer.dll
			pBar.Value++;
			Copy( "BoxServer.dll", Path.Combine( RunUOFolder, "BoxServer.dll" ) );

			// 2. Update Assemblies.cfg
			pBar.Value++;
			UpdateAssemblies();

			// 3. Copy spawner file
			pBar.Value++;
			CopySpawner();

			// 4.Copy all files
			foreach( string file in files )
			{
				pBar.Value++;
				string from = Path.Combine( "Data", file );
				string to = Path.Combine( BoxFolder, file );

				Copy( from, to );
			}
		}

		private static Assembly m_Asm;

		private static void AddToLog( string format, params string[] args )
		{
			format = "- " + format;
			Log.Add( string.Format( format, args ) );
		}

		private static void EnsureDirectory( string path )
		{
			string dir = Path.GetDirectoryName( path );

			if ( ! Directory.Exists( dir ) )
				Directory.CreateDirectory( dir );
		}

		private static void Copy( string from, string to )
		{
			from = string.Format( "BoxServerSetup.{0}", from );
			from = from.Replace( "\\", "." );

			EnsureDirectory( to );

			Stream stream = m_Asm.GetManifestResourceStream( from );
			FileStream fStream = new FileStream( to, FileMode.Create, FileAccess.Write, FileShare.Read );
			
			byte[] data = new byte[ stream.Length ];
			stream.Read( data, 0, data.Length );
			fStream.Write( data, 0, data.Length );

			AddToLog( "File created: {0}", to );

			stream.Close();
			fStream.Close();
		}

		private static void UpdateAssemblies()
		{
			StreamReader reader = new StreamReader( Path.Combine( RunUOFolder, @"Data\Assemblies.cfg" ) );

			bool boxserver = false;
			bool remoting = false;
			bool newline = false;

			while ( reader.Peek() != -1 )
			{
				string line = reader.ReadLine();

				if ( line.IndexOf( "BoxServer.dll" ) > -1 )
				{
					boxserver = true;
				}

				if ( line.IndexOf( "System.Runtime.Remoting.dll" ) > -1 )
				{
					remoting = true;
				}

				if ( line.EndsWith( "\n" ) )
				{
					newline = true;
				}
				else
				{
					newline = false;
				}
			}

			reader.Close();

			if ( ! ( boxserver && remoting ) )
			{
				StreamWriter writer = new StreamWriter( Path.Combine( RunUOFolder, @"Data\Assemblies.cfg" ), true );

				if ( !newline )
				{
					writer.WriteLine( "\r\n" );
				}

				if ( !boxserver )
				{
					writer.WriteLine( "BoxServer.dll" );
					AddToLog( "Entry added to Assemblies.cfg : BoxServer.dll" );
				}

				if ( !remoting )
				{
					writer.WriteLine( "System.Runtime.Remoting.dll" );
					AddToLog( "Entry added to Assemblies.cfg : System.Runtime.Remoting.dll" );
				}

				writer.Close();
			}
		}

		private static void CopySpawner()
		{
			string source = string.Format( "Spawner.{0}.cs", Spawner );
			string dest = Path.Combine( BoxFolder, @"Core\SpawnerHelper.cs" );

			Copy( source, dest );
		}
	}

	public class BoxModule
	{
		public string Name;
		public string Description;
		public bool Install = true;
		// Issue 10 - Update the code to Net Framework 3.5 - http://code.google.com/p/pandorasbox3/issues/detail?id=10 - Smjert
		public List<string> Files;
		// Issue 10 - End

		public BoxModule( string name, string description, params string[] files )
		{
			Name = name;
			Description = description;
			// Issue 10 - Update the code to Net Framework 3.5 - http://code.google.com/p/pandorasbox3/issues/detail?id=10 - Smjert
			Files = new List<string>( files );
			// Issue 10 - End
		}
	}
}
