#include <pspkernel.h>
#include <pspctrl.h>
#include <pspdebug.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>


#define printf pspDebugScreenPrintf


#define MAXFILES 1000
#define PAGESIZE 32


static struct fileentries {
	char filename[FILENAME_MAX];
	char path[FILENAME_MAX];
	int flags;
} thefiles[MAXFILES];

static int maxfiles;


/****************************************************************************
 * get_buttons
 *
 ****************************************************************************/

static unsigned int get_buttons()
{
	SceCtrlData pad;

	sceCtrlReadBufferPositive(&pad, 1);
	return pad.Buttons;
}

/****************************************************************************
 * ParseDirectory
 *
 * Parse the directory, returning the number of files found
 ****************************************************************************/

int parse_dir (char *path)
{
	DIR *dir;
	DIR *test_dir;
	struct dirent *dirent = 0;
	struct stat fstat;
	char file_name[FILENAME_MAX];
	FILE *file;

	maxfiles = 0;
	/* open directory */
	if ( ( dir = opendir( path ) ) == 0 )
		return 0;

	while ( ( dirent = readdir( dir ) ) != 0 )
	{
		if ( dirent->d_name[0] == '.' ) continue;
		/* get stats */
		sprintf( file_name, "%s/%s", path, dirent->d_name );
		if ( stat( file_name, &fstat ) == -1 ) continue;
		/* check directory */
		if ( S_ISDIR( fstat.st_mode ) )
		{
			if ( ( test_dir = opendir( file_name ) ) == 0  ) continue;
			closedir( test_dir );
			memset (&thefiles[maxfiles], 0, sizeof (struct fileentries));
			strncpy(thefiles[maxfiles].path, path, FILENAME_MAX);
			thefiles[maxfiles].path[FILENAME_MAX-1] = 0;
			strncpy(thefiles[maxfiles].filename, dirent->d_name, FILENAME_MAX);
			thefiles[maxfiles].filename[FILENAME_MAX-1] = 0;
			thefiles[maxfiles].flags = 1;
			maxfiles++;
		}
		else
		/* check regular file */
		if ( S_ISREG( fstat.st_mode ) )
		{
			/* test it */
			if ( ( file = fopen( file_name, "r" ) ) == 0 ) continue;
			fclose( file );
			memset (&thefiles[maxfiles], 0, sizeof (struct fileentries));
			strncpy(thefiles[maxfiles].path, path, FILENAME_MAX);
			thefiles[maxfiles].path[FILENAME_MAX-1] = 0;
			strncpy(thefiles[maxfiles].filename, dirent->d_name, FILENAME_MAX);
			thefiles[maxfiles].filename[FILENAME_MAX-1] = 0;
			maxfiles++;
		}

		if (maxfiles == MAXFILES)
			break;
	}
	/* close dir */
	closedir( dir );

	return maxfiles;
}

/****************************************************************************
 * ShowFiles
 *
 * Support function for FileSelector
 ****************************************************************************/

void ShowFiles( int offset, int selection )
{
	int i,j;
	char text[69];

	pspDebugScreenClear();

	j = 0;
	for ( i = offset; i < ( offset + PAGESIZE ) && i < maxfiles ; i++ )
	{
		if ( thefiles[i].flags )
		{
			strcpy(text,"[");
			strncat(text, thefiles[i].filename,66);
			strcat(text,"]");
		}
		else
			strncpy(text, thefiles[i].filename, 68);

		text[68]=0;

		pspDebugScreenSetTextColor(j == ( selection - offset ) ? 0xFFFFFF : 0xAAAAAA);
		pspDebugScreenSetXY((68 - strlen(text)) / 2, i - offset + 1);
		printf("%s", text);

		j++;
	}
	pspDebugScreenSetTextColor(0xFFFFFF);
}

/****************************************************************************
 * FileSelector
 *
 * Press X to select, O to cancel, and Triangle to go back a level
 ****************************************************************************/

