/*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      File System Hooks.
 *
 *      By Thomas Fjellstrom.
 *
 *      See readme.txt for copyright information.
 */

/* Title: Filesystem routines
*/

#include "allegro5/allegro5.h"
#include ALLEGRO_INTERNAL_HEADER
#include "allegro5/debug.h"
#include "allegro5/fshook.h"
#include "allegro5/path.h"
#include "allegro5/internal/aintern.h"
#include "allegro5/internal/aintern_fshook.h"
#include "allegro5/internal/aintern_memory.h"


struct ALLEGRO_FS_HOOK_SYS_INTERFACE *_al_sys_fshooks = &_al_stdio_sys_fshooks;
struct ALLEGRO_FS_HOOK_ENTRY_INTERFACE *_al_entry_fshooks = &_al_stdio_entry_fshooks;


/* Function: al_create_entry
 */
ALLEGRO_FS_ENTRY *al_create_entry(const char *path)
{
   return _al_fs_hook_create(path);
}


/* Function: al_destroy_entry
 */
void al_destroy_entry(ALLEGRO_FS_ENTRY *handle)
{
   if (handle) {
      _al_fs_hook_destroy(handle);
   }
}


/* Function: al_open_entry
 */
bool al_open_entry(ALLEGRO_FS_ENTRY *handle)
{
   ASSERT(handle != NULL);

   return _al_fs_hook_open(handle);
}


/* Function: al_close_entry
 */
void al_close_entry(ALLEGRO_FS_ENTRY *handle)
{
   if (handle) {
      _al_fs_hook_close(handle);
   }
}


/* Function: al_get_entry_name
 */
ALLEGRO_PATH *al_get_entry_name(ALLEGRO_FS_ENTRY *fp)
{
   ASSERT(fp != NULL);

   return _al_fs_hook_entry_name(fp);
}


/* Function: al_fstat
 */
bool al_fstat(ALLEGRO_FS_ENTRY *fp)
{
   ASSERT(fp != NULL);

   return _al_fs_hook_entry_stat(fp);
}


/* Function: al_opendir
 */
ALLEGRO_FS_ENTRY *al_opendir(const char *path)
{
   ALLEGRO_FS_ENTRY *dir = NULL;

   ASSERT(path != NULL);

   dir = _al_fs_hook_opendir(path);
   if (!dir)
      return NULL;

   return dir;
}


/* Function: al_closedir
 */
bool al_closedir(ALLEGRO_FS_ENTRY *dir)
{
   ASSERT(dir != NULL);

   return _al_fs_hook_closedir(dir);
}


/* Function: al_readdir
 */
ALLEGRO_FS_ENTRY *al_readdir(ALLEGRO_FS_ENTRY *dir)
{
   ASSERT(dir != NULL);

   return _al_fs_hook_readdir(dir);
}


/* Function: al_get_entry_mode
 */
uint32_t al_get_entry_mode(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);
   return _al_fs_hook_entry_mode(e);
}


/* Function: al_get_entry_atime
 */
time_t al_get_entry_atime(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);
   return _al_fs_hook_entry_atime(e);
}


/* Function: al_get_entry_mtime
 */
time_t al_get_entry_mtime(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);
   return _al_fs_hook_entry_mtime(e);
}


/* Function: al_get_entry_ctime
 */
time_t al_get_entry_ctime(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);
   return _al_fs_hook_entry_ctime(e);
}


/* Function: al_get_entry_size
 */
off_t al_get_entry_size(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);

   return _al_fs_hook_entry_size(e);
}


/* Function: al_remove_entry
 */
bool al_remove_entry(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);

   return _al_fs_hook_entry_remove(e);
}


/* Function: al_is_present
 */
bool al_is_present(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);

   return _al_fs_hook_entry_exists(e);
}


/* Function: al_is_directory
 */
bool al_is_directory(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);
   return al_get_entry_mode(e) & ALLEGRO_FILEMODE_ISDIR;
}


/* Function: al_is_file
 */
bool al_is_file(ALLEGRO_FS_ENTRY *e)
{
   ASSERT(e != NULL);
   return al_get_entry_mode(e) & ALLEGRO_FILEMODE_ISFILE;
}


/* Function: al_getcwd
 */
ALLEGRO_PATH *al_getcwd(void)
{
   return _al_fs_hook_getcwd();
}


/* Function: al_chdir
 */
bool al_chdir(const char *path)
{
   ASSERT(path);

   return _al_fs_hook_chdir(path);
}


/* Function: al_mkdir
 */
bool al_mkdir(const char *path)
{
   ASSERT(path);

   return _al_fs_hook_mkdir(path);
}


/* Function: al_add_search_path
 */
bool al_add_search_path(const char *path)
{
   ASSERT(path);

   return _al_fs_hook_add_search_path(path);
}


/* Function: al_search_path_count
 */
int32_t al_search_path_count()
{
   return _al_fs_hook_search_path_count();
}


/* Function: al_get_search_path
 */
bool al_get_search_path(uint32_t idx, char *dest, size_t len)
{
   ASSERT(dest);
   ASSERT(len);

   return _al_fs_hook_get_search_path(idx, dest, len);
}


/* Function: al_drive_sep
 */
int32_t al_drive_sep(char *sep, size_t len)
{
   ASSERT(len > 0);
   ASSERT(sep);

   return _al_fs_hook_drive_sep(sep, len);
}


