<?php


namespace Mainto\RpcServer\Util\IO;


use Mainto\RpcServer\Util\Binary;
use Mainto\RpcServer\Util\Bytes\Bytes;

class WriteBuffer implements Writer {
    private Writer $w;

    private ?string $buf;

    private int $bufUsedSize = 0;

    private int $writeBufSize;

    public function __construct (Writer $w, int $writeBufSize) {
        $this->w = $w;
        $this->writeBufSize = $writeBufSize;
        $this->buf = Bytes::makeBytes($writeBufSize);
    }

    public function write (string $p): int {
        $needWriteLen = strlen($p);

        if ($needWriteLen > $this->writeBufSize) {
            $buf = substr($this->buf, 0, $this->bufUsedSize).$p;
            $this->bufUsedSize = 0;

            return $this->w->write($buf);
        }

        $curWriteLen = 0;

        while (true) {
            $copySize = Binary::copy($this->buf, $this->bufUsedSize, 0, $p);
            $this->bufUsedSize += $copySize;
            $curWriteLen += $copySize;

            if ($this->bufUsedSize === $this->writeBufSize) {
                $this->flush();
            }

            if ($curWriteLen >= $needWriteLen) {
                return $curWriteLen;
            }

            $p = substr($p, $curWriteLen);
        }
    }

    public function flush () {
        $this->w->write(substr($this->buf, 0, $this->bufUsedSize));
        $this->bufUsedSize = 0;
    }
}