#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pspkernel.h>
#include <pspgu.h>
#include <pspgum.h>
#include "main.h"

struct CSActor {
	char name[128];
	struct AnimMesh *mesh;
	Image *skin;
	Image *icon;

	// for MD2
	int frameElapsed;
	int lastFrame;
	int frame;
	enum MotionType motion;

	float x,y,z,angle;	// target position
};

typedef enum SpeakerType { ST_HERO, ST_KING, ST_BROTHER } SpeakerType;

struct CSDialog {
	char *message;
	SpeakerType speaker;	// the actor speaking
	float dist1;
	float dist2;
} csDialog[]={
{"Vidar! How dare you show yourself in Yggdrasil!",ST_KING,100,60},
{"Relax Heimdallr, I come peacfully.",ST_BROTHER,40,40},
{"You will address him as King or father you traitor!",ST_HERO,40,40},
{"Be quiet, Njord! Let me deal with this.",ST_KING,100,100},
{"Yes, leave this matter to your aging dragon of a father.",ST_BROTHER,40,40},
{"Why you-!",ST_HERO,60,60},
//HEIMDALLR: Enough! How dare you use your powers here, Vidar!
{"The little twerp should not start things he can't finish.",ST_BROTHER,30,30},
{"Why are you here, Vidar? Enough of this game.",ST_KING,100,100},
{"I will cut to the chase then. I am here to tell you that Yggdrasil has one month before the kingdom of Hall declares war on it.",ST_BROTHER,100,100},
{"What is this nonsense? We have done nothing to offend your kingdom.",ST_KING,30,30},
{"Yes, but our king does seem to like this land very much and if you do not give it to him we will declare war on you. We know you have no champion so I suggest you simply hand over control and be done with it.",ST_BROTHER,30,30},
{ "I will not deal with those who would betray their own family and especially not with Hall!",ST_KING,60,60},
{ "Nevertheless, you have been warned. Hand over Yggdrasil or we will find out whether or not you can still handle yourself in battle. As you know, if a kingdom has no champion it is their king's duty to act as the champion and fight.",ST_BROTHER,60,120},
	//VIDAR turns and leaves the thrown. NJORD moves to his father's side.
{"Father, you surely do not believe you could ever defeat Vidar in battle, do you?",ST_HERO,60,30},
{"Not I, Njord, but you can. I have arranged to speed up your training - you will be going to Sushi Island.",ST_KING,60,60},
{"Are you saying that I am the new champion?",ST_HERO,30,30},
{"Yes, son. You will be leaving today. We only have a few weeks to get ready. If you face Vidar as our champion and win, we can divert war and keep our land. It is the only way.",ST_KING,80,80},
{"I... I understand father.",ST_HERO,60,120},
};
int csDialogCount=17;

struct CutScene {
	struct AnimMesh *brickMesh;
	struct CSActor actor[3];
	int dialogPos;
	int dialogElapsed;
	int throneId;
};

void loadCSActor(struct CSActor *actor,char *name,struct AnimMesh *mesh)
{
	char buf[256];
	strcpy(actor->name,name);
	sprintf(buf,"models/brick/%s_i.png",name);
	actor->icon=loadPng(buf);
	swizzleFast(actor->icon);
	sprintf(buf,"models/brick/%s.png",name);
	actor->skin=loadPng(buf);
	swizzleFast(actor->skin);
	actor->motion=MT_STAND;
	actor->mesh=mesh;
}

void setCSActorPos(struct CSActor *actor,float x,float z,float angle)
{
	actor->x=x;
	actor->y=0;
	actor->z=z;
	actor->angle=angle;
}

void freeCSActor(struct CSActor *actor)
{
	freeImage(actor->icon);
	freeImage(actor->skin);	
}

struct CutScene *initCutScene()
{
	struct CutScene *cs=calloc(sizeof(struct CutScene),1);

	freeItems();	// free all of the models.
	cs->throneId=loadItemImage("buildings/throneroom");
	cs->brickMesh=md2Load("models/brick/tris.md2");
	loadCSActor(&cs->actor[ST_HERO],"blue",cs->brickMesh);
	loadCSActor(&cs->actor[ST_BROTHER],"yellow",cs->brickMesh);
	loadCSActor(&cs->actor[ST_KING],"ice2001s",cs->brickMesh);
	setCSActorPos(cs->actor+ST_HERO,25,60,(GU_PI*2)*1/3);
	setCSActorPos(cs->actor+ST_KING,-25,60,(GU_PI*2)*2/3);
	setCSActorPos(cs->actor+ST_BROTHER,0,100,(GU_PI*2)*0/3);

	return cs;
}