/* Function: al_path_sep
 */
int32_t al_path_sep(char *sep, size_t len)
{
   ASSERT(len > 0);
   ASSERT(sep);

   return _al_fs_hook_path_sep(sep, len);
}


/* Function: al_get_entry_mode_str
 */
uint32_t al_get_entry_mode_str(const char *path)
{
   ASSERT(path != NULL);
   return _al_fs_hook_stat_mode(path);
}


/* Function: al_remove_str
 */
bool al_remove_str(const char *path)
{
   ASSERT(path != NULL);
   return _al_fs_hook_remove(path);
}


/* Function: al_is_present_str
 */
bool al_is_present_str(const char *path)
{
   ASSERT(path != NULL);

   return _al_fs_hook_exists(path);
}


/* maybe find a better place for this later */
static bool _al_find_resource_exists(const char *path, const char *base,
   const char *resource, uint32_t fm, char *buffer, size_t len)
{
   ALLEGRO_PATH *fp;
   bool ret = false;
   const char *s;

   memset(buffer, 0, len);

   fp = al_path_create(path);
   /* XXX this isn't strictly correct, is it? */
   al_path_append(fp, base);

   if (resource) {
      ALLEGRO_PATH *resp = al_path_create(resource);
      al_path_concat(fp, resp);
      al_path_free(resp);
   }

   s = al_path_to_string(fp, ALLEGRO_NATIVE_PATH_SEP);
   _al_sane_strncpy(buffer, s, len);

   if (al_is_present_str(buffer) && (al_get_entry_mode_str(buffer) & fm) == fm) {
      ret = true;
   }
   else if (fm & ALLEGRO_FILEMODE_WRITE) {
      /* XXX update this */
      /* XXX is this supposed to be chr or rchr? */
      /* FIXME: Or rather, what was this even supposed to accomplish??? */
      /*char *rchr = strchr(buffer, ALLEGRO_NATIVE_PATH_SEP);
      if (rchr) {
         usetc(rchr, '\0');

         if (al_is_present_str(buffer) && al_get_entry_mode_str(buffer) & ALLEGRO_FILEMODE_WRITE) {
            ret = true;
         }

         *rchr = ALLEGRO_NATIVE_PATH_SEP;
      }
      * */
   }

   al_path_free(fp);

   return ret;
}


// FIXME: Not needed after some code cleanup.
static char const *path_to_buffer(ALLEGRO_PATH *path, char *buffer, size_t size)
{
   char const *str = al_path_to_string(path, '/');
   _al_sane_strncpy(buffer, str, size);
   al_path_free(path);
   return buffer;
}


/* Function: al_find_resource
 */
char *al_find_resource(const char *base, const char *resource, uint32_t fm,
   char *buffer, size_t len)
{
   ALLEGRO_PATH *path;
   char tmp[PATH_MAX];
   char base_new[256];
   const char *s;
   bool r;

   ASSERT(base != NULL);
   ASSERT(resource != NULL);
   ASSERT(buffer != NULL);

   fm |= ALLEGRO_FILEMODE_READ;

   memset(buffer, 0, len);

#ifdef ALLEGRO_WINDOWS
   memset(base_new, 0, 256);
#else
   strcpy(base_new, ".");
#endif

   strcat(base_new, base);

   path = al_get_standard_path(ALLEGRO_USER_DATA_PATH);
   //printf("find_resource: AL_USER_DATA_PATH\n");
   if (_al_find_resource_exists(path_to_buffer(path, tmp, PATH_MAX),
      base_new, resource, fm, buffer, len)) {
      return buffer;
   }

   path = al_get_standard_path(ALLEGRO_PROGRAM_PATH);
   //printf("find_resource: AL_PROGRAM_PATH\n");
   if (_al_find_resource_exists(path_to_buffer(path, tmp, PATH_MAX),
      "data", resource, fm, buffer, len)) {
      return buffer;
   }

   path = al_getcwd();
   r = _al_find_resource_exists(al_path_to_string(path, '/'), "data",
      resource, fm, buffer, len);
   al_path_free(path);
   //printf("find_resource: getcwd\n");
   if (r) {
      return buffer;
   }

   path = al_get_standard_path(ALLEGRO_SYSTEM_DATA_PATH);
   //printf("find_resource: AL_SYSTEM_DATA_PATH\n");
   if (_al_find_resource_exists(path_to_buffer(path, tmp, PATH_MAX),
      base_new, resource, fm, buffer, len)) {
      return buffer;
   }

   /* file didn't exist anywhere, lets return whatever we can */

   path = al_get_standard_path(ALLEGRO_USER_DATA_PATH);
   //printf("find_resource: def AL_USER_DATA_PATH\n");
   al_path_append(path, base_new);

   if (resource) {
      ALLEGRO_PATH *resp = al_path_create(resource);
      al_path_concat(path, resp);
      al_path_free(resp);
   }

   s = al_path_to_string(path, ALLEGRO_NATIVE_PATH_SEP);
   _al_sane_strncpy(buffer, s, len);

   al_path_free(path);

   return buffer;
}


/*
 * Local Variables:
 * c-basic-offset: 3
 * indent-tabs-mode: nil
 * End:
 */
/* vim: set sts=3 sw=3 et: */
