// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
// for ex. property getter/setter access. To get optimal decompilation results, please manually add the missing references to the list of loaded assemblies.
// EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Eden.AutoMorpher.ClothInstanceTotal
using System.Collections.Generic;
using UnityEngine;

public class ClothInstanceTotal
{
    private readonly List<ClothInstance> clothInstances;

    public int TotalVertexCount { get; private set; }

    public Vector3[] GlobalPositions { get; private set; }

    public Vector3[] GlobalDeltas { get; private set; }

    public List<int>[] GlobalAdjacencyTopology { get; private set; }

    public List<int>[] GlobalAdjacencyDistance { get; private set; }

    public List<int>[] GlobalAdjacencyMerged { get; private set; }

    public int[] VertexOffsets { get; private set; }

    public ClothInstanceTotal(List<ClothInstance> clothInstances, float distanceBuildRadius, int maxNeighborsPerVertex = 0)
    {
        if (clothInstances == null || clothInstances.Count == 0)
        {
            throw new AutoMorpherException("Cloth Instances are Missing", "[ClothInstanceTotal] ClothInstanceTotal\n - clothInstances is null or empty");
        }
        if (distanceBuildRadius <= 0f)
        {
            throw new AutoMorpherException("Distance Build Radius is Invalid", "[ClothInstanceTotal] ClothInstanceTotal\n - distanceBuildRadius must be > 0");
        }
        this.clothInstances = clothInstances;
        this.BuildTopologyCache();
        this.BuildDistanceAdjacencyCandidates(distanceBuildRadius, maxNeighborsPerVertex);
        this.BuildMergedAdjacency();
    }

    public void SetGlobalDeltas(Vector3[] globalDeltas)
    {
        if (globalDeltas == null || globalDeltas.Length != this.TotalVertexCount)
        {
            throw new AutoMorpherException("Global Deltas are Invalid", "[ClothInstanceTotal] SetGlobalDeltas\n - globalDeltas is null or length mismatch");
        }
        this.GlobalDeltas = globalDeltas;
    }

    public void UpdateGlobalBuffersFromClothInstances()
    {
        this.ValidateGlobalBufferReady("[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances");
        for (int i = 0; i < this.clothInstances.Count; i++)
        {
            ClothInstance clothInstance = this.clothInstances[i];
            if (clothInstance != null)
            {
                if (clothInstance.worldVertices == null || clothInstance.deltasLocal == null)
                {
                    throw new AutoMorpherException("Cloth Instance Data is Missing", "[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances\n - worldVertices or deltasLocal is null");
                }
                int num = this.VertexOffsets[i];
                int num2 = clothInstance.worldVertices.Length;
                if (num2 != clothInstance.deltasLocal.Length)
                {
                    throw new AutoMorpherException("Cloth Instance Array Length Mismatch", "[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances\n - worldVertices.Length != deltasLocal.Length");
                }
                for (int j = 0; j < num2; j++)
                {
                    this.GlobalPositions[num + j] = clothInstance.worldVertices[j];
                    this.GlobalDeltas[num + j] = clothInstance.deltasLocal[j];
                }
            }
        }
    }

    public void ApplyGlobalDeltasToClothInstances()
    {
        this.ValidateGlobalBufferReady("[ClothInstanceTotal] ApplyGlobalDeltasToClothInstances");
        for (int i = 0; i < this.clothInstances.Count; i++)
        {
            ClothInstance clothInstance = this.clothInstances[i];
            if (clothInstance != null)
            {
                if (clothInstance.deltasLocal == null)
                {
                    throw new AutoMorpherException("Cloth Deltas are Missing", "[ClothInstanceTotal] ApplyGlobalDeltasToClothInstances\n - deltasLocal is null");
                }
                int num = this.VertexOffsets[i];
                int num2 = clothInstance.deltasLocal.Length;
                for (int j = 0; j < num2; j++)
                {
                    clothInstance.deltasLocal[j] = this.GlobalDeltas[num + j];
                }
            }
        }
    }

