//
// 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 <win/WSDwinFS.h>
#include <WSCstring.h>
#include <WSDenv.h>
#include <unistd.h>
#include <sys/stat.h>
#include <WSClistData.h>
#include <WSClocaleSet.h>
#include <Winnetwk.h>

WSDfileSystem* _win_fs_chandler(){
  return new WSDwinFS();
}
void WSGFinitWinFileSystem(){
static long _init = 0;
  if (_init != 0){
    return;
  }
  _init = 1;
extern void WSGFwinEnvInit();
  WSGFwinEnvInit();
  WSDfileSystem::setCreateInstanceHandler(_win_fs_chandler);
}
class _win_fs_init{
  public: _win_fs_init(){
extern void WSGFwinEnvInit();
    WSGFwinEnvInit();
    WSDfileSystem::setCreateInstanceHandler(_win_fs_chandler);
  };
};
_win_fs_init _win_fs_init_execute;

WSDwinFS::WSDwinFS(){}
WSDwinFS::~WSDwinFS(){}

char* WSDwinFS::adjustFileName(char* src){
static char  buf[1024];

  WSCstring str( WSGIappEnvironment()->getPlaneString(src) );
  str.delHeadSpace();
  str.replaceString("\n","",0);
  str.replaceString("\\","/",0);

  strncpy(buf,str.getString(),1023);
  return buf;
}

long WSDwinFS::rename(char* old_name,char* new_name){
  WSCstring name1(old_name);
  WSCstring name2(new_name);
  remove(name2.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()));
  long ret = ::rename(name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
                      name2.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()));
  if (ret == 0){
    return WS_NO_ERR;
  }
  return WS_ERR;
}

long WSDwinFS::deleteFile(char* name){
  WSCstring fname(name);
  char* fn = fname.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  if (remove(fn) == 0){
    return WS_NO_ERR;
  }
  return WS_ERR;
}

long WSDwinFS::createDir(char* name){
  WSCstring fname(name);
  char* fn = fname.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  if (_mkdir(fn) == 0){
    return WS_NO_ERR;
  }
  return WS_ERR;
}

long WSDwinFS::deleteDir(char* name){
  WSCstring fname(name);
  char* fn = fname.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  if (rmdir(fn) == 0){
    return WS_NO_ERR;
  }
  return WS_ERR;
}

#define WS_CANNOT 0
#define WS_DIR 1
#define WS_WRITABLE_FILE 2
#define WS_READONLY_FILE 3
#if 0
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,2 /*W_OK*/) == -1){
    return WS_READONLY_FILE;
  }
  return WS_WRITABLE_FILE;
}
#endif
long WSDwinFS::check(char* fname){
  WSCstring name(fname);
  char* fn = name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  struct _stat sret;
  long ret = 0;
  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;
  }
  if ( _access(fn,W_OK) == -1){
    ret |= WS_FS_READONLY;
  }
  return ret;
}

