/*  RetroArch - A frontend for libretro.
 *  Copyright (C) 2011-2017 - 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 <compat/strl.h>
#include <lists/string_list.h>
#include <string/stdstring.h>
#include <file/file_path.h>
#include <file/archive_file.h>

#include <lists/dir_list.h>

#include <boolean.h>

#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif

#include "menu_filebrowser.h"

#include "../menu_driver.h"
#include "../menu_displaylist.h"

#include "../../configuration.h"
#include "../../paths.h"

#include "../../retroarch.h"
#include "../../core.h"
#include "../../content.h"
#include "../../verbosity.h"
#include "../../dynamic.h"

static enum filebrowser_enums filebrowser_types = FILEBROWSER_NONE;

enum filebrowser_enums filebrowser_get_type(void)
{
   return filebrowser_types;
}

void filebrowser_clear_type(void)
{
   filebrowser_types = FILEBROWSER_NONE;
}

void filebrowser_set_type(enum filebrowser_enums type)
{
   filebrowser_types = type;
}

void filebrowser_parse(menu_displaylist_info_t *info, unsigned type_data)
{
   size_t i, list_size;
   struct string_list *str_list         = NULL;
   unsigned items_found                 = 0;
   unsigned files_count                 = 0;
   unsigned dirs_count                  = 0;
   settings_t *settings                 = config_get_ptr();
   enum menu_displaylist_ctl_state type = (enum menu_displaylist_ctl_state)
                                          type_data;
   const char *path                     = info ? info->path : NULL;
   bool path_is_compressed              = !string_is_empty(path)
      ? path_is_compressed_file(path) : false;
   bool filter_ext                      =
      settings->bools.menu_navigation_browser_filter_supported_extensions_enable;

   rarch_system_info_t *system = runloop_get_system_info();
   const struct retro_subsystem_info *subsystem;

   /* Core fully loaded, use the subsystem data */
   if (system->subsystem.data)
      subsystem = system->subsystem.data + content_get_subsystem();
   /* Core not loaded completely, use the data we peeked on load core */
   else
      subsystem = subsystem_data + content_get_subsystem();

   if (info && string_is_equal(info->label,
            msg_hash_to_str(MENU_ENUM_LABEL_SCAN_FILE)))
      filter_ext = false;

   if (info && path_is_compressed)
   {
      if (filebrowser_types != FILEBROWSER_SELECT_FILE_SUBSYSTEM)
         str_list = file_archive_get_file_list(path, info->exts);
      else if (subsystem && subsystem_current_count > 0)
         str_list  = file_archive_get_file_list(path, subsystem->roms[content_get_subsystem_rom_id()].valid_extensions);
   }
   else if (!string_is_empty(path))
   {
      if (filebrowser_types == FILEBROWSER_SELECT_FILE_SUBSYSTEM)
      {
         if (subsystem && subsystem_current_count > 0 && content_get_subsystem_rom_id() < subsystem->num_roms)
            str_list = dir_list_new(path,
                  (filter_ext && info) ? subsystem->roms[content_get_subsystem_rom_id()].valid_extensions : NULL,
                  true, settings->bools.show_hidden_files, true, false);
      }
      else
         str_list = dir_list_new(path,
               (filter_ext && info) ? info->exts : NULL,
               true, settings->bools.show_hidden_files, true, false);
   }

   switch (filebrowser_types)
   {
      case FILEBROWSER_SCAN_DIR:
#ifdef HAVE_LIBRETRODB
         if (info)
            menu_entries_prepend(info->list,
                  msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY),
                  msg_hash_to_str(MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY),
                  MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY,
                  FILE_TYPE_SCAN_DIRECTORY, 0 ,0);
