/*
 * 
 * Phasing System
 * Beta Version 2.6
 * Designed for SVN 663 + ML
 * 
 * Authored by Dougan Ironfist
 * Last Updated on 3/7/2011
 *
 * The purpose of these scripts is to allow shard administrators to create phasing abilities for quests.
 * This simulates the phasing abilities of games like World of Warcraft.
 * 
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using Server;
using Server.Mobiles;
using Server.Network;
using Server.Engines.XmlSpawner2;

/// THIS IS A CORE SCRIPT AND SHOULD NOT BE ALTERED ///

namespace Server.Phasing
{
    public enum SystemType
    {
        Server,
        Player
    }

    public class PhaseSystemManager
    {
        private static Hashtable SystemEntries = new Hashtable();
        private static Hashtable RegistryEntries = new Hashtable();

        private static int m_MaxRefreshRange = 40;
        public static int MaxRefreshRange { get { return m_MaxRefreshRange; } set { m_MaxRefreshRange = value; } }

        public static void Initialize()
        {
            LoadServerPhases();

            EventSink.WorldSave += new WorldSaveEventHandler(EventSink_WorldSave);
        }

        public static bool RegisterPhaseSystem(BasePhaseSystem phaseSystem)
        {
            if (RegistryEntries.ContainsKey(phaseSystem.PhaseSystemName))
                return false;

            RegistryEntries[phaseSystem.PhaseSystemName] = phaseSystem;
            return true;
        }

        public static int GetCurrentPhase(PlayerMobile player, string systemName)
        {
            return GetCurrentPhase(player, systemName, false);
        }

        public static int GetCurrentPhase(PlayerMobile player, string systemName, bool selfOnly)
        {
            PhasingAttachment attachment = FindAttachment(player);

            if (attachment == null)
                return (player.AccessLevel < AccessLevel.GameMaster ? -1 : -99);

            if (attachment.ShowAllPhases)
                return -99;

            if (!RegistryEntries.ContainsKey(systemName))
                return (player.AccessLevel < AccessLevel.GameMaster ? -1 : -99);

            SystemType type = ((BasePhaseSystem)RegistryEntries[systemName]).PhaseSystemType;

            if (type == SystemType.Server)
            {
                if (SystemEntries.ContainsKey(systemName))
                    return (int)SystemEntries[systemName];
                else
                    SystemEntries[systemName] = 0;
            }
            else
            {
                if (attachment != null && !selfOnly)
                {
                    if (attachment.DupedPlayer != null)
                    {
                        PlayerMobile p = attachment.DupedPlayer;
                        attachment = FindAttachment(p);
                    }
                }

                if (attachment != null)
                {
                    if (attachment.SystemEntries.ContainsKey(systemName))
                        return (int)(attachment.SystemEntries[systemName]);
                    else
                        attachment.SystemEntries[systemName] = 0;
                }
            }

            return 0;
        }

        public static void IncrementPlayerPhase(PlayerMobile player, string systemName)
        {
            if (!RegistryEntries.ContainsKey(systemName))
                return;

            SystemType type = ((BasePhaseSystem)RegistryEntries[systemName]).PhaseSystemType;

            if (type != SystemType.Server)
            {
                PhasingAttachment attachment = FindAttachment(player);

                if (attachment != null && attachment.SystemEntries.ContainsKey(systemName))
                    attachment.SystemEntries[systemName] = ((int)(attachment.SystemEntries[systemName])) + 1;

                OnPhaseChange(player);

                foreach (PlayerMobile p in attachment.DupedBy)
                    OnPhaseChange(p);
            }
        }

        public static void SetPlayerPhase(PlayerMobile player, string systemName, int stage)
        {
            if (!RegistryEntries.ContainsKey(systemName))
                return;

            SystemType type = ((BasePhaseSystem)RegistryEntries[systemName]).PhaseSystemType;

            if (type != SystemType.Server)
            {
                PhasingAttachment attachment = FindAttachment(player);

                if (attachment != null && attachment.SystemEntries.ContainsKey(systemName))
                    attachment.SystemEntries[systemName] = stage;

                OnPhaseChange(player);

                foreach (PlayerMobile p in attachment.DupedBy)
                    OnPhaseChange(p);
            }
        }

        public static void IncrementServerPhase(string systemName)
        {
            if (!RegistryEntries.ContainsKey(systemName))
                return;

            SystemType type = ((BasePhaseSystem)RegistryEntries[systemName]).PhaseSystemType;

            if (type == SystemType.Server)
            {
                if (SystemEntries.ContainsKey(systemName))
                {
                    int newPhase = ((int)SystemEntries[systemName]) + 1;
                    SystemEntries[systemName] = newPhase;
                    ((BasePhaseSystem)RegistryEntries[systemName]).OnServerPhaseChanged(newPhase);
                }

                List<NetState> list = NetState.Instances;
                for (int i = 0; i < list.Count; ++i)
                    if (list[i].Mobile != null && list[i].Mobile is PlayerMobile)
                        OnPhaseChange((PlayerMobile)list[i].Mobile);
            }
        }

        public static void SetServerPhase(string systemName, int stage)
        {
            if (!RegistryEntries.ContainsKey(systemName))
                return;

            SystemType type = ((BasePhaseSystem)RegistryEntries[systemName]).PhaseSystemType;

            if (type == SystemType.Server)
            {
                if (SystemEntries.ContainsKey(systemName))
                {
                    SystemEntries[systemName] = stage;
                    ((BasePhaseSystem)RegistryEntries[systemName]).OnServerPhaseChanged(stage);
                }

                List<NetState> list = NetState.Instances;
                for (int i = 0; i < list.Count; ++i)
                    if (list[i].Mobile != null && list[i].Mobile is PlayerMobile)
                        OnPhaseChange((PlayerMobile)list[i].Mobile);
            }
        }

        public static void OnPhaseChange(PlayerMobile player)
        {
            IPooledEnumerable eable = player.GetItemsInRange(MaxRefreshRange);

            foreach (Item item in eable)
            {
                if (item is IPhasable)
                {
                    item.ReleaseWorldPackets();

                    Point3D worldLoc = item.GetWorldLocation();

                    if (!player.CanSee(item) && player.InRange(worldLoc, item.GetUpdateRange(player)))
                        player.NetState.Send(item.RemovePacket);

                    item.Delta(ItemDelta.Update);
                }
            }

            eable.Free();

            eable = player.GetMobilesInRange(MaxRefreshRange);

            foreach (Mobile mob in eable)
            {
                if (mob is IPhasable)
                {
                    Point3D worldLoc = mob.Location;

                    if (!player.CanSee(mob))
                        player.NetState.Send(mob.RemovePacket);
                    else
                    {
                        if (player.NetState.StygianAbyss)
                            player.NetState.Send(new MobileIncoming(player, mob));
                        else
                            player.NetState.Send(new MobileIncomingOld(player, mob));

                        if (ObjectPropertyList.Enabled)
                            player.NetState.Send(mob.OPLPacket);
                    }
                }
            }

            eable.Free();
        }

        public static PhasingAttachment FindAttachment(Mobile m)
        {
            PhasingAttachment attachment = (PhasingAttachment)XmlAttach.FindAttachment(m, typeof(PhasingAttachment));

            if (attachment == null)
            {
                attachment = new PhasingAttachment();
                XmlAttach.AttachTo(m, attachment);
            }

            return attachment;
        }

        static void EventSink_WorldSave(WorldSaveEventArgs e)
        {
            SaveServerPhases();
        }

        public static void LoadServerPhases()
        {
            SystemEntries = new Hashtable();

            try
            {
                XmlTextReader reader = new XmlTextReader(@"Saves\Phasing\ServerPhases.xml");

                while (reader.Read())
                {
                    switch (reader.NodeType)
                    {
                        case XmlNodeType.Element:
                            if (reader.Name == "System")
                            {
                                string systemName = "";
                                int phase = 0;

                                if (reader.HasAttributes)
                                {
                                    while (reader.MoveToNextAttribute())
                                    {
                                        switch (reader.Name)
                                        {
                                            case "SystemName":
                                                systemName = reader.Value;

                                                break;
                                            case "Phase":
                                                try { phase = Convert.ToInt32(reader.Value); }
                                                catch { phase = 0; }

                                                break;
                                        }
                                    }
                                }

                                if (systemName != "")
                                    SystemEntries[systemName] = phase;
                            }

                            break;
                    }
                }

                reader.Close();
            }
            catch { }
        }

        public static void SaveServerPhases()
        {
            try { Directory.CreateDirectory(@"Saves\Phasing"); }
            catch { }

            if (File.Exists(@"Saves\Phasing\ServerPhases.backup"))
                File.Delete(@"Saves\Phasing\ServerPhases.backup");

            if (File.Exists(@"Saves\Phasing\ServerPhases.xml"))
                File.Move(@"Saves\Phasing\ServerPhases.xml", @"Saves\Phasing\ServerPhases.backup");

            XmlTextWriter writer = new XmlTextWriter(@"Saves\Phasing\ServerPhases.xml", Encoding.ASCII);

            writer.Formatting = Formatting.Indented;
            writer.WriteStartDocument();

            writer.WriteStartElement("PHASESAVE");

            foreach(DictionaryEntry entry in SystemEntries)
            {
                writer.WriteStartElement("System");

                writer.WriteStartAttribute("SystemName");
                writer.WriteValue(entry.Key.ToString());
                writer.WriteEndAttribute();

                writer.WriteStartAttribute("Phase");
                writer.WriteValue(entry.Value.ToString());
                writer.WriteEndAttribute();

                writer.WriteEndElement();
            }

            writer.WriteEndElement();

            writer.WriteEndDocument();

            writer.Close();
        }
    }
}
