#include "fs/Pipe.h"
#include "thread/Scheduler.h"

Result<void> Pipe::create(SharedPtr<VFS::Inode>& rpipe, SharedPtr<VFS::Inode>& wpipe)
{
    auto pipe = TRY(make_shared<Pipe>());

    auto writer = TRY(make_shared<PipeWriter>());
    auto reader = TRY(make_shared<PipeReader>());

    auto auth = Scheduler::current()->auth;

    pipe->m_writer = writer.ptr();
    pipe->m_reader = reader.ptr();

    writer->m_pipe = reader->m_pipe = pipe;
    writer->m_metadata.inum = 0;
    writer->m_metadata.uid = auth.euid;
    writer->m_metadata.gid = auth.egid;
    writer->m_metadata.mode = 0200;
    reader->m_metadata.inum = 0;
    reader->m_metadata.uid = auth.euid;
    reader->m_metadata.gid = auth.egid;
    reader->m_metadata.mode = 0400;

    rpipe = reader;
    wpipe = writer;

    return {};
}

Result<usize> Pipe::read(u8* buf, usize, usize length)
{
    if (length > m_data_buffer.size()) length = m_data_buffer.size();

    memcpy(buf, m_data_buffer.data(), length);

    memmove(m_data_buffer.data(), m_data_buffer.data() + length, m_data_buffer.size() - length);

    TRY(m_data_buffer.try_resize(m_data_buffer.size() - length));

    return length;
}

Result<usize> Pipe::write(const u8* buf, usize, usize length)
{
    if (!m_reader)
    {
        Scheduler::current()->send_signal(SIGPIPE);
        return err(EPIPE);
    }

    u8* slice = TRY(m_data_buffer.slice_at_end(length));
    memcpy(slice, buf, length);

    return length;
}

bool Pipe::will_block_if_read() const
{
    return !m_data_buffer.size() && m_writer;
}

PipeWriter::~PipeWriter()
{
    m_pipe->m_writer = nullptr;
}

PipeReader::~PipeReader()
{
    m_pipe->m_reader = nullptr;
}