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

public class MorphEngine : MonoBehaviour {

	// ëSÇƒÇÃï\èÓÇÃÉAÉjÉÅÅ[ÉVÉáÉìÉJÅ[Éu
	private Dictionary< string, AnimationCurve > allMorphingAnimeCurve;
	
	// ëSÇƒÇÃÉÇÅ[ÉtÉBÉìÉOçáê¨ÇçsÇ¡ÇΩÇ†Ç∆ÇÃÉ^Å[ÉQÉbÉgç¿ïW
	private Vector3[] allMorphingTargetVertices;
	
	// ëSÇƒÇÃÉÇÅ[ÉtÉBÉìÉOçáê¨ÇìKâûÇ∑ÇÈÉ^Å[ÉQÉbÉgí∏ì_
	private int[] allMorpingTargetIndexes;

	// ÉXÉLÉìÉfÅ[É^
	private Mesh mesh;

	// å≥Ç…ñﬂÇ∑ÇΩÇﬂÇÃÉÅÉbÉVÉÖÉfÅ[É^É\Å[ÉX
	private int[] sourceMeshIndexes;
	private Vector3[] sourceMeshVertices;

	// ÉÇÅ[ÉtÉBÉìÉOÇ∑ÇÈç€ÇÃí∏ì_ÇëŒâûÇ≥ÇπÇÈ
	private int[] sourceSkinBaseIndexes;

	// ÉÇÅ[ÉtÉBÉìÉOÇ…ïKóvÇ»ÉfÅ[É^Çï€éùÇ∑ÇÈ
	private VMDDataForMorph[] skinAnimationMorph;
	private SkinDataForMorph[] skinMorph;

    // VMD Data Frame Count For Morphing 
    public float frameCount = 0; 
    private const int FPS = 30;
    
    private float animeClipMaxFrame = 0;
    
	// Use this for initialization
	void Start () {
		Application.targetFrameRate = 30;

		// VMDDataForMorphÇéùÇ¬éqãüÇΩÇøÇÃÉfÅ[É^ÇéÊìæ
		skinAnimationMorph = gameObject.GetComponentsInChildren<VMDDataForMorph>();
		// MMDEngineÇéùÇ¬ï\èÓÉIÉuÉWÉFÉNÉgÇÃÉfÅ[É^ÇéÊìæ
		skinMorph = gameObject.GetComponentsInChildren<SkinDataForMorph>();

		// MMDEngine Ç©ÇÁÉxÅ[ÉXéÊìæ
		MMDEngine engine = gameObject.GetComponent<MMDEngine>();
		sourceSkinBaseIndexes = engine.baseSkinVertCountStorageArray;

		// í∏ì_ÉfÅ[É^éÊìæ
		mesh = gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh as Mesh;
		sourceMeshVertices = mesh.vertices;
		sourceMeshIndexes = new int[ mesh.vertexCount ];
	
		// ï\èÓÇ≤Ç∆ÇÃïœâªÇ∑ÇÈÉtÉåÅ[ÉÄêîÇ∆ÉEÉFÉCÉgílÇäiî[
		Dictionary< string, VMDDataForMorph > vmdMotionDictionary;
	
		// ï\èÓñàÇÃìÆÇ©Ç∑í∏ì_Ç‚à íuèÓïÒÇäiî[
		Dictionary<string, SkinDataForMorph> skinMorphDictionary;

		// èâä˙âª
		allMorphingAnimeCurve = new Dictionary<string, AnimationCurve>();
		vmdMotionDictionary = new Dictionary<string, VMDDataForMorph>();
		skinMorphDictionary = new Dictionary<string, SkinDataForMorph>();

		// VMDDataForMorphÇÃÉfÅ[É^Çé´ìTÇ…ìoò^
		foreach( VMDDataForMorph motionData in skinAnimationMorph ) {
			Debug.Log( "SkinName : " + motionData.skinName );
			vmdMotionDictionary.Add( motionData.skinName, motionData );
		}

		// SkinDataForMorphÇÃÉfÅ[É^Çé´ìTÇ…ìoò^
		foreach( SkinDataForMorph skinData in skinMorph ) {
			skinMorphDictionary.Add( skinData.skinName, skinData );
		}
		
		// ï\èÓÇÃêîÇæÇØ
		for( int i = 0; i < skinMorph.Length; i++ ){
			// ï\èÓÇ≤Ç∆Ç…AnimationCurveçÏê¨
			AnimationCurve curve = createAnimationCurveForSkinMorph( skinAnimationMorph[i] );
			allMorphingAnimeCurve.Add( skinMorph[i].name, curve );
		}
	}
	
