// natFileDescriptorWin32.cc - Native part of FileDescriptor class.

/* Copyright (C) 1998, 1999, 2000, 2001  Red Hat, Inc.

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

// FIXME: In order to support interrupting of IO operations, we
// need to change to use the windows asynchronous IO functions

#include <config.h>

#include <stdio.h>
#include <string.h>

#include <windows.h>

#include <gcj/cni.h>
#include <jvm.h>
#include <java/io/FileDescriptor.h>
#include <java/io/SyncFailedException.h>
#include <java/io/IOException.h>
#include <java/io/InterruptedIOException.h>
#include <java/io/EOFException.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/NullPointerException.h>
#include <java/lang/String.h>
#include <java/lang/Thread.h>
#include <java/io/FileNotFoundException.h>

static char *
winerr (void)
{
  static LPVOID last = NULL;
  LPVOID old = NULL;

  if (last)
    old = last;

  FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) &last,
    0,
    NULL);

  if (old)
    LocalFree (old);

  return (char *)last;
}

jboolean
java::io::FileDescriptor::valid (void) {
  BY_HANDLE_FILE_INFORMATION info;
  return GetFileInformationByHandle ((HANDLE)fd, &info) != 0;
}

void
java::io::FileDescriptor::sync (void) {
  if (! FlushFileBuffers ((HANDLE)fd))
    throw new SyncFailedException (JvNewStringLatin1 (winerr ()));
}

jint
java::io::FileDescriptor::open (jstring path, jint jflags) {

  HANDLE handle = NULL;
  DWORD access = 0;
  DWORD share = FILE_SHARE_READ;
  DWORD create = OPEN_EXISTING;
  char buf[MAX_PATH] = "";

  jsize total = JvGetStringUTFRegion(path, 0, path->length(), buf);
  buf[total] = '\0';

  JvAssert((jflags & READ) || (jflags & WRITE));

  if ((jflags & READ) && (jflags & WRITE))
    {
      access = GENERIC_READ | GENERIC_WRITE;
      share = 0;
      if (jflags & APPEND)
	create = OPEN_ALWAYS;
      else
	create = CREATE_ALWAYS;
    }
  else if(jflags & READ)
    access = GENERIC_READ;
  else
    {
      access = GENERIC_WRITE;
      share = 0;
      if (jflags & APPEND)
	create = OPEN_ALWAYS;
      else
        create = CREATE_ALWAYS;
    }

  handle = CreateFile(buf, access, share, NULL, create, 0, NULL);

  if (handle == INVALID_HANDLE_VALUE)
    {
      char msg[MAX_PATH + 1000];
      sprintf (msg, "%s: %s", buf, winerr ());
      throw new FileNotFoundException (JvNewStringLatin1 (msg));
    }

  return (jint)handle;
}

void
java::io::FileDescriptor::write (jint b)
{
  DWORD bytesWritten;
  jbyte buf = (jbyte)b;

  if (WriteFile ((HANDLE)fd, &buf, 1, &bytesWritten, NULL))
    {
      if (java::lang::Thread::interrupted())
        {
          InterruptedIOException *iioe = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
          iioe->bytesTransferred = bytesWritten;
	  throw iioe;
        }
      if (bytesWritten != 1)
	throw new IOException (JvNewStringLatin1 (winerr ()));
    }
  else
    throw new IOException (JvNewStringLatin1 (winerr ()));
  // FIXME: loop until bytesWritten == 1
}

void
java::io::FileDescriptor::write(jbyteArray b, jint offset, jint len)
{
  if (! b)
    throw new java::lang::NullPointerException;
  if(offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
    throw new java::lang::ArrayIndexOutOfBoundsException;

  jbyte *buf = elements (b) + offset;
  DWORD bytesWritten;
  if (WriteFile ((HANDLE)fd, buf, len, &bytesWritten, NULL))
    {
      if (java::lang::Thread::interrupted())
        {
          InterruptedIOException *iioe = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
          iioe->bytesTransferred = bytesWritten;
	  throw iioe;
        }
    }
  else
    throw new IOException (JvNewStringLatin1 (winerr ()));
  // FIXME: loop until bytesWritten == len
}

void
java::io::FileDescriptor::close (void)
{
  HANDLE save = (HANDLE)fd;
  fd = (jint)INVALID_HANDLE_VALUE;
  if (! CloseHandle (save))
    throw new IOException (JvNewStringLatin1 (winerr ()));
}

jint
java::io::FileDescriptor::seek (jlong pos, jint whence, jboolean eof_trunc)
{
  JvAssert (whence == SET || whence == CUR);

  jlong len = length();
  jlong here = getFilePointer();

  if (eof_trunc
      && ((whence == SET && pos > len) || (whence == CUR && here + pos > len)))
    {
      whence = SET;
      pos = len;
    }

  LONG high = pos >> 32;
  DWORD low = SetFilePointer ((HANDLE)fd, (DWORD)(0xffffffff & pos), &high, whence == SET ? FILE_BEGIN : FILE_CURRENT);
  if ((low == 0xffffffff) && (GetLastError () != NO_ERROR))
    throw new IOException (JvNewStringLatin1 (winerr ()));
  return low;
}

jlong
java::io::FileDescriptor::getFilePointer(void)
{
  LONG high = 0;
  DWORD low = SetFilePointer ((HANDLE)fd, 0, &high, FILE_CURRENT);
  if ((low == 0xffffffff) && (GetLastError() != NO_ERROR))
    throw new IOException (JvNewStringLatin1 (winerr ()));
  return (((jlong)high) << 32L) | (jlong)low;
}

jlong
java::io::FileDescriptor::length(void)
{
  DWORD high;
  DWORD low;

  low = GetFileSize ((HANDLE)fd, &high);
  // FIXME: Error checking
  return (((jlong)high) << 32L) | (jlong)low;
}

jint
java::io::FileDescriptor::read(void)
{
  CHAR buf;
  DWORD read;

  if (! ReadFile ((HANDLE)fd, &buf, 1, &read, NULL))
    throw new IOException (JvNewStringLatin1 (winerr ()));
  if (! read)
    return -1;
  else
    return (jint)(buf & 0xff);
}

jint
java::io::FileDescriptor::read(jbyteArray buffer, jint offset, jint count)
{
  if (! buffer)
    throw new java::lang::NullPointerException;

  jsize bsize = JvGetArrayLength (buffer);
  if (offset < 0 || count < 0 || offset + count > bsize)
    throw new java::lang::ArrayIndexOutOfBoundsException;

  jbyte *bytes = elements (buffer) + offset;

  DWORD read;
  if (! ReadFile((HANDLE)fd, bytes, count, &read, NULL))
    throw new IOException (JvNewStringLatin1 (winerr ()));

  return (jint)read;
}

jint
java::io::FileDescriptor::available(void)
{
  // FIXME:
  return length() - getFilePointer();
}
