/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "file_impl.h"

#include <cassert>

#ifdef _WIN32
    #include <Windows.h>
#else
    #include <stdarg.h>
    #include <string.h>
#endif

namespace webrtc {
FileWrapper* FileWrapper::Create()
{
    return new FileWrapperImpl();
}

FileWrapperImpl::FileWrapperImpl()
    : _id(NULL),
      _open(false),
      _looping(false),
      _readOnly(false),
      _text(false),
      _maxSizeInBytes(-1),
      _sizeInBytes(0)
{
    memset(_fileNameUTF8, 0, kMaxFileNameSize);
}

FileWrapperImpl::~FileWrapperImpl()
{
    if (_id != NULL)
    {
        fclose(_id);
    }
}

WebRtc_Word32 FileWrapperImpl::CloseFile()
{
    if (_id != NULL)
    {
        fclose(_id);
        _id = NULL;
    }
    memset(_fileNameUTF8, 0, kMaxFileNameSize);
    _open = false;
    return 0;
}

int FileWrapperImpl::Rewind()
{
    if(_looping || !_readOnly)
    {
        if (_id != NULL)
        {
            _sizeInBytes = 0;
            return fseek(_id, 0, SEEK_SET);
        }
    }
    return -1;
}

WebRtc_Word32 FileWrapperImpl::SetMaxFileSize(WebRtc_Word32 bytes)
{
    _maxSizeInBytes = bytes;
    return 0;
}

WebRtc_Word32 FileWrapperImpl::Flush()
{
    if (_id != NULL)
    {
        return fflush(_id);
    }
    return -1;
}

WebRtc_Word32 FileWrapperImpl::FileName(WebRtc_Word8* fileNameUTF8,
                                        WebRtc_UWord32 size) const
{
    WebRtc_Word32 len = static_cast<WebRtc_Word32>(strlen(_fileNameUTF8));
    if(len > kMaxFileNameSize)
    {
        assert(false);
        return -1;
    }
    if(len < 1)
    {
        return -1;
    }
    // Make sure to NULL terminate
    if(size < (WebRtc_UWord32)len)
    {
        len = size - 1;
    }
    memcpy(fileNameUTF8, _fileNameUTF8, len);
    fileNameUTF8[len] = 0;
    return 0;
}

bool
FileWrapperImpl::Open() const
{
    return _open;
}

WebRtc_Word32 FileWrapperImpl::OpenFile(const WebRtc_Word8 *fileNameUTF8,
                                        const bool readOnly, const bool loop,
                                        const bool text)
{
    WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
    if (length > kMaxFileNameSize)
    {
        return -1;
    }

    _readOnly = readOnly;

    FILE *tmpId = NULL;
#if defined _WIN32
    wchar_t wideFileName[kMaxFileNameSize];
    wideFileName[0] = 0;

    MultiByteToWideChar(CP_UTF8,
                        0 /*UTF8 flag*/,
                        fileNameUTF8,
                        -1 /*Null terminated string*/,
                        wideFileName,
                        kMaxFileNameSize);
    if(text)
    {
        if(readOnly)
        {
            tmpId = _wfopen(wideFileName, L"rt");
        } else {
            tmpId = _wfopen(wideFileName, L"wt");
        }
    } else {
        if(readOnly)
        {
            tmpId = _wfopen(wideFileName, L"rb");
        } else {
            tmpId = _wfopen(wideFileName, L"wb");
        }
    }
#else
    if(text)
    {
        if(readOnly)
        {
            tmpId = fopen(fileNameUTF8, "rt");
        } else {
            tmpId = fopen(fileNameUTF8, "wt");
        }
    } else {
        if(readOnly)
        {
            tmpId = fopen(fileNameUTF8, "rb");
        } else {
            tmpId = fopen(fileNameUTF8, "wb");
        }
    }
#endif

    if (tmpId != NULL)
    {
        // + 1 comes fro copying the NULL termination charachter too
        memcpy(_fileNameUTF8, fileNameUTF8, length + 1);
        if (_id != NULL)
        {
            fclose(_id);
        }
        _id = tmpId;
        _looping = loop;
        _open = true;
        return 0;
    }
    return -1;
}

int FileWrapperImpl::Read(void *buf, int len)
{
    if(len < 0)
    {
        return 0;
    }
    if (_id != NULL)
    {
        WebRtc_Word32 res = static_cast<WebRtc_Word32>(fread(buf, 1, len, _id));
        if (res != len)
        {
            if(!_looping)
            {
                CloseFile();
            }
        }
        return res;
    }
    return -1;
}

WebRtc_Word32 FileWrapperImpl::WriteText(const WebRtc_Word8* text, ...)
{
    assert(!_readOnly);
    assert(!_text);

    if (_id == NULL)
    {
        return -1;
    }

    char tempBuff[kFileMaxTextMessageSize];
    if (text)
    {
        va_list args;
        va_start(args, text);
#ifdef _WIN32
        _vsnprintf(tempBuff, kFileMaxTextMessageSize-1, text, args);
#else
        vsnprintf(tempBuff, kFileMaxTextMessageSize-1, text, args);
#endif
        va_end(args);
        WebRtc_Word32 nBytes;
        nBytes = fprintf(_id, "%s", tempBuff);
        if (nBytes > 0)
        {
            return 0;
        }
        CloseFile();
    }
    return -1;
}

bool FileWrapperImpl::Write(const void* buf, int len)
{
    assert(!_readOnly);
    if (_id != NULL)
    {
        // Check if it's time to stop writing.
        if ((_maxSizeInBytes != -1) &&
             _sizeInBytes + len > (WebRtc_UWord32)_maxSizeInBytes)
        {
            Flush();
            return false;
        }

        size_t nBytes = fwrite((WebRtc_UWord8*)buf, 1, len, _id);
        if (nBytes > 0)
        {
            _sizeInBytes += static_cast<WebRtc_Word32>(nBytes);
            return true;
        }
        CloseFile();
    }
    return false;
}
} // namespace webrtc
