#include "tcp_buffer.hpp"
#include "logger.hpp"
#include <cstddef>
#include <cstring>
#include <vector>



namespace tinyrpc {

    void TcpBuffer::adjustBuffer() {
        
        std::vector<char> newBuffer(m_buffer.size());
        std::memcpy(newBuffer.data(), m_buffer.data() + m_read_index, getReadable());
        m_buffer.swap(newBuffer);
        m_write_index -= m_read_index;
        m_read_index = 0;
        
    }


    void TcpBuffer::readOffset(std::size_t offset)  {
        std::size_t newReadIdx = m_read_index + offset;
        if(newReadIdx > m_write_index) {
            logger() << "read index overflow write index"; 
            return;
        }
        m_read_index = newReadIdx;
        if(getWriteable() < m_read_index) {
            adjustBuffer();
        }

    }

    void TcpBuffer::writeOffset(std::size_t offset)  {
        std::size_t newWriteIdx = m_write_index + offset;
        m_write_index = newWriteIdx;
        if(newWriteIdx > m_buffer.size()) {
            logger() << "newReadIdx overflow buffer size"; 
            resize(getReadable() + offset * 2);
        }

        if(getWriteable() < m_read_index) {
            adjustBuffer();
        }

    }

    void TcpBuffer::clear() {
        m_buffer.clear();
        m_read_index = m_write_index = 0u;
    }

    int TcpBuffer::readFromBuffer(void* buf, std::size_t size) {

        int cnt = std::min(getReadable(), size);
        if(cnt == 0) return 0;
        memcpy(buf, getReadAddress(), cnt);
        m_read_index += cnt;

        if(getWriteable() < m_read_index) {
            adjustBuffer();
        }

        return cnt;

    }
    int TcpBuffer::writeToBuffer(const void* buf, std::size_t size) {

        if(getWriteable() < size && m_read_index == 0) {
            resize((m_buffer.size() + size) * 1.5);
        }

        if(getWriteable() < size) {
            adjustBuffer();
        }
        
        if(getWriteable() < size) {
            resize((m_buffer.size() + size) * 1.5);
        }

        int cnt = std::min(getWriteable(), size);
        if(cnt == 0) return 0;
        memcpy(getWriteAddress(), buf, cnt);
        m_write_index += cnt;
        return cnt;
    }

    void TcpBuffer::resize(std::size_t size) {
        logger() << " resize beg";
        std::vector<char> newBuffer(size);
        int cnt = std::min(size, getReadable());
        memcpy(newBuffer.data(), getReadAddress(), cnt);
        m_write_index = cnt;
        m_read_index = 0;
        logger() << " resize end";
    }

}