using System;
using System.IO;
using System.Data;
using System.Linq;
using System.Threading;
using System.ServiceProcess;
using System.Collections.Generic;

using FilterAPI;
using FilterAPI.Portals;
using FilterAPI.ItemExchange;
using FilterAPI.CustomCurrency;

using FilterZone.LocalHandlers;
using FilterZone.LocalNetworking;

using FilterZone.ZoneHandlers;
using FilterZone.ZoneNetworking;

namespace FilterZone
{
    public partial class Service : ServiceBase
    {
        private Boolean AAbstatesIsDone = true;
        private Boolean MSpawnerIsDone = true;
        private Boolean MAbstatesIsDone = true;
        private Boolean AECheckerIsDone = true;
        private Boolean ISGiverIsDone = true;
        private Boolean DSenderIsDone = true;
        private Boolean AAAbstatesIsDone = true;

        public Service() { }

		internal void Init(bool interactive)
		{
			if (interactive)
				Program.ZoneID = "04";
			else
				Program.ZoneID = AppDomain.CurrentDomain.FriendlyName.Replace("FilterZone", "").Replace(".exe", "");
			AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

			Program.Auth = new Authentication();
			Program.SQL = new Database(Program.Auth);
			Program.Currencies = new CurrencyLoader(Program.Auth);
			Program.Tokens = new TokenLoader(Program.Auth);
			Program.Portals = new PortalLoader(Program.Auth);
			Program.ItemCreator = new Item(Program.SQL);
			Program.LocalHandlers = new LocalHandlerLoader();

			Program.LocalClient = new LocalClient();
			Program.LoadSHNs();

			ZoneListener ZListen = new ZoneListener();

			Program.ZoneHandlers = new ZoneHandlerLoader();

			if (Convert.ToBoolean(Program.Auth.ConfigValues[String.Format("Zone{0}AATE", Program.ZoneID)]))
			{
				Thread NewThread = new Thread(delegate ()
				{
					while (true)
					{
						if (AAbstatesIsDone) { RunAAbstates(); }

						Thread.Sleep(Convert.ToInt32(Program.Auth.ConfigValues[String.Format("Zone{0}AATI", Program.ZoneID)]) * 1000);
					}
				});

				NewThread.Start();
			}

			if (Convert.ToBoolean(Program.Auth.ConfigValues[String.Format("Zone{0}MSTE", Program.ZoneID)]))
			{
				Thread NewThread = new Thread(delegate ()
				{
					while (true)
					{
						if (MSpawnerIsDone) { RunMSpawner(); }

						Thread.Sleep(Convert.ToInt32(Program.Auth.ConfigValues[String.Format("Zone{0}MSTI", Program.ZoneID)]) * 1000);
					}
				});

				NewThread.Start();
			}

			if (Convert.ToBoolean(Program.Auth.ConfigValues[String.Format("Zone{0}MATE", Program.ZoneID)]))
			{
				Thread NewThread = new Thread(delegate ()
				{
					while (true)
					{
						if (MAbstatesIsDone) { RunMAbstates(); }

						Thread.Sleep(Convert.ToInt32(Program.Auth.ConfigValues[String.Format("Zone{0}MATI", Program.ZoneID)]) * 1000);
					}
				});

				NewThread.Start();
			}

			if (Convert.ToBoolean(Program.Auth.ConfigValues[String.Format("Zone{0}AECTE", Program.ZoneID)]))
			{
				Thread NewThread = new Thread(delegate ()
				{
					while (true)
					{
						if (AECheckerIsDone) { RunAEChecker(); }

						Thread.Sleep(Convert.ToInt32(Program.Auth.ConfigValues[String.Format("Zone{0}AECTI", Program.ZoneID)]) * 1000);
					}
				});

				NewThread.Start();
			}

			if (Convert.ToBoolean(Program.Auth.ConfigValues[String.Format("Zone{0}ISGTE", Program.ZoneID)]))
			{
				Thread NewThread = new Thread(delegate ()
				{
					while (true)
					{
						if (ISGiverIsDone) { RunISGiver(); }

						Thread.Sleep(Convert.ToInt32(Program.Auth.ConfigValues[String.Format("Zone{0}ISGTI", Program.ZoneID)]) * 1000);
					}
				});

				NewThread.Start();
			}

			if (Convert.ToBoolean(Program.Auth.ConfigValues[String.Format("Zone{0}DSTE", Program.ZoneID)]))
			{
				Thread NewThread = new Thread(delegate ()
				{
					while (true)
					{
						if (DSenderIsDone) { RunDSender(); }

						Thread.Sleep(Convert.ToInt32(Program.Auth.ConfigValues[String.Format("Zone{0}DSTI", Program.ZoneID)]) * 1000);
					}
				});

				NewThread.Start();
			}

			if (true == true)
			{
				Thread NewThread = new Thread(delegate ()
				{
					while (true)
					{
						if (AAAbstatesIsDone) { RunAAAbstates(); }

						Thread.Sleep(1000);
					}
				});

				NewThread.Start();
			}
		}

