#include "ikSolver.h"
#include "skeleton.h"
#include "bone.h"

namespace vb01{
	void IkSolver::calculateFabrik(int chainLength, Bone **boneChain, Vector3 boneIkPos[], Vector3 targetPos){
		float sumLengths = 0;

		for(int i = 0; i < chainLength; i++)
			sumLengths += boneChain[i]->getLength();
		
		Skeleton *skeleton = boneChain[0]->getSkeleton();
		Bone *subBase = (Bone*)skeleton->getBone(boneChain[0]->getIkTarget())->getParent();
		Vector3 startPos = subBase->globalToLocalPosition(boneChain[chainLength - 1]->localToGlobalPosition(Vector3::VEC_ZERO));
		
		if(startPos.getDistanceFrom(targetPos) < sumLengths){
			int numIterations = 500;
	
			for(int i = 0 ; i < numIterations; i++){
				bool backward = (i % 2 == 0);

				for(int j = 0; j < chainLength; j++){
					int boneId;
					float length;
					Vector3 ikPos, bonePos, fromBoneToIkPos;

					if(backward){
						boneId = j;
						length = boneChain[boneId]->getLength();
						ikPos = (j == 0 ? targetPos : boneIkPos[boneId - 1]);
					}
					else{
						boneId = chainLength - 1 - j;

						if(j == 0){
							ikPos = startPos;
							length = 0;
						}
						else{
							ikPos = boneIkPos[boneId + 1];
							length = boneChain[boneId + 0]->getLength();
						}
					}

					bonePos = boneIkPos[boneId];
					fromBoneToIkPos = (ikPos - bonePos).norm();
					boneIkPos[boneId] = ikPos - fromBoneToIkPos * length;
				}
			}
		}
		else{
			Vector3 startToEndVec = (targetPos - startPos).norm();

			for(int i = chainLength - 1; i >= 0; i--){
				float length;
				Vector3 bonePos;

				if(i == chainLength - 1){
					length = 0;
					bonePos = boneIkPos[i];
				}
				else{
					length = boneChain[i]->getLength();
					bonePos = boneIkPos[i + 1];
				}

				boneIkPos[i] = bonePos + startToEndVec * length;
			}
		}
	}
}
