//
// 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.

#ifdef BTRON
#include <basic.h>
#include <tstring.h>
#include <btron/file.h>
#endif
#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>
#include <WSClocaleSet.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){
  WSCstring name1(old_name);
  WSCstring name2(new_name);
#ifdef MacOS
  if (WSGIappLocaleSet()->getSystemLocaleEncoding() == WS_EN_UTF8){
extern char* utf8_to_macutf8(char*);
    char* mstr1 = utf8_to_macutf8(
          name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()));
    char* mstr2 = utf8_to_macutf8(
          name2.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()));
    long ret;
    if (mstr1 != NULL && mstr2 != NULL){
      ret = unix_rename(mstr1,mstr2);
    }
    if (mstr1 != NULL){
      delete mstr1;
    }
    if (mstr2 != NULL){
      delete mstr2;
    }
    return ret;
  }else{
    return unix_rename(
     name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
     name2.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()));
  }
#else
  return unix_rename(
     name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
     name2.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()));
#endif
}

long WSDunixFS::deleteFile(char* name){
  WSCstring name1(name);
  char* fn = name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
#ifdef MacOS
  if (WSGIappLocaleSet()->getSystemLocaleEncoding() == WS_EN_UTF8){
extern char* utf8_to_macutf8(char*);
    char* fn2 = utf8_to_macutf8(fn);
    if (fn2 != NULL){
      if (remove(fn2) == 0){
        delete fn2;
        return WS_NO_ERR;
      }
      delete fn2;
    }else{
      if (remove(fn) == 0){
        return WS_NO_ERR;
      }
    }
  }else{
    if (remove(fn) == 0){
      return WS_NO_ERR;
    }
  }
#else
  if (remove(fn) == 0){
    return WS_NO_ERR;
  }
#endif
  return WS_ERR;
}

long WSDunixFS::createDir(char* name){
  WSCstring name1(name);
  char* fn = name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
#ifdef MacOS
  if (WSGIappLocaleSet()->getSystemLocaleEncoding() == WS_EN_UTF8){
extern char* utf8_to_macutf8(char*);
    char* fn2 = utf8_to_macutf8(fn);
    if (fn2 != NULL){
      if (mkdir(fn2,0777) == 0){
        delete fn2;
        return WS_NO_ERR;
      }
      delete fn2;
    }else{
      if (mkdir(fn,0777) == 0){
        return WS_NO_ERR;
      }
    }
  }else{
    if (mkdir(fn,0777) == 0){
      return WS_NO_ERR;
    }
  }
#else
  if (mkdir(fn,0777) == 0){
    return WS_NO_ERR;
  }
#endif
  return WS_ERR;
}