        protected override void OnStart(String[] Args)
        {
			Init(false);
        }

        private void RunAAbstates()
        {
            AAbstatesIsDone = false;
            
            try
            {
                foreach (ZoneClient ZClient in Program.ZoneClients.Values.Where(IsReady => IsReady.IsReady == true))
                {
                    foreach (DataRow Row in Program.CustomAbstateAreas.Table.Rows.Cast<DataRow>().Where(ItemArray => ItemArray.ItemArray[0].ToString() == ZClient.sMap))
                    {
                        if (!(ZClient.X >= Convert.ToInt32(Row.ItemArray[1])) && ZClient.X >= Convert.ToInt32(Row.ItemArray[3]) && !(ZClient.Y >= Convert.ToInt32(Row.ItemArray[2])) && ZClient.Y >= Convert.ToInt32(Row.ItemArray[4])) { Command.SetAbstate(ZClient, Convert.ToString(Row.ItemArray[5]), Convert.ToInt16(Row.ItemArray[6]), Convert.ToByte(Row.ItemArray[7])); }
                    }
                }
            }
            catch (Exception Error) { Program.SendConsoleText(ConsoleColor.Red, "Zone error - Abstate area\n{0}", Error.ToString()); }

            AAbstatesIsDone = true;
        }

        private void RunMSpawner()
        {
            MSpawnerIsDone = false;

            try
            {
                foreach (ZoneClient ZClient in Program.ZoneClients.Values.Where(IsReady => IsReady.IsReady == true))
                {
                    foreach (DataRow Row in Program.CustomMobAreas.Table.Rows.Cast<DataRow>().Where(ItemArray => ItemArray.ItemArray[0].ToString() == ZClient.sMap))
                    {
                        if (ZClient.sMapMobs < Convert.ToUInt16(Row.ItemArray[12]) && !(ZClient.X >= Convert.ToInt32(Row.ItemArray[1])) && ZClient.X >= Convert.ToInt32(Row.ItemArray[3]) && !(ZClient.Y >= Convert.ToInt32(Row.ItemArray[2])) && ZClient.Y >= Convert.ToInt32(Row.ItemArray[4]))
                        {
                            Random RandomGenerator = new Random();

                            Byte RatioOutput = Convert.ToByte(RandomGenerator.Next(0, Convert.ToByte(Row[11])));

                            if (RatioOutput < Convert.ToByte(Row[10]))
                            {
                                Byte nLevel = Program.SQL.GetnLevelFromsID(ZClient.sID);

                                Boolean Spawn = true;

                                if (Convert.ToBoolean(Row.ItemArray[5]) && (Convert.ToByte(Row.ItemArray[6]) > nLevel || Convert.ToByte(Row.ItemArray[7]) < nLevel)) { Spawn = false; }

                                if (Spawn)
                                {
                                    for (Byte Counter = 0; Counter < Convert.ToByte(Row.ItemArray[9]); Counter++) { Command.Mobbreed(ZClient, Convert.ToString(Row[8]), 1, 0, false, 1); }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception Error) { Program.SendConsoleText(ConsoleColor.Red, "Zone error - Mob area\n{0}", Error.ToString()); }

            MSpawnerIsDone = true;
        }

        private void RunMAbstates()
        {
            MAbstatesIsDone = false;

            try
            {
                foreach (ZoneClient ZClient in Program.ZoneClients.Values.Where(IsReady => IsReady.IsReady == true).Where(IsMounted => IsMounted.IsMounted == true))
                {
                    foreach (DataRow Row in Program.MountAbstates.Table.Rows.Cast<DataRow>().Where(ItemArray => Convert.ToUInt16(ItemArray.ItemArray[0]) == ZClient.RidingID)) { Command.SetAbstate(ZClient, Convert.ToString(Row[1]), Convert.ToInt32(Row[2]), Convert.ToByte(Row[3])); }
                }
            }
            catch (Exception Error) { Program.SendConsoleText(ConsoleColor.Red, "Zone error - Mount abstates\n{0}", Error.ToString()); }

            MAbstatesIsDone = true;
        }

        private void RunAEChecker()
        {
            AECheckerIsDone = false;

            try
            {
                foreach (ZoneClient ZClient in Program.ZoneClients.Values.Where(IsReady => IsReady.IsReady == true).Where(IsMounted => IsMounted.IsMounted == true))
                {
                    if (ZClient.sID != String.Empty)
                    {
                        Int64 GuildMoney = Program.SQL.GetnMoneyFromnNo(Program.SQL.GetnNoFromnCharNo(ZClient.nCharNo));

                        if (0 > GuildMoney) { ZClient.Dispose(); }
                    }
                }
            }
            catch (Exception Error) { Program.SendConsoleText(ConsoleColor.Red, "Zone error - Academy earn checker\n{0}", Error.ToString()); }

            AECheckerIsDone = true;
        }

        private void RunISGiver()
        {
            ISGiverIsDone = false;

            try
            {
                foreach (ZoneClient ZClient in Program.ZoneClients.Values.Where(IsReady => IsReady.IsReady == true).Where(IsVT => IsVT.IsVending == true || IsVT.InTrade == true)) { Command.SetAbstate(ZClient, "StaImmortal", 7500); }
            }
            catch (Exception Error) { Program.SendConsoleText(ConsoleColor.Red, "Zone error - Idle state giver\n{0}", Error.ToString()); }

            ISGiverIsDone = true;
        }

        private void RunDSender()
        {
            DSenderIsDone = false;

            try
            {
                foreach (ZoneClient ZClient in Program.ZoneClients.Values.Where(IsReady => IsReady.IsReady == true))
                {
                    Command.Distribute(ZClient);

                    Thread.Sleep(100);
                }
            }
            catch (Exception Error) { Program.SendConsoleText(ConsoleColor.Red, "Zone error - &Distribute sender\n{0}", Error.ToString()); }

            DSenderIsDone = true;
        }

        private void RunAAAbstates()
        {
            AAAbstatesIsDone = false;

            try
            {
                foreach (ZoneClient ZClient in Program.ZoneClients.Values.Where(IsReady => IsReady.IsReady == true).Where(AutoAttacking => AutoAttacking.AutoAttacking == true))
                {
                    Dictionary<Int32, Dictionary<Byte, UInt16>> nOwnernItemIDs = Program.SQL.GetnItemIDsFornStorageType(8);

                    foreach (DataRow Row in Program.AutoAttackAbstates.Table.Rows)
                    {
                        if (nOwnernItemIDs[ZClient.nCharNo].ContainsValue(Convert.ToUInt16(Row[0])))
                        {
                            Random RandomGenerator = new Random();

                            Byte RatioOutput = Convert.ToByte(RandomGenerator.Next(0, Convert.ToByte(Row[5])));

                            if (RatioOutput < Convert.ToByte(Row[4])) { Command.SetAbstate(ZClient, Convert.ToString(Row[1]), Convert.ToInt32(Row[2]), Convert.ToByte(Row[3])); }
                        }
                    }
                }
            }
            catch (Exception Error) { Program.SendConsoleText(ConsoleColor.Red, "Zone error - Auto attack abstate giver\n{0}", Error.ToString()); }

            AAAbstatesIsDone = true;
        }

        private void CurrentDomain_UnhandledException(Object Sender, UnhandledExceptionEventArgs Args)
        {
            File.WriteAllLines(String.Format("{0}{1}Crash.txt", AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName.Replace(".exe", "")), new String[] { ((Exception)Args.ExceptionObject).ToString() });

            Program.SendConsoleText(ConsoleColor.Red, ((Exception)Args.ExceptionObject).ToString());
        }

        protected override void OnStop()
		{
			
		}
    }
}