#endif
         break;
      case FILEBROWSER_SELECT_DIR:
         if (info)
            menu_entries_prepend(info->list,
                  msg_hash_to_str(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY),
                  msg_hash_to_str(MENU_ENUM_LABEL_USE_THIS_DIRECTORY),
                  MENU_ENUM_LABEL_USE_THIS_DIRECTORY,
                  FILE_TYPE_USE_DIRECTORY, 0 ,0);
         break;
      default:
         break;
   }

   if (!str_list)
   {
      const char *str = path_is_compressed
         ? msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE)
         : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND);

      if (info)
         menu_entries_append_enum(info->list, str, "",
               MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, 0, 0, 0);
      goto end;
   }

   dir_list_sort(str_list, true);

   list_size = str_list->size;

   if (list_size == 0)
   {
      string_list_free(str_list);
      str_list = NULL;
   }
   else
   {
      for (i = 0; i < list_size; i++)
      {
         char label[64];
         bool is_dir                   = false;
         enum msg_hash_enums enum_idx  = MSG_UNKNOWN;
         enum msg_file_type file_type  = FILE_TYPE_NONE;
         const char *path              = str_list->elems[i].data;

         label[0] = '\0';

         switch (str_list->elems[i].attr.i)
         {
            case RARCH_DIRECTORY:
               file_type = FILE_TYPE_DIRECTORY;
               break;
            case RARCH_COMPRESSED_ARCHIVE:
               file_type = FILE_TYPE_CARCHIVE;
               break;
            case RARCH_COMPRESSED_FILE_IN_ARCHIVE:
               file_type = FILE_TYPE_IN_CARCHIVE;
               break;
            case RARCH_PLAIN_FILE:
            default:
               if (filebrowser_types == FILEBROWSER_SELECT_FONT)
                  file_type = FILE_TYPE_FONT;
               else
                  file_type = (enum msg_file_type)info->type_default;
               switch (type)
               {
                  /* in case of deferred_core_list we have to interpret
                   * every archive as an archive to disallow instant loading
                   */
                  case DISPLAYLIST_CORES_DETECTED:
                     if (path_is_compressed_file(path))
                        file_type = FILE_TYPE_CARCHIVE;
                     break;
                  default:
                     break;
               }
               break;
         }

         is_dir = (file_type == FILE_TYPE_DIRECTORY);

         if (!is_dir)
         {
            if (filebrowser_types == FILEBROWSER_SELECT_DIR)
               continue;
            if (filebrowser_types == FILEBROWSER_SCAN_DIR)
               continue;
         }

         /* Need to preserve slash first time. */

         if (!string_is_empty(path) && !path_is_compressed)
            path = path_basename(path);

         if (filebrowser_types == FILEBROWSER_SELECT_COLLECTION)
         {
            if (is_dir)
               file_type = FILE_TYPE_DIRECTORY;
            else
               file_type = FILE_TYPE_PLAYLIST_COLLECTION;
         }

         if (!is_dir && path_is_media_type(path) == RARCH_CONTENT_MUSIC)
            file_type = FILE_TYPE_MUSIC;
         else if (!is_dir &&
               (settings->bools.multimedia_builtin_mediaplayer_enable ||
                settings->bools.multimedia_builtin_imageviewer_enable))
         {
            switch (path_is_media_type(path))
            {
               case RARCH_CONTENT_MOVIE:
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
                  if (settings->bools.multimedia_builtin_mediaplayer_enable)
                     file_type = FILE_TYPE_MOVIE;
#endif
                  break;
               case RARCH_CONTENT_IMAGE:
#ifdef HAVE_IMAGEVIEWER
                  if (settings->bools.multimedia_builtin_imageviewer_enable
                        && type != DISPLAYLIST_IMAGES)
                     file_type = FILE_TYPE_IMAGEVIEWER;
                  else
                     file_type = FILE_TYPE_IMAGE;
#endif
                  if (filebrowser_types == FILEBROWSER_SELECT_IMAGE)
                     file_type = FILE_TYPE_IMAGE;
                  break;
               default:
                  break;
            }
         }

         switch (file_type)
         {
            case FILE_TYPE_PLAIN:
#if 0
               enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_PLAIN_FILE;
#endif
               files_count++;
               break;
            case FILE_TYPE_MOVIE:
               enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_MOVIE_OPEN;
               files_count++;
               break;
            case FILE_TYPE_MUSIC:
               enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_MUSIC_OPEN;
               files_count++;
               break;
            case FILE_TYPE_IMAGE:
               enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_IMAGE;
               files_count++;
               break;
            case FILE_TYPE_IMAGEVIEWER:
               enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_IMAGE_OPEN_WITH_VIEWER;
               files_count++;
               break;
            case FILE_TYPE_DIRECTORY:
               enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
               dirs_count++;
               break;
            default:
               break;
         }

         items_found++;
         menu_entries_append_enum(info->list, path, label,
               enum_idx,
               file_type, 0, 0);
      }
   }

   if (str_list && str_list->size > 0)
      string_list_free(str_list);

   if (items_found == 0)
   {
      menu_entries_append_enum(info->list,
            msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ITEMS),
            msg_hash_to_str(MENU_ENUM_LABEL_NO_ITEMS),
            MENU_ENUM_LABEL_NO_ITEMS,
            MENU_SETTING_NO_ITEM, 0, 0);
   }

end:
   if (info && !path_is_compressed)
      menu_entries_prepend(info->list,
            msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY),
            path,
            MENU_ENUM_LABEL_PARENT_DIRECTORY,
            FILE_TYPE_PARENT_DIRECTORY, 0, 0);
}