/*  RetroArch - A frontend for libretro.
 *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
 *  Copyright (C) 2011-2015 - Daniel De Matteis
 * 
 *  RetroArch is free software: you can redistribute it and/or modify it under the terms
 *  of the GNU General Public License as published by the Free Software Found-
 *  ation, either version 3 of the License, or (at your option) any later version.
 *
 *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE.  See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with RetroArch.
 *  If not, see <http://www.gnu.org/licenses/>.
 */

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

#include <debug.h>
#include <xenos/xenos.h>
//#include <diskio/dvd.h>
#include <diskio/ata.h>
#include <input/input.h>
#include <console/console.h>
//#include <diskio/diskio.h>
#include <usb/usbmain.h>
#include <time/time.h>
#include <ppc/timebase.h>
#include <xenon_soc/xenon_power.h>
#include <elf/elf.h>
#include <dirent.h>
#include "../compat/strl.h"

#undef main

int rarch_main(int argc, char **argv);
static void start_rarch(const char *path)
{
   char arg0[] = "retroarch";
   char arg1[256];
   strlcpy(arg1, path, sizeof(arg1));
   char *argv[3] = { arg0, arg1, NULL };
   rarch_main(sizeof(argv) / sizeof(argv[0]) - 1, argv);
}

#define FG_COL -1
#define BG_COL 0

#define MAX_FILES 1000
#define STICK_THRESHOLD 25000
#define MAX_DISPLAYED_ENTRIES 20

//#define MAX(a, b) (((a) > (b)) ? (a) : (b))
//#define MIN(a, b) (((a) < (b)) ? (a) : (b))

static struct dirent entries[MAX_FILES];
static int entrycount;

static void load_dir(const char *path)
{
   DIR *d = opendir(path);
   entrycount = 0;

   if (!d)
      return;

   for (struct dirent *de = readdir(d); de; de = readdir(d))
   {
      if (strcmp(de->d_name, "."))
      {
         memcpy(&entries[entrycount], de, sizeof(struct dirent));
         entrycount++;
      }
   }

   closedir(d);
}

static void append_dir_to_path(char *path, const char *dir)
{
   if (!strcmp(dir, ".."))
   {
      int i = strlen(path);
      int delimcount = 0;

      while (i >= 0 && delimcount < 2)
      {
         if (path[i] == '/')
         {
            delimcount++;

            if (delimcount > 1)
               path[i + 1]= '\0';
         }
         i--;
      }
   }
   else if (!strcmp(dir, "."))
      return;
   else
   {
      strlcat(path,  dir, sizeof(path));
      strlcat(path, "/", sizeof(path));
   }
}

int main(void)
{
   const char *s = NULL;
   char path[256];

   int handle;
   struct controller_data_s pad;
   int pos = 0, ppos = -1;

   xenos_init(VIDEO_MODE_AUTO);
   console_init();
   xenon_make_it_faster(XENON_SPEED_FULL);
   usb_init();
   usb_do_poll();
   xenon_ata_init();
   //dvd_init();

   handle = -1;
   handle = bdev_enum(handle, &s);
   if (handle < 0)
      return 0;

   strlcpy(path, s, sizeof(path));
   strlcat(path, ":/", sizeof(path));	

   load_dir(path);

   for (;;)
   {
      usb_do_poll();		
      get_controller_data(&pad, 0);

      if (pad.s1_y > STICK_THRESHOLD || pad.up)
         pos--;
      if (pad.s1_y < -STICK_THRESHOLD || pad.down)
         pos++;

      if (entrycount && (pos < 0 || pos >= entrycount))
      {
         pos = ppos;
         continue;
      }

      if (pad.logo)
         return 0;

      if (pad.a)
      {
         if (entries[pos].d_type & DT_DIR)
         {
            append_dir_to_path(path,entries[pos].d_name);
            load_dir(path);
            ppos = -1;
            pos = 0;
         }
         else
         {
            char fn[256];
            strlcpy(fn, path, sizeof(fn));
            strlcat(fn, entries[pos].d_name, sizeof(fn));

            printf("%s\n", fn);

            start_rarch(fn);
         }
      }

      if (pad.back)
      {
         append_dir_to_path(path, "..");
         load_dir(path);
         ppos = -1;
         pos = 0;
      }

      if (pad.b)
      {
         do
         {
            handle = bdev_enum(handle, &s);
         } while (handle < 0);

         strlcpy(path, s, sizeof(path));
         strlcat(path, ":/", sizeof(path));
         load_dir(path);
         ppos = -1;
         pos = 0;
      }

      if (ppos == pos)
         continue;

      memset(&pad, 0, sizeof(pad));

      console_set_colors(BG_COL, FG_COL);
      console_clrscr();
      printf("A: select, B: change disk, Back: parent dir, Logo: reload Xell\n\n%s\n\n", path);

      int start = MAX(0, pos - MAX_DISPLAYED_ENTRIES / 2);
      int count = MIN(MAX_DISPLAYED_ENTRIES, entrycount - start);

      for (int i = start; i < start + count; i++)
      {
         struct dirent *de = &entries[i];

         if (i == pos)
            console_set_colors(FG_COL, BG_COL);
         else
            console_set_colors(BG_COL, FG_COL);

         if (de->d_type & DT_DIR)
            console_putch('[');

         s = de->d_name;
         while (*s)
            console_putch(*s++);

         if (de->d_type & DT_DIR)
            console_putch(']');

         console_putch('\r');
         console_putch('\n');
      }

      ppos = pos;

      do
      {
         usb_do_poll();		
         get_controller_data(&pad, 0);
      } while (pad.a || pad.b || pad.back || pad.s1_y > STICK_THRESHOLD || pad.s1_y < -STICK_THRESHOLD);
   }

   return 0;
}
