//
// 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 <WScom.h>
#include <WSClocaleSet.h>
#include <win/WSDwinFile.h>
#include <stdio.h>
#include <fcntl.h>
//#include <WShttp.h>

WSMFclassInit(WSDwinFile,WSDfile);

WSDfile* _win_file_chandler(){
  return new WSDwinFile;
}

void WSGFinitializeWinFile(){
static long _init = 0;
  if (_init != 0){
    return;
  }
  _init = 1;
  WSDfile::setCreateInstanceHandler((void*)_win_file_chandler);
}

class _win_file_init {
  public: _win_file_init(){
    WSDfile::setCreateInstanceHandler((void*)_win_file_chandler);
  };
};
_win_file_init  _win_file_init_execute;

WSDwinFile::WSDwinFile(){
  _file = NULL;
  _mfile = NULL;
  _file2 = INVALID_HANDLE_VALUE;
}

WSDwinFile::~WSDwinFile(){
  close();
}

long WSDwinFile::open(char* name,char* mode){
  _file_name.setString(name);
  _file_name.delHeadSpace();
//  _file_name.replaceString("/","\\",0);
#if 0 //DEVELOP...
  char* fn = _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding());
  if (!strncmp("http://",fn,7)){
    char*  pbuf = NULL;
    char*  ctype = NULL;
    long  size = 0;
    long  ishtml = 0;
    WSGFloadRemoteFile(fn,&pbuf,&ctype,&size,&ishtml,1);
    if (pbuf != NULL){
      if (_mfile == NULL){
        _mfile = new WSCmfile();
      }
      _mfile->open(pbuf,size);
      delete pbuf;
      return WS_NO_ERR;
    }
    return WS_ERR;
  }
#endif
//printf("XXZZ filename=%s mode=%s\n",_file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),mode);
  _file = fopen(
             _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
             mode);
