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)
        {
            List<SceneObjectData> allList = new List<SceneObjectData>();
            allList.AddRange(src.Points);
            allList.AddRange(src.Regions);
            allList.AddRange(src.Decorations);
            allList.AddRange(src.Units);
            allList.AddRange(src.Items);
            allList.AddRange(src.Areas);

            //单位信息
            foreach (var unit in allList)
            {
                try
                {
                    if (unit.MapShow)
                    {
                        UnitSnapDataItem rgs = new UnitSnapDataItem();
                        rgs.unitName = unit.Name;
                        rgs.x = unit.X;
                        rgs.y = unit.Y;
                        rgs.mapShow = unit.MapShow;
                        rgs.unitMName = unit.UnitName;
                        rgs.unitMIcon = unit.UnitIcon;
                        rgs.offsetX = unit.OffsetX;
                        rgs.offsetY = unit.OffsetY;
                        rgs.lableOffsetX = unit.LableOffsetX;
                        rgs.lableOffsetY = unit.LableOffsetY;
                        rgs.lableColor = unit.LableColor;
                        rgs.lableSize = unit.LableSize;
                        rgs.lableOutLine = unit.LableOutline;
                        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 float x, y;
        public bool mapShow;
        public String unitMName;
        public String unitMIcon;
        public float offsetX;
        public float offsetY;
        public float lableOffsetX;
        public float lableOffsetY;
        public int lableColor;
        public int lableSize;
        public bool lableOutLine;

        public void ReadExternal(IInputStream input)
        {
            this.unitName = input.GetUTF();
            this.x = input.GetF32();
            this.y = input.GetF32();
            this.mapShow = input.GetBool();
            this.unitMName = input.GetUTF();
            this.unitMIcon = input.GetUTF();
            this.offsetX = input.GetF32();
            this.offsetY = input.GetF32();
            this.lableOffsetX = input.GetF32();
            this.lableOffsetY = input.GetF32();
            this.lableColor = input.GetS32();
            this.lableSize = input.GetS32();
            this.lableOutLine = input.GetBool();
        }
        public void WriteExternal(IOutputStream output)
        {
            output.PutUTF(this.unitName);
            output.PutF32(this.x);
            output.PutF32(this.y);
            output.PutBool(this.mapShow);
            output.PutUTF(this.unitMName);
            output.PutUTF(this.unitMIcon);
            output.PutF32(this.offsetX);
            output.PutF32(this.offsetY);
            output.PutF32(this.lableOffsetX);
            output.PutF32(this.lableOffsetY);
            output.PutS32(this.lableColor);
            output.PutS32(this.lableSize);
            output.PutBool(this.lableOutLine);
        }
    }

	// 编辑器路点信息
	[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);
		}
	}
}