using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class createRotationOffset6 : MonoBehaviour
{

    public GameObject userAvatar;
    public GameObject referenceSkeleton;
    Dictionary<string, string> parentIndexes;
    Dictionary<string, string> referenceParentIndexes;
    Dictionary<string, Quaternion> absoluteRotations;
    Dictionary<string, Quaternion> referenceAbsoluteRotations;
    Dictionary<string, string> avatarToMecanimBoneNameMap;
    Dictionary<string, string> mecanimToReferenceBoneNameMap;

    void setParentIDs(Transform modelBone, Dictionary<string, string> indexes)
    {
        for (int i = 0; i < modelBone.childCount; i++)
        {
            setParentIDs(modelBone.GetChild(i), indexes);
        }
        if (modelBone.parent != null)
        {
            indexes.Add(modelBone.name, modelBone.parent.name);
            //Debug.Log("the name is : " + modelBone.name);
        }
        else
        {
            Debug.Log("setting root parent " + modelBone.name);
            indexes.Add(modelBone.name, "root");
        }
    }
	
	string findLastRequiredParentBone (string currentBone){
		string ret = currentBone;
		while (ret != "root" && !avatarToMecanimBoneNameMap.ContainsKey(ret)){
            Debug.Log("stuck in while loop " + ret);
		    ret = parentIndexes[ret];
            //if (avatarToMecanimBoneNameMap.ContainsKey(ret))
            //{
                //then quit the loop
              //  break;
            //}
            
        }
        Debug.Log("parent is " + ret);
        return ret;
	}


    // Use this for initialization
    void Start()
    {
        parentIndexes = new Dictionary<string, string>();
        referenceParentIndexes = new Dictionary<string, string>();
        absoluteRotations = new Dictionary<string, Quaternion>();
        referenceAbsoluteRotations = new Dictionary<string, Quaternion>();
        avatarToMecanimBoneNameMap = new Dictionary<string, string>();
        mecanimToReferenceBoneNameMap = new Dictionary<string, string>();


        if (userAvatar != null)
        {
            setParentIDs(userAvatar.transform, parentIndexes);
            setParentIDs(referenceSkeleton.transform, referenceParentIndexes);

            AssetImporter importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(userAvatar));
            AssetImporter importerForReferenceSkeleton = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(referenceSkeleton));
            if ((importer != null) && (importerForReferenceSkeleton != null))
            {
                ModelImporter modelImporter = importer as ModelImporter;
                ModelImporter referenceImporter = importerForReferenceSkeleton as ModelImporter;
                if ((modelImporter != null) && (referenceImporter != null))
                {
                    HumanDescription avatarDescription = modelImporter.humanDescription;
                    HumanBone[] boneMap = avatarDescription.human;
                    SkeletonBone[] skeletonMap = avatarDescription.skeleton;

                    HumanDescription referenceAvatarDescription = referenceImporter.humanDescription;
                    HumanBone[] referenceBoneMap = referenceAvatarDescription.human;
                    SkeletonBone[] referenceSkeletonMap = referenceAvatarDescription.skeleton;
                    //create the name map from the user avatar to human
                    foreach (HumanBone bone in boneMap)
                    {
                        avatarToMecanimBoneNameMap.Add(bone.boneName, bone.humanName);
                        Debug.Log("avatar to mecanim bone map key is: " + bone.boneName);
                    }
                    // create the name map from human to the reference skeleton
                    foreach (HumanBone rBone in referenceBoneMap)
                    {
                        mecanimToReferenceBoneNameMap.Add(rBone.humanName, rBone.boneName);
                    }


                    foreach (SkeletonBone refBone in referenceSkeletonMap)
                    {
                        if (referenceParentIndexes.ContainsKey(refBone.name))
                        {
                            //Debug.Log("ref joint name is: " + refBone.name);
                            referenceAbsoluteRotations.Add(refBone.name, referenceAbsoluteRotations[referenceParentIndexes[refBone.name]] * refBone.rotation);
                        }
                        else
                        {
                            // if clone then we have the root
                            if (refBone.name.Contains("(Clone)"))
                            {
                                string[] splitName = refBone.name.Split('(');
                                referenceAbsoluteRotations.Add(splitName[0], refBone.rotation);
                            }
                        }
                    }
                    // Quaternion lastGoodReferenceBone = new Quaternion(0.0f,0.0f,0.0f,1.0f);
                    foreach (SkeletonBone userBone in skeletonMap)
                    {
                        // if the parent is root then use userBone rotation
                        if (parentIndexes.ContainsKey(userBone.name))
                        {
                            Debug.Log("joint name is: " + userBone.name + " parent name is:" + parentIndexes[userBone.name]);
                            absoluteRotations.Add(userBone.name, absoluteRotations[parentIndexes[userBone.name]] * userBone.rotation);
                        }
                        else
                        {
                            if (userBone.name.Contains("(Clone)"))
                            {
                                string[] splitName = userBone.name.Split('(');
                                absoluteRotations.Add(splitName[0], userBone.rotation);
                            }
                        }
                        if (avatarToMecanimBoneNameMap.ContainsKey(userBone.name) && mecanimToReferenceBoneNameMap.ContainsKey(avatarToMecanimBoneNameMap[userBone.name]))
                        {
                            // lastGoodReferenceBone = referenceAbsoluteRotations[mecanimToReferenceBoneNameMap[avatarToMecanimBoneNameMap[userBone.name]]];
                            Quaternion jointOffset = Quaternion.Inverse(absoluteRotations[userBone.name]) * referenceAbsoluteRotations[mecanimToReferenceBoneNameMap[avatarToMecanimBoneNameMap[userBone.name]]];
                            Debug.Log(userBone.name + " absolute: " + absoluteRotations[userBone.name] + " ref abs " + referenceAbsoluteRotations[mecanimToReferenceBoneNameMap[avatarToMecanimBoneNameMap[userBone.name]]] + " offset " + jointOffset);
                        }
                        else
                        {
                            if (absoluteRotations.ContainsKey(userBone.name))
                            {
								string lastRequiredParent = findLastRequiredParentBone(userBone.name);
								Quaternion lastRequiredParentRotation = referenceAbsoluteRotations[mecanimToReferenceBoneNameMap[avatarToMecanimBoneNameMap[lastRequiredParent]]];
								
								Quaternion extraBoneOffset = Quaternion.Inverse(absoluteRotations[userBone.name]) * lastRequiredParentRotation;
								if (avatarToMecanimBoneNameMap[userBone.name] == "UpperChest"){
									extraBoneOffset = Quaternion.Inverse(absoluteRotations[userBone.name]) * referenceAbsoluteRotations[mecanimToReferenceBoneNameMap[avatarToMecanimBoneNameMap[userBone.name]]];
								}
								Debug.Log("extra bone " + userBone.name + " : " + userBone.rotation + " abs is " + absoluteRotations[userBone.name] + " offset " + extraBoneOffset);
                                // take the previous offset and multiply it by the current local when we have an extra joint.
                            }
                        }
                    }
                }
                else
                {
                    Debug.Log("model not imported correctly");
                }
            }
            else
            {
                Debug.Log("didn't find the file");
            }
        }
        else
        {
            Debug.Log("no user avartar specified");
        }

    }



    // Update is called once per frame
    void Update()
    {
    }

}