// ---------------------------------------------------------------------------
// - cdir.cxx                                                                -
// - standard platform library - c directory function implementation         -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - This program  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.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2011 amaury darsch                                   -
// ---------------------------------------------------------------------------

#include "cdir.hpp"
#include "cstr.hpp"
#include "cdir.hxx"

namespace afnix {

  // -------------------------------------------------------------------------
  // - private section                                                       -
  // -------------------------------------------------------------------------

  // the maximum directory size
  static const long CDIR_MAX_SIZE = 1024;

  // -------------------------------------------------------------------------
  // - public section                                                        -
  // -------------------------------------------------------------------------

  // return the root directory name

  const char* c_rootdir (void) {
    return AFNIX_PLATFORM_RDIR;
  }

  // return the temporary directory name

  const char* c_tempdir (void) {
    return AFNIX_PLATFORM_TDIR;
  }

  // return the os dependant directory separator
  
  const char c_dirsep (void) {
    return AFNIX_PLATFORM_DSEP;
  }

  // open a directory by name and return a handle

  void* c_opendir (const char* name) {
    // check for name first
    if (c_strlen (name) == 0) return 0;
    return opendir (name);
  }

  // get the next entry in the directory

  char* c_readdir (void* handle) {
    // get the handle
    if (!handle) return 0;
    DIR* dirp = (DIR*) handle;
    // get the next name
    struct dirent* ent = readdir (dirp);
    if (!ent) return 0;
    return c_strdup (ent->d_name);
  }

  // rewind the directory

  void c_rewinddir (void* handle) {
    // get the handle
    if (!handle) return;
    DIR* dirp = (DIR*) handle;
    rewinddir (dirp);
  }

  // close the directory structure

  void c_closedir (void* handle) {
    // get the handle
    if (!handle) return;
    DIR* dirp = (DIR*) handle;
    closedir (dirp);
  }

  // check if the name if a dot directory

  bool c_isdot (const char* name) {
    // check for nil
    if (name == nilp) return false;
    // loop in the dot directories
    const char* ddot[] = AFNIX_PLATFORM_DDOT;
    const char** ptr   = &ddot[0];
    while (*ptr != nilp) {
      if (c_strcmp (*ptr, name) == true) return true;
      ptr++;
    }
    return false;
  }

  // return the current directory name

  char* c_getcwd (void) {
    char* buffer = new char[CDIR_MAX_SIZE];
    char* name   = getcwd (buffer, CDIR_MAX_SIZE);
    char* result = c_strdup (name);
    delete [] buffer;
    return result;
  }

  // create a directory. If the directory exists, the function return
  // true. In case of error, return false

  bool c_mkdir (const char* name) {
    int         status;
    struct stat buffer;

    // check the name
    if (c_strlen (name) == 0) return false;
  
    // check if directory exists
    status = stat (name, &buffer);
    if ((status == 0) && S_ISDIR(buffer.st_mode)) return true;
  
    // try to create the directory
    status = mkdir (name,S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
    if (status  == 0) return true;
    return false;
  }

  // remove a directory - the function returns true on success

  bool c_rmdir (const char* name) {
    if (c_strlen (name) == 0) return true;
    if (rmdir (name)    != 0) return false;
    return true;
  }

  // rename a file with a new name

  bool c_rename (const char* opath, const char* npath) {
    if (c_strlen (opath) == 0) return false;
    if (c_strlen (npath) == 0) return false;
    if (rename (opath, npath) != 0) return false;
    return true;
  }

  // find a character extension position in reverse mode
  static long find_ext_reverse (const char* name, const char cbrk) {
    // get length and check
    long size = c_strlen (name);
    if (size == 0) return -1;
    for (long i = size-1; i >= 0; i--) {
      if (name[i] == cbrk)  return i;
      if (name[i] == AFNIX_PLATFORM_DSEP) break;
    }
    return -1;
  }

  // extract the directory name from a path

  char* c_xdir (const char* path) {
    // get extension position
    long pos = find_ext_reverse (path, AFNIX_PLATFORM_DSEP);
    if (pos == -1) return nilp;
    // prepare result
    char* result = new char[pos+1];
    for (long i = 0; i < pos; i++) result[i] = path[i];
    result[pos] = nilc;
    return result;
  }

  // extract the file name from a path

  char* c_xname (const char* path) {
    // get extension position
    long pos = find_ext_reverse (path, AFNIX_PLATFORM_DSEP);
    if (pos == -1) return c_strdup (path);
    // compute result size
    long size = c_strlen (path);
    long rlen = size - pos;
    long blen = rlen - 1;
    if (blen < 0) return c_strdup (path);
    // create result and copie
    char* result = new char[rlen];
    for (long i = 0; i < blen; i++) result[i] = path[pos+i+1];
    result[blen] = nilc;
    return result;
  }

  // remove the file extension from a file name

  char* c_rmext (const char* name) {
    // get extension position
    long pos = find_ext_reverse (name, '.');
    if (pos == -1) return c_strdup (name);
    // prepare result
    char* result = new char[pos+1];
    for (long i = 0; i < pos; i++) result[i] = name[i];
    result[pos] = nilc;
    return result;
  }

  // extract the file name extension

  char* c_xext (const char* name) {
    // get extension position
    long pos = find_ext_reverse (name, '.');
    if (pos == -1) return nilp;
    // compute result size
    long size = c_strlen (name);
    long rlen = size - pos;
    long blen = rlen - 1;
    if (blen < 0) return nilp;
    // create result and copie
    char* result = new char[rlen];
    for (long i = 0; i < blen; i++) result[i] = name[pos+i+1];
    result[blen] = nilc;
    return result;
  }
}