WSClistData* WSDwinFS::showNetDir(char* dn,char* prvn){
//printf("WSDwinFS::showNetDir 0x%x 0x%x\n",dname,prvname);
  WSCstring name1(dn);
  char* dname = name1.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  WSCstring name2(prvn);
  char* prvname = name2.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  if (prvname != NULL && dname == NULL){
    return showDir(dn);
  }
  if (dname != NULL){
//printf("WSDwinFS::showNetDir dname=%s\n",dn);
  }
  if (prvname != NULL){
//printf("WSDwinFS::showNetDir prvname=%s\n",prvn);
  }
  NETRESOURCE  NetResource;
  NETRESOURCE  lpBuffer[128];
  HANDLE       lphEnum;
  DWORD        lpcCount;
  DWORD        lpBufferSize;
  DWORD        re, i;
  char  lpBuffer2[4096];

  lphEnum  = 0;
  lpcCount = 0xFFFFFFF;
  lpBufferSize = sizeof(lpBuffer);

  NetResource.dwScope		= RESOURCE_GLOBALNET;
  NetResource.dwType		= RESOURCETYPE_ANY;
  NetResource.dwDisplayType	= RESOURCEDISPLAYTYPE_DOMAIN;
  NetResource.dwUsage		= RESOURCEUSAGE_CONTAINER;
  if (dname != NULL ){
    WSCstring str(dname);
    str.replaceString("/","\\",0);
    strcpy(lpBuffer2,str.getString());
    NetResource.lpRemoteName = lpBuffer2;
  }else{
    NetResource.lpRemoteName = dname;
  }
  NetResource.lpProvider		= prvname;
  re = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, &NetResource, &lphEnum);
  if (re != 0){
    return NULL;
  }

  WSClistData* ret = NULL;
  for (;;) {
    re = WNetEnumResource(lphEnum, &lpcCount, &lpBuffer[0], &lpBufferSize);
    if (re == ERROR_NO_MORE_ITEMS){
      break;
    }else if (re != NO_ERROR){
      break;
    }
    for (i = 0;; i++) {
      if (i >= 128){
        break;
      }else if (i >= lpcCount){
        break;
      }

      WSCstring str;
      str.setString(lpBuffer[i].lpRemoteName,WSGIappLocaleSet()->getSystemLocaleEncoding());
      str.replaceString("\\","/",0);
      if (dname != NULL ){
        if (!strncmp(dname,"//",2)){
          WSCstring tmp(dname);
          tmp << "/";
          str.replaceString(tmp,"",1);
        }else
        if (!strncmp(dname,"\\\\",2)){
          WSCstring tmp(dname);
          tmp.replaceString("\\\\","//",1);
          tmp << "/";
          str.replaceString(tmp,"",1);
        }
      }
      if (ret == NULL){
        ret = new WSClistData();
      }
      ret->add((void*)WSGFstrdup(str.getString(WSGIappLocaleSet()->getSystemLocaleEncoding())));
    }
    break;
  }
  WNetCloseEnum(lphEnum);
  return ret;
}
WSClistData* WSDwinFS::showDir(char* name){
  WSClistData* ret = new WSClistData;
  WIN32_FIND_DATA fd;
  WSCstring str;
  str.setString(name,WS_EN_DEFAULT);
  if (!strcmp("",name)){
    DWORD drives = GetLogicalDrives();
    unsigned int i;
    for(i=0; i<sizeof(drives)*8;i++){
      char buf[3];
      if (drives & (1<<i)){
        buf[0] = 'A'+i;
        buf[1] = ':';
        buf[2] = 0;
        ret->add((void*)WSGFstrdup(buf));
      }
    }
    return ret;
  }
  str << "/*";
  str.replaceString("/","\\",0);
  HANDLE hFind = FindFirstFile(
             str.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()), &fd);

  while( hFind != INVALID_HANDLE_VALUE ){
    if ( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0){
       if (!strcmp(fd.cFileName,".") || !strcmp(fd.cFileName,"..")){
         // reject...
       }else{
         long i;
         long num = ret->getNum();
         WSCbool add_flag = False;
         for(i=0; i<num; i++){
           char* item = (char*)(*ret)[i];
           if (strcmp(item,fd.cFileName) > 0){
             WSCstring str;
             str.setString(fd.cFileName,WSGIappLocaleSet()->getSystemLocaleEncoding());
             ret->add((void*)WSGFstrdup(str.getString(WS_EN_DEFAULT)),i);
             add_flag = True;
             break;
           }
         }
         if (add_flag == False){
           str.setString(fd.cFileName,WSGIappLocaleSet()->getSystemLocaleEncoding());
           ret->add((void*)WSGFstrdup(str.getString(WS_EN_DEFAULT)));
           add_flag = True;
         }
       }
    }
    WSCbool exist = FindNextFile(hFind,&fd);
    if (exist == False){
      break;
    }
  }
  return ret;
}
WSClistData* WSDwinFS::showFile(char* name){
  WSClistData* ret = new WSClistData();
  WIN32_FIND_DATA fd;
  WSCstring str;
  str.setString(name,WS_EN_DEFAULT);
  str << "/*";
  str.replaceString("/","\\",0);
  HANDLE hFind = FindFirstFile(
             str.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()), &fd);

  while( hFind != INVALID_HANDLE_VALUE ){
    if ( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0){
      long i;
      long num = ret->getNum();
      WSCbool add_flag = False;
      for(i=0; i<num; i++){
        char* item = (char*)(*ret)[i];
        if (strcmp(item,fd.cFileName)>0){
          WSCstring str;
          str.setString(fd.cFileName,WSGIappLocaleSet()->getSystemLocaleEncoding());
          ret->add((void*)WSGFstrdup(str.getString(WS_EN_DEFAULT)),i);
          add_flag = True;
          break;
        }
      }
      if (add_flag == False){
        WSCstring str;
        str.setString(fd.cFileName,WSGIappLocaleSet()->getSystemLocaleEncoding());
        ret->add((void*)WSGFstrdup(str.getString(WS_EN_DEFAULT)));
      }
    }
    WSCbool exist = FindNextFile(hFind,&fd);
    if (exist == False){
      break;
    }
  }
  return ret;
}
