using System;
using System.Collections;
using System.IO;
using Server;
using Server.Commands;
using Server.HuePickers;
using Server.Gumps;
using Knives.Utils;

namespace Knives.Chat3
{
    public enum ChatStyle { Global, Regional }

    public class Channel
    {
        private static ArrayList s_Channels = new ArrayList();
        
        public static ArrayList Channels { get{ return s_Channels; } }
        
        public static void Register(Channel c)
        {
            foreach (string str in c.Commands)
                CommandSystem.Register(str, AccessLevel.Player, new CommandEventHandler(ChannelCommand));
        }

        public static Channel GetByName(string str)
        {
            foreach (Channel c in s_Channels)
                if (c.Name == str)
                    return c;

            return null;
        }

        private static void ChannelCommand(CommandEventArgs args)
        {
            foreach (Channel c in s_Channels)
                foreach (string str in c.Commands)
                    if (str == args.Command)
                    {
                        c.OnChat(args.Mobile, args.ArgString);
                        return;
                    }
        }

        public static void AddCommand(string str)
        {
            CommandSystem.Register(str, AccessLevel.Player, new CommandEventHandler(ChannelCommand));
        }

        public static void RemoveCommand(string str)
        {
            CommandSystem.Entries.Remove(str);
        }

        public static void Save()
        {
            if (!Directory.Exists("Saves/Chat/"))
                Directory.CreateDirectory("Saves/Chat/");

            GenericWriter writer = new BinaryFileWriter(Path.Combine("Saves/Chat/", "Channels34.bin"), true);

            writer.Write(0); // version

            ArrayList list = new ArrayList();

            foreach (Channel c in s_Channels)
                if (c.Mod)
                    list.Add(c);

            writer.Write(list.Count);
            foreach (Channel c in list)
                c.Save(writer);

            writer.Close();
        }

        public static void Load()
        {
    		if ( !File.Exists( Path.Combine( "Saves/Chat/", "Channels34.bin" ) ) )
				return;

            using (FileStream bin = new FileStream(Path.Combine("Saves/Chat/", "Channels34.bin"), FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                GenericReader reader = new BinaryFileReader(new BinaryReader(bin));

                int version = reader.ReadInt();

                int count = reader.ReadInt();
                Channel c;
                for (int i = 0; i < count; ++i)
                {
                    c = new Channel("");
                    c.Load(reader);
                }
            }
       }

        #region Class Definitions

        private string c_Name;
        private ArrayList c_Commands;
        private int c_DefaultC;
        private ChatStyle c_Style;
        private bool c_Mod, c_ToIrc, c_NewChars;

        public string Name { get { return c_Name; } set { c_Name = value; } }
        public ArrayList Commands { get { return c_Commands; } }
        public int DefaultC { get { return c_DefaultC; } set { c_DefaultC = value; } }
        public ChatStyle Style { get { return c_Style; } set { c_Style = value; } }
        public bool Mod { get { return c_Mod; } set { c_Mod = value; } }
        public bool ToIrc { get { return c_ToIrc; } set { c_ToIrc = value; } }
        public bool NewChars { get { return c_NewChars; } set { c_NewChars = value; } }

        #endregion

        #region Constructors

        public Channel( string name )
        {
            c_Name = name;

            c_Commands = new ArrayList();
            c_DefaultC = 0x47E;

            s_Channels.Add(this);
        }

        #endregion

        #region Methods

        public virtual string NameFor(Mobile m)
        {
            if (c_Style == ChatStyle.Regional && m.Region != null && m.Region.Name != "")
                return c_Name + " (" + m.Region.Name + ")";

            return c_Name;
        }

        public virtual bool CanChat(Mobile m, bool say)
        {
            if (Data.GetData(m).Banned)
            {
                if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(33));
                return false;
            }

            if (c_Style == ChatStyle.Regional && (m.Region == null || m.Region.Name == ""))
            {
                if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(35));
                return false;
            }

            return true;
        }

        private void OnChat(object o)
        {
            if (!(o is object[]))
                return;

            object[] obj = (object[])o;

            if (obj.Length != 2 || !(obj[0] is Mobile) || !(obj[1] is string))
                return;

            OnChat((Mobile)obj[0], obj[1].ToString(), false);
        }

        public virtual void OnChat(Mobile m, string msg)
        {
            OnChat(m, msg, true);
        }

