#include "..\..\source\fun3d\ScriptUtils.h"
#include <crtdbg.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>


#define MAX_ACTIONS 500

struct ActionTime {
	int startTime;
	int endTime;
	int actionNumber;
	int actionType;  // 1= Actor, 2= sound, 3= camera
} AllActionTimes[MAX_ACTIONS];

struct ActorAction {
	int actionTimeNumber;  // which of the action times is mine
	int actionNumber;
	int actionType;
	char actorName[20];
	char targetName[20];
} ActorActions[100];
	
struct SoundAction {
	int actionTimeNumber;  // which of the action times is mine
	int actionNumber;
	int fadeToVolume;
	int startFade;
	char sound[10];
} SoundActions[30];

struct CameraAction {
	int moveType; //1=dolly, 2=pan, 3=rotate, 4=chase
	float moveDuration;  //how long should this camera move take
	char attachObject[20]; //for chase and rotate. What object am I attached to?
	char viewObject[20]; //for chase and rotate. What object am I looking at?
	float rotation; //6.28 = a full rotation
	int startPosition; //0 = behind vehicle, 3.14 = in front of vehicle
	int xOffset; 
	int yOffset;
	int zOffset;
	Vector s_Position;
	Vector s_Direction;
	Vector e_Position;
	Vector e_Direction;
	char moveName[10];
} CameraActions[30];


/* Below are some variables declared to avoid repeating manage the cin move through
a series of frames.  These variables get cleaned up when a move ends.  We need to make sure
that we do this clean up if the player skips out of a cineractive.*/

CameraAction *playMe; //I've declared this as a global so that I do not need to search for the camera move to play every frame.
Vector position;
Vector direction;
Vector changePosition;
Vector changeDirection; 
bool startMove = false; //this tells us if we need to setup for the move or just continue a move
bool moveDone = false; //This will return true when the current camera move is done
int moveCount = 0; //this keep track of where we are in the move so we know when to end it
float t = 0.0;
float end = 0.0;
float speed = 0.0;



//add two vectors
Vector AddVectors(const Vector &A, const Vector &B)
{
	Vector v;
	v.x = A.x + B.x;
	v.y = A.y + B.y;
	v.z = A.z + B.z;
	return v;
}

// subtract two vectors
Vector SubVectors(const Vector &A, const Vector &B)
{
	Vector v;
	v.x = A.x - B.x;
	v.y = A.y - B.y;
	v.z = A.z - B.z;
	return v;
}

// divide a vector by a float
Vector DivVector(const Vector &A, float B)
{
	Vector v;
	v.x = A.x/B;
	v.y = A.y/B;
	v.z = A.z/B;
	return v;
}

//set one vector equal to another
Vector SetVector(const Vector &A)
{
	Vector v;
	v.x = A.x;
	v.y = A.y;
	v.z = A.z;
	return v;
}

//get the length of a vector
float VecLen(const Vector &A) {
	return (float)sqrt(A.x*A.x + A.y*A.y + A.z*A.z);
}


/* This function replaces CameraObject.  The target object will become the
offset point for any movement specified in the  X Y Z values that are passed
in.  The camera will look at the target object immediatly if the speed is set
to 0.  If speed is set to any other value the camera will interpolate its
direction from where it is now to the target object.
*/

void OffsetCamera(Handle attachObject, Handle targetObject, int xDist, int yDist, int zDist) {
    /* Set the camera position.  The camera will be set at the 
    exact offset specified by the parameters passed to the 
    function.
    */
    Vector rotatePoint = GetPosition(attachObject);
    GetCameraPosition(position, direction);
    position.x = (rotatePoint.x + xDist);
    position.y = (rotatePoint.y + yDist);
    position.z = (rotatePoint.z + zDist);
	Vector viewObject = GetPosition(targetObject);
	Vector distance = SubVectors(viewObject, position);
	distance = Normalize_Vector(distance);
    direction.x = distance.x;
    direction.y = distance.y;
    direction.z = distance.z;
    SetCameraPosition(position, direction);    
    
}
/* DollyCamera will move the camera from a start position and
orientation to an end postition and orientation. */

