using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.RTS.Manhattan;
using CommonAI.Zone.ZoneEditor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommonLang;
using CommonAI.Zone.Helper;

namespace CommonAI.ZoneClient
{
    public abstract class ZoneFlag : ZoneLayerObject
    {
        protected readonly SceneObjectData data;
        public string Name { get; private set; }
        public bool Enable { get; internal set; }
        public string Tag { get; internal set; }
        public SceneObjectData EditorData { get { return data; } }
        public ZoneFlag(SceneObjectData data, ZoneLayer parent)
            : base(parent)
        {
            this.data = data;
            this.Name = data.Name;
            this.mPos.SetX(data.X);
            this.mPos.SetY(data.Y);
            this.Enable = data.Enable;
            this.Tag = data.Tag;
        }
        public virtual void OnInit() { }
    }

    public class ZoneEditorUnit : ZoneFlag
    {
        public readonly UnitData Data;
        public ZoneEditorUnit(UnitData data, ZoneLayer parent)
            : base(data, parent)
        {
            this.Data = data;
        }
    }
    public class ZoneEditorItem : ZoneFlag
    {
        public readonly ItemData Data;
        public ZoneEditorItem(ItemData data, ZoneLayer parent)
            : base(data, parent)
        {
            this.Data = data;
        }
    }
    public class ZoneEditorRegion : ZoneFlag
    {
        public readonly RegionData Data;
        public ZoneEditorRegion(RegionData data, ZoneLayer parent)
            : base(data, parent)
        {
            this.Data = data;
        }
    }
    public class ZoneEditorPoint : ZoneFlag
    {
        public readonly PointData Data;
        public ZoneEditorPoint(PointData data, ZoneLayer parent)
            : base(data, parent)
        {
            this.Data = data;
        }
    }

    public class ZoneEditorDecoration : ZoneFlag
    {
        public readonly DecorationData Data;
        public readonly float W;
        public readonly float H;
        private readonly Rectangle BoundingBox;

        public ZoneEditorDecoration(DecorationData flag, ZoneLayer parent)
            : base(flag, parent)
        {
            this.Data = flag;
            this.W = flag.W;
            this.H = flag.H;
            switch (Data.RegionType)
            {
                case DecorationData.Shape.STRIP:
                    TLine2 line = new TLine2(X, Y, X, Y);
                    MathVector.movePolarExt(ref line.p, Data.StripDirection, -H / 2);
                    MathVector.movePolarExt(ref line.q, Data.StripDirection, +H / 2);
                    BoundingBox = new Rectangle(
                        Math.Min(line.p.X, line.q.X),
                        Math.Min(line.p.Y, line.q.Y),
                        Math.Abs(line.p.X - line.q.X),
                        Math.Abs(line.p.Y - line.q.Y));
                    break;
                case DecorationData.Shape.RECTANGLE:
                case DecorationData.Shape.ROUND:
                default:
                    BoundingBox = new Rectangle(X - W / 2, Y - H / 2, W, H);
                    break;
            }
        }

        public void DecorationChanged()
        {
            if (Data.Blockable)
            {
                if (Enable)
                {
                    this.FillTerrain(fill_Terrain_value);
                }
                else
                {
                    this.FillTerrain(fill_Terrain_reset);
                }
            }
        }
        public override void OnInit()
        {
            this.DecorationChanged();
        }

        #region FillTerrain

        private void fill_Terrain_value(int bx, int by)
        {
            Parent.PathFinder.TryFillTerrain(bx, by, Data.BlockValue);
        }
        private void fill_Terrain_reset(int bx, int by)
        {
            Parent.PathFinder.TryFillTerrain(bx, by, Parent.TerrainSrc.TerrainMatrix[bx, by]);
        }
        protected void FillTerrain(AstarManhattan.ForEachTerrainAction fillAction)
        {
            if (!Parent.IsShareTerrain)
            {
                var mmap = Parent.PathFinder.MMap;
                switch (Data.RegionType)
                {
                    case DecorationData.Shape.RECTANGLE:
                        AstarManhattan.ForEachTerrainRect(mmap, X - W / 2, Y - H / 2, W, H, fillAction);
                        break;
                    case DecorationData.Shape.ROUND:
                        AstarManhattan.ForEachTerrainEllipse(mmap, X - W / 2, Y - H / 2, W, H, fillAction);
                        break;
                    case DecorationData.Shape.STRIP:
                        TLine2 line = new TLine2(X, Y, X, Y);
                        MathVector.movePolarExt(ref line.p, Data.StripDirection, -H / 2);
                        MathVector.movePolarExt(ref line.q, Data.StripDirection, +H / 2);
                        AstarManhattan.ForEachTerrainStripWidth(mmap, line.p.X, line.p.Y, line.q.X, line.q.Y, W / 2, fillAction);
                        break;
                }
                Parent.PathFinder.BeginFindPath();
            }
        }

        public bool TouchBlock(float x, float y)
        {
            if (Data.Blockable && Enable && Parent.PathFinder.MMap.TestBlockValue(Data.BlockValue))
            {
                int bx = (((int)x) / Parent.TerrainSrc.GridCellW);
                int by = (((int)y) / Parent.TerrainSrc.GridCellH);
                var mmap = Parent.PathFinder.MMap;
                switch (Data.RegionType)
                {
                    case DecorationData.Shape.RECTANGLE:
                        return AstarManhattan.ForEachTerrainRect(mmap, X - W / 2, Y - H / 2, W, H,
                            (cx, cy) => { return cx == bx && cy == by; });
                    case DecorationData.Shape.ROUND:
                        return AstarManhattan.ForEachTerrainEllipse(mmap, X - W / 2, Y - H / 2, W, H,
                            (cx, cy) => { return cx == bx && cy == by; });
                    case DecorationData.Shape.STRIP:
                        TLine2 line = new TLine2(X, Y, X, Y);
                        MathVector.movePolarExt(ref line.p, Data.StripDirection, -H / 2);
                        MathVector.movePolarExt(ref line.q, Data.StripDirection, +H / 2);
                        return AstarManhattan.ForEachTerrainStripWidth(mmap, line.p.X, line.p.Y, line.q.X, line.q.Y, W / 2,
                            (cx, cy) => { return cx == bx && cy == by; });
                }
            }
            return false;
        }


        #endregion
    }

    public class ZoneEditorArea : ZoneFlag
    {
        public readonly AreaData Data;
        public readonly float W;
        public readonly float H;
        public int CurrentMapNodeValue { get; private set; }

        public ZoneEditorArea(AreaData data, ZoneLayer parent)
            : base(data, parent)
        {
            this.Data = data;
            this.W = data.W;
            this.H = data.H;
        }

        public override void OnInit()
        {
            var current_node = Parent.PathFinder.GetMapNodeByPos(X, Y);
            if (current_node != null)
            {
                this.CurrentMapNodeValue = current_node.Value;
                var list = Parent.TerrainAreaGenerator.GetContinuousMapNode(X, Y, W / 2, H / 2);
                foreach (var index in list)
                {
                    var node = Parent.PathFinder.GetMapNode(index.BX, index.BY) as ZoneMapNode;
                    if (node != null)
                    {
                        node.SetClientArea(this);
                    }
                }
            }
        }
    }

}