    private void ValidateGlobalBufferReady(string functionContext)
    {
        if (this.clothInstances == null || this.clothInstances.Count == 0)
        {
            throw new AutoMorpherException("Cloth Instances are Missing", functionContext + "\n - clothInstances is null or empty");
        }
        if (this.TotalVertexCount <= 0 || this.GlobalPositions == null || this.GlobalDeltas == null || this.VertexOffsets == null || this.GlobalAdjacencyMerged == null)
        {
            throw new AutoMorpherException("Cloth Instance Total Cache is Not Ready", functionContext + "\n - total/global buffers/merged adjacency are not initialized");
        }
    }

    private void BuildTopologyCache()
    {
        this.TotalVertexCount = this.CalculateTotalVertexCount(this.clothInstances);
        if (this.TotalVertexCount <= 0)
        {
            throw new AutoMorpherException("Total Vertex Count is Zero", "[ClothInstanceTotal] BuildTopologyCache\n - TotalVertexCount <= 0");
        }
        this.GlobalPositions = new Vector3[this.TotalVertexCount];
        this.GlobalDeltas = new Vector3[this.TotalVertexCount];
        this.GlobalAdjacencyTopology = new List<int>[this.TotalVertexCount];
        this.VertexOffsets = new int[this.clothInstances.Count];
        int num = 0;
        for (int i = 0; i < this.clothInstances.Count; i++)
        {
            ClothInstance clothInstance = this.clothInstances[i];
            this.VertexOffsets[i] = num;
            if (clothInstance == null)
            {
                continue;
            }
            if (clothInstance.worldVertices == null || clothInstance.deltasLocal == null || clothInstance.vertexAdjacency == null)
            {
                throw new AutoMorpherException("Cloth Instance Data is Missing", "[ClothInstanceTotal] BuildTopologyCache\n - worldVertices/deltasLocal/vertexAdjacency is null");
            }
            int num2 = clothInstance.worldVertices.Length;
            if (num2 != clothInstance.deltasLocal.Length || num2 != clothInstance.vertexAdjacency.Length)
            {
                throw new AutoMorpherException("Cloth Instance Array Length Mismatch", "[ClothInstanceTotal] BuildTopologyCache\n - worldVertices/deltasLocal/vertexAdjacency lengths differ");
            }
            for (int j = 0; j < num2; j++)
            {
                this.GlobalPositions[num + j] = clothInstance.worldVertices[j];
                this.GlobalDeltas[num + j] = clothInstance.deltasLocal[j];
                int capacity = clothInstance.vertexAdjacency[j]?.Count ?? 0;
                this.GlobalAdjacencyTopology[num + j] = new List<int>(capacity);
            }
            for (int k = 0; k < num2; k++)
            {
                List<int> list = clothInstance.vertexAdjacency[k];
                if (list == null)
                {
                    continue;
                }
                int num3 = num + k;
                List<int> list2 = this.GlobalAdjacencyTopology[num3];
                for (int l = 0; l < list.Count; l++)
                {
                    int num4 = list[l];
                    if ((uint)num4 >= (uint)num2)
                    {
                        throw new AutoMorpherException("Vertex Adjacency Index is Out of Range", "[ClothInstanceTotal] BuildTopologyCache\n - vertexAdjacency contains invalid neighbor index");
                    }
                    list2.Add(num + num4);
                }
            }
            num += num2;
        }
    }

