#include "AudioUtils.h"

void Utils::Audio::play(std::string path, float volume, bool loop) {
    pXAudio2 = nullptr;
    XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR);

    pMasterVoice = nullptr;
    pXAudio2->CreateMasteringVoice(&pMasterVoice);

    WAVEFORMATEXTENSIBLE wfx = { 0 };
    XAUDIO2_BUFFER buffer = { 0 };

    TCHAR* strFileName = new TCHAR[path.size() + 1];
    strFileName[path.size()] = 0;
    std::copy(path.begin(), path.end(), strFileName);

    HANDLE hFile = CreateFile(strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);

    if (INVALID_HANDLE_VALUE == hFile || INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) return;

    DWORD dwChunkSize;
    DWORD dwChunkPosition;

    auto findChunk = [&](DWORD fourcc, DWORD& dwChunkSize, DWORD& dwChunkDataPosition) -> HRESULT {
        HRESULT hr = S_OK;
        if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
            return HRESULT_FROM_WIN32(GetLastError());

        DWORD dwChunkType, dwChunkDataSize, dwRIFFDataSize = 0, dwFileType, bytesRead = 0, dwOffset = 0;

        while (hr == S_OK) {
            DWORD dwRead;
            if (0 == ReadFile(hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL))
                hr = HRESULT_FROM_WIN32(GetLastError());

            if (0 == ReadFile(hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL))
                hr = HRESULT_FROM_WIN32(GetLastError());

            switch (dwChunkType) {
            case 'FFIR':
                dwRIFFDataSize = dwChunkDataSize;
                dwChunkDataSize = 4;
                if (0 == ReadFile(hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL))
                    hr = HRESULT_FROM_WIN32(GetLastError());
                break;

            default:
                if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, dwChunkDataSize, NULL, FILE_CURRENT))
                    return HRESULT_FROM_WIN32(GetLastError());
            }

            dwOffset += sizeof(DWORD) * 2;

            if (dwChunkType == fourcc) {
                dwChunkSize = dwChunkDataSize;
                dwChunkDataPosition = dwOffset;
                return S_OK;
            }

            dwOffset += dwChunkDataSize;

            if (bytesRead >= dwRIFFDataSize) return S_FALSE;
        }

        return S_OK;
        };

    auto readChunkData = [&](void* buffer, DWORD buffersize, DWORD bufferoffset) -> HRESULT {
        HRESULT hr = S_OK;
        if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, bufferoffset, NULL, FILE_BEGIN))
            return HRESULT_FROM_WIN32(GetLastError());
        DWORD dwRead;
        if (0 == ReadFile(hFile, buffer, buffersize, &dwRead, NULL))
            hr = HRESULT_FROM_WIN32(GetLastError());
        return hr;
        };

    findChunk('FFIR', dwChunkSize, dwChunkPosition);
    DWORD filetype;
    readChunkData(&filetype, sizeof(DWORD), dwChunkPosition);
    if (filetype != 'EVAW') return;

    findChunk(' tmf', dwChunkSize, dwChunkPosition);
    readChunkData(&wfx, dwChunkSize, dwChunkPosition);
    findChunk('atad', dwChunkSize, dwChunkPosition);
    BYTE* pDataBuffer = new BYTE[dwChunkSize];
    readChunkData(pDataBuffer, dwChunkSize, dwChunkPosition);

    buffer.AudioBytes = dwChunkSize;
    buffer.pAudioData = pDataBuffer;
    buffer.Flags = XAUDIO2_END_OF_STREAM;
    if (loop) buffer.LoopCount = XAUDIO2_LOOP_INFINITE;

    IXAudio2SourceVoice* pSourceVoice;
    pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx);
    pSourceVoice->SubmitSourceBuffer(&buffer);

    pSourceVoice->SetVolume(volume);
    pSourceVoice->Start(0);
}

void Utils::Audio::playmc(std::string name, float volume, float pitch) {
    auto clientinstance = Client::clientinstance;
    if (!clientinstance) return;

    auto minecraftgame = clientinstance->getMinecraftGame();
    if (!minecraftgame) return;

    minecraftgame->playUI(name, volume, pitch);
    return;

    clientinstance->playUI(name, volume, pitch);
    (name, volume, pitch);
}
