#include <stdio.h>
#include <string.h>

#include "sys.h"
#include "ds.h"

/*
===============================================================================

FILE IO

===============================================================================
*/

volatile unsigned int in_file_stuff = 0;

#define MAX_HANDLES             10
FILE    *sys_handles[MAX_HANDLES];

int             findhandle (void)
{
	int             i;
	
	for (i=1 ; i<MAX_HANDLES ; i++)
		if (!sys_handles[i])
			return i;
	Sys_Error ("out of handles");
	return -1;
}


/*
================
filelength
================
*/
int filelength (FILE *f)
{
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_lock();
	file_lock();
	
	int             pos;
	int             end;

	pos = ftell (f);
	fseek (f, 0, SEEK_END);
	end = ftell (f);
	fseek (f, pos, SEEK_SET);

	file_unlock();
	
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_unlock();
	
	return end;
}

int Sys_FileOpenRead (char *path, int *hndl)
{
//	printf("fopen %s\n", path);
	FILE    *f;
	int             i;
	
	char filename[256];
	strncpy(filename, path, 256);
	
	i = findhandle ();

	if (ds_find_dldi_slot() == 2)
		ds_try_exram_lock();
	file_lock();
	f = fopen(filename, "rb");
	file_unlock();
	
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_unlock();
	
	if (!f)
	{
		*hndl = -1;
//		printf("failed to open file %s\n", path);
		return -1;
	}
	sys_handles[i] = f;
	*hndl = i;
	
	int l = filelength(f);
	
	return l;
}

int Sys_FileOpenWrite (char *path)
{
	char filename[256];
	strncpy(filename, path, 256);
	
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_lock();
	file_lock();
	
	FILE    *f;
	int             i;
	
	i = findhandle ();

	f = fopen(filename, "wb");
	if (!f)
		Sys_Error ("Error opening %s", path);
	sys_handles[i] = f;
	
	file_unlock();
	
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_unlock();
	
	return i;
}

void Sys_FileClose (int handle)
{
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_lock();
	file_lock();
	
	fclose (sys_handles[handle]);
	sys_handles[handle] = 0;
	
	file_unlock();
	
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_unlock();
}

void Sys_FileSeek (int handle, int position)
{
	if (handle >= 0)
	{
		if (ds_find_dldi_slot() == 2)
			ds_try_exram_lock();
		file_lock();
		fseek (sys_handles[handle], position, SEEK_SET);
	//	printf("soke to %d (%d)\n", position, handle);
		file_unlock();
		
		if (ds_find_dldi_slot() == 2)
			ds_try_exram_unlock();
	}
	else
		printf("seeking with invalid handle\n");
}

void Sys_FileSeekMore (int handle, int position, int whence)
{
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_lock();
	file_lock();
	fseek (sys_handles[handle], position, whence);
//	printf("more to %d (%d)\n", position, handle);
	file_unlock();
	
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_unlock();
}

int Sys_FileRead (int handle, void *dest_r, int count)
{
	unsigned char *dest = (unsigned char *)dest_r;
	unsigned char buf[2048];
	int needs_read = count;
	int total_read = 0;
	
	while (needs_read > 0)
	{
		int to_read = needs_read > 2048 ? 2048 : needs_read;
		
		if (ds_find_dldi_slot() == 2)
			ds_try_exram_lock();
		file_lock();
	
		int length_read = fread (buf, 1, to_read, sys_handles[handle]);
	
		if (length_read != to_read)
			Sys_Printf("read was too short: wanted %d got %d\n", to_read, length_read);
		
		if (length_read == 0)
		{
			Sys_Printf("premature end to file\n");
			break;
		}
	
		file_unlock();
		
		if (ds_find_dldi_slot() == 2)
			ds_try_exram_unlock();
		
		ds_memcpy(dest, buf, to_read);
		dest += length_read;
		needs_read -= length_read;
		total_read += length_read;
	}
	
//	file_lock();
//	int length_read = fread (dest, 1, count, sys_handles[handle]);
//	if (length_read != count)
//		Sys_Printf("read was too short: wanted %d got %d\n", count, length_read);
//	file_unlock();
	
//	for (int count = 0; count < 4; count++)
//		printf("%02x%02x%02x%02x ", dest[count * 4 + 0], dest[count * 4 + 1], dest[count * 4 + 2], dest[count * 4 + 3]);
//	printf("\nread %d\n", length_read);
		
	return total_read;
}

