using System;
using Game.Plugins.JNGame.Sync.Frame.AStar.Util;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Plugins.JNGame.Sync.Frame.AStar.Entity
{
    
    /// <summary>  
    /// 表示与其他节点的连接  
    /// </summary>  
    public struct Connection {  
        /// <summary>  
        /// 该连接所指向的节点  
        /// </summary>  
        public GraphNode node;  
  
        /// <summary>  
        /// 沿此连接移动的成本。  
        /// 成本为1000大约对应于移动一个世界单位的成本。  
        /// </summary>  
        public uint cost;  
  
        /// <summary>  
        /// 该连接所使用的节点形状的边。  
        /// 用于网格节点。  
        /// 值为0表示使用节点上的顶点0和顶点1的边。1表示顶点1和2的边，以此类推。  
        /// 如果值为<see cref="NoSharedEdge"/>，则表示此连接不使用任何边（这主要用于网格外的链接）。  
        ///  
        /// 注意：由于对齐，<see cref="node"/>和<see cref="cost"/>字段使用12个字节，当在数组中使用时，即使移除此字段，也会填充到16个字节。  
        /// 因此，此字段不会增加内存使用量。  
        ///  
        /// 请参阅：TriangleMeshNode  
        /// 请参阅：TriangleMeshNode.AddConnection  
        /// </summary>  
        public byte shapeEdge;  
  
        /// <summary>  
        /// 表示连接不使用任何边的常量值  
        /// </summary>  
        public const byte NoSharedEdge = 0xFF;  
  
        /// <summary>  
        /// Connection结构体的构造函数  
        /// </summary>  
        /// <param name="node">连接的节点</param>  
        /// <param name="cost">连接的成本</param>  
        /// <param name="shapeEdge">节点形状的边，默认为NoSharedEdge</param>  
        public Connection(GraphNode node, uint cost, byte shapeEdge = NoSharedEdge) {  
            this.node = node;  
            this.cost = cost;  
            this.shapeEdge = shapeEdge;  
        }  
  
        /// <summary>  
        /// 重写GetHashCode方法，以基于node和cost生成此连接的唯一哈希码  
        /// </summary>  
        /// <returns>此连接的哈希码</returns>  
        public override int GetHashCode() {  
            return node.GetHashCode() ^ (int)cost;  
        }  
  
        /// <summary>  
        /// 重写Equals方法，以基于node、cost和shapeEdge比较此连接与另一个对象是否相等  
        /// </summary>  
        /// <param name="obj">要比较的另一个对象</param>  
        /// <returns>如果相等，则返回true；否则返回false</returns>  
        public override bool Equals(object obj) {  
            if (obj == null) return false;  
            var conn = (Connection)obj;  
            return conn.node == node && conn.cost == cost && conn.shapeEdge == shapeEdge;  
        }  
    }
    
    public abstract class GraphNode
    {
        private JNAStarPath astar;
        
        /// <summary>图形索引位的开始位置。参见：<see cref="GraphIndex"/></summary>  
        const int FlagsGraphOffset = 24;  
        /// <summary>图形索引位的掩码。参见：<see cref="GraphIndex"/></summary>  
        const uint FlagsGraphMask = (256u-1) << FlagsGraphOffset;
        /// <summary>最大图形数量减一</summary>  
        public const uint MaxGraphIndex = FlagsGraphMask >> FlagsGraphOffset;
        
        /// <summary>Start of <see cref="IsHierarchicalNodeDirty"/> bits. See: <see cref="IsHierarchicalNodeDirty"/></summary>
        const int HierarchicalDirtyOffset = 18;

        /// <summary>  
        /// <see cref="IsHierarchicalNodeDirty"/>位的掩码。  
        /// 参见：<see cref="IsHierarchicalNodeDirty"/>  
        /// </summary>  
        const uint HierarchicalDirtyMask = 1 << HierarchicalDirtyOffset;

        
        /// <summary>  
        /// 内部唯一索引。同时存储一些位打包的值，如<see cref="TemporaryFlag1"/>和<see cref="TemporaryFlag2"/>。  
        /// </summary>  
        private int nodeIndex; // 定义一个私有整数变量nodeIndex，用于存储节点的内部唯一索引，并可能包含一些位打包的值，如TemporaryFlag1和TemporaryFlag2。  
  
        /// <summary>  
        /// 位打包字段，包含多个数据片段。  
        /// 参见：Walkable  
        /// 参见：Area  
        /// 参见：GraphIndex  
        /// 参见：Tag  
        /// </summary>  
        protected uint flags; // 定义一个受保护的无符号整数变量flags，用于存储位打包的多个字段。这些字段可能表示节点的不同属性，如可走性(Walkable)、区域(Area)、图索引(GraphIndex)和标签(Tag)等。
        
        /// <summary>  
        /// 节点在世界空间中的位置。  
        /// 注意：该位置以 Int3 类型存储，而不是 Vector3 类型。  
        /// 你可以使用显式转换将 Int3 转换为 Vector3。  
        /// 示例代码：var v3 = (Vector3)node.position;  
        /// </summary>  
        public Int3 position;
        
        
        // 如果任何人创建了超过大约2亿个节点，那么事情就不会那么顺利了。然而，到了那个时候，人们肯定会遇到更紧迫的问题，比如内存耗尽  
        // 定义了一个常量NodeIndexMask，它是一个整数掩码，用于从nodeIndex中提取索引值  
        // NodeIndexMask的值为0xFFFFFFF（即31个连续的1），这意味着索引值可以是从0到16,777,215（2^24 - 1）的任何整数  
        const int NodeIndexMask = 0xFFFFFFF;  
  
        // 定义了一个常量DestroyedNodeIndex，表示被销毁的节点的索引值  
        // 它等于NodeIndexMask减去1，因此其值为16,777,214  
        // 这意味着当一个节点的索引被设置为DestroyedNodeIndex时，它可以被视为一个不再使用的、已被销毁的节点  
        const int DestroyedNodeIndex = NodeIndexMask - 1;  
  
        // 定义了一个常量TemporaryFlag1Mask，它是一个位掩码，用于表示TemporaryFlag1的状态  
        // 该掩码的最高位被设置为1（即第28位），而所有其他位都为0  
        // 通过将nodeIndex与TemporaryFlag1Mask进行按位与操作，可以检查TemporaryFlag1是否被设置  
        // 如果结果是非零值，那么TemporaryFlag1就被设置了；否则，它未被设置  
        const int TemporaryFlag1Mask = 0x10000000;  
  
        // 定义了一个常量TemporaryFlag2Mask，它也是一个位掩码，用于表示TemporaryFlag2的状态  
        // 该掩码的第二高位被设置为1（即第29位），而所有其他位都为0  
        // 通过将nodeIndex与TemporaryFlag2Mask进行按位与操作，可以检查TemporaryFlag2是否被设置  
        // 如果结果是非零值，那么TemporaryFlag2就被设置了；否则，它未被设置  
        const int TemporaryFlag2Mask = 0x20000000;
        
        
        public bool Destroyed {
            get {
                return NodeIndex == DestroyedNodeIndex;
            }
        }
        
        /// <summary>  
        /// 内部簿记。用于标记层次化节点是否已更改。  
        /// </summary>  
        internal bool IsHierarchicalNodeDirty {  
            // 获取IsHierarchicalNodeDirty属性的值  
            get {  
                // 使用位运算检查flags变量中是否设置了HierarchicalDirtyMask位掩码  
                // 如果设置了该位掩码，则IsHierarchicalNodeDirty为true，否则为false  
                return (flags & HierarchicalDirtyMask) != 0;  
            }  
            // 设置IsHierarchicalNodeDirty属性的值  
            set {  
                // 如果value为true，则将flags变量的HierarchicalDirtyOffset位置为1  
                // 如果value为false，则将flags变量的HierarchicalDirtyOffset位置为0  
                // 使用位运算实现上述操作  
                flags = flags & ~HierarchicalDirtyMask | (value ? 1U : 0U) << HierarchicalDirtyOffset;  
            }  
        }
        
        /// <summary>  
        /// 内部唯一索引。  
        /// 每个节点都会获得一个唯一索引。  
        /// 这个索引不一定与例如节点在图中的位置相关联。  
        /// </summary>  
        public int NodeIndex   
        {   
            get { return nodeIndex & NodeIndexMask; }   
            private set { nodeIndex = (nodeIndex & ~NodeIndexMask) | value; }   
        }
        
        /// <summary>  
        /// 图形节点的构造函数。  
        /// </summary>  
        /// <param name="astar">AstarPath实例，提供路径寻找功能。</param>  
        protected GraphNode(JNAStarPath astar)
        {
            this.astar = astar;
            // 检查传入的AstarPath对象是否为null  
            if (!Object.ReferenceEquals(astar, null)) {  
                // 如果不是null，则获取一个新的节点索引，并将其赋值给当前节点的nodeIndex属性  
                this.nodeIndex = astar.GetNewNodeIndex();  
          
                // 使用AstarPath对象初始化当前节点  
                astar.InitializeNode(this);  
            } else {  
                // 如果AstarPath对象是null，则抛出异常，说明没有可绑定的活动AstarPath对象  
                throw new Exception("No active AstarPath object to bind to");  
            }  
        }
        
        /// <summary>  
        /// 这个节点表面上距离点p最近的点  
        /// </summary>  
        /// <param name="p">给定的点</param>  
        /// <returns>返回节点表面上距离点p最近的点的坐标</returns>  
        public abstract Vector3 ClosestPointOnNode(Vector3 p);
        
        /// <summary>  
        /// 从此节点移除所有连接。  
        /// </summary>  
        /// <param name="alsoReverse">  
        /// 如果为true，将请求邻居节点也移除到此节点的连接。  
        /// </param>  
        public abstract void ClearConnections(bool alsoReverse);

        /// <summary>  
        /// 销毁节点。  
        /// 清理用于此节点的任何临时路径查找数据。  
        /// 当节点被销毁时，图形应负责调用此方法，包括当整个图形被销毁时。  
        /// 否则可能会出现内存泄漏。  
        ///  
        /// 一旦调用，<see cref="Destroyed"/> 属性将返回 true，后续对此方法的调用将不执行任何操作。  
        ///  
        /// 注意：假设当前活动的 AstarPath 实例是创建此节点的同一个实例。  
        ///  
        /// 警告：只有图形类应该在其自己的节点上调用此方法  
        /// </summary>  
        public void Destroy () {  
            // 如果节点已经被销毁，则直接返回，不执行后续操作  
            if (Destroyed) return;  
  
            // 清除节点的所有连接  
            ClearConnections(true);  
  
            // 如果存在活动的 AstarPath 实例，则调用其 DestroyNode 方法销毁此节点  
            // if (AstarPath.active != null) {  
            //     AstarPath.active.DestroyNode(this);  
            // }  
  
            // 将节点的索引设置为已销毁节点的索引，可能用于内部跟踪或管理  
            NodeIndex = DestroyedNodeIndex;  
        }
        
    }


    /// <summary>  
    /// 表示网格节点的抽象类，继承自GraphNode类。  
    /// </summary>  
    public abstract class MeshNode : GraphNode {  
        /// <summary>  
        /// MeshNode类的受保护构造函数，调用基类GraphNode的构造函数。  
        /// </summary>  
        /// <param name="astar">AstarPath实例，提供路径寻找功能。</param>  
        protected MeshNode(JNAStarPath astar) : base(astar) {  
        }  
  
        /// <summary>  
        /// 从此节点出发的所有连接。  
        /// 请参阅：<see cref="AddConnection"/>（添加连接）  
        /// 请参阅：<see cref="RemoveConnection"/>（移除连接）  
        ///  
        /// 注意：如果你修改此数组或其内容，你必须调用<see cref="SetConnectivityDirty"/>（设置连接性为脏）。  
        ///  
        /// 如果节点没有连接，则可能为null。  
        /// </summary>  
        public Connection[] connections;  
    }
}