long WSDunixFS::deleteDir(char* name){
  WSCstring name1(name);
  char* fn = name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
#ifdef MacOS
  if (WSGIappLocaleSet()->getSystemLocaleEncoding() == WS_EN_UTF8){
extern char* utf8_to_macutf8(char*);
    char* fn2 = utf8_to_macutf8(fn);
    if (fn2 != NULL){
      if (rmdir(fn2) == 0){
        delete fn2;
        return WS_NO_ERR;
      }
      delete fn2;
    }else{
      if (rmdir(fn) == 0){
        return WS_NO_ERR;
      }
    }
  }else{
    if (rmdir(fn) == 0){
      return WS_NO_ERR;
    }
  }
#else
  if (rmdir(fn) == 0){
    return WS_NO_ERR;
  }
#endif
  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){
  WSCstring name1(fname);
  char* fn = name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  struct stat sret;
  long ret = 0;
#ifdef MacOS
  char* fn2 = NULL;
  if (WSGIappLocaleSet()->getSystemLocaleEncoding() == WS_EN_UTF8){
extern char* utf8_to_macutf8(char*);
    fn2 = utf8_to_macutf8(fn);
  }else{
    fn2 = WSGFstrdup(fn);
  }
  if (fn2 == NULL){
    return WS_ERR;
  }
  if (stat(fn2,&sret) == -1){
    delete fn2;
    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(fn,W_OK) == -1){
    ret |= WS_FS_READONLY;
  }
  delete fn2;
#else
  if (stat(fn,&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;
  }
#ifndef TE
  if ( access(fn,W_OK) == -1){
    ret |= WS_FS_READONLY;
  }
#endif
#endif 
  return ret;
}





WSClistData* WSDunixFS::showDir(char* dname){
  struct stat sret;
  dirent* finddata;
  WSCstring name1(dname);
  char* dn = name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  if (getenv("SHELL") == NULL){
#ifdef BTRON
  if (!strcmp(dn,"/")){
    F_ATTACH buf[128];
    W cnt = 128;
    cnt = lst_fls(buf,cnt);
    long i;
    WSClistData* list = new WSClistData;
    WSClistData* list2 = new WSClistData;
    for(i=0; i<cnt; i++){
      long clen = tcstoeucs(NULL,buf[i].a_name); 
      if (clen > 0){
        char* name = new char[clen+1];
#ifdef TE
        tcstoeucs((UB*)name,buf[i].a_name); 
#else
        tcstoeucs(name,buf[i].a_name); 
#endif
//printf("i=%d #%s#\n",i,name);
        WSCstring tmp(name,WS_EN_EUCJP);
        delete name;
        list->add((void*)WSGFstrdup(tmp.getString()));
      }
    }
    WSGFsortCharList(list,list2);
    delete list;
    return list2;
  }
#endif
  }
  DIR* dptr = opendir(dn);
//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 << dn << "/" << finddata->d_name;
    int ret = stat((char*)fname,&sret);
    if (ret < 0){
      continue;
    }
    if (sret.st_mode & S_IFDIR){
      WSCstring tmp;
#ifdef MacOS
      if (WSGIappLocaleSet()->getSystemLocaleEncoding() == WS_EN_UTF8){
extern char* macutf8_to_utf8(char*);
        char* t2 = macutf8_to_utf8(finddata->d_name);
        if (t2 != NULL){
          tmp.setString(t2,
                    WSGIappLocaleSet()->getSystemLocaleEncoding());
          delete t2;
        }else{
          tmp.setString(finddata->d_name,
                    WSGIappLocaleSet()->getSystemLocaleEncoding());
        }
      }else{
        tmp.setString(finddata->d_name,
                    WSGIappLocaleSet()->getSystemLocaleEncoding());
      }
#else
//printf("> #%s#\n",finddata->d_name);
      tmp.setString(finddata->d_name,
                    WSGIappLocaleSet()->getSystemLocaleEncoding());
#endif
//printf(">> #%s# %d\n",tmp.getString(),WSGIappLocaleSet()->getSystemLocaleEncoding());
      list->add((void*)WSGFstrdup(tmp.getString()));
    }
  }
//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;
  WSCstring name1(dname);
  char* dn = name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
#ifdef BTRON
  if (!strcmp(dn,"/")){
    WSClistData* list = new WSClistData;
    return list;
  }
#endif
 DIR* dptr = opendir(dn);
  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){
      WSCstring tmp;
#ifdef MacOS
      if (WSGIappLocaleSet()->getSystemLocaleEncoding() == WS_EN_UTF8){
extern char* macutf8_to_utf8(char*);
        char* t2 = macutf8_to_utf8(finddata->d_name);
        if (t2 != NULL){
          tmp.setString(t2,
                    WSGIappLocaleSet()->getSystemLocaleEncoding());
          delete t2;
        }else{
          tmp.setString(finddata->d_name,
                    WSGIappLocaleSet()->getSystemLocaleEncoding());
        }
      }else{
        tmp.setString(finddata->d_name,
                    WSGIappLocaleSet()->getSystemLocaleEncoding());
      }
#else
//printf("f> #%s#\n",finddata->d_name);
      tmp.setString(finddata->d_name,
                    WSGIappLocaleSet()->getSystemLocaleEncoding());
#endif
//printf("f>> #%s# %d\n",tmp.getString(),WSGIappLocaleSet()->getSystemLocaleEncoding());
      list->add((void*)WSGFstrdup(tmp.getString()));
    }
  }
  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
}

