/*
	TODO:
*/

#include <stdlib.h>
#include <string.h>
#include "speechy.h"

#define SILENCE			0x80
#define SAMPLE_RATE		8000
#define MILLISECONDS	1000

// Initialize a new voice with "count" amount of allophone slots
SPEECHY_VOICE *speechy_init(unsigned int num)
{
	SPEECHY_VOICE *voice;
	SPEECHY_SIGNAL *table;

	if(num>END_SEQ)
		return NULL;

	voice=(SPEECHY_VOICE*)malloc(sizeof(SPEECHY_VOICE));
	if(!voice)
		return NULL;

	table=(SPEECHY_SIGNAL*)calloc(sizeof(SPEECHY_SIGNAL), num);
	if(!table)
	{
		free(voice);
		return NULL;
	}

	voice->max=num;
	voice->count=0;
	voice->sequence=NULL;
	voice->pos=0;

	voice->table=table;

	return voice;
}


int speechy_add(SPEECHY_VOICE *voice, unsigned char *buffer, 
	unsigned int length, int copy)
{
	SPEECHY_SIGNAL *allophone;

	// Make sure we have a slot left
	if(voice->count>=voice->max)
		return 0;

	if(!length)
		return 0;

	allophone=&voice->table[voice->count];

	// Allocate space for the sample data
	if(copy)
	{
		allophone->data=malloc(sizeof(unsigned char*)*length);
		if(!allophone->data)
		{
			free(allophone->data);
			return 0;
		}
		allophone->copy=copy;
	}
	else
	{
		allophone->data=buffer;
	}

	// Copy the bytes over
	memcpy(allophone->data, buffer, length);
	allophone->length=length;

	// Increment allophone count
	voice->count++;

	return length;
}


int speechy_add_silence(SPEECHY_VOICE *voice, unsigned int time)
{
	SPEECHY_SIGNAL *allophone;
	unsigned int length;

	// Make sure we have a slot left
	if(voice->count>=voice->max)
		return 0;

	if(!time)
		return 0;

	allophone=&voice->table[voice->count];

	// TODO: Calculate the number of samples in "time" milliseconds, and allocate a
	// buffer for it. Don't forget to set "copy" to TRUE
	length=(SAMPLE_RATE/MILLISECONDS)*time;

	allophone->data=malloc(sizeof(unsigned char*)*length);
	if(!allophone->data)
	{
		free(allophone->data);
		return 0;
	}
	allophone->copy=length;

	// Copy the bytes over
	memset(allophone->data, SILENCE, length);
	allophone->length=length;

	// Increment allophone count
	voice->count++;

	return length;
}


int speechy_sequence(SPEECHY_VOICE *voice, short *sequence)
{
	unsigned short *ptr;
	int len;

	if(!sequence)
	{
		voice->sequence=NULL;
		voice->pos=0;
		return 0;
	}

	ptr=sequence;
	len=0;

	// Get the total length of the sequence in samples
	while(*ptr!=END_SEQ)
	{
		if(*ptr>=voice->count)
			return 0;

		len+=voice->table[*ptr].length;
		ptr++;
	}

	voice->sequence=sequence;
	voice->pos=0;

	return len;		
}


int speechy_read(SPEECHY_VOICE *voice, unsigned char *buffer, 
	unsigned int length)
{
	unsigned int i, pos, len, read_count=0, current;
	unsigned short *ptr;

	
	if(!voice->sequence || !length || !buffer)
		return 0;

	// Set positions to our next sample in the sequence
	ptr=voice->sequence;
	pos=voice->pos;
	current=ptr[0];
	len=voice->table[current].length;

	if(current!=END_SEQ)
	{
		// Give required samples to the user
		for(i=0; i<length; i++)
		{
			buffer[i]=voice->table[current].data[pos];
			pos++;

			// We've hit the end of this allophone, go to the next in sequence
			if(pos>=len)
			{
				pos=0;
				ptr++;
				current=*ptr;
				
				if(current==END_SEQ)
				{
					i++;
					break;
				}

				// Length of new allophone
				len=voice->table[current].length;
			}
		}

		read_count=i;
	}
	else
	{
		// Already at the end, so we read nothing
		read_count=0;
	}

	// End of the sequence, so reset everything
	if(*ptr==END_SEQ)
	{
		ptr=NULL;
		pos=0;
	}


	// Adjust the voice place-keepers before exiting
	voice->sequence=ptr;
	voice->pos=pos;

	return read_count;
}


void speechy_reset(SPEECHY_VOICE *voice)
{
	voice->sequence=NULL;
	voice->pos=0;
}


void free_allophone(SPEECHY_VOICE *voice, unsigned int index)
{
	SPEECHY_SIGNAL *allophone;

	allophone=&voice->table[index];

	if(allophone&&allophone->data&&allophone->copy)
	{
		free(allophone->data);
	}
}


void speechy_exit(SPEECHY_VOICE *voice)
{
	// Free all the allophones
	while(voice->count)
	{
		free_allophone(voice, voice->count);
		voice->count--;
	}

	free(voice->table);
	free(voice);
}
