// canm.cpp
#include "canm.h"

#ifndef PandaWave_RESOURCES
#include "RevengeResources.h"
#endif

#include "RevengeApp.h"
#include <XMessages.h>
#include <assert.h>
#include "vengeance_script.h"

typedef struct ase_channel_s
{
	struct ase_channel_s* prev, *next;
	
	int tick;
	float q[4];
} ase_channel_t;

ase_channel_t* alloc_ase_channel( void )
{
	ase_channel_t* c = (ase_channel_t*)malloc(sizeof(ase_channel_t));
	if(c)
		c->next = 0;
	return c;
}

void free_channel_chain( ase_channel_t* chain )
{
	ase_channel_t* next;
	
	if( !chain )
		return;
		
	for( ; chain; chain = next )
	{
		next = chain->next;
		free(chain);
	}
}

byte_swap_code canm_int_codes[] =
{
	_begin_bs_array, 1,
	_4byte,
	_end_bs_array
};

byte_swap_code canm_q_codes[] =
{
	_begin_bs_array, 1,
	
	_4byte,
	_4byte,
	_4byte,
	_4byte,
	
	_end_bs_array
};
	
tag_entry* parse_camera_animation_from_ase( tag_file* t_file, XGFileSpecifier& ase_file )
{
	if( !load_script( &ase_file ) )
		return 0;

	char t[1024];		
	int rot_num=0, pos_num=0;
	ase_channel_t* rot_channel=0, *pos_channel=0, *frame;
	
	// parse out pos track first.
	if( !seek_to_token("*CONTROL_POS_TRACK") )
		goto fucked_in_the_ass;
	if( !parse_token(t) || strcmp(t, "{") )
		goto fucked_in_the_ass;
	
	if( !parse_token(t) )
		goto fucked_in_the_ass;
		
	while( strcmp(t, "}") )
	{
		if( strcmp(t, "*CONTROL_POS_SAMPLE") )
			goto fucked_in_the_ass;
			
		frame = alloc_ase_channel();
		if(!frame)
			goto fucked_in_the_ass;
		
		frame->next = pos_channel;
		frame->prev = 0;
		
		if(pos_channel)
			pos_channel->prev = frame;
		pos_channel = frame;
		
		if( !parse_int(&frame->tick) )
			goto fucked_in_the_ass;
		if( !parse_float(&frame->q[0]) )
			goto fucked_in_the_ass;
		if( !parse_float(&frame->q[1]) )
			goto fucked_in_the_ass;
		if( !parse_float(&frame->q[2]) )
			goto fucked_in_the_ass;
		
		frame->q[3] = 0.0f;
		
		pos_num++;
		
		if( !parse_token(t) )
			goto fucked_in_the_ass;
	}
	
	// parse out rot track.
	if( !seek_to_token("*CONTROL_ROT_TRACK") )
		goto fucked_in_the_ass;
	if( !parse_token(t) || strcmp(t, "{") )
		goto fucked_in_the_ass;
	
	if( !parse_token(t) )
		goto fucked_in_the_ass;
		
	while( strcmp(t, "}") )
	{
		if( strcmp(t, "*CONTROL_ROT_SAMPLE") )
			goto fucked_in_the_ass;
			
		frame = alloc_ase_channel();
		if(!frame)
			goto fucked_in_the_ass;
		
		frame->next = rot_channel;
		frame->prev = 0;
		
		if(rot_channel)
			rot_channel->prev = frame;
		rot_channel = frame;
		
		if( !parse_int(&frame->tick) )
			goto fucked_in_the_ass;
		if( !parse_float(&frame->q[0]) )
			goto fucked_in_the_ass;
		if( !parse_float(&frame->q[1]) )
			goto fucked_in_the_ass;
		if( !parse_float(&frame->q[2]) )
			goto fucked_in_the_ass;
		if( !parse_float(&frame->q[3]) )
			goto fucked_in_the_ass;

		rot_num++;
		
		if( !parse_token(t) )
			goto fucked_in_the_ass;
	}
	
	// close down the script.
	free_script();
	
	// allocate memory for the tag.
	int len = 8+6*4*(rot_num+pos_num);
	unsigned char* data = (unsigned char*)malloc(len);
	unsigned char* data_pos = data;
	
	if( !data )
		goto fucked_in_the_ass;
		
	// store the pos count.
	byte_swap_move_be("fuck you", data_pos, &pos_num, 4, 1, canm_int_codes);
	// store the rot count.
	byte_swap_move_be("fuck you", data_pos+4, &rot_num, 4, 1, canm_int_codes);
	data_pos+=8;
	
	// store pos frames.
	for(frame = pos_channel; frame->next; frame = frame->next) {}
	// go backwards because things are put on backwards.
	for(; frame; frame = frame->prev )
	{
		byte_swap_move_be("fuck you", data_pos, &frame->tick, 4, 1, canm_int_codes);
		byte_swap_move_be("fuck you", data_pos+4, frame->q, 16, 1, canm_q_codes);
		*((int*)(data_pos+20)) = 0; // pad.
		data_pos+=24;
	}
	
	// store rot frames.
	for(frame = rot_channel; frame->next; frame = frame->next) {}
	for(; frame; frame = frame->prev)
	{
		byte_swap_move_be("fuck you", data_pos, &frame->tick, 4, 1, canm_int_codes);
		byte_swap_move_be("fuck you", data_pos+4, frame->q, 16, 1, canm_q_codes);
		*((int*)(data_pos+20)) = 0;
		data_pos+=24;
	}
	
	assert( (data_pos-data) == len );
	
	free_channel_chain(rot_channel);
	free_channel_chain(pos_channel);
	
	tag_entry* entry = add_tag_entry(t_file, 'canm', 0, get_type_version('canm'), 0, 0, len, data, TRUE);
	
	return entry;
	
fucked_in_the_ass:
	free_script();
	free_channel_chain(rot_channel);
	free_channel_chain(pos_channel);
	return 0;
}