using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

/// <summary>
/// 表情の管理クラス
/// </summary>
public class ExpressionManagerScript : MonoBehaviour
{
	public Mesh mesh;	// メッシュ
	private Mesh renderer_shared_mesh;	// レンダー共有メッシュ

	/// <summary>
	/// 頂点モーフ
	/// </summary>
	[System.Serializable]
	public class VertexMorph {
		public int[] indices;			// 頂点インデックス
		public Vector3[] source;		// 頂点元座標
		public MMDSkinsScript[] script;	// 頂点モーフのスクリプト配列
		
		public VertexMorph(int[] i = null, Vector3[] s = null, MMDSkinsScript[] c = null) {indices = i; source = s; script = c;}
	}
	public VertexMorph vertex_morph = null;	// 頂点モーフ

	/// <summary>
	/// UVモーフ
	/// </summary>
	[System.Serializable]
	public class UvMorph {
		public int[] indices;			// UVインデックス
		public Vector2[] source;		// UV元座標
		public MMDSkinsScript[] script;	// UVモーフのスクリプト配列
		
		public UvMorph(int[] i = null, Vector2[] s = null, MMDSkinsScript[] c = null) {indices = i; source = s; script = c;}
	}
	public UvMorph[] uv_morph;			// UVモーフ


	/// <summary>
	/// 初回更新前処理
	/// </summary>
	void Start()
	{
		// meshの取得
		if (!mesh) {
			//後方互換用コード(新コンバータでは mesh は必ず設定される)
			//メッシュが設定されていなければ SkinnedMeshRenderer から取得する
			mesh = transform.parent.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh;
		}
		renderer_shared_mesh = (Mesh)Instantiate(mesh); //複製して、書き換えはそちらで行う
		renderer_shared_mesh.name = "ExpressionManagerScript/" + mesh.name;
		transform.parent.gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh = renderer_shared_mesh;

		// 頂点モーフ取得
		if (0 == vertex_morph.indices.Length) {
			//前方互換用コード(新コンバータでは vertex_morph は既に設定されている)
			int[] indices = transform.FindChild("base").GetComponent<MMDSkinsScript>().targetIndices;
			Vector3[] source = indices.Select(x=>mesh.vertices[x]).ToArray();
			MMDSkinsScript[] script = transform.GetComponentsInChildren<MMDSkinsScript>();
			vertex_morph = new VertexMorph(indices, source, script);
		}
	}
	
	/// <summary>
	/// 後更新処理
	/// </summary>
	void LateUpdate()
	{
		//描画確認
		if(!transform.parent.renderer.enabled) {
			//描画されていないなら
			//実行しない
			return;
		}
		
		//頂点モーフ計算
		ComputeVertexMorph();
		
		//UVモーフ計算
		ComputeUvMorph();
	}

	/// <summary>
	/// 頂点モーフ計算
	/// </summary>
	void ComputeVertexMorph()
	{
		if (0 < vertex_morph.indices.Length) {
			//各表情の合成ベクトルを初期化しておく
			Vector3[] composite = new Vector3[vertex_morph.source.Length];
			Array.Copy(vertex_morph.source, composite, vertex_morph.source.Length);
	
			// 表情ごとに計算する
			foreach (var s in vertex_morph.script) {
				s.Compute(composite);
			}
	
			// ここで計算結果を入れていく
			var vtxs = renderer_shared_mesh.vertices;	// 配列を受け入れ
			for (int i = 0, i_max = vertex_morph.indices.Length; i < i_max; ++i) {
				vtxs[vertex_morph.indices[i]] = composite[i];
			}
			renderer_shared_mesh.vertices = vtxs;	// ここで反映
		}
	}
	
	/// <summary>
	/// UVモーフ計算
	/// </summary>
	void ComputeUvMorph()
	{
		for (int i = 0, i_max = Math.Min(uv_morph.Length, 2); i < i_max; ++i) {
#if false
			//各表情の合成ベクトルを初期化しておく
			Vector2[] composite = new Vector2[uv_morph[i].source.Length];
			Array.Copy(uv_morph[i].source, composite, uv_morph[i].source.Length);
			
			// 表情ごとに計算する
			foreach (var s in uv_morph[i].script) {
				s.Compute(composite);
			}
			
			// ここで計算結果を入れていく
			var uvs = ((0 == i)? renderer_shared_mesh.uv: renderer_shared_mesh.uv2);	// 配列を受け入れ
			for (int k = 0, k_max = uv_morph[i].indices.Length; k < k_max; ++k) {
				uvs[uv_morph[i].indices[k]] = composite[k];
			}
			if (0 == i) {
				renderer_shared_mesh.uv = uvs;	// ここで反映
			} else {
				renderer_shared_mesh.uv2 = uvs;	// ここで反映
			}
#endif
		}
	}
}
