using CommonAI.Zone;
using CommonAI.Zone.ZoneEditor;
using CommonLang;
using CommonLang.IO;
using CommonLang.IO.Attribute;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace XmdsCommon.EditorData
{
    public static class SceneSnapManager
    {
        private static string mSnapDataRoot;
        private static string mSnapDataRootExt;
        public static void SaveAllSceneSnap(EditorTemplatesData datas, DirectoryInfo data_root)
        {
            if (!data_root.Exists) { data_root.Create(); }
            foreach (var sd in datas.Scenes.Values)
            {
                //场景快照
                var snd = new SceneSnapData(sd);
                var bin = IOUtil.ObjectToBin(TemplateManager.MessageCodec, snd);
                File.WriteAllBytes(data_root.FullName + Path.DirectorySeparatorChar + sd.ID + ".snd", bin);
            }
        }

        public static void SaveAllSceneSnapExt(EditorTemplatesData datas, DirectoryInfo data_root)
        {
            if (!data_root.Exists) { data_root.Create(); }
            foreach (var sd in datas.Scenes.Values)
            {
                //单位快照
                var snd = new UnitSnapData(sd);
                var bin = IOUtil.ObjectToBin(TemplateManager.MessageCodec, snd);
                File.WriteAllBytes(data_root.FullName + Path.DirectorySeparatorChar + sd.ID + ".snd", bin);
            }
		}

        internal static void InitSceneSnap(string path, string pathExt)
        {
            mSnapDataRoot = path;
            mSnapDataRootExt = pathExt;
        }


        private static readonly Dictionary<int, SceneSnapData> dic = new Dictionary<int, SceneSnapData>();
        private static readonly Dictionary<int, UnitSnapData> unitDic = new Dictionary<int, UnitSnapData>();

        public static SceneSnapData LoadSceneSnapData(int sid)
        {
            SceneSnapData ret;
            if(dic.TryGetValue(sid , out ret))
            {
                return ret;
            }
            byte[] bin = Resource.LoadData(mSnapDataRoot + "/" + sid + ".snd");
            if (bin != null)
            {
                try
                {
                    ret = IOUtil.BinToObject<SceneSnapData>(TemplateManager.MessageCodec, bin);
                    dic.Add(sid , ret);
                    return ret;
                }
                catch (Exception err)
                {
                    throw new Exception("Load SceneSnap error ! " + sid, err);
                }
            }
            return null;
        }
        
        public static SceneSnapData LoadSceneSnapData(int sid ,byte[] bin)
        {
            SceneSnapData ret;
            if (dic.TryGetValue(sid, out ret))
            {
                return ret;
            }
            if (bin != null)
            {
                ret = IOUtil.BinToObject<SceneSnapData>(TemplateManager.MessageCodec, bin);
                dic.Add(sid, ret);
                return ret;
            }
            return null;
        }

        public static UnitSnapData LoadBinUnitSnapData(int sid, byte[] bin)
        {
            UnitSnapData ret;
            if (unitDic.TryGetValue(sid, out ret))
            {
                return ret;
            }
            if (bin != null)
            {
                ret = IOUtil.BinToObject<UnitSnapData>(TemplateManager.MessageCodec, bin);
                unitDic.Add(sid, ret);
                return ret;
            }
            return null;
        }

        public static UnitSnapData LoadSceneUnitSnapData(int sid)
        {
            UnitSnapData ret;
            if (unitDic.TryGetValue(sid, out ret))
            {
                return ret;
            }

            byte[] bin = Resource.LoadData(mSnapDataRootExt + "/" + sid + ".snd");
            if (bin != null)
            {
                try
                {
                    ret = IOUtil.BinToObject<UnitSnapData>(TemplateManager.MessageCodec, bin);
                    unitDic.Add(sid, ret);
                    return ret;
                }
                catch (Exception err)
                {
                    throw new Exception("Load UnitSnapData error ! " + sid, err);
                }
            }
            return null;
        }
    }

    /// <summary>
    /// 场景快照数据
    /// </summary>
    [MessageType(0xFA00000)]
    public class SceneSnapData : IExternalizable
    {
        public int id;
        public string name;
        public float width, height;
        public List<RegionSnapData> regions = new List<RegionSnapData>();

        public SceneSnapData() { }
        public SceneSnapData(SceneData src)
        {
            this.id = src.ID;
            this.name = src.Name;
            this.width = src.ZoneData.TotalWidth;
            this.height = src.ZoneData.TotalHeight;
            char[] split = new char[] { '_' };
            foreach (var rg in src.Regions)
            {
                try
                {
                    if (rg.Name.StartsWith("snap_"))
                    {
                        RegionSnapData rgs = new RegionSnapData();
                        rgs.full_name = rg.Name;
                        rgs.x = rg.X;
                        rgs.y = rg.Y;
                        rgs.attributes.ParseLines(rg.Attributes);
                        this.regions.Add(rgs);
                    }
                }
                catch (Exception err)
                {
                    throw new Exception(string.Format("parse snap data error : scene={0} region={1}", src, rg.Name), err);
                }
            }
        }

        public void ReadExternal(IInputStream input)
        {
            this.id = input.GetS32();
            this.name = input.GetUTF();
            this.width = input.GetF32();
            this.height = input.GetF32();
            this.regions = input.GetList<RegionSnapData>(input.GetExt<RegionSnapData>);
        }
        public void WriteExternal(IOutputStream output)
        {
            output.PutS32(this.id);
            output.PutUTF(this.name);
            output.PutF32(this.width);
            output.PutF32(this.height);
            output.PutList(this.regions, output.PutExt);
        }
    }
    
    [MessageType(0xFA00001)]
    public class RegionSnapData : IExternalizable
    {
        public string full_name;
        public float x, y;
        public readonly Properties attributes = new Properties();

        public void ReadExternal(IInputStream input)
        {
            this.full_name = input.GetUTF();
            this.x = input.GetF32();
            this.y = input.GetF32();
            int count = input.GetS32();
            for (int i=0; i< count; i++)
            {
                string k = input.GetUTF();
                string v = input.GetUTF();
                attributes[k] = v;
            }
        }
        public void WriteExternal(IOutputStream output)
        {
            output.PutUTF(this.full_name);
            output.PutF32(this.x);
            output.PutF32(this.y);
            output.PutS32(this.attributes.Count);
            foreach (var e in this.attributes)
            {
                output.PutUTF(e.Key);
                output.PutUTF(e.Value);
            }
        }
    }

    [MessageType(0xFA00002)]
    public class UnitSnapData : IExternalizable
    {
		//单位信息
        public List<UnitSnapDataItem> units = new List<UnitSnapDataItem>();
		//路点信息
		public List<PointFlagSnapDataItem> pointFlags = new List<PointFlagSnapDataItem>();

        public UnitSnapData() { }
        public UnitSnapData(SceneData src)
        {
			//单位信息
            foreach (var unit in src.Units)
            {
                try
                {
                    UnitSnapDataItem rgs = new UnitSnapDataItem();
                    rgs.unitID = unit.UnitTemplateID;
                    rgs.unitName = unit.Name;
                    rgs.x = unit.X;
                    rgs.y = unit.Y;
                    this.units.Add(rgs);
				}
                catch (Exception err)
                {
                    throw new Exception(string.Format("parse snap unit data error : scene={0} region={1}", src, unit.Name), err);
                }
            }

			// 路点信息
			foreach (var point in src.Points)
			{
				try
				{
					PointFlagSnapDataItem pointFlag = new PointFlagSnapDataItem();
					pointFlag.pointName = point.Name;
					pointFlag.x = point.X;
					pointFlag.y = point.Y;

					this.pointFlags.Add(pointFlag);
				}
				catch (Exception err)
				{
					throw new Exception(string.Format("parse snap point flag data error : scene={0} region={1}", src, point.Name), err);
				}
			}
		}

        public void ReadExternal(IInputStream input)
        {
            this.units = input.GetList<UnitSnapDataItem>(input.GetExt<UnitSnapDataItem>);

			this.pointFlags = input.GetList<PointFlagSnapDataItem>(input.GetExt<PointFlagSnapDataItem>);
		}
        public void WriteExternal(IOutputStream output)
        {
            output.PutList(this.units, output.PutExt);

			output.PutList(this.pointFlags, output.PutExt);
		}
    }

    [MessageType(0xFA00003)]
    public class UnitSnapDataItem : IExternalizable
    {
        public String unitName;
        public int unitID;
        public float x, y;

        public void ReadExternal(IInputStream input)
        {
            this.unitName = input.GetUTF();
            this.unitID = input.GetS32();
            this.x = input.GetF32();
            this.y = input.GetF32();
        }
        public void WriteExternal(IOutputStream output)
        {
            output.PutUTF(this.unitName);
            output.PutS32(this.unitID);
            output.PutF32(this.x);
            output.PutF32(this.y);
        }
    }

	// 编辑器路点信息
	[MessageType(0xFA00004)]
	public class PointFlagSnapDataItem : IExternalizable
	{
		public String pointName;
		public float x, y;

		public void ReadExternal(IInputStream input)
		{
			this.pointName = input.GetUTF();
			this.x = input.GetF32();
			this.y = input.GetF32();
		}
		public void WriteExternal(IOutputStream output)
		{
			output.PutUTF(this.pointName);
			output.PutF32(this.x);
			output.PutF32(this.y);
		}
	}
}