/*
 * ExNihilo 3D Engine
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Please read AUTHORS file !!!
 * 

 *
 */

#include "ExCAnimation.h"

ExCAnimation::ExCAnimation()
{
Guard(ExCAnimation::ExCAnimation())
	ExCObject3D::ExCObject3D();
	SetName("ExCAnimation");
	SetType(typeid(this).name());
	m_Time=0;
	m_CurrentAnimation=0;
	m_Pause=false;
UnGuard
}

ExCAnimation::~ExCAnimation()
{
Guard(ExCAnimation::~ExCAnimation())
UnGuard
}


void ExCAnimation::Draw(void)
{
Guard(void ExCAnimation::Draw(void))
	//Draw gizmo line
	for(unsigned int i=0;i<m_VecAnimation.size();i++)
	{
		m_VecAnimation.at(i).m_Line.Draw();
		//Draw Angle interpol point
		if(m_ShowPath)
		{
			ExCVec3D PositionAngle;
			glColor3f(0,0,1);
			glPushMatrix();
			PositionAngle=m_VecAnimation.at(i).m_Line.PointOnCurve(0.25);
			glTranslatef(PositionAngle.GetX(),PositionAngle.GetY(),PositionAngle.GetZ());
			glutWireSphere(5,8,8);
			glPopMatrix();

			glPushMatrix();
			PositionAngle=m_VecAnimation.at(i).m_Line.PointOnCurve(0.5);
			glTranslatef(PositionAngle.GetX(),PositionAngle.GetY(),PositionAngle.GetZ());
			glutWireSphere(5,8,8);
			glPopMatrix();

			glPushMatrix();
			PositionAngle=m_VecAnimation.at(i).m_Line.PointOnCurve(0.75);
			glTranslatef(PositionAngle.GetX(),PositionAngle.GetY(),PositionAngle.GetZ());
			glutWireSphere(5,8,8);
			glPopMatrix();
		}
	}
	float AgX,AgY,AgZ;
	//Get posistion on curve
	m_Object->m_Position=m_VecAnimation.at(m_CurrentAnimation).m_Line.PointOnCurve(m_Time);
	
	if(!m_Pause)
	{
		//Interpol angle
		float nbriterprc;
		nbriterprc=m_VecAnimation.at(m_CurrentAnimation).m_NumberIter/4;
		if(m_Time==0)
		{
			m_Object->m_Angle.SetValue(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetX(),
				m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetY(),
				m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetZ());

		}else
		{
			if(m_Time<=0.25)
			{
				AgX=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetX()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint1.GetX())/nbriterprc;
				AgY=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetY()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint1.GetY())/nbriterprc;
				AgZ=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetZ()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint1.GetZ())/nbriterprc;
				m_Object->m_Angle.DecX(AgX);
				m_Object->m_Angle.DecY(AgY);				
				m_Object->m_Angle.DecZ(AgZ);

			}
			if(m_Time>0.25&&m_Time<0.5)
			{

				AgX=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint1.GetX()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint2.GetX())/nbriterprc;
				AgY=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint1.GetY()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint2.GetY())/nbriterprc;
				AgZ=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint1.GetZ()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint2.GetZ())/nbriterprc;
				m_Object->m_Angle.DecX(AgX);
				m_Object->m_Angle.DecY(AgY);
				m_Object->m_Angle.DecZ(AgZ);
			}
			if(m_Time>0.5&&m_Time<0.75)
			{
				AgX=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint2.GetX()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint3.GetX())/nbriterprc;
				AgY=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint2.GetY()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint3.GetY())/nbriterprc;
				AgZ=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint2.GetZ()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint3.GetZ())/nbriterprc;
				m_Object->m_Angle.DecX(AgX);
				m_Object->m_Angle.DecY(AgY);
				m_Object->m_Angle.DecZ(AgZ);
			}
			if(m_Time>0.75&&m_Time<1)
			{
				AgX=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint3.GetX()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint4.GetX())/nbriterprc;
				AgY=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint3.GetY()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint4.GetY())/nbriterprc;
				AgZ=(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint3.GetZ()-m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint4.GetZ())/nbriterprc;
				m_Object->m_Angle.DecX(AgX);
				m_Object->m_Angle.DecY(AgY);
				m_Object->m_Angle.DecZ(AgZ);
			}

			
		}


		if(m_Loop)m_Time=m_Time+m_VecAnimation.at(m_CurrentAnimation).m_Speed;
		if (m_Time>1)
		{
			//std::cout<<"NExt anim "<<m_VecAnimation.at(m_CurrentAnimation).m_EndAction<<std::endl;
			if(m_VecAnimation.at(m_CurrentAnimation).m_EndAction.m_Action!=0)
			{
				FluxAction->Push(m_VecAnimation.at(m_CurrentAnimation).m_EndAction);
			}
			m_Time=0;
			m_CurrentAnimation++;
			if(m_CurrentAnimation>=m_VecAnimation.size())
			{
				if(m_Loop)
				{
					m_CurrentAnimation=0;
				}	
			}
		}
	}