void DollyCamera(CameraAction *CamMove) {
	if (startMove == false) {
		position = SubVectors(CamMove->e_Position, CamMove->s_Position);
		direction = SubVectors(CamMove->e_Direction, CamMove->s_Direction);
		changePosition = DivVector(position, CamMove->moveDuration);
		changeDirection = DivVector(direction, CamMove->moveDuration);
		startMove = true; 
	}
	if (startMove == true) {
		if (moveCount <= CamMove->moveDuration) {
			GetCameraPosition(position, direction);
			position = AddVectors(position, changePosition);
			direction = AddVectors(direction, changeDirection);
		    SetCameraPosition(position, direction);
			moveCount++; 
			moveDone = false;
		}
		else if (moveCount > CamMove->moveDuration) {
			moveDone = true;
			startMove = false;
			moveCount = 0;
		}
	}
}

void PanCamera(CameraAction *CamMove) {
	if (startMove == false) {
		position = SubVectors(CamMove->e_Position, CamMove->s_Position);
		changePosition = DivVector(position, CamMove->moveDuration);
		startMove = true; 
	}
	
	if (startMove == true) {
		if (moveCount <= CamMove->moveDuration) {
			GetCameraPosition(position, direction);
			position = AddVectors(position, changePosition);
		    SetCameraPosition(position, direction);
			moveCount++; 
			moveDone = false;
		}
		else if (moveCount > CamMove->moveDuration) {
			moveDone = true;
			startMove = false;
			moveCount = 0;
		}

	}
}

void RotateCamera(CameraAction *CamMove) {
	if (startMove == false) {
		Vector object = GetFront(CamMove->attachObject[20]);
		t = ((float) ((atan2(object.x,object.z)) + CamMove->startPosition));
		end = (t + CamMove->rotation);
		startMove = true;
		speed = (CamMove->moveDuration/CamMove->rotation);
	}
	if (t <= end) {
		Handle attachObject = GetHandle(CamMove->attachObject);
		Handle viewObject = GetHandle(CamMove->viewObject);
		OffsetCamera(attachObject, viewObject, (int)(sin(t)*CamMove->xOffset), CamMove->yOffset, (int)(cos(t)*CamMove->zOffset));
		t += speed;
		moveDone = false;
	}
	else if (t > end) {
		moveDone = true;
		startMove = false;
		t = 0.0;
		speed = 0.0;
	}
}

void ChaseObject(CameraAction *CamMove) {
	if (moveCount <= CamMove->moveDuration) {
		/*set the offset position from the attached object.*/
		Handle aObj = GetHandle(CamMove->attachObject);
		Vector attachObject = GetPosition(aObj);
		Vector front = GetFront(aObj);
		position.x = (attachObject.x + (-front.x*CamMove->xOffset));
		position.y = (attachObject.y + CamMove->yOffset);
		position.z = (attachObject.z + (-front.z*CamMove->zOffset));
  		
		//set the camera to look at the appropriate target.	
		Handle vObj = GetHandle(CamMove->viewObject);
		Vector viewObject = GetPosition(vObj);
		Vector distance = SubVectors(viewObject, position);
		distance = Normalize_Vector(distance);
 		direction.x = distance.x;
		direction.y = distance.y;
		direction.z = distance.z;
		SetCameraPosition(position, direction);
		moveCount++;
		moveDone = false;
	}
	else if (moveCount > CamMove->moveDuration) {
		moveDone = true;
		startMove = false;
		moveCount = 0;
	}
}


CameraAction *findMoveData(char *moveName) {
	for (int i = 0; i < 30; i++) {
		if (strcmp(CameraActions[i].moveName,moveName) == 0)
			return &CameraActions[i];
	}
	return NULL;
}


void StartCamAction(CameraAction *CamMove) {
	switch (CamMove->moveType) {
	case 1:
		DollyCamera(CamMove);
		break;
	case 2:
		PanCamera(CamMove);
		break;
	case 3:
		RotateCamera(CamMove);
		break;
	case 4:
		ChaseObject(CamMove);
		break;
	}
}


void PlayAction(char *actionname) {
	if (startMove == false) {
		playMe = findMoveData(actionname); //playme is declared above as a global so we do not have to findMoveData on every frame
	}
	_ASSERTE(playMe != NULL);
	if (playMe != NULL) {
		StartCamAction(playMe);
	}
}


void GeorgeReadsData() { 

}