        public virtual void OnChat(Mobile m, string msg, bool spam)
        {
            if (msg == null || msg == "")
            {
                if( Data.GetData(m).Channels.Contains(c_Name))
                    Data.GetData(m).CurrentChannel = this;

                ChannelGump.SendTo(m);
                return;
            }

            if (!CanChat(m, true))
                return;

            msg = Filter.FilterText(m, msg);

            if (!CanChat(m, false))
                return;

            if (!Data.GetData(m).Channels.Contains(c_Name))
            {
                m.SendMessage(Data.GetData(m).SystemC, General.Local(34));
                return;
            }

            if (!TrackSpam.LogSpam(m, "Chat", TimeSpan.FromSeconds(Data.ChatSpam)))
            {
                if (spam) m.SendMessage(Data.GetData(m).SystemC, General.Local(97));
                Timer.DelayCall(TimeSpan.FromSeconds(4), new TimerStateCallback(OnChat), new object[] { m, msg });
                return;
            }

            Broadcast(m, msg);

            if (c_ToIrc && IrcConnection.Connection.Connected)
                IrcConnection.Connection.SendUserMessage(m, "(" + c_Name + ") " + msg);
        }

        protected virtual void Broadcast(Mobile m, string msg)
        {
            foreach (Data data in Data.Datas.Values)
            {
                if (data.Channels.Contains(c_Name) && !data.Ignores.Contains(m))
                {
                    if (c_Style == ChatStyle.Regional && data.Mobile.Region != m.Region)
                        continue;

                    data.Mobile.SendMessage(m.AccessLevel == AccessLevel.Player ? data.ColorFor(this) : Data.GetData(m).StaffC, String.Format("<{0}{1}> {2}: {3}", c_Name, (c_Style == ChatStyle.Regional && m.Region != null ? "-" + m.Region.Name : ""), m.Name, msg));
                }
                else if (data.Mobile.AccessLevel >= m.AccessLevel && ((data.GlobalC && !data.GIgnores.Contains(m)) || data.GListens.Contains(m)))
                    data.Mobile.SendMessage(data.GlobalCC, String.Format("(Global) <{0}{1}> {2}: {3}", c_Name, (c_Style == ChatStyle.Regional && m.Region != null ? "-" + m.Region.Name : ""), m.Name, msg ));
            }
        }

        public virtual void GumpOptions( GumpPlus g, int x, int y )
        {
            int oldY = y;

            g.AddHtml(x, y + 10, 300, 21, HTML.White + "<CENTER>" + c_Name + " " + General.Local(40), false, false);

            string txt = HTML.White + General.Local(42) + ":";

            foreach (string str in Data.GetData(g.Owner).CurrentChannel.Commands)
                txt += " " + str;

            g.AddHtml(x + 30, y += 30, 170, 21, txt, false, false);

            g.AddHtml(x + 130, y += 25, 120, 21, HTML.White + c_Name + " " + General.Local(49), false, false);
            g.AddImage(x + 100, y, 0x2342, Data.GetData(g.Owner).ColorFor(this));
            g.AddButton(x + 104, y + 4, 0x2716, 0x2716, "Channel Color", new TimerStateCallback(ChannelColor), g);

            g.Entries.Insert( 0, new GumpBackground(x, oldY, 300, y-oldY+40, 0x1400));
        }

        public virtual ArrayList BuildList(Mobile m)
        {
            ArrayList list = new ArrayList();

            foreach (Data data in Data.Datas.Values)
            {
                if (m.AccessLevel < data.Mobile.AccessLevel && !Data.ShowStaff)
                    continue;

                if (!data.Channels.Contains(c_Name))
                    continue;

                if (data.Status == OnlineStatus.Hidden && data.Mobile.AccessLevel >= m.AccessLevel)
                    continue;

                list.Add(data.Mobile);
            }

            return list;
        }

        private void ChannelColor(object o)
        {
            if (!(o is GumpPlus))
                return;

            ((GumpPlus)o).Owner.SendHuePicker(new InternalPicker((GumpPlus)o, this));
        }

        private void Save(GenericWriter writer)
        {
            writer.Write(0); // Version

            writer.Write(c_Name);
            writer.Write((int)c_Style);
            writer.Write(c_ToIrc);
            writer.Write(c_NewChars);

            writer.Write(c_Commands.Count);
            foreach (string str in c_Commands)
                writer.Write(str);
        }

        private void Load(GenericReader reader)
        {
            int version = reader.ReadInt();

            c_Name = reader.ReadString();
            c_Style = (ChatStyle)reader.ReadInt();
            c_ToIrc = reader.ReadBool();
            c_NewChars = reader.ReadBool();

            int count = reader.ReadInt();
            for (int i = 0; i < count; ++i)
                c_Commands.Add(reader.ReadString());

            foreach (string str in c_Commands)
                AddCommand(str);

            c_Mod = true;
        }

        #endregion

        #region Internal Classes

        protected class InternalPicker : HuePicker
        {
            private GumpPlus c_Gump;
            private Channel c_Chan;

            public InternalPicker(GumpPlus g, Channel c) : base(0x1018)
            {
                c_Gump = g;
                c_Chan = c;
            }

            public override void OnResponse(int hue)
            {
                Data.GetData(c_Gump.Owner).ChannelColors[c_Chan.Name] = hue;

                c_Gump.NewGump();
            }
        }

        #endregion

    }
}