using System;
using System.IO;
using Server;
using Server.Accounting;
using System.Collections;

namespace Server.Commands
{
	public class CommandLogging
	{
		private static StreamWriter m_Output;
		private static bool m_Enabled = true;

		public static bool Enabled{ get{ return m_Enabled; } set{ m_Enabled = value; } }

		public static StreamWriter Output{ get{ return m_Output; } }

		public static void Initialize()
		{
			EventSink.Command += new CommandEventHandler( EventSink_Command );

			if ( !Directory.Exists( "Logs" ) )
				Directory.CreateDirectory( "Logs" );

			string directory = "Logs/Commands";

			if ( !Directory.Exists( directory ) )
				Directory.CreateDirectory( directory );

			try
			{
				m_Output = new StreamWriter( Path.Combine( directory, String.Format( "{0}.log", DateTime.Now.ToLongDateString() ) ), true );

				m_Output.AutoFlush = true;

				m_Output.WriteLine( "##############################" );
				m_Output.WriteLine( "Log started on {0}", DateTime.Now );
				m_Output.WriteLine();
			}
			catch
			{
			}
		}

		public static object Format( object o )
		{
			if ( o is Mobile )
			{
				Mobile m = (Mobile)o;

				if ( m.Account == null )
					return String.Format( "{0} (no account)", m );
				else
					return String.Format( "{0} ('{1}')", m, m.Account.Username );
			}
			else if ( o is Item )
			{
				Item item = (Item)o;

				return String.Format( "0x{0:X} ({1})", item.Serial.Value, item.GetType().Name );
			}

			return o;
		}

		public static void WriteLine( Mobile from, string format, params object[] args )
		{
			WriteLine( from, String.Format( format, args ) );
		}

		public static void WriteLine( Mobile from, string text )
		{
			if ( !m_Enabled )
				return;

			try
			{
				m_Output.WriteLine( "{0}: {1}: {2}", DateTime.Now, from.NetState, text );

				string path = Core.BaseDirectory;

				Account acct = from.Account as Account;

				string name = ( acct == null ? from.RawName : acct.Username );

				AppendPath( ref path, "Logs" );
				AppendPath( ref path, "Commands" );
				AppendPath( ref path, from.AccessLevel.ToString() );
				path = Path.Combine( path, String.Format( "{0}.log", name ) );

				using ( StreamWriter sw = new StreamWriter( path, true ) )
					sw.WriteLine( "{0}: {1}: {2}", DateTime.Now, from.NetState, text );
			}
			catch
			{
			}
		}

		private static char[] m_NotSafe = new char[]{ '\\', '/', ':', '*', '?', '"', '<', '>', '|' };

		public static void AppendPath( ref string path, string toAppend )
		{
			path = Path.Combine( path, toAppend );

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

		public static string Safe( string ip )
		{
			if ( ip == null )
				return "null";

			ip = ip.Trim();

			if ( ip.Length == 0 )
				return "empty";

			bool isSafe = true;

			for ( int i = 0; isSafe && i < m_NotSafe.Length; ++i )
				isSafe = ( ip.IndexOf( m_NotSafe[i] ) == -1 );

			if ( isSafe )
				return ip;

			System.Text.StringBuilder sb = new System.Text.StringBuilder( ip );

			for ( int i = 0; i < m_NotSafe.Length; ++i )
				sb.Replace( m_NotSafe[i], '_' );

			return sb.ToString();
		}
		
		public static void EventSink_Command( CommandEventArgs e )
		{
         ArrayList noLog = new ArrayList();
         
         noLog.Add("C");
         noLog.Add("CHAT");
         noLog.Add("PM");
         noLog.Add("IM");
         noLog.Add("E");
         noLog.Add("EMOTE");
         noLog.Add("AFK");
         noLog.Add("GRAB");
         noLog.Add("INFO");
         noLog.Add("EP");
         noLog.Add("WHO");
         noLog.Add("SKILLS");
         noLog.Add("TOOLBAR");
         noLog.Add("S");
         noLog.Add("U");
         noLog.Add("UNBLESS");
         noLog.Add("MEDIK");
         noLog.Add("MEDIC");
         noLog.Add("EBS");
         noLog.Add("ENHANCEDBANDSELF");
         
         if ( !noLog.Contains( e.Command.ToUpper() ) )
            WriteLine( e.Mobile, "{0} {1} used command '{2} {3}'", e.Mobile.AccessLevel, Format( e.Mobile ), e.Command, e.ArgString );
		}

		public static void LogChangeProperty( Mobile from, object o, string name, string value )
		{
			WriteLine( from, "{0} {1} set property '{2}' of {3} to '{4}'", from.AccessLevel, Format( from ), name, Format( o ), value );
		}
	}
}