#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;
} cdfiles[MAXFILES];

static int maxfiles;


// Sort the cdfiles by the order of string and DIR first.
static int cmpstringp(const void* p1, const void* p2)
{
    // We need to use qsort to sort, so this function is needed
    return strcmp(((struct fileentries*)p1) -> filename, ((struct fileentries*)p2) -> filename);
}

void sort_cdfiles()
{
    struct fileentries cdfiles_new[MAXFILES];
    int i, j = 0;
    qsort(&cdfiles, maxfiles, sizeof(struct fileentries), cmpstringp); 
    // Now we have to make the dir appear first, file next
    for(i = 0; i < maxfiles; i++){
        if(cdfiles[i].flags){
            cdfiles_new[j] = cdfiles[i];
            j++;
        }
    }
    for(i = 0; i < maxfiles; i++){
        if(!cdfiles[i].flags){
            cdfiles_new[j] = cdfiles[i];
            j++;
        }
    }
    // Now copy back from cdfiles_new to cdfiles;
    for(i = 0; i < maxfiles; i++){
        cdfiles[i] = cdfiles_new[i];
    }
}


/****************************************************************************
 * 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 (&cdfiles[maxfiles], 0, sizeof (struct fileentries));
         strncpy(cdfiles[maxfiles].path, path, FILENAME_MAX);
         cdfiles[maxfiles].path[FILENAME_MAX-1] = 0;
         strncpy(cdfiles[maxfiles].filename, dirent->d_name, FILENAME_MAX);
         cdfiles[maxfiles].filename[FILENAME_MAX-1] = 0;
         cdfiles[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 (&cdfiles[maxfiles], 0, sizeof (struct fileentries));
         strncpy(cdfiles[maxfiles].path, path, FILENAME_MAX);
         cdfiles[maxfiles].path[FILENAME_MAX-1] = 0;
         strncpy(cdfiles[maxfiles].filename, dirent->d_name, FILENAME_MAX);
         cdfiles[maxfiles].filename[FILENAME_MAX-1] = 0;
         maxfiles++;
      }

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

   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 ( cdfiles[i].flags )
      {
         strcpy(text,"[");
         strncat(text, cdfiles[i].filename,66);
         strcat(text,"]");
      }
      else
         strncpy(text, cdfiles[i].filename, 68);

      text[68]=0;

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

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

/****************************************************************************
 * 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 ( cdfiles[selection].flags )   /*** This is directory ***/
         {
            char fname[FILENAME_MAX+FILENAME_MAX];

            strncpy(fname, cdfiles[selection].path, FILENAME_MAX);
            fname[FILENAME_MAX-1] = 0;
            strncat(fname, cdfiles[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(cdfiles[1].path) - 2;

         while (pathpos > 5)
         {
            if (cdfiles[1].path[pathpos] == '/') break;
            pathpos--;
         }
         if (pathpos < 5) pathpos = 5; /** handle root case */
         strncpy(fname, cdfiles[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
 ****************************************************************************/

int save_path(char* p)
{
    FILE* pathfile = fopen("initpath", "w");
    if(pathfile == NULL){
        return -1;
    }
    fprintf(pathfile, "%s\n", p);
    fclose(pathfile);
    return 0;
}

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, cdfiles[selection].path, FILENAME_MAX);

   if(save_path(fname) == 0){
       printf("Error writing initpath file!\n");
   }

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

   return fname;
} 