//printf("XXZZ _file=0x%x errno=%d\n",_file,errno);
  if (_file == NULL){
    WSCstring fname2(_file_name);
    fname2.to_upper();
    _file = fopen(
             fname2.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
             mode);
  }
  if (_file != NULL){
    return WS_NO_ERR;
  }else{
    if (!strcmp("r+",mode)){
      _file = fopen(
             _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
             "a");
      if (_file != NULL){
        return WS_NO_ERR;
      }else{
        WSCstring fname2(_file_name);
        fname2.to_upper();
        _file = fopen(
             fname2.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
             "a");
        if (_file != NULL){
          return WS_NO_ERR;
        }
      }
    }
  }
  if (_file == NULL){
    if (!strcmp("r",mode)){
      _file2 = CreateFile(
           _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
           GENERIC_READ,
           FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    }else
    if (!strcmp("r+",mode)){
      _file2 = CreateFile(
           _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
           GENERIC_READ | GENERIC_WRITE,
           FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
      if (_file2 != INVALID_HANDLE_VALUE){
        SetFilePointer(_file2,0,NULL,FILE_BEGIN);
      }
    }else
    if (!strcmp("w",mode)){
      _file2 = CreateFile(
           _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
           GENERIC_WRITE,
           FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
      if (_file2 != INVALID_HANDLE_VALUE){
        SetFilePointer(_file2,0,NULL,FILE_BEGIN);
        SetEndOfFile(_file2);
      }
    }else
    if (!strcmp("w+",mode)){
      _file2 = CreateFile(
           _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
           GENERIC_READ| GENERIC_WRITE,
           FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
      if (_file2 != INVALID_HANDLE_VALUE){
        SetFilePointer(_file2,0,NULL,FILE_BEGIN);
        SetEndOfFile(_file2);
      }
    }else
    if (!strcmp("a",mode)){
      _file2 = CreateFile(
           _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
           GENERIC_WRITE,
           FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
      if (_file2 != INVALID_HANDLE_VALUE){
        SetFilePointer(_file2,0,NULL,FILE_END);
      }
    }else
    if (!strcmp("a+",mode)){
      _file2 = CreateFile(
           _file_name.getString(WSGIappLocaleSet()->getSystemLocaleEncoding()),
           GENERIC_READ| GENERIC_WRITE,
           FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
      if (_file2 != INVALID_HANDLE_VALUE){
        SetFilePointer(_file2,0,NULL,FILE_END);
      }
    }
    if (_file2 != INVALID_HANDLE_VALUE){
      return WS_NO_ERR;
    }
  }
  return WS_ERR;
}

long WSDwinFile::close(){
  if (_file != NULL){
    fclose(_file);
    _file = NULL;
  }
  if (_mfile != NULL){
    delete _mfile;
    _mfile = NULL;
  }
  if (_file2 != INVALID_HANDLE_VALUE){
    CloseHandle(_file2);
    _file2 = INVALID_HANDLE_VALUE;
  }
  return WS_NO_ERR;
}
long WSDwinFile::read(void* buf,long len){
  if (_mfile != NULL){
    return _mfile->read(buf,len);
  }
  if (_file != NULL){
    return fread(buf,1,len,_file);
  }
  if (_file2 != INVALID_HANDLE_VALUE){
    DWORD bytes;
    BOOL ret = ReadFile(_file2,(char*)buf,len,&bytes,NULL);
    if (ret == TRUE){
      return bytes;
    } 
  }
  return 0;
}
long WSDwinFile::write(void* buf,long len){
  if (_mfile != NULL){
    return _mfile->write(buf,len);
  }
  if (_file != NULL){
    return fwrite(buf,1,len,_file);
  }
  if (_file2 != INVALID_HANDLE_VALUE){
    DWORD bytes;
    BOOL ret = WriteFile(_file2,(char*)buf,len,&bytes,NULL);
    if (ret == TRUE){
      return bytes;
    } 
  }
  return 0;
}
WSCbool WSDwinFile::eof(){
  if (_mfile != NULL){
    return _mfile->eof();
  }
  if (_file != NULL){
    if (feof(_file) != False){
      return True;
    }
    return False;
  }
  if (_file2 != INVALID_HANDLE_VALUE){
    long val = SetFilePointer(_file2,0,NULL,FILE_CURRENT);
    long size = GetFileSize(_file2,NULL);
    if (val == size){
      return True;
    }
  }
  return False;
}

long WSDwinFile::seekSet(){
  return seek(0);
}
long WSDwinFile::seekEnd(){
  if (_mfile != NULL){
    _mfile->seekEnd();
    return WS_NO_ERR;
  }
  if (_file != NULL){
    fseek(_file,0,SEEK_END);
    return WS_NO_ERR;
  }
  if (_file2 != INVALID_HANDLE_VALUE){
    SetFilePointer(_file2,0,NULL,FILE_END);
    return WS_NO_ERR;
  }else{
    return WS_ERR;
  }
  return WS_NO_ERR;
}
long WSDwinFile::seek(long addr){
  if (_mfile != NULL){
    return _mfile->seek(addr);
  }
  if (_file != NULL){
    fseek(_file,addr,SEEK_SET);
    return WS_NO_ERR;
  }
  if (_file2 != INVALID_HANDLE_VALUE){
    SetFilePointer(_file2,addr,NULL,FILE_BEGIN);
    return WS_NO_ERR;
  }else{
    return WS_ERR;
  }
WSMFtrace("WSDwinFDB::_seek error file=NULL\n");
  return WS_NO_ERR;
}
long WSDwinFile::getSize(){
  if (_mfile != NULL){
    return _mfile->getSize();
  }
  if (_file != NULL){
    long pos = ftell(_file);
    fseek(_file,0,SEEK_END);
    long ret = ftell(_file);
    fseek(_file,pos,SEEK_SET);
    return ret;
  }
  if (_file2 != INVALID_HANDLE_VALUE){
    return GetFileSize(_file2,NULL);
  }
  return 0;
}
long WSDwinFile::tell(){
  if (_mfile != NULL){
    return _mfile->tell();
  }
  if (_file != NULL){
    return ftell(_file);
  }
  if (_file2 != INVALID_HANDLE_VALUE){
    return SetFilePointer(_file2,0,NULL,FILE_CURRENT);
  }
  return 0;
}