	/// <summary>
	/// ï\èÓÇÃAnimationCurveê∂ê¨Ç∑ÇÈä÷êî
	/// </summary>
	AnimationCurve createAnimationCurveForSkinMorph( VMDDataForMorph skinAnimationMorph) {
		int i = 0;
		Keyframe[] frames = new Keyframe[ skinAnimationMorph.frameArray.Length ];

		foreach( int frame in skinAnimationMorph.frameArray ) {
			frames[i] = new Keyframe( frame, skinAnimationMorph.weightArray[ i++ ] );
		}
		
		AnimationCurve curve = new AnimationCurve( frames );
		return curve;
	}
	
	// Update is called once per frame
	void Update () {

		// âΩÉtÉåÅ[ÉÄåoâﬂÇµÇΩÇ©
		frameCount += Time.deltaTime * FPS;
        float frame = frameCount;
		Debug.Log( "frameCount : " + frameCount );
		// ï\èÓÉÇÅ[ÉtÉBÉìÉOÇ™ÇPÉtÉåÅ[ÉÄñàÇ…ãyÇ⁄Ç∑í∏ì_Ç÷ÇÃâeãøÇ
		// àÍéûìIÇ…äiî[Ç∑ÇÈèÍèä
		Vector3[] weightVertices = new Vector3[ sourceSkinBaseIndexes.Length ];
		// ï\èÓópÇÃäeí∏ì_Ç≤Ç∆Ç…â¡éZÇ≥ÇÍÇΩâÒêîÇÉJÉEÉìÉg
		// ÇªÇÃå„â¡éZÇ≥ÇÍÇΩâÒêîÇ≈äÑÇÈÇ±Ç∆Ç≈ïΩãœílÇãÅÇﬂÇÈ
		int[] weightVecCount = new int[ sourceSkinBaseIndexes.Length ];
		
		// åªç›ÇÃà íuÇéÊìæ
		Vector3[] vertices = mesh.vertices;
		int count = 0;
		
		// ï\èÓÇ≤Ç∆Ç…
		foreach( SkinDataForMorph skin in skinMorph ){
			// baseÇÕï\èÓópÇÃí∏ì_î‘çÜÇ∆ÉÇÉfÉãÇÃÉXÉLÉìÇÃí∏ì_î‘çÜÇëŒâûïtÇØÇÈÇ‡ÇÃ
			// Ç»ÇÃÇ≈ï\èÓÇ≈ÇÕÇ»Ç¢
			if( skin.skinName != "base" ){
				AnimationCurve curve = allMorphingAnimeCurve[ skin.skinName ];
				int[] targetMeshIndexes = skin.skinIndexArray;
				Vector3[] targetMeshVertices = skin.skinPosArray;
				
				// weightVertices : ï\èÓÉÇÅ[ÉtÉBÉìÉOópí∏ì_ÇÃà íuèÓïÒÇâ¡éZÇµÇƒämï€
				//					ÇªÇÃå„Ç±ÇÍÇå≥Ç…ïΩãœílÇãÅÇﬂÅAÇªÇÍÇÇªÇÃÉtÉåÅ[ÉÄÇÃ
				//					ÉÇÅ[ÉtÉBÉìÉOèÓïÒÇ∆ÇµÇƒégóp
				// weightVecCount : ï\èÓÉÇÅ[ÉtÉBÉìÉOópÇÃäeí∏ì_Ç…ëŒÇµÇƒï€ë∂ÇµÇΩÇ©
				// Å@Å@Å@Å@Å@Å@Å@ ÉJÉEÉìÉgÇµ, ÇªÇÃå„ïΩãœílÇãÅÇﬂÇÈÇÃÇ…égóp
				for( int i = 0; i < targetMeshIndexes.Length; i++ ) {
					// curve.Evaluate( frame ) : åªç›ÇÃÉtÉåÅ[ÉÄÇ…Ç®ÇØÇÈÉEÉFÉCÉgíl
					// TODO : í≤êÆÇ™ïKóv
					if( curve.Evaluate( frame ) != 0 ){
						weightVertices[ targetMeshIndexes[ i ] ] += targetMeshVertices[ i ] * curve.Evaluate( frame );
						weightVecCount[ targetMeshIndexes[ i ] ] += 1;
					} else {
						// weightílÇ™ïœâªÇµÇƒÇ¢Ç»Ç¢Ç»ÇÁéüÇÃï\èÓÇ÷
						// ñ≥ë Çè»Ç≠
						break;
					}
				}
			}
		}
		
		for( int i = 0; i < weightVertices.Length; i++ ){
			if( weightVecCount[ i ] != 0 ){
				weightVertices[ i ] /= weightVecCount[i];
			}
		}

		// ÉÇÅ[ÉtÉBÉìÉO
		// AnimationCurve Test
		for( int i = 0; i < weightVertices.Length; i++ ) {
			//Debug.Log( "a" + i );
			vertices[ sourceSkinBaseIndexes[ i ] ] = Vector3.Lerp( sourceMeshVertices[ sourceSkinBaseIndexes[ i ] ], sourceMeshVertices[ sourceSkinBaseIndexes[ i ] ] + weightVertices[ i ], 1);
		}

		mesh.vertices = vertices;
	}
	
