// 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.BodyPoseToClothApplier
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class BodyPoseToClothApplier
{
    private class BoneMapping
    {
        public Transform proxyBone;

        public Transform clothBone;

        public int depth;

        public HumanBodyBones? humanBone;
    }

    public void ApplyBodyPoseToClothes(Transform bodyProxyRoot, Transform clothesRoot, Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> clothToBodyMatched, Dictionary<Transform, Transform> sourceToProxy, bool copyPosition = true, bool copyRotation = false, bool copyScale = true)
    {
        if (bodyProxyRoot == null)
        {
            throw new AutoMorpherException("Body Proxy Root is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - bodyProxyRoot is null");
        }
        if (clothesRoot == null)
        {
            throw new AutoMorpherException("Clothes Root is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - clothesRoot is null");
        }
        if (clothToBodyMatched == null || clothToBodyMatched.Count == 0)
        {
            throw new AutoMorpherException("Cloth To Body Matched Map is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - clothToBodyMatched is null or empty");
        }
        if (sourceToProxy == null)
        {
            throw new AutoMorpherException("Source To Proxy Map is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - sourceToProxy is null");
        }
        clothesRoot.localScale = bodyProxyRoot.localScale;
        Animator component = bodyProxyRoot.GetComponent<Animator>();
        if (component == null)
        {
            throw new AutoMorpherException("Body Proxy Animator is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - bodyProxyRoot has no Animator");
        }
        Transform transform = component.transform;
        Dictionary<Transform, int> dictionary = this.BuildDepthMap(transform);
        Dictionary<Transform, Transform> dictionary2 = new Dictionary<Transform, Transform>();
        List<BoneMapping> list = new List<BoneMapping>();
        HashSet<Transform> hashSet = new HashSet<Transform>();
        foreach (KeyValuePair<Transform, BoneMatchUtil.BoneRootLocalData> item in clothToBodyMatched)
        {
            Transform key = item.Key;
            BoneMatchUtil.BoneRootLocalData value = item.Value;
            if (key == null || value == null)
            {
                continue;
            }
            Transform t = value.t;
            if (t == null || !sourceToProxy.TryGetValue(t, out var value2) || value2 == null)
            {
                continue;
            }
            HumanBodyBones hBone = value.hBone;
            if (hashSet.Add(key))
            {
                int depth = 999;
                if (dictionary != null && dictionary.TryGetValue(value2, out var value3))
                {
                    depth = value3;
                }
                list.Add(new BoneMapping
                {
                    proxyBone = value2,
                    clothBone = key,
                    depth = depth,
                    humanBone = ((hBone != HumanBodyBones.LastBone) ? new HumanBodyBones?(hBone) : ((HumanBodyBones?)null))
                });
            }
            if (!dictionary2.ContainsKey(value2))
            {
                dictionary2.Add(value2, key);
            }
        }
        this.MirrorBoneMarkers(transform, dictionary2, dictionary, list);
        foreach (BoneMapping item2 in (from m in list
                                       where m != null && m.proxyBone != null && m.clothBone != null
                                       orderby m.depth
                                       select m).ToList())
        {
            if (!(item2.proxyBone == null) && !(item2.clothBone == null))
            {
                if (copyPosition)
                {
                    item2.clothBone.position = item2.proxyBone.position;
                }
                if (copyRotation)
                {
                    item2.clothBone.rotation = item2.proxyBone.rotation;
                }
                if (copyScale)
                {
                    item2.clothBone.localScale = item2.proxyBone.localScale;
                }
            }
        }
    }

    private Dictionary<Transform, int> BuildDepthMap(Transform root)
    {
        Dictionary<Transform, int> dictionary = new Dictionary<Transform, int>();
        if (root == null)
        {
            return dictionary;
        }
        Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(includeInactive: true);
        foreach (Transform transform in componentsInChildren)
        {
            if (!(transform == null))
            {
                dictionary[transform] = this.GetDepthFromRoot(transform, root);
            }
        }
        return dictionary;
    }

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

    private void MirrorBoneMarkers(Transform proxyArmature, Dictionary<Transform, Transform> proxyToCloth, Dictionary<Transform, int> proxyDepthMap, List<BoneMapping> mappings)
    {
        if (proxyArmature == null || proxyToCloth == null || mappings == null)
        {
            return;
        }
        TempBoneMarker[] componentsInChildren = proxyArmature.GetComponentsInChildren<TempBoneMarker>(includeInactive: true);
        if (componentsInChildren == null || componentsInChildren.Length == 0)
        {
            return;
        }
        HashSet<Transform> hashSet = new HashSet<Transform>();
        for (int i = 0; i < mappings.Count; i++)
        {
            BoneMapping boneMapping = mappings[i];
            if (boneMapping != null && boneMapping.proxyBone != null)
            {
                hashSet.Add(boneMapping.proxyBone);
            }
        }
        foreach (TempBoneMarker item in (from bm in componentsInChildren
                                         where bm != null && bm.transform != null
                                         orderby (proxyDepthMap != null && proxyDepthMap.TryGetValue(bm.transform, out var value3)) ? value3 : int.MaxValue
                                         select bm).ToList())
        {
            Transform transform = item.transform;
            if (transform == null)
            {
                continue;
            }
            Transform originalParent = item.originalParent;
            if (originalParent == null || !proxyToCloth.TryGetValue(originalParent, out var value) || value == null)
            {
                continue;
            }
            List<Transform> list = this.CollectDirectChilds(value);
            Transform transform2 = this.FindMarkerInChild(value);
            TempBoneMarker tempBoneMarker = null;
            if (transform2 == null)
            {
                transform2 = new GameObject(transform.name).transform;
                transform2.SetParent(value, worldPositionStays: true);
                tempBoneMarker = transform2.gameObject.AddComponent<TempBoneMarker>();
            }
            else
            {
                tempBoneMarker = transform2.GetComponent<TempBoneMarker>();
            }
            transform2.position = transform.position;
            transform2.rotation = transform.rotation;
            transform2.localScale = transform.localScale;
            tempBoneMarker.originalParent = value;
            tempBoneMarker.additionalInfo = item.additionalInfo;
            tempBoneMarker.wrappedChildNames = item.wrappedChildNames;
            for (int num = 0; num < list.Count; num++)
            {
                Transform transform3 = list[num];
                if (!(transform3 == null) && !(transform3 == transform2))
                {
                    transform3.SetParent(transform2, worldPositionStays: true);
                }
            }
            if (!proxyToCloth.ContainsKey(transform))
            {
                proxyToCloth.Add(transform, transform2);
            }
            if (hashSet.Add(transform))
            {
                int depth = 999;
                if (proxyDepthMap != null && proxyDepthMap.TryGetValue(transform, out var value2))
                {
                    depth = value2;
                }
                mappings.Add(new BoneMapping
                {
                    proxyBone = transform,
                    clothBone = transform2,
                    depth = depth,
                    humanBone = null
                });
            }
        }
    }

    private Transform FindMarkerInChild(Transform parent)
    {
        if (parent == null)
        {
            return null;
        }
        for (int i = 0; i < parent.childCount; i++)
        {
            Transform child = parent.GetChild(i);
            if (!(child == null) && child.GetComponent<TempBoneMarker>() != null)
            {
                return child;
            }
        }
        return null;
    }

    private List<Transform> CollectDirectChilds(Transform parentTransform)
    {
        int childCount = parentTransform.childCount;
        List<Transform> list = new List<Transform>(childCount);
        for (int i = 0; i < childCount; i++)
        {
            list.Add(parentTransform.GetChild(i));
        }
        return list;
    }
}
