/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "rsContext.h"
#include "rsThreadIO.h"
#include "rsgApiStructs.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <fcntl.h>
#include <poll.h>


namespace android {
namespace renderscript {

ThreadIO::ThreadIO() {
    mRunning = true;
    mMaxInlineSize = 1024;
}

ThreadIO::~ThreadIO() {
}

bool ThreadIO::init() {
    return mToClient.init() && mToCore.init();
}

void ThreadIO::shutdown() {
    mRunning = false;
    mToCore.shutdown();
}

void * ThreadIO::coreHeader(uint32_t cmdID, size_t dataLen) {
    //ALOGE("coreHeader %i %i", cmdID, dataLen);
    CoreCmdHeader *hdr = (CoreCmdHeader *)&mSendBuffer[0];
    hdr->bytes = dataLen;
    hdr->cmdID = cmdID;
    mSendLen = dataLen + sizeof(CoreCmdHeader);
    //mToCoreSocket.writeAsync(&hdr, sizeof(hdr));
    //ALOGE("coreHeader ret ");
    return &mSendBuffer[sizeof(CoreCmdHeader)];
}

void ThreadIO::coreCommit() {
    mToCore.writeAsync(&mSendBuffer, mSendLen);
}

void ThreadIO::clientShutdown() {
    mToClient.shutdown();
}

void ThreadIO::coreWrite(const void *data, size_t len) {
    //ALOGV("core write %p %i", data, (int)len);
    mToCore.writeAsync(data, len, true);
}

void ThreadIO::coreRead(void *data, size_t len) {
    //ALOGV("core read %p %i", data, (int)len);
    mToCore.read(data, len);
}

void ThreadIO::coreSetReturn(const void *data, size_t dataLen) {
    uint32_t buf;
    if (data == nullptr) {
        data = &buf;
        dataLen = sizeof(buf);
    }

    mToCore.readReturn(data, dataLen);
}

void ThreadIO::coreGetReturn(void *data, size_t dataLen) {
    uint32_t buf;
    if (data == nullptr) {
        data = &buf;
        dataLen = sizeof(buf);
    }

    mToCore.writeWaitReturn(data, dataLen);
}

void ThreadIO::setTimeoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
    //mToCore.setTimeoutCallback(cb, dat, timeout);
}

bool ThreadIO::playCoreCommands(Context *con, int waitFd) {
    bool ret = false;

    uint8_t buf[2 * 1024];
    const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0];
    const void * data = (const void *)&buf[sizeof(CoreCmdHeader)];

    struct pollfd p[2];
    p[0].fd = mToCore.getReadFd();
    p[0].events = POLLIN;
    p[0].revents = 0;
    p[1].fd = waitFd;
    p[1].events = POLLIN;
    p[1].revents = 0;
    int pollCount = 1;
    if (waitFd >= 0) {
        pollCount = 2;
    }

    if (con->props.mLogTimes) {
        con->timerSet(Context::RS_TIMER_IDLE);
    }

    int waitTime = -1;
    while (mRunning) {
        int pr = poll(p, pollCount, waitTime);
        if (pr <= 0) {
            break;
        }

        if (p[0].revents) {
            size_t r = 0;
            r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
            mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
            if (r != sizeof(CoreCmdHeader)) {
              // exception or timeout occurred.
              break;
            }

            ret = true;
            if (con->props.mLogTimes) {
                con->timerSet(Context::RS_TIMER_INTERNAL);
            }
            //ALOGV("playCoreCommands 3 %i %i", cmd->cmdID, cmd->bytes);

            if (cmd->cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
                rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
                ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID);
            }

            gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);

            if (con->props.mLogTimes) {
                con->timerSet(Context::RS_TIMER_IDLE);
            }

            if (waitFd < 0) {
                // If we don't have a secondary wait object we should stop blocking now
                // that at least one command has been processed.
                waitTime = 0;
            }
        }

        if (p[1].revents && !p[0].revents) {
            // We want to finish processing fifo events before processing the vsync.
            // Otherwise we can end up falling behind and having tremendous lag.
            break;
        }
    }
    return ret;
}

RsMessageToClientType ThreadIO::getClientHeader(size_t *receiveLen, uint32_t *usrID) {
    //ALOGE("getClientHeader");
    mToClient.read(&mLastClientHeader, sizeof(mLastClientHeader));

    receiveLen[0] = mLastClientHeader.bytes;
    usrID[0] = mLastClientHeader.userID;
    //ALOGE("getClientHeader %i %i %i", mLastClientHeader.cmdID, usrID[0], receiveLen[0]);
    return (RsMessageToClientType)mLastClientHeader.cmdID;
}

RsMessageToClientType ThreadIO::getClientPayload(void *data, size_t *receiveLen,
                                uint32_t *usrID, size_t bufferLen) {
    //ALOGE("getClientPayload");
    receiveLen[0] = mLastClientHeader.bytes;
    usrID[0] = mLastClientHeader.userID;
    if (bufferLen < mLastClientHeader.bytes) {
        return RS_MESSAGE_TO_CLIENT_RESIZE;
    }
    if (receiveLen[0]) {
        mToClient.read(data, receiveLen[0]);
    }
    //ALOGE("getClientPayload x");
    return (RsMessageToClientType)mLastClientHeader.cmdID;
}

bool ThreadIO::sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data,
                            size_t dataLen, bool waitForSpace) {

    //ALOGE("sendToClient %i %i %i", cmdID, usrID, (int)dataLen);
    ClientCmdHeader hdr;
    hdr.bytes = (uint32_t)dataLen;
    hdr.cmdID = cmdID;
    hdr.userID = usrID;

    mToClient.writeAsync(&hdr, sizeof(hdr));
    if (dataLen) {
        mToClient.writeAsync(data, dataLen);
    }

    //ALOGE("sendToClient x");
    return true;
}

} // namespace renderscript
} // namespace android
