<?php

namespace Beehive\GuzzleHttp\Message;

use Beehive\GuzzleHttp\Stream\StreamInterface;
abstract class AbstractMessage implements \Beehive\GuzzleHttp\Message\MessageInterface
{
    /** @var array HTTP header collection */
    private $headers = [];
    /** @var array mapping a lowercase header name to its name over the wire */
    private $headerNames = [];
    /** @var StreamInterface Message body */
    private $body;
    /** @var string HTTP protocol version of the message */
    private $protocolVersion = '1.1';
    public function __toString()
    {
        return static::getStartLineAndHeaders($this) . "\r\n\r\n" . $this->getBody();
    }
    public function getProtocolVersion()
    {
        return $this->protocolVersion;
    }
    public function getBody()
    {
        return $this->body;
    }
    public function setBody(\Beehive\GuzzleHttp\Stream\StreamInterface $body = null)
    {
        if ($body === null) {
            // Setting a null body will remove the body of the request
            $this->removeHeader('Content-Length');
            $this->removeHeader('Transfer-Encoding');
        }
        $this->body = $body;
    }
    public function addHeader($header, $value)
    {
        if (\is_array($value)) {
            $current = \array_merge($this->getHeaderAsArray($header), $value);
        } else {
            $current = $this->getHeaderAsArray($header);
            $current[] = (string) $value;
        }
        $this->setHeader($header, $current);
    }
    public function addHeaders(array $headers)
    {
        foreach ($headers as $name => $header) {
            $this->addHeader($name, $header);
        }
    }
    public function getHeader($header)
    {
        $name = \strtolower($header);
        return isset($this->headers[$name]) ? \implode(', ', $this->headers[$name]) : '';
    }
    public function getHeaderAsArray($header)
    {
        $name = \strtolower($header);
        return isset($this->headers[$name]) ? $this->headers[$name] : [];
    }
    public function getHeaders()
    {
        $headers = [];
        foreach ($this->headers as $name => $values) {
            $headers[$this->headerNames[$name]] = $values;
        }
        return $headers;
    }
    public function setHeader($header, $value)
    {
        $header = \trim($header);
        $name = \strtolower($header);
        $this->headerNames[$name] = $header;
        if (\is_array($value)) {
            foreach ($value as &$v) {
                $v = \trim($v);
            }
            $this->headers[$name] = $value;
        } else {
            $this->headers[$name] = [\trim($value)];
        }
    }
    public function setHeaders(array $headers)
    {
        $this->headers = $this->headerNames = [];
        foreach ($headers as $key => $value) {
            $this->addHeader($key, $value);
        }
    }
    public function hasHeader($header)
    {
        return isset($this->headers[\strtolower($header)]);
    }
    public function removeHeader($header)
    {
        $name = \strtolower($header);
        unset($this->headers[$name], $this->headerNames[$name]);
    }
    /**
     * Parse an array of header values containing ";" separated data into an
     * array of associative arrays representing the header key value pair
     * data of the header. When a parameter does not contain a value, but just
     * contains a key, this function will inject a key with a '' string value.
     *
     * @param MessageInterface $message That contains the header
     * @param string           $header  Header to retrieve from the message
     *
     * @return array Returns the parsed header values.
     */
    public static function parseHeader(\Beehive\GuzzleHttp\Message\MessageInterface $message, $header)
    {
        static $trimmed = "\"'  \n\t\r";
        $params = $matches = [];
        foreach (self::normalizeHeader($message, $header) as $val) {
            $part = [];
            foreach (\preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
                if (\preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
                    $m = $matches[0];
                    if (isset($m[1])) {
                        $part[\trim($m[0], $trimmed)] = \trim($m[1], $trimmed);
                    } else {
                        $part[] = \trim($m[0], $trimmed);
                    }
                }
            }
            if ($part) {
                $params[] = $part;
            }
        }
        return $params;
    }
    /**
     * Converts an array of header values that may contain comma separated
     * headers into an array of headers with no comma separated values.
     *
     * @param MessageInterface $message That contains the header
     * @param string              $header  Header to retrieve from the message
     *
     * @return array Returns the normalized header field values.
     */
    public static function normalizeHeader(\Beehive\GuzzleHttp\Message\MessageInterface $message, $header)
    {
        $h = $message->getHeaderAsArray($header);
        for ($i = 0, $total = \count($h); $i < $total; $i++) {
            if (\strpos($h[$i], ',') === \false) {
                continue;
            }
            foreach (\preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) {
                $h[] = \trim($v);
            }
            unset($h[$i]);
        }
        return $h;
    }
    /**
     * Gets the start-line and headers of a message as a string
     *
     * @param MessageInterface $message
     *
     * @return string
     */
    public static function getStartLineAndHeaders(\Beehive\GuzzleHttp\Message\MessageInterface $message)
    {
        return static::getStartLine($message) . self::getHeadersAsString($message);
    }
    /**
     * Gets the headers of a message as a string
     *
     * @param MessageInterface $message
     *
     * @return string
     */
    public static function getHeadersAsString(\Beehive\GuzzleHttp\Message\MessageInterface $message)
    {
        $result = '';
        foreach ($message->getHeaders() as $name => $values) {
            $result .= "\r\n{$name}: " . \implode(', ', $values);
        }
        return $result;
    }
    /**
     * Gets the start line of a message
     *
     * @param MessageInterface $message
     *
     * @return string
     * @throws \InvalidArgumentException
     */
    public static function getStartLine(\Beehive\GuzzleHttp\Message\MessageInterface $message)
    {
        if ($message instanceof \Beehive\GuzzleHttp\Message\RequestInterface) {
            return \trim($message->getMethod() . ' ' . $message->getResource()) . ' HTTP/' . $message->getProtocolVersion();
        } elseif ($message instanceof \Beehive\GuzzleHttp\Message\ResponseInterface) {
            return 'HTTP/' . $message->getProtocolVersion() . ' ' . $message->getStatusCode() . ' ' . $message->getReasonPhrase();
        } else {
            throw new \InvalidArgumentException('Unknown message type');
        }
    }
    /**
     * Accepts and modifies the options provided to the message in the
     * constructor.
     *
     * Can be overridden in subclasses as necessary.
     *
     * @param array $options Options array passed by reference.
     */
    protected function handleOptions(array &$options)
    {
        if (isset($options['protocol_version'])) {
            $this->protocolVersion = $options['protocol_version'];
        }
    }
}