//
// Copyright (C) 1999-2002 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <WSCstring.h>
#include <WSDenv.h>
#include <WSClistData.h>
#include <x11/WSDunixFS.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>

WSDfileSystem* _unix_fs_chandler(){
  return new WSDunixFS();
}
void WSGFinitUnixFileSystem(){
extern void WSGFunixEnvInit();
    WSGFunixEnvInit();
    WSDfileSystem::setCreateInstanceHandler(_unix_fs_chandler);
}
class _unix_fs_init{
  public: _unix_fs_init(){
extern void WSGFunixEnvInit();
    WSGFunixEnvInit();
    WSDfileSystem::setCreateInstanceHandler(_unix_fs_chandler);
  };
};
_unix_fs_init _unix_fs_init_execute;

WSDunixFS::WSDunixFS(){}
WSDunixFS::~WSDunixFS(){}

char* WSDunixFS::adjustFileName(char* src){
static char  buf[1024];
//printf("WSDunixFS::adjustFileName(%s)\n",src);
  WSCstring str( WSGIappEnvironment()->getPlaneString(src));
  str.delHeadSpace();
  str.replaceString("\n","",0);
  str.replaceString("\\","/",0);

  char* fn = str.getString();
  if (fn[0] != 0 && fn[1] == ':'){
    str.deleteChars(0,2);
  }

  strncpy(buf,str.getString(),1023);
//printf("WSDunixFS::adjustFileName ->%s\n",buf);
  return buf;
}

static long unix_rename(char* old_name,char* new_name){
  if (rename(old_name,new_name) == 0){
    return WS_NO_ERR;
  }
  return WS_ERR;
}

long WSDunixFS::rename(char* old_name,char* new_name){
  return unix_rename(old_name,new_name);
}

long WSDunixFS::deleteFile(char* name){
  if (remove(name) == 0){
    return WS_NO_ERR;
  }
  return WS_ERR;
}

long WSDunixFS::createDir(char* name){
  if (mkdir(name,0777) == 0){
    return WS_NO_ERR;
  }
  return WS_ERR;
}

long WSDunixFS::deleteDir(char* name){
  if (rmdir(name) == 0){
    return WS_NO_ERR;
  }
  return WS_ERR;
}
#if 0
#define WS_CANNOT 0
#define WS_DIR 1
#define WS_WRITABLE_FILE 2
#define WS_READONLY_FILE 3
static long chk_file(char* file){
  struct stat sret;
  if (stat(file,&sret) == -1){
    return 0;
  }else if ((sret.st_mode & S_IFMT) == S_IFDIR){
    return WS_DIR;
  }else if (!(sret.st_mode & S_IFREG) || access(file,W_OK) == -1){
    return WS_READONLY_FILE;
  }
  return WS_WRITABLE_FILE;
}
#endif
long WSDunixFS::check(char* fname){
  struct stat sret;
  long ret = 0;
  if (stat(fname,&sret) == -1){
    return 0;
  }
  if ((sret.st_mode & S_IFMT) == S_IFDIR){
    ret |= WS_FS_DIR;
  }
  if (!(sret.st_mode & S_IFREG)){
    ret |= WS_FS_FILE;
  }
  if ( access(fname,W_OK) == -1){
    ret |= WS_FS_READONLY;
  }
  return ret;
}





WSClistData* WSDunixFS::showDir(char* dname){
  struct stat sret;
  dirent* finddata;
  DIR* dptr = opendir(dname);
//printf("dname=%s\n",dname);
  if (dptr == NULL){
//printf("dname=%s return NULL\n",dname);
    return NULL;
  }
  WSClistData* list = new WSClistData;
  WSClistData* list2 = new WSClistData;
  seekdir(dptr,0);
  while( (finddata = readdir(dptr)) != NULL){
//printf(" +-%s\n",finddata->d_name);
    if (!strcmp(finddata->d_name,"..")){
      continue;
    }
    if (!strcmp(finddata->d_name,".")){
      continue;
    }
    WSCstring fname;
    fname << dname << "/" << finddata->d_name;
    int ret = stat((char*)fname,&sret);
    if (ret < 0){
      continue;
    }
    if (sret.st_mode & S_IFDIR){
      list->add((void*)WSGFstrdup(finddata->d_name));
    }
  }
//printf(" done\n");
  closedir(dptr);
  WSGFsortCharList(list,list2);
  delete list;
  return list2;
#if 0
  char buf[8192];
  sprintf(buf,"/bin/ls %s",dname);

  FILE* pp;
  if (!(pp = popen(buf,"r"))){
    return NULL;
  }
  WSClistData* list = new WSClistData;

  while(fgets(buf,sizeof(buf),pp)){
    WSCstring str(buf);
    str.delString("\n",0);
    WSCstring str2(dname);
    str2.addString("/");
    str2.addString(str);
    if (chk_file(str2.getString()) == WS_DIR){
      list->add((void*)WSGFstrdup(str.getString()));
    }
  }
  pclose(pp);
  return list;
#endif
}
WSClistData* WSDunixFS::showFile(char* dname){
  struct stat sret;
  dirent* finddata;
  DIR* dptr = opendir(dname);
  if (dptr == NULL){
    return NULL;
  }
  WSClistData* list = new WSClistData;
  WSClistData* list2 = new WSClistData;
  while( (finddata = readdir(dptr)) != NULL){
    if (!strcmp(finddata->d_name,"..")){
      continue;
    }
    if (!strcmp(finddata->d_name,".")){
      continue;
    }
    WSCstring fname;
    fname << dname << "/" << finddata->d_name;
    int ret = stat((char*)fname,&sret);
    if (ret < 0){
      continue;
    }
    if (sret.st_mode & S_IFREG){
      list->add((void*)WSGFstrdup(finddata->d_name));
    }
  }
  closedir(dptr);
  WSGFsortCharList(list,list2);
  delete list;
  return list2;
#if 0
  char  buf[8192];
  sprintf(buf,"/bin/ls %s",name);

  FILE* pp;
  if (!(pp = popen(buf,"r"))){
    return NULL;
  }
  WSClistData* list = new WSClistData;

  while(fgets(buf,sizeof(buf),pp)){
    WSCstring str(buf);
    str.delString("\n",0);
    WSCstring str2(name);
    str2.addString("/");
    str2.addString(str);
    long iret = chk_file(str2.getString());
    if (iret  != WS_DIR && iret != WS_CANNOT){
      list->add((void*)WSGFstrdup(str.getString()));
    }
  }
  pclose(pp);
  return list;
#endif
}