    private void BuildDistanceAdjacencyCandidates(float radius, int maxNeighborsPerVertex)
    {
        if (this.GlobalPositions == null || this.GlobalPositions.Length == 0)
        {
            throw new AutoMorpherException("Reference Positions are Missing", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidates\n - GlobalPositions is null or empty");
        }
        this.GlobalAdjacencyDistance = this.BuildDistanceAdjacencyCandidatesInternal(this.GlobalPositions, radius, maxNeighborsPerVertex);
    }

    private void BuildMergedAdjacency()
    {
        if (this.GlobalAdjacencyTopology == null || this.GlobalAdjacencyDistance == null)
        {
            throw new AutoMorpherException("Adjacency Inputs are Missing", "[ClothInstanceTotal] BuildMergedAdjacency\n - GlobalAdjacencyTopology or GlobalAdjacencyDistance is null");
        }
        if (this.GlobalAdjacencyTopology.Length != this.GlobalAdjacencyDistance.Length)
        {
            throw new AutoMorpherException("Adjacency Length Mismatch", "[ClothInstanceTotal] BuildMergedAdjacency\n - topology and distance adjacency length differ");
        }
        int num = this.GlobalAdjacencyTopology.Length;
        this.GlobalAdjacencyMerged = new List<int>[num];
        for (int i = 0; i < num; i++)
        {
            List<int> list = new List<int>((this.GlobalAdjacencyTopology[i]?.Count ?? 0) + (this.GlobalAdjacencyDistance[i]?.Count ?? 0));
            HashSet<int> hashSet = new HashSet<int>();
            List<int> list2 = this.GlobalAdjacencyTopology[i];
            if (list2 != null)
            {
                for (int j = 0; j < list2.Count; j++)
                {
                    int num2 = list2[j];
                    if (num2 != i && hashSet.Add(num2))
                    {
                        list.Add(num2);
                    }
                }
            }
            List<int> list3 = this.GlobalAdjacencyDistance[i];
            if (list3 != null)
            {
                for (int k = 0; k < list3.Count; k++)
                {
                    int num3 = list3[k];
                    if (num3 != i && hashSet.Add(num3))
                    {
                        list.Add(num3);
                    }
                }
            }
            this.GlobalAdjacencyMerged[i] = list;
        }
    }

    private int CalculateTotalVertexCount(List<ClothInstance> clothInstances)
    {
        int num = 0;
        for (int i = 0; i < clothInstances.Count; i++)
        {
            ClothInstance clothInstance = clothInstances[i];
            if (clothInstance != null && clothInstance.worldVertices != null)
            {
                num += clothInstance.worldVertices.Length;
            }
        }
        return num;
    }

    private List<int>[] BuildDistanceAdjacencyCandidatesInternal(Vector3[] referencePositions, float radius, int maxNeighborsPerVertex)
    {
        if (referencePositions == null || referencePositions.Length == 0)
        {
            throw new AutoMorpherException("Reference Positions are Missing", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidatesInternal\n - referencePositions is null or empty");
        }
        if (radius <= 0f)
        {
            throw new AutoMorpherException("Radius is Invalid", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidatesInternal\n - radius must be > 0");
        }
        int num = referencePositions.Length;
        List<int>[] array = new List<int>[num];
        for (int i = 0; i < num; i++)
        {
            array[i] = new List<int>(8);
        }
        float num2 = 1f / Mathf.Max(radius, 1E-12f);
        float num3 = radius * radius;
        Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>(num);
        for (int j = 0; j < num; j++)
        {
            Vector3 vector = referencePositions[j];
            Vector3Int key = new Vector3Int(Mathf.FloorToInt(vector.x * num2), Mathf.FloorToInt(vector.y * num2), Mathf.FloorToInt(vector.z * num2));
            if (!dictionary.TryGetValue(key, out var value))
            {
                value = new List<int>(16);
                dictionary.Add(key, value);
            }
            value.Add(j);
        }
        for (int k = 0; k < num; k++)
        {
            Vector3 vector2 = referencePositions[k];
            Vector3Int vector3Int = new Vector3Int(Mathf.FloorToInt(vector2.x * num2), Mathf.FloorToInt(vector2.y * num2), Mathf.FloorToInt(vector2.z * num2));
            List<int> list = array[k];
            for (int l = -1; l <= 1; l++)
            {
                for (int m = -1; m <= 1; m++)
                {
                    for (int n = -1; n <= 1; n++)
                    {
                        Vector3Int key2 = new Vector3Int(vector3Int.x + l, vector3Int.y + m, vector3Int.z + n);
                        if (!dictionary.TryGetValue(key2, out var value2))
                        {
                            continue;
                        }
                        for (int num4 = 0; num4 < value2.Count; num4++)
                        {
                            int num5 = value2[num4];
                            if (num5 != k && !((referencePositions[num5] - vector2).sqrMagnitude > num3))
                            {
                                list.Add(num5);
                                if (maxNeighborsPerVertex > 0 && list.Count >= maxNeighborsPerVertex)
                                {
                                    break;
                                }
                            }
                        }
                        if (maxNeighborsPerVertex > 0 && list.Count >= maxNeighborsPerVertex)
                        {
                            break;
                        }
                    }
                }
            }
        }
        return array;
    }
}
