#include <nds.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../ds_arm9/ds_shared.h"

//////////////////////////////////////////////////////////////////////


void startSound(const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F,  u8 pan=63) {
  SCHANNEL_TIMER(channel)  = SOUND_FREQ(11025);
  SCHANNEL_SOURCE(channel) = (uint32)data;
  SCHANNEL_LENGTH(channel) = bytes;
  SCHANNEL_CR(channel)     = SCHANNEL_ENABLE | SOUND_ONE_SHOT | SOUND_VOL(vol) | SOUND_PAN(pan) | SOUND_8BIT;
}

static int soundChannelPrior[16];
static int soundChannelId[16];
static int otherPlaying;

void EnsureSoundAlive(int id)
{
	int i = 0;
	while (i < g_sharedSound->clearSoundNum)
	{
		if (g_sharedSound->clearSoundIdImportance[i] == id)
		{
			g_sharedSound->clearSoundIdImportance[i] = -1;
		}
		i++;
	}
}

void KillSoundById(int id, int index)
{
	int i = 0;
	otherPlaying = 0;
	//before adding, make sure no other channels are playing the same sound right now
	while (i < 16)
	{
		if (i != index &&
			soundChannelId[i] == id)
		{
			otherPlaying = 1;
			break;
		}
		i++;
	}
	if (!otherPlaying && g_sharedSound->clearSoundNum < CLEAR_SOUND_MAX)
	{
		g_sharedSound->clearSoundIdImportance[g_sharedSound->clearSoundNum] = id;
		g_sharedSound->clearSoundNum++;
	}
}


void KillDeadSounds(void)
{
	int i;
	for (i = 0; i < 16; i++)
	{
		if (soundChannelId[i] != -1 &&
			(SCHANNEL_CR(i) & SCHANNEL_ENABLE) == 0)
		{
			KillSoundById(soundChannelId[i], i);
			soundChannelId[i] = -1;
		}
	}
}


int getFreeSoundChannel(int priority) {
  int i;

  for (i=0; i<16; i++)
  {
	  if ( (SCHANNEL_CR(i) & SCHANNEL_ENABLE) == 0 && soundChannelId[i] == -1 )
	  {
		  return i;
	  }
  }

  //if didn't find an open channel, try cutting something off
  for (i=0; i<16; i++)
  {
	  if (soundChannelPrior[i] < priority)
	  {
		  SCHANNEL_CR(i) = 0;
		  if (soundChannelId[i] != -1)
		  {
			  KillSoundById(soundChannelId[i], i);
		  }
		  return i;
	  }
  }

  return -1;
}

//////////////////////////////////////////////////////////////////////
//void ARM7InterruptHandler(void) {
void VblankHandler(void) {
	static int heartbeat = 0;

	uint16 but=0, x=0, y=0, xpx=0, ypx=0, z1=0, z2=0, batt=0, aux=0;
	int t1=0, t2=0;
	uint32 temp=0;
	uint8 ct[sizeof(IPC->curtime)];
	u32 i;

	// Update the heartbeat
	heartbeat++;

	// Read the touch screen

	but = REG_KEYXY;

	if (!(but & (1<<6))) {

		touchPosition tempPos = touchReadXY();

		x = tempPos.x;
		y = tempPos.y;
		xpx = tempPos.px;
		ypx = tempPos.py;
	}

	z1 = touchRead(TSC_MEASURE_Z1);
	z2 = touchRead(TSC_MEASURE_Z2);

	
	batt = touchRead(TSC_MEASURE_BATTERY);
	aux  = touchRead(TSC_MEASURE_AUX);

	// Read the time
	rtcGetTime((uint8 *)ct);
	BCDToInteger((uint8 *)&(ct[1]), 7);

	// Read the temperature
	temp = touchReadTemperature(&t1, &t2);

	// Update the IPC struct
	IPC->heartbeat	= heartbeat;
	IPC->buttons		= but;
	IPC->touchX			= x;
	IPC->touchY			= y;
	IPC->touchXpx		= xpx;
	IPC->touchYpx		= ypx;
	IPC->touchZ1		= z1;
	IPC->touchZ2		= z2;
	IPC->battery		= batt;
	IPC->aux			= aux;

	for(i=0; i<sizeof(ct); i++) {
		IPC->curtime[i] = ct[i];
	}

	IPC->temperature = temp;
	IPC->tdiode1 = t1;
	IPC->tdiode2 = t2;

	KillDeadSounds();

    //sound code  :)
    TransferSound *snd = IPC->soundData;
    IPC->soundData = 0;

    if (snd) {
	  int count = snd->count;
	  snd->count = 0;
      for (int i=0; i<count; i++) {
        int chan = getFreeSoundChannel(snd->data[i].format);
        if (chan >= 0) {
		  soundChannelPrior[chan] = snd->data[i].format;
		  soundChannelId[chan] = snd->data[i].rate; //rate == id
		  EnsureSoundAlive(snd->data[i].rate);
          startSound(snd->data[i].data, snd->data[i].len, chan, snd->data[i].vol, snd->data[i].pan);
        }
      }
    }
}
 
int main(int argc, char ** argv) {
	int i;
  // Reset the clock if needed
  rtcReset();

  //enable sound
  powerON(POWER_SOUND);
  SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F); //DSPIP4
  IPC->soundData = 0;

  for (i = 0; i < 16; i++)
  {
	  soundChannelPrior[i] = 0;
	  soundChannelId[i] = -1;
  }
  g_sharedSound->clearSoundNum = 0;

  // Set up the interrupt handler
  /*
  REG_IME = 0;
  IRQ_HANDLER = &ARM7InterruptHandler;
  REG_IE = IRQ_VBLANK|IRQ_TIMER3; //DSPIP
  REG_IF = ~0;
  DISP_SR = DISP_VBLANK_IRQ;
  REG_IME = 1;
  */
  irqInit();
  irqSet(IRQ_VBLANK, VblankHandler);
  irqEnable(IRQ_VBLANK);
  irqEnable(IRQ_VBLANK);

  // Keep the ARM7 out of main RAM
  while (1)
  {
	  swiWaitForVBlank();
  }
  return 0;
}

 
//////////////////////////////////////////////////////////////////////