//int mmap_file_handle = -1;
//unsigned mmap_file_length;
//
//void* mmap_openfile(char *filename)
//{
//	mmap_file_length = Sys_FileOpenRead(filename, &mmap_file_handle);
//	
//	if (mmap_file_length < 0)
//	{
//		Sys_Printf("failed to load in mmapped file, %s\n", filename);
//		return NULL;
//	}
//	else
//	{
//		Sys_Printf("file %s successfully mmapped\n", filename);
//		return (void *)0x10000000;
//	}
//}
//
//void mmap_closefile(void)
//{
//	 mmap_file_length = 0;
//	 Sys_FileClose(mmap_file_handle);
//}
//
unsigned int mmap_handle(unsigned ea, int direction, int size)
{
}
//{
//	unsigned int data;
////	ea = ea - 0x10000000;
//	
//	if (size == 0)
//		size = 4;
//	
//	Sys_Printf("handle %08x, %d, %d\n", ea, direction, size);
//	
//	if (direction == 1)			//load
//	{
////		Sys_FileSeek(mmap_file_handle, ea);
////		Sys_FileRead(mmap_file_handle, &data, size);
//		data = ea;
//		
////		Sys_Printf("data is %08x\n", data);
//	}
//	else if (direction == 0)	//store
//	{
//	}
//	else
//		Sys_Error("\nmemory direction is %d!\n", direction);
//	
////	while(1);
//	return data;
//}

//int Sys_FileWrite (int handle, void *data, int count) __attribute__ ((no_instrument_function));
//int Sys_FileWrite (int handle, void *data, int count)
//{
//#ifdef USE_EXTRA_RAM
//	if (((unsigned int)data >= (unsigned int)ds_exram_base())
//		&& ((unsigned int)data < (unsigned int)ds_exram_base() + ds_exram_size()))
//		Sys_Error("error: trying to write from extended memory (%08x > %08x)\n",
//			data, ds_exram_base());
//#endif
//	
//	if (ds_find_dldi_slot() == 2)
//		ds_try_exram_lock();
//	file_lock();
//	
//	int res = fwrite (data, 1, count, sys_handles[handle]);
//	
//	file_unlock();
//	
//	if (ds_find_dldi_slot() == 2)
//		ds_try_exram_unlock();
//	
//	return res;
//}

int Sys_FileWrite (int handle, void *data, int count)
{
	unsigned char *source = (unsigned char *)data;
	unsigned char buf[2048];
	int needs_write = count;
	int total_written = 0;
	
	while (needs_write > 0)
	{
		int to_write = needs_write > 2048 ? 2048 : needs_write;
		
		ds_memcpy(buf, source, to_write);
		
		if (ds_find_dldi_slot() == 2)
			ds_try_exram_lock();
		file_lock();
	
		int length_written = fwrite (buf, 1, to_write, sys_handles[handle]);
	
		if (length_written != to_write)
			Sys_Printf("write was too short: wanted %d got %d\n", to_write, length_written);
		
		if (length_written == 0)
		{
			Sys_Printf("premature end to file\n");
			break;
		}
	
		file_unlock();
		
		if (ds_find_dldi_slot() == 2)
			ds_try_exram_unlock();
		
		source += length_written;
		needs_write -= length_written;
		total_written += length_written;
	}
	
	return total_written;
}

int Sys_FileTime (char *path)
{
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_lock();
	file_lock();
	
	FILE    *f;
	
	f = fopen(path, "r");
	if (f)
	{
		fclose(f);
		file_unlock();
		return 1;
	}
	
	file_unlock();
	
	if (ds_find_dldi_slot() == 2)
		ds_try_exram_unlock();
	
	return -1;
}

int files_locked(void)
{
	return in_file_stuff;
}

void file_lock(void)
{
	int lock_count = 0;
	while (in_file_stuff == 1)
	{
		if (lock_count > 1000000)
		{
			printf("trying to lock file access\n");
			lock_count = 0;
		}
		lock_count++;
	}
	
	in_file_stuff = 1;
	
//	ds_try_exram_lock();
//	printf("file access locked\n");
}

void file_unlock(void)
{
//	printf("file access unlocked\n");
	if (in_file_stuff == 0)
		Sys_Error("trying to unlock memory - already unlocked!\n");
	in_file_stuff = 0;
//	ds_try_exram_unlock();
}