UnGuard
}

void ExCAnimation::SetShowPathState(bool state)
{
	m_ShowPath=state;
	for(unsigned int i=0;i<m_VecAnimation.size();i++)
	{
		 m_VecAnimation.at(i).m_Line.SetVisibleState(m_ShowPath);
	}
}

bool ExCAnimation::LoadFile(std::string FileName)
{
Guard(bool ExCAnimation::LoadFile(std::string FileName))
	m_VecAnimation.clear();
	SetFileName(FileName);
	SetName(FileName);
	char			buffer[255];
	sprintf(buffer, "../Data/Animation/%s", FileName.data());
	std::ifstream fin;
	std::string buffstring;
	char b[256];
	fin.open(buffer,std::ios::in);
	
	AnimationStruct Anim;
	int tmpNumber;
	if(fin.is_open())
	{
		try
		{
			//----Read Type
			memset(b,0,255);
			fin.getline(b,256,'\n');
			//----Read Loop
			memset(b,0,255);
			fin.getline(b,256,'\n');
			m_Loop=ExNihilo::ExtractIntValueFromSring(b,"<Loop>","<#Loop>");
			//----Read TargetObjectType
			memset(b,0,255);
			fin.getline(b,256,'\n');
			m_TargetObjectType=ExNihilo::ExtracValueFromSring(b,"<TargetObjectType>","<#TargetObjectType>");
			//----Read TargetObjectName
			memset(b,0,255);
			fin.getline(b,256,'\n');
			m_TargetObjectName=ExNihilo::ExtracValueFromSring(b,"<TargetObjectName>","<#TargetObjectName>");
			//----Read ShowPath
			memset(b,0,255);
			fin.getline(b,256,'\n');
			m_ShowPath=(bool)ExNihilo::ExtractIntValueFromSring(b,"<ShowPath>","<#ShowPath>");
			//----Read Number of Bezier
			memset(b,0,255);
			fin.getline(b,256,'\n');
			tmpNumber=ExNihilo::ExtractIntValueFromSring(b,"<NumberOfBezier>","<#NumberOfBezier>");
		
			for(int i=0;i<tmpNumber;i++)
			{
				//----Read Bezier file
				memset(b,0,255);
				fin.getline(b,256,'\n');
				Anim.m_Line.LoadFile(ExNihilo::ExtracValueFromSring(b,"<BezierFile>","<#BezierFile>"));
				//----Read speed
				memset(b,0,255);
				fin.getline(b,256,'\n');
				Anim.m_Speed=ExNihilo::ExtractFloatValueFromSring(b,"<Speed>","<#Speed>");
				//----Read end action
				memset(b,0,255);
				fin.getline(b,256,'\n');
							
				buffstring=ExNihilo::ExtracValueFromSring(b,"<Exec_Action>","<#Exec_Action>");
				Anim.m_EndAction.m_Action=ExNihilo::ExtractIntValueFromSring(buffstring,"<Action>","<#Action>");
				Anim.m_EndAction.m_Param=ExNihilo::ExtracValueFromSring(buffstring,"<Param>","<#Param>");
				Anim.m_EndAction.m_Param1=ExNihilo::ExtracValueFromSring(buffstring,"<Param1>","<#Param1>");
				Anim.m_EndAction.m_Param2=ExNihilo::ExtracValueFromSring(buffstring,"<Param2>","<#Param2>");
				Anim.m_EndAction.m_ExecutingLife=ExNihilo::ExtractIntValueFromSring(buffstring,"<Timer>","<#Timer>");
				Anim.m_EndAction.m_StartingLife=(double)((double)glutGet(GLUT_ELAPSED_TIME)/1000);

				//---- Read CtrtPoint0Angle
				memset(b,0,255);
				fin.getline(b,256,'\n');
				buffstring=ExNihilo::ExtracValueFromSring(b,"<CtrlPoint0Angle>","<#CtrlPoint0Angle>");
				Anim.m_AngleCtrlPoint0.SetValue(ExNihilo::ExtractFloatValueFromSring(buffstring,"<X>","<#X>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Y>","<#Y>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Z>","<#Z>"));
				//---- Read CtrtPoint1Angle
				memset(b,0,255);
				fin.getline(b,256,'\n');
				buffstring=ExNihilo::ExtracValueFromSring(b,"<CtrlPoint1Angle>","<#CtrtPoint1Angle>");
				Anim.m_AngleCtrlPoint1.SetValue(ExNihilo::ExtractFloatValueFromSring(buffstring,"<X>","<#X>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Y>","<#Y>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Z>","<#Z>"));
				//---- Read CtrtPoint2Angle
				memset(b,0,255);
				fin.getline(b,256,'\n');
				buffstring=ExNihilo::ExtracValueFromSring(b,"<CtrlPoint2Angle>","<#CtrlPoint2Angle>");
				Anim.m_AngleCtrlPoint2.SetValue(ExNihilo::ExtractFloatValueFromSring(buffstring,"<X>","<#X>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Y>","<#Y>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Z>","<#Z>"));
				//---- Read CtrtPoint3Angle
				memset(b,0,255);
				fin.getline(b,256,'\n');
				buffstring=ExNihilo::ExtracValueFromSring(b,"<CtrlPoint3Angle>","<#CtrlPoint3Angle>");
				Anim.m_AngleCtrlPoint3.SetValue(ExNihilo::ExtractFloatValueFromSring(buffstring,"<X>","<#X>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Y>","<#Y>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Z>","<#Z>"));
				//---- Read CtrtPoint4Angle
				memset(b,0,255);
				fin.getline(b,256,'\n');
				buffstring=ExNihilo::ExtracValueFromSring(b,"<CtrlPoint4Angle>","<#CtrlPoint4Angle>");
				Anim.m_AngleCtrlPoint4.SetValue(ExNihilo::ExtractFloatValueFromSring(buffstring,"<X>","<#X>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Y>","<#Y>"),
					ExNihilo::ExtractFloatValueFromSring(buffstring,"<Z>","<#Z>"));
				
				Anim.m_NumberIter=1/Anim.m_Speed;
				m_VecAnimation.push_back(Anim);
			}
			fin.close();
		}
		catch(ExCExpStringNotFound)
		{
			std::cout<<"ExCExpStringNotFound"<<std::endl;
		}
		catch(...)
		{
			std::cout<<"ExCExpFileReadError"<<std::endl;
			throw ExCExpFileReadError();
		}
	}else throw   ExCExpFileNotFound();
	SetShowPathState(m_ShowPath);
	
	//Find manager where is the object and get pointer to object
	try
	{
	
		if(strcmpi(ManagerId->GetObjectManagerType(m_TargetObjectType).data(),"ExManagerCamera")==0)
		{
			m_Object=ManagerCamera->GetObject(ManagerId->GetObjectId(m_TargetObjectName,m_TargetObjectType));
			
		}
		if(strcmpi(ManagerId->GetObjectManagerType(m_TargetObjectType).data(),"ExManagerModel")==0)
		{
			m_Object=ManagerModel->GetObject(ManagerId->GetObjectId(m_TargetObjectName,m_TargetObjectType));
			
		}
		if(strcmpi(ManagerId->GetObjectManagerType(m_TargetObjectType).data(),"ExManagerEntity")==0)
		{
			m_Object=ManagerEntity->GetObject(ManagerId->GetObjectId(m_TargetObjectName,m_TargetObjectType));
			
		}
		m_Object->m_Angle.SetValue(m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetX(),
			m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetY(),
			m_VecAnimation.at(m_CurrentAnimation).m_AngleCtrlPoint0.GetZ());
		return true;
	}catch (...)
	{
		std::cout<<"Wrong animation object chek name or object type in your anim file"<<std::endl;
		return false;
	}
	return false;
UnGuard
}