void drawCSActor(struct CSActor *actor)
{
	if(!actor->mesh) return;
	int frameDuration=1000/animMotion[actor->motion].fps;
	float fraction=(actor->frameElapsed%frameDuration)/(float)frameDuration;
	int frame,nextFrame;
	frame=actor->lastFrame;
	nextFrame=actor->frame;

	struct AnimMesh *mesh=actor->mesh;
	struct Vertex3DTP *buffer=(struct Vertex3DTP *)sceGuGetMemory( sizeof(struct Vertex3DTP)*mesh->polyCount*3);
	//if(model->cullBackface==0) buffer=(struct Vertex3DTP *)(0x0fffffff&(int)buffer);
	buffer=(struct Vertex3DTP *)((int)buffer&~0x40000000);
	float minMax[6];
	md2GetFractionalFrame(mesh,frame,nextFrame,fraction,buffer,minMax);
	sceKernelDcacheWritebackAll();

	Image *source=actor->skin;
	if(source) {
		sceGuTexMode(GU_PSM_8888, 0, 0, source->isSwizzled);
		sceGuTexImage(0, source->textureWidth, source->textureHeight, source->textureWidth, source->data);
	}
	sceGumMatrixMode(GU_MODEL);
	sceGumPushMatrix();
	/*
	int i;
	for(i=0;i<6;i++) printf("minMax[%d]=%.2f; ",i,minMax[i]);
	printf("\n");
	*/
	ScePspFVector3 trans={actor->x,actor->y+25,actor->z};
	sceGumTranslate(&trans);
	sceGumRotateY(actor->angle);
	sceGumDrawArray(GU_TRIANGLES,GU_VERTEX_32BITF|GU_TEXTURE_32BITF|GU_TRANSFORM_3D,mesh->polyCount*3,0,buffer);
	sceGumPopMatrix();
	//printf("acting\n");
}

void drawCutScene(struct CutScene *cs)
{
	sceGumPushMatrix();
	ScePspFVector3 scale={5,5,5};
	sceGumScale(&scale);
	renderItem(cs->throneId);
	sceGumPopMatrix();
	drawCSActor(cs->actor+0);
	drawCSActor(cs->actor+1);
	drawCSActor(cs->actor+2);
	// Now draw the current dialog.
	drawFilledRect(0,172,480,272-172,GU_RGBA(0,0,0,0x80));
	drawSprite(0,0,32,32,cs->actor[csDialog[cs->dialogPos].speaker].icon,2,202);
	intraFontPrintColumn(iFont[FONT_MESSAGE],36,172+18,434,csDialog[cs->dialogPos].message);
}

void updateCSActor(struct CSActor *actor,int elapsed)
{
//	if(actor->oldMotion!=actor->motion) {
		//printf("character %s now doing motion %s.\n",actor->name,animMotionName[actor->motion]);
//		actor->oldMotion=actor->motion;
//	}

	actor->frameElapsed+=elapsed;
	
	// animate the MD2
	struct AnimMotion *motion=animMotion+actor->motion;
	int frameMod=actor->frameElapsed/(1000/motion->fps);
	frameMod+=motion->startFrame;
	if(frameMod>motion->endFrame) {
		frameMod=motion->startFrame;
		actor->frameElapsed=0;
		// we always cycle whatever motion.
	}
	if(frameMod!=actor->frame) {
		actor->lastFrame=actor->frame;
		actor->frame=frameMod;
	}
}

int updateCutScene(struct CutScene *cs,int elapsed)
{
	float fx=50,fy=80,fz=200,tx=0,ty=40,tz=0;
	
	cs->dialogElapsed+=elapsed;

	if(cs->dialogPos<csDialogCount) {
		SpeakerType who=csDialog[cs->dialogPos].speaker;
		tx=cs->actor[who].x;
		ty=cs->actor[who].y+20;
		tz=cs->actor[who].z;
		
		float cent=cs->dialogElapsed/1000.0f;
		if(cent>1) cent=1;
		float per=1-cent;
		//if(per!=0.0f) printf("Percent at %.3f\n",per);
		float dist=(csDialog[cs->dialogPos].dist1*per+csDialog[cs->dialogPos].dist2*cent)*1.5f;
		fx=tx+sinf(cs->actor[who].angle+GU_PI)*dist;
		fz=tz+cosf(cs->actor[who].angle+GU_PI)*dist;
		fy=ty+dist/2;
		updateCSActor(cs->actor+who,elapsed);
	}
	cameraSetFromTo(fx,fy,fz,tx,ty,tz);
	//updateCSActor(cs->actor+0,elapsed);
	//updateCSActor(cs->actor+1,elapsed);
	//updateCSActor(cs->actor+2,elapsed);
	
	return cs->dialogPos==csDialogCount;	// returns 1 when complete.
}

int handleCutScene(struct CutScene *cs,Buttons button)
{
	switch(button) {
	case BT_CROSS:
		cs->dialogPos++;
		cs->dialogElapsed=0;
		break;
	case BT_CIRCLE:
		cs->dialogPos=csDialogCount;
	default:
		break;
	}
	return 0;
}

void freeCutScene(struct CutScene *cs)
{
	if(cs->brickMesh) cs->brickMesh->texture=0;
	md2Free(cs->brickMesh);
	freeCSActor(cs->actor+0);
	freeCSActor(cs->actor+1);
	freeCSActor(cs->actor+2);
	freeItems();
}