	// 特定のアニメーションクリップの表情を設定
	void Play( string skinAnimeName ){
	
	
	
		// ï\èÓÇ≤Ç∆ÇÃïœâªÇ∑ÇÈÉtÉåÅ[ÉÄêîÇ∆ÉEÉFÉCÉgílÇäiî[
		Dictionary<string, VMDDataForMorph> vmdMotionDictionary;

		// ï\èÓñàÇÃìÆÇ©Ç∑í∏ì_Ç‚à íuèÓïÒÇäiî[
		Dictionary<string, SkinDataForMorph> skinMorphDictionary;

		// èâä˙âª
		allMorphingAnimeCurve = new Dictionary<string, AnimationCurve>();
		vmdMotionDictionary = new Dictionary<string, VMDDataForMorph>();
		skinMorphDictionary = new Dictionary<string, SkinDataForMorph>();

		// VMDDataForMorphÇÃÉfÅ[É^Çé´ìTÇ…ìoò^
		foreach( VMDDataForMorph motionData in skinAnimationMorph ) {
			Debug.Log( "SkinName : " + motionData.skinName );
			vmdMotionDictionary.Add( motionData.skinName, motionData );
		}

		// SkinDataForMorphÇÃÉfÅ[É^Çé´ìTÇ…ìoò^
		foreach( SkinDataForMorph skinData in skinMorph ) {
			skinMorphDictionary.Add( skinData.skinName, skinData );
		}

		// ï\èÓÇÃêîÇæÇØ
		for( int i = 0; i < skinMorph.Length; i++ ) {
			// ï\èÓÇ≤Ç∆Ç…AnimationCurveçÏê¨
			AnimationCurve curve = createAnimationCurveForSkinMorph( skinAnimationMorph[ i ] );
			allMorphingAnimeCurve.Add( skinMorph[ i ].name, curve );
		}
	}
	
	
	
	void OnApplicationQuit() {
		// sharedMeshÇÃèÍçá, ñ{óàÇÃÉÅÉbÉVÉÖèÓïÒÇïœçXÇµÇƒÇµÇ‹Ç§ÇΩÇﬂ
		// å≥ÇÃèÛë‘ÇÃí∏ì_èÓïÒÇèIóπéûÇ…ñﬂÇµÇƒè„Ç∞ÇÈïKóvÇ™Ç†ÇÈ
		Vector3[] vertices = mesh.vertices;

		for( int i = 0; i < vertices.Length; i++ ) {
			vertices[ i ] = sourceMeshVertices[ i ];
		}
		mesh.vertices = vertices;
	}
}
