// EdenAutoMorpher_ProfileSaver_Script, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Eden.AutoMorpher.profile.ProfileUtils_BoneUtil
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class ProfileUtils_BoneUtil
{
    public HashSet<Transform> GetBodyMeshBones(SkinnedMeshRenderer smr, float weightThreshold = 0.0001f)
    {
        Mesh sharedMesh = smr.sharedMesh;
        if (sharedMesh == null)
        {
            Debug.LogError("[ProfileUtils_BoneUtil] SkinnedMeshRenderer에 연결된 Mesh가 없습니다.");
            return new HashSet<Transform>();
        }
        Transform[] bones = smr.bones;
        BoneWeight[] boneWeights = sharedMesh.boneWeights;
        HashSet<int> hashSet = new HashSet<int>();
        BoneWeight[] array = boneWeights;
        for (int i = 0; i < array.Length; i++)
        {
            BoneWeight boneWeight = array[i];
            if (boneWeight.weight0 > weightThreshold)
            {
                hashSet.Add(boneWeight.boneIndex0);
            }
            if (boneWeight.weight1 > weightThreshold)
            {
                hashSet.Add(boneWeight.boneIndex1);
            }
            if (boneWeight.weight2 > weightThreshold)
            {
                hashSet.Add(boneWeight.boneIndex2);
            }
            if (boneWeight.weight3 > weightThreshold)
            {
                hashSet.Add(boneWeight.boneIndex3);
            }
        }
        HashSet<Transform> hashSet2 = new HashSet<Transform>();
        foreach (int item in hashSet)
        {
            if (item >= 0 && item < bones.Length)
            {
                hashSet2.Add(bones[item]);
            }
        }
        return hashSet2;
    }

    public Dictionary<HumanBodyBones, HashSet<Transform>> GetHumanoidMeshBoneMap(Animator animator, IReadOnlyList<SkinnedMeshRenderer> bodyMeshes, float posTolerance = 0.0001f, float weightThreshold = 0.0001f)
    {
        Dictionary<HumanBodyBones, HashSet<Transform>> dictionary = new Dictionary<HumanBodyBones, HashSet<Transform>>();
        if (animator == null)
        {
            Debug.LogError("[MeshHumanoidBoneMatcher] Animator is Empty");
            return dictionary;
        }
        HashSet<Transform> hashSet = new HashSet<Transform>();
        if (bodyMeshes != null)
        {
            foreach (SkinnedMeshRenderer bodyMesh in bodyMeshes)
            {
                if (bodyMesh == null)
                {
                    continue;
                }
                foreach (Transform activeBone in this.GetActiveBones(bodyMesh, weightThreshold))
                {
                    if (activeBone != null)
                    {
                        hashSet.Add(activeBone);
                    }
                }
            }
        }
        for (int i = 0; i < 55; i++)
        {
            HumanBodyBones humanBodyBones = (HumanBodyBones)i;
            Transform boneTransform = animator.GetBoneTransform(humanBodyBones);
            if (boneTransform == null)
            {
                continue;
            }
            HashSet<Transform> hashSet2 = new HashSet<Transform>();
            hashSet2.Add(boneTransform);
            foreach (Transform item in this.FindBonesByPosition(boneTransform, hashSet, posTolerance))
            {
                hashSet2.Add(item);
            }
            dictionary[humanBodyBones] = hashSet2;
        }
        return dictionary;
    }

    public HashSet<Transform> GetActiveBones(SkinnedMeshRenderer smr, float weightThreshold = 0.0001f)
    {
        Mesh sharedMesh = smr.sharedMesh;
        if (sharedMesh == null)
        {
            Debug.LogError("SkinnedMeshRenderer에 연결된 Mesh가 없습니다.");
            return new HashSet<Transform>();
        }
        Transform[] bones = smr.bones;
        BoneWeight[] boneWeights = sharedMesh.boneWeights;
        HashSet<int> hashSet = new HashSet<int>();
        BoneWeight[] array = boneWeights;
        for (int i = 0; i < array.Length; i++)
        {
            BoneWeight boneWeight = array[i];
            if (boneWeight.weight0 > weightThreshold)
            {
                hashSet.Add(boneWeight.boneIndex0);
            }
            if (boneWeight.weight1 > weightThreshold)
            {
                hashSet.Add(boneWeight.boneIndex1);
            }
            if (boneWeight.weight2 > weightThreshold)
            {
                hashSet.Add(boneWeight.boneIndex2);
            }
            if (boneWeight.weight3 > weightThreshold)
            {
                hashSet.Add(boneWeight.boneIndex3);
            }
        }
        HashSet<Transform> hashSet2 = new HashSet<Transform>();
        foreach (int item in hashSet)
        {
            if (item >= 0 && item < bones.Length)
            {
                hashSet2.Add(bones[item]);
            }
        }
        return hashSet2;
    }

    private List<Transform> FindBonesByPosition(Transform boneToCheck, HashSet<Transform> smrBoneSet, float posTolerance = 0.0001f)
    {
        List<Transform> list = new List<Transform>();
        if (boneToCheck == null)
        {
            return list;
        }
        float num = posTolerance * posTolerance;
        Vector3 position = boneToCheck.position;
        foreach (Transform item in smrBoneSet)
        {
            if (!(item == null) && !(item == boneToCheck) && this.NameMatches(item.gameObject.name, boneToCheck.gameObject.name) && (item.position - position).sqrMagnitude <= num)
            {
                list.Add(item);
            }
        }
        return list;
    }

    private string[] TokenizeBoneName(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
        {
            return Array.Empty<string>();
        }
        char[] separator = new char[5] { '-', '_', ':', '.', '|' };
        name = name.Trim();
        return name.Split(separator, StringSplitOptions.RemoveEmptyEntries);
    }

    private bool NameMatches(string boneToCheckName, string candidateName)
    {
        string[] array = this.TokenizeBoneName(boneToCheckName);
        string[] array2 = this.TokenizeBoneName(candidateName);
        if (array.Length == 0 || array2.Length == 0)
        {
            return false;
        }
        if (!array[0].Equals(array2[0], StringComparison.OrdinalIgnoreCase))
        {
            return false;
        }
        if (array.Length > 1 && array2.Length > 1 && !array[1].Equals(array2[1], StringComparison.OrdinalIgnoreCase))
        {
            return false;
        }
        return true;
    }

    public List<BoneData> GetBoneDatas(Transform rootTransform, HashSet<Transform> avatarBones, Dictionary<HumanBodyBones, HashSet<Transform>> sourceBoneMap)
    {
        Dictionary<Transform, HumanBodyBones> dictionary = new Dictionary<Transform, HumanBodyBones>();
        foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> item2 in sourceBoneMap)
        {
            HumanBodyBones key = item2.Key;
            HashSet<Transform> value = item2.Value;
            if (value == null)
            {
                continue;
            }
            foreach (Transform item3 in value)
            {
                if (!(item3 == null) && !dictionary.ContainsKey(item3))
                {
                    dictionary[item3] = key;
                }
            }
        }
        List<BoneData> list = new List<BoneData>();
        BoneData item = new BoneData
        {
            id = 0,
            boneName = ((rootTransform != null) ? rootTransform.name : "Root"),
            parentName = null,
            hierarchyPath = "",
            hBone = HumanBodyBones.LastBone,
            parentId = -1,
            childrenIds = new List<int>(),
            rootLocalPosition = Vector3.zero,
            rootLocalRotation = Quaternion.identity,
            rootLocalScale = Vector3.one
        };
        list.Add(item);
        List<Transform> list2 = (from t in avatarBones
                                 where t != null
                                 orderby this.GetDepthFromSkeletonRoot(rootTransform, t), this.GetHierarchyPath(rootTransform, t)
                                 select t).ToList();
        Dictionary<Transform, int> dictionary2 = new Dictionary<Transform, int>(list2.Count);
        int num = 1;
        foreach (Transform item4 in list2)
        {
            dictionary2[item4] = num++;
            string hierarchyPath = this.GetHierarchyPath(rootTransform, item4);
            HumanBodyBones value2;
            HumanBodyBones hBone = (dictionary.TryGetValue(item4, out value2) ? value2 : HumanBodyBones.LastBone);
            Vector3 rootLocalPosition = ((rootTransform != null) ? rootTransform.InverseTransformPoint(item4.position) : item4.position);
            Quaternion rootLocalRotation = ((rootTransform != null) ? (Quaternion.Inverse(rootTransform.rotation) * item4.rotation) : item4.rotation);
            Vector3 rootLocalScale = item4.lossyScale;
            if (rootTransform != null)
            {
                Vector3 lossyScale = rootTransform.lossyScale;
                rootLocalScale = new Vector3(this.SafeDiv(rootLocalScale.x, lossyScale.x), this.SafeDiv(rootLocalScale.y, lossyScale.y), this.SafeDiv(rootLocalScale.z, lossyScale.z));
            }
            list.Add(new BoneData
            {
                id = dictionary2[item4],
                boneName = item4.name,
                parentName = ((item4.parent != null) ? item4.parent.name : ""),
                hierarchyPath = hierarchyPath,
                hBone = hBone,
                parentId = -1,
                childrenIds = new List<int>(),
                rootLocalPosition = rootLocalPosition,
                rootLocalRotation = rootLocalRotation,
                rootLocalScale = rootLocalScale
            });
        }
        Dictionary<int, List<int>> dictionary3 = new Dictionary<int, List<int>>();
        foreach (BoneData item5 in list)
        {
            dictionary3[item5.id] = new List<int>();
        }
        foreach (BoneData node in list.Where((BoneData n) => n.id != 0))
        {
            Transform key2 = dictionary2.FirstOrDefault((KeyValuePair<Transform, int> kv) => kv.Value == node.id).Key;
            int num2 = 0;
            if (key2 != null)
            {
                Transform parent = key2.parent;
                while (parent != null)
                {
                    if (dictionary2.TryGetValue(parent, out var value3))
                    {
                        num2 = value3;
                        break;
                    }
                    if (parent == rootTransform)
                    {
                        num2 = 0;
                        break;
                    }
                    parent = parent.parent;
                }
            }
            node.parentId = num2;
            dictionary3[num2].Add(node.id);
        }
        foreach (BoneData item6 in list)
        {
            item6.childrenIds = dictionary3[item6.id];
        }
        return list;
    }

    private float SafeDiv(float a, float b)
    {
        if (!(Mathf.Abs(b) < 1E-08f))
        {
            return a / b;
        }
        return 0f;
    }

    private int GetDepthFromSkeletonRoot(Transform root, Transform t)
    {
        int num = 0;
        Transform transform = t;
        while (transform != null && transform != root)
        {
            num++;
            transform = transform.parent;
        }
        return num;
    }

    private string GetHierarchyPath(Transform root, Transform t)
    {
        if (t == null)
        {
            return "";
        }
        if (root == null)
        {
            return t.name;
        }
        if (!t.IsChildOf(root) && t != root)
        {
            Debug.LogError("[ProfileUtils_BoneUtil] GetHierarchyPath - bone " + t.name + " is not child of root " + root.name);
            return "";
        }
        if (t == root)
        {
            return "";
        }
        Stack<string> stack = new Stack<string>();
        Transform transform = t;
        while (transform != null && transform != root)
        {
            stack.Push(transform.name);
            transform = transform.parent;
        }
        return string.Join("/", stack);
    }
}
