<?php
declare(strict_types=1);

namespace Archive\StreamWrapper\Filter\Filters;

use Archive\StreamWrapper\Filter\StreamFilterInterface;

/**
 * Stream-Filter für Base64-Kodierung
 */
class Base64EncodeFilter extends \php_user_filter implements StreamFilterInterface
{
    private string $filterName = 'transform.base64encode';
    private array $supportedModes = ['write'];
    private array $params = [];

    private bool $urlSafe = false;

    public function onCreate(): bool
    {
        // Parameter aus dem Stream-Context extrahieren
        if (isset($this->params)) {
            $this->params = $this->params;
        }

        $this->urlSafe = $this->getParam('url_safe', false);
        return true;
    }

    public function onClose(): void
    {
        // Cleanup falls nötig
    }

    public function getFilterName(): string
    {
        return $this->filterName;
    }

    public function getSupportedModes(): array
    {
        return $this->supportedModes;
    }

    public function filter($in, $out, &$consumed, bool $closing): int
    {
        $data = $this->readFromBrigade($in);
        $consumed = strlen($data);

        if (!empty($data)) {
            $encoded = base64_encode($data);

            if ($this->urlSafe) {
                $encoded = strtr($encoded, '+/', '-_');
                $encoded = rtrim($encoded, '=');
            }

            $this->writeToBrigade($out, $encoded);
        }

        return PSFS_PASS_ON;
    }

    /**
     * Hilfsmethode zum Lesen von Daten aus der Input-Brigade
     */
    private function readFromBrigade($brigade): string
    {
        $data = '';
        while ($bucket = stream_bucket_make_writeable($brigade)) {
            $data .= $bucket->data;
        }
        return $data;
    }

    /**
     * Hilfsmethode zum Schreiben von Daten in die Output-Brigade
     */
    private function writeToBrigade($brigade, string $data): void
    {
        if (!empty($data)) {
            $bucket = stream_bucket_new($this->stream, $data);
            stream_bucket_append($brigade, $bucket);
        }
    }

    /**
     * Gibt einen Parameter zurück
     */
    private function getParam(string $key, $default = null)
    {
        return $this->params[$key] ?? $default;
    }
}