int FileSelector()
{
	int offset = 0;
	int selection = 0;
	int havefile = 0;
	int redraw = 1;
	unsigned int p = get_buttons();

	while ( havefile == 0 && !(p & PSP_CTRL_CIRCLE) )
	{
		if ( redraw )
			ShowFiles( offset, selection );
		redraw = 0;

		while (!(p = get_buttons()))
			sceKernelDelayThread(10000);
		while (p == get_buttons())
			sceKernelDelayThread(10000);

		if ( p & PSP_CTRL_DOWN )
		{
			selection++;
			if ( selection == maxfiles )
				selection = offset = 0;	// wrap around to top

			if ( ( selection - offset ) == PAGESIZE )
				offset += PAGESIZE; // next "page" of entries

			redraw = 1;
		}

		if ( p & PSP_CTRL_UP )
		{
			selection--;
			if ( selection < 0 )
			{
				selection = maxfiles - 1;
				offset = maxfiles > PAGESIZE ? selection - PAGESIZE + 1 : 0; // wrap around to bottom
			}

			if ( selection < offset )
			{
				offset -= PAGESIZE; // previous "page" of entries
				if ( offset < 0 )
					offset = 0;
			}

			redraw = 1;
		}

		if ( p & PSP_CTRL_RIGHT )
		{
			selection += PAGESIZE;
			if ( selection >= maxfiles )
				selection = offset = 0;	// wrap around to top

			if ( ( selection - offset ) >= PAGESIZE )
				offset += PAGESIZE; // next "page" of entries

			redraw = 1;
		}

		if ( p & PSP_CTRL_LEFT )
		{
			selection -= PAGESIZE;
			if ( selection < 0 )
			{
				selection = maxfiles - 1;
				offset = maxfiles > PAGESIZE ? selection - PAGESIZE + 1 : 0; // wrap around to bottom
			}

			if ( selection < offset )
			{
				offset -= PAGESIZE; // previous "page" of entries
				if ( offset < 0 )
					offset = 0;
			}

			redraw = 1;
		}

		if ( p & PSP_CTRL_CROSS )
		{
			if ( thefiles[selection].flags )	/*** This is directory ***/
			{
				char fname[FILENAME_MAX+FILENAME_MAX];

				strncpy(fname, thefiles[selection].path, FILENAME_MAX);
				fname[FILENAME_MAX-1] = 0;
				strncat(fname, thefiles[selection].filename, FILENAME_MAX);
				fname[FILENAME_MAX+FILENAME_MAX-2] = 0;
				strcat(fname, "/");
				offset = selection = 0;
				parse_dir(fname);
			}
			else
				return selection;

			redraw = 1;
		}

		if ( p & PSP_CTRL_TRIANGLE )
		{
			char fname[FILENAME_MAX];
			int pathpos = strlen(thefiles[1].path) - 2;

			while (pathpos > 5)
			{
				if (thefiles[1].path[pathpos] == '/') break;
				pathpos--;
			}
			if (pathpos < 5) pathpos = 5; /** handle root case */
			strncpy(fname, thefiles[1].path, pathpos+1);
			fname[pathpos+1] = 0;
			offset = selection = 0;
			parse_dir(fname);

			redraw = 1;
		}
	}

	return -1; // no file selected
}

/****************************************************************************
 * RequestFile
 *
 * return pointer to filename selected
 ****************************************************************************/

char *RequestFile (char *initialPath)
{
	int selection;
	static char fname[FILENAME_MAX+FILENAME_MAX];

	if (!parse_dir(initialPath))
		return 0;

	selection = FileSelector ();
	if (selection < 0)
		return 0;

	strncpy (fname, thefiles[selection].path, FILENAME_MAX);
	fname[FILENAME_MAX-1] = 0;
	strncat (fname, thefiles[selection].filename, FILENAME_MAX);
	fname[FILENAME_MAX+FILENAME_MAX-1] = 0;

	return fname;
}
