//
//
//

#define DBG_LEVEL 0
#include <Raym/Log.h>
#include <Raym/Raym.h>

namespace Raym
{

static const int TIMEOUT = 1000;

FileInputStream::FileInputStream()
{
    DebugLog2("FileInputStream::FileInputStream()");

    _handle = NULL;
}

FileInputStream::~FileInputStream()
{
    RELEASE(_handle);

    DebugLog2("FileInputStream::~FileInputStream()");
}

FileInputStream *FileInputStream::fileInputStream(FileHandle *handle)
{
    DebugLog2("FileInputStream::fileInputStream(handle)");

    FileInputStream *result = new FileInputStream();
    result->initWithFileHandle(handle)->autorelease();
    return result;
}

FileInputStream *FileInputStream::initWithFileHandle(FileHandle *handle)
{
    DebugLog2("FileInputStream::initWithFileHandle(handle)");

    _handle = handle;
    _handle->retain();
    return this;
}

/*
bool FileInputStream::available()
{
    DebugLog2("FileInputStream::available()");

    bool result = false;
    if (_handle->isPipe())
    {
        DebugLog3("_handle is pipe.");
        char buf[1024];
        DWORD BytesRead = -1;
        DWORD TotalBytesAvail = -1;
        DWORD BytesLeftThisMessage = -1;
        if (PeekNamedPipe(_handle->handle(), buf, sizeof(buf), &BytesRead, &TotalBytesAvail, &BytesLeftThisMessage))
        {
            DebugLog3("PeekNamedPipe() success: %d, %d, %d", BytesRead, TotalBytesAvail, BytesLeftThisMessage);
            result = (TotalBytesAvail > 0);

            DWORD len;
            memset(buf, 0x0, sizeof(buf));
            ReadFile(_handle->handle(), buf, sizeof(buf) - 1, &len, NULL);
            DebugLog3("kore: %s", buf);
        }
        else
        {
            DebugLog3("PeekNamedPipe() error: %d", GetLastError());
        }
    }
    return result;
}
*/

String *FileInputStream::readLine()
{
    DebugLog2("FileInputStream::readLine()");

    String *result = String::string();
    if (_handle->isPipe())
    {
        int count = 0;
        while (true)
        {
            // パイプを調べる
            char buf[4096];
            DWORD read = -1;
            DWORD avail = -1;
            if (!PeekNamedPipe(_handle->handle(), buf, sizeof(buf) - 1, &read, &avail, NULL))
            {
                // 失敗した場合は終了
                DebugLog3("FileInputStream::readLine(): PeekNamedPipe() error.");
                result = NULL;
                break;
            }

            // 読み込み可能データがあるか
            if (avail == 0)
            {
                // データが無い場合：最大 TIMEOUT[ms] まで待つ
                if (count++ >= TIMEOUT / 10)
                {
                    DebugLog3("FileInputStream::readLine(): timed out.");
                    result = NULL;
                    break;
                }
                Sleep(10);
            }
            else
            {
                // データが有る場合：

                // 改行コードをチェック
                char *p = strstr(buf, "\r\n");
                if (p != NULL)
                {
                    // CR+LF がある場合
                    read = (DWORD)(p - buf + 2);
                }

                DWORD len;
                if (!ReadFile(_handle->handle(), buf, read, &len, NULL))
                {
                    // 失敗した場合は終了
                    DebugLog3("FileInputStream::readLine(): ReadFile() error.");
                    result = NULL;
                    break;
                }
                buf[len] = '\0';

                // 再度 改行コードをチェック
                p = strstr(buf, "\r\n");
                if (p != NULL)
                {
                    *p = '\0';
                }

                result = result->stringByAppendingString(buf);

                if (p != NULL)
                {
                    break;
                }
            }
        }
    }

    return result;
}

const char *FileInputStream::className()
{
    return "FileInputStream";
}

} // Raym
