/**
 *  PhysicsHair.h
 *
 *  Created on: 2010/11/29
 *  Copyright(c) Live2D Inc. All rights reserved.
 *  [[ CONFIDENTIAL ]]
 */
#ifndef __LIVE2D_PHYSICS_HAIR_H__
#define __LIVE2D_PHYSICS_HAIR_H__


#include "../Live2D.h"
#include "../memory/LDObject.h"
#include "../ALive2DModel.h"
#define _USE_MATH_DEFINES

#include	"../util/UtMath.h"

//--------- LIVE2D NAMESPACE ------------
namespace live2d 
{
	class IPhysicsSrc ;
	class IPhysicsTarget ;
	class MemoryParam ;

#ifndef __SKIP_DOC__

	
	class PhysicsPoint  : public live2d::LDObject 
	{
	public:
		PhysicsPoint()
			: mass(1) , x(0) ,y(0) ,vx(0),vy(0) ,ax(0),ay(0) , fx(0) , fy(0)
			, last_x(0) , last_y(0) , last_vx(0) , last_vy(0)
		{

		}
		
		void setupLast()
		{
			this->last_x = x ;
			this->last_y = y ;
			this->last_vx = vx ;
			this->last_vy = vy ;
		}

	public:
		float 	mass ;					// 質量(kg)
		
		float 	x  , y ;				// 位置(m)
		float 	vx ,vy ;				// 速度(m/s)
		float 	ax ,ay ;				// 加速度(m/s2)
			
		float 	fx ,fy ;				// 外力

		float 	last_x , last_y ;		// 
		float 	last_vx , last_vy ;		// 
		
	} ;

	
#endif // __SKIP_DOC__


	
	class PhysicsHair : public live2d::LDObject 
	{
	public:
		typedef enum 
		{
			SRC_TO_X = 0 ,
			SRC_TO_Y ,
			SRC_TO_G_ANGLE 
		} Src ;

		typedef enum 
		{
			TARGET_FROM_ANGLE = 0 ,// 髪の毛モデルのゆれの角度
			TARGET_FROM_ANGLE_V  // 髪の毛モデルのゆれの角速度（髪揺れの変形方向は速度方向に依存する）
		} Target ;

	public:
		// Constructor
		PhysicsHair() ;
		PhysicsHair(float baseLengthM , float airRegistance, float mass ) ;

		// Destructor
		virtual ~PhysicsHair();

	public:
		//  セットアップ
		//  baseLengthM 		髪の毛の長さ（メートル）
		//  airRegistance 	空気抵抗（デフォルト値 0.5）
		//  mass				髪の毛の質量（Kg）
		void setup(float baseLengthM , float airRegistance, float mass ) ;

		// 外部から点の位置初期化などを行った場合に呼ぶ
		void setup() ;


		// 髪の毛の基準点の X に紐づける値
		void addSrcParam( PhysicsHair::Src srcType , const char * paramID , float scale , float weight ) ;

		// 髪の毛の基準点の X に紐づける値
		void addTargetParam( PhysicsHair::Target targetType , const char * paramID , float scale , float weight ) ;
		
		//  更新
		void update(live2d::ALive2DModel * model , long long time);

		//  髪の根元の質点取得
		PhysicsPoint & getPhysicsPoint1(){ return p1 ; }

		//  髪の先端の質点取得
		PhysicsPoint & getPhysicsPoint2(){ return p2 ; }

		//  重力角度取得
		float getGravityAngleDeg(){ return this->gravityAngleDeg ; }

		//  重力角度セット
		void setGravityAngleDeg(float angleDeg){ this->gravityAngleDeg = angleDeg ; }
		
		//  角速度の取得
		float getAngleP1toP2Deg(){ return angleP1toP2Deg ; }

		//  各速度の計算結果取得
		float getAngleP1toP2Deg_velocity(){ return angleP1toP2Deg_v ; }
		

	private:
		//  更新
		void update_exe(live2d::ALive2DModel *& model, float dt);

		inline float calc_angleP1toP2()
		{
			return (float)(-180*(L2D_ATAN2(p1.x - p2.x, -(p1.y - p2.y)))/M_PI_F) ;
		}

	private:
		PhysicsPoint 						p1 ;							// 質点１（髪の根元）
		PhysicsPoint 						p2 ;							// 質点２（髪の先端）

		float		 						baseLengthM;					// 
		float 								gravityAngleDeg;				// 
		float 								airResistance;					// 

		float 								angleP1toP2Deg ;				// 計算結果
		float 								last_angleP1toP2Deg ;

		float 								angleP1toP2Deg_v ;				// 各速度の計算結果

		// 時刻情報
		long long 							startTime;						// 
		long long 							lastTime;						// 

		
		live2d::LDVector<IPhysicsSrc*>* 	srcListPtr ;					// 物理演算に関係づける元のパラメータ値

	   
		live2d::LDVector<IPhysicsTarget*>*	targetListPtr ;				 	// 物理演算結果を対応づけるパラメータ値

		live2d::MemoryParam*  				memoryManagement ;
		live2d::AMemoryHolder*				memoryHolderFixedMain ;

	};

}
//--------- LIVE2D NAMESPACE ------------



#endif	// __LIVE2D_PHYSICS_HAIR_H__