//FIXME:initialize shutdown

#include "speech.h"
#include<stdlib.h>
#include"string.h"
#include<unistd.h>
#include"wave.h"
#include"ao/ao.h"
#include"debug.h"

#define BLOCK_SIZE 512

static t_wave_callback* my_callback_is_output_enabled=NULL;
static int requested_sample_rate = 0;
static size_t total_samples_sent = 0;
static ao_device* ao_dev = NULL;

void wave_init(int samplerate)
{
  ENTER("wave_init");
  ao_initialize();
  requested_sample_rate = samplerate;
  ao_sample_format format;
  bzero(&format, sizeof(ao_sample_format));
  const int default_driver = ao_default_driver_id();
  format.bits = 16;
  format.channels = 1;
  format.rate = samplerate;
  format.byte_format = AO_FMT_LITTLE;
  ao_dev = ao_open_live(default_driver, &format, NULL);
  if (ao_dev == NULL) 
    {
      SHOW("ERROR:wave_init() cannot create proper libao device for audio output with sample rate %u\n", samplerate);
      return;
    }
  SHOW("libao audio device was successfully created for sample rate %u\n", samplerate);
}

// TBD: the arg could be "alsa", "oss",...
void* wave_open(const char* the_api)
{
  ENTER("wave_open");
  return ao_dev;
}

size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize)
{
  ENTER("wave_write");
  //FIXME:big endian;
  if (theHandler == NULL)
    return 0;
  if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled())) 
    {
      SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
      return 0;
    }
  SHOW("ao:requested playback of %uk of audio data\n", theSize / 1024);
  size_t played = 0;
  while (played < theSize)
    {
      size_t pos, len;
      if (theSize - played > BLOCK_SIZE)
	{
	  pos = played;
	  len = BLOCK_SIZE;
	} else 
	{
	  pos = played;
	  len = theSize - played;
	}
      ao_device* device = (ao_device*)theHandler;
      const int res = ao_play(device, &theMono16BitsWaveBuffer[pos], len);
      SHOW("ao:ao_play() has returned %u to playback request of %u bytes of data", res, len);
      if (res == 0)
	{
	  SHOW("ao_play has returned an error exit code on operation to play %u bytes of data\n", theSize);
	  return 0;
	}
      played += len;
    }
  total_samples_sent += theSize / 2;
  SHOW("%u samples were successfully played by ao_play()", theSize);
  return theSize;
}

int wave_close(void* theHandler)
{
  //FIXME:
  return 0;
}

void wave_flush(void* theHandler)
{
  //FIXME:
}

int wave_is_busy(void* theHandler)
{
  //FIXME:
  return 0;
}

void wave_terminate()
{
  //FIXME:
}

uint32_t wave_get_read_position(void* theHandler)
{
  //FIXME:
  return 0;
}

uint32_t wave_get_write_position(void* theHandler)
{
  //FIXME:
  return 0;
}

// Supply the remaining time in ms before the sample is played
// (or 0 if the event has been already played).
// sample: sample identifier
// time: supplied value in ms
//
// return 0 if ok or -1 otherwise (stream not opened).
int wave_get_remaining_time(uint32_t sample, uint32_t* time)
{
  //FIXME:
  return 0;
}

// set the callback which informs if the output is still enabled.
// Helpful if a new sample is waiting for free space whereas sound must be stopped.
void wave_set_callback_is_output_enabled(t_wave_callback* cb)
{
  //FIXME:
}

// general functions
void clock_gettime2(struct timespec *ts)
{
  //FIXME:
}

void add_time_in_ms(struct timespec *ts, int time_in_ms)
{
  //FIXME:
}

// for tests
void *wave_test_get_write_buffer()
{
  //FIXME:
  return NULL;
}

