#include <stdlib.h>
#include <stdio.h>

#include <nds.h>

#include "ds.h"
#include "quake_ipc.h"

unsigned char *S_LoadSound(char *name);
extern int com_filesize;
extern volatile unsigned int decoder_stopped;

unsigned int time_to_sleep = 0;

void ipc_block_ready_9to7(void)
{
	while (quake_ipc_9to7->message == 0xffffffff);
}

bool ipc_test_ready_9to7(void)
{
	return (quake_ipc_9to7->message == 0xffffffff);
}

void ipc_set_ready_9to7(void)
{
	quake_ipc_9to7->message = 0xffffffff;
}

void ipc_block_ready_7to9(void)
{
	while (quake_ipc_7to9->message == 0xffffffff);
}

bool arm7_ping = false;
void handle_ipc(void) __attribute__((section(".itcm"), long_call));
void handle_ipc(void)
{
	if (files_locked())
		return;
	
	if (quake_ipc_7to9->message == 0xffffffff)
	{
		switch (quake_ipc_7to9->message_type)
		{
			case kPrintMessage:
			{
				printf("%s", quake_ipc_7to9_buf);
				break;
			}
			case kPrintNumber:
			{
				printf("ARM7: %08x", *(unsigned int *)quake_ipc_7to9_buf);
				break;
			}
			case kPrintFloat:
			{
				printf("ARM7: %d", (int)*(volatile float *)quake_ipc_7to9_buf);
//				do
//				{
//					scanKeys();
//				} while (keysHeld());
				break;
			}
			case kMalloc:
			{
				printf("ARM7 malloc req %db...", *(volatile unsigned int *)quake_ipc_7to9_buf);
				volatile unsigned int addr = (volatile unsigned int)malloc(*(volatile unsigned int *)quake_ipc_7to9_buf);
				
				if (addr == 0)
					printf("\nARM7 MALLOC FAILED!\n");
				
				addr |= 0x400000;
				
//				printf("9 says %08x\n", addr);
				
				*(volatile unsigned int *)quake_ipc_7to9_buf = addr;
				quake_ipc_7to9->message_type = kMallocResponse;
				
//				printf("9 says %08x\n", addr);
				
				break;
			}
			case kFree:
			{
				printf("ARM7 free req on %08x\n", *(volatile unsigned int *)quake_ipc_7to9_buf);
				void *ptr = (void *)*(volatile unsigned int *)quake_ipc_7to9_buf;
				free(ptr);
				break;
			}
			case kFOpen:
			{
				file_lock();
				//this ain't gonna work for the exram build
				printf("ARM7 fopen: %s\n", quake_ipc_7to9_buf);
				FILE *fp = fopen((char *)quake_ipc_7to9_buf, "rb");
				
				if (fp)
					printf("...ok\n");
				else
				{
					printf("...failed to open\n", quake_ipc_7to9_buf);
					printf("message is %08x\nmessage type is %08x\ndata block is\n%08x\n%08x\n%08x\n",
						quake_ipc_7to9->message, quake_ipc_7to9->message_type,
						*(unsigned int *)quake_ipc_7to9_buf,
						*((unsigned int *)quake_ipc_7to9_buf + 1),
						*((unsigned int *)quake_ipc_7to9_buf + 2));
					*(int *)0 = 0;
					while(1);
				}
				
				printf("9: fp is %08x\n", (unsigned int)fp);
				
				*(volatile unsigned int *)quake_ipc_9to7_buf = (volatile unsigned int)fp;
				
				file_unlock();
				
				break;
			}
			case kFClose:
			{
				file_lock();
				
				printf("ARM7 fclose: %08x\n", *(volatile unsigned int *)quake_ipc_7to9_buf);
				unsigned int fp = *(volatile unsigned int *)quake_ipc_7to9_buf;
				fclose((FILE *)fp);
				
				file_unlock();
				
				break;
			}
			case kFRead:
			{
				file_lock();
				
				unsigned int buf = ((volatile unsigned int *)quake_ipc_7to9_buf)[0];
				unsigned int size = ((volatile unsigned int *)quake_ipc_7to9_buf)[1];
				unsigned int num = ((volatile unsigned int *)quake_ipc_7to9_buf)[2];
				unsigned int fp = ((volatile unsigned int *)quake_ipc_7to9_buf)[3];
				
				printf("ARM7 fread(%08x %d %d %08x)\n",
						buf, size, num, fp);
				
				unsigned int result = fread((unsigned char *)buf, size, num, (FILE *)fp);
				*(volatile unsigned int *)quake_ipc_9to7_buf = result;
				
				if (result != num)
					printf("9: too short\n");
				
				file_unlock();

				break;
			}
			case kStopMP3:
			{
				printf("received decoder stop message\n");
				decoder_stopped = 1;
				break;
			}
			case kS_LoadSound:
			{
//				printf("ARM9: S_LoadSound, %s\n", (char *)quake_ipc_7to9_buf);
				unsigned char *data = S_LoadSound((char *)quake_ipc_7to9_buf);
//				unsigned char *data = S_LoadSound("weapons/lhit.wav");
				
//				FILE *fp = fopen("fat0:/out.wav", "wb");
//				if (fp == NULL)
//					Sys_Error("failed to open file\n");
//				fwrite(data, 1, com_filesize, fp);
//				fclose(fp);
//				printf("done\n");
//				while(1);
				
				((unsigned int *)quake_ipc_7to9_buf)[0] = (unsigned int)data;	//yeah, I know
				((unsigned int *)quake_ipc_7to9_buf)[1] = com_filesize;
				
//				printf("ARM9: sound data is in %08x, size %d\n", (unsigned int)data, com_filesize);
//				printf("ARM9: read size as %d bytes\n", ((unsigned int *)data)[1] + 8);
				
				sysSetCartOwner(BUS_OWNER_ARM7);
				quake_ipc_7to9->message_type = kS_LoadSoundResponse;
				
				while (quake_ipc_7to9->message_type == kS_LoadSoundResponse);
				sysSetCartOwner(BUS_OWNER_ARM9);
				break;
			}
			case kHalt:
			{
				printf("ARM7 IS HALTING!\n");
				*(int *)0 = 0;
				while(1);
				break;
			}
			case kLidHasClosed:
			{
				printf("lid has closed\n");
				time_to_sleep = 1;
				break;
			}
			case kPing:
			{
				arm7_ping = !arm7_ping;
				unsigned short *text_map = (unsigned short *)SCREEN_BASE_BLOCK_SUB(9);
		
				if (arm7_ping)
					text_map[32 * 23] = 0xf058;
				else
					text_map[32 * 23] = 0xf02b;
					
				break;
			}	
		}
		
		quake_ipc_7to9->message = 0;
	}
}
