<?php
/**
 * ExchangeRatesApi
 * PHP version 8.1
 *
 * @category Class
 * @package  OpenAPI\Client
 * @author   OpenAPI Generator team
 * @link     https://openapi-generator.tech
 */

/**
 * FX Historical REST API
 *
 * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
 *
 * The version of the OpenAPI document: v1
 * Contact: support@apibricks.io
 * Generated by: https://openapi-generator.tech
 * Generator version: 7.14.0
 */

/**
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

namespace OpenAPI\Client\Api;

use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use OpenAPI\Client\ApiException;
use OpenAPI\Client\Configuration;
use OpenAPI\Client\FormDataProcessor;
use OpenAPI\Client\HeaderSelector;
use OpenAPI\Client\ObjectSerializer;

/**
 * ExchangeRatesApi Class Doc Comment
 *
 * @category Class
 * @package  OpenAPI\Client
 * @author   OpenAPI Generator team
 * @link     https://openapi-generator.tech
 */
class ExchangeRatesApi
{
    /**
     * @var ClientInterface
     */
    protected $client;

    /**
     * @var Configuration
     */
    protected $config;

    /**
     * @var HeaderSelector
     */
    protected $headerSelector;

    /**
     * @var int Host index
     */
    protected $hostIndex;

    /** @var string[] $contentTypes **/
    public const contentTypes = [
        'getSpecificRate' => [
            'application/json',
        ],
        'v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet' => [
            'application/json',
        ],
        'v1ExchangerateAssetIdBaseGet' => [
            'application/json',
        ],
        'v1ExchangerateHistoryPeriodsGet' => [
            'application/json',
        ],
    ];

    /**
     * @param ClientInterface $client
     * @param Configuration   $config
     * @param HeaderSelector  $selector
     * @param int             $hostIndex (Optional) host index to select the list of hosts if defined in the OpenAPI spec
     */
    public function __construct(
        ?ClientInterface $client = null,
        ?Configuration $config = null,
        ?HeaderSelector $selector = null,
        int $hostIndex = 0
    ) {
        $this->client = $client ?: new Client();
        $this->config = $config ?: Configuration::getDefaultConfiguration();
        $this->headerSelector = $selector ?: new HeaderSelector();
        $this->hostIndex = $hostIndex;
    }

    /**
     * Set the host index
     *
     * @param int $hostIndex Host index (required)
     */
    public function setHostIndex($hostIndex): void
    {
        $this->hostIndex = $hostIndex;
    }

    /**
     * Get the host index
     *
     * @return int Host index
     */
    public function getHostIndex()
    {
        return $this->hostIndex;
    }

    /**
     * @return Configuration
     */
    public function getConfig()
    {
        return $this->config;
    }

    /**
     * Operation getSpecificRate
     *
     * Get specific rate
     *
     * @param  string $asset_id_base Requested exchange rate base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rate quote asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $time Time at which exchange rate is calculated (optional, if not supplied then current rate is returned) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getSpecificRate'] to see the possible values for this operation
     *
     * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \OpenAPI\Client\Model\V1ExchangeRate
     */
    public function getSpecificRate($asset_id_base, $asset_id_quote, $time = null, string $contentType = self::contentTypes['getSpecificRate'][0])
    {
        list($response) = $this->getSpecificRateWithHttpInfo($asset_id_base, $asset_id_quote, $time, $contentType);
        return $response;
    }

    /**
     * Operation getSpecificRateWithHttpInfo
     *
     * Get specific rate
     *
     * @param  string $asset_id_base Requested exchange rate base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rate quote asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $time Time at which exchange rate is calculated (optional, if not supplied then current rate is returned) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getSpecificRate'] to see the possible values for this operation
     *
     * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \OpenAPI\Client\Model\V1ExchangeRate, HTTP status code, HTTP response headers (array of strings)
     */
    public function getSpecificRateWithHttpInfo($asset_id_base, $asset_id_quote, $time = null, string $contentType = self::contentTypes['getSpecificRate'][0])
    {
        $request = $this->getSpecificRateRequest($asset_id_base, $asset_id_quote, $time, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        '\OpenAPI\Client\Model\V1ExchangeRate',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                '\OpenAPI\Client\Model\V1ExchangeRate',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 200:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        '\OpenAPI\Client\Model\V1ExchangeRate',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation getSpecificRateAsync
     *
     * Get specific rate
     *
     * @param  string $asset_id_base Requested exchange rate base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rate quote asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $time Time at which exchange rate is calculated (optional, if not supplied then current rate is returned) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getSpecificRate'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getSpecificRateAsync($asset_id_base, $asset_id_quote, $time = null, string $contentType = self::contentTypes['getSpecificRate'][0])
    {
        return $this->getSpecificRateAsyncWithHttpInfo($asset_id_base, $asset_id_quote, $time, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation getSpecificRateAsyncWithHttpInfo
     *
     * Get specific rate
     *
     * @param  string $asset_id_base Requested exchange rate base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rate quote asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $time Time at which exchange rate is calculated (optional, if not supplied then current rate is returned) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getSpecificRate'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function getSpecificRateAsyncWithHttpInfo($asset_id_base, $asset_id_quote, $time = null, string $contentType = self::contentTypes['getSpecificRate'][0])
    {
        $returnType = '\OpenAPI\Client\Model\V1ExchangeRate';
        $request = $this->getSpecificRateRequest($asset_id_base, $asset_id_quote, $time, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'getSpecificRate'
     *
     * @param  string $asset_id_base Requested exchange rate base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rate quote asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $time Time at which exchange rate is calculated (optional, if not supplied then current rate is returned) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['getSpecificRate'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function getSpecificRateRequest($asset_id_base, $asset_id_quote, $time = null, string $contentType = self::contentTypes['getSpecificRate'][0])
    {

        // verify the required parameter 'asset_id_base' is set
        if ($asset_id_base === null || (is_array($asset_id_base) && count($asset_id_base) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $asset_id_base when calling getSpecificRate'
            );
        }

        // verify the required parameter 'asset_id_quote' is set
        if ($asset_id_quote === null || (is_array($asset_id_quote) && count($asset_id_quote) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $asset_id_quote when calling getSpecificRate'
            );
        }



        $resourcePath = '/v1/exchangerate/{asset_id_base}/{asset_id_quote}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $time,
            'time', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);


        // path params
        if ($asset_id_base !== null) {
            $resourcePath = str_replace(
                '{' . 'asset_id_base' . '}',
                ObjectSerializer::toPathValue($asset_id_base),
                $resourcePath
            );
        }
        // path params
        if ($asset_id_quote !== null) {
            $resourcePath = str_replace(
                '{' . 'asset_id_quote' . '}',
                ObjectSerializer::toPathValue($asset_id_quote),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            ['text/plain', 'application/json', 'text/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires API key authentication
        $apiKey = $this->config->getApiKeyWithPrefix('X-CoinAPI-Key');
        if ($apiKey !== null) {
            $headers['X-CoinAPI-Key'] = $apiKey;
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'GET',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet
     *
     * Timeseries data
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $period_id Identifier of requested timeseries period (required, e.g. &#x60;5SEC&#x60; or &#x60;1HRS&#x60;) (optional)
     * @param  string|null $time_start Timeseries starting time in ISO 8601 (required) (optional)
     * @param  string|null $time_end Timeseries ending time in ISO 8601 (required) (optional)
     * @param  int|null $limit Amount of items to return (optional, mininum is 1, maximum is 100000, default value is 100, if the parameter is used then every 100 output items are counted as one request) (optional, default to 100)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'] to see the possible values for this operation
     *
     * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \OpenAPI\Client\Model\V1ExchangeRatesTimeseriesItem[]
     */
    public function v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet($asset_id_base, $asset_id_quote, $period_id = null, $time_start = null, $time_end = null, $limit = 100, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'][0])
    {
        list($response) = $this->v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetWithHttpInfo($asset_id_base, $asset_id_quote, $period_id, $time_start, $time_end, $limit, $contentType);
        return $response;
    }

    /**
     * Operation v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetWithHttpInfo
     *
     * Timeseries data
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $period_id Identifier of requested timeseries period (required, e.g. &#x60;5SEC&#x60; or &#x60;1HRS&#x60;) (optional)
     * @param  string|null $time_start Timeseries starting time in ISO 8601 (required) (optional)
     * @param  string|null $time_end Timeseries ending time in ISO 8601 (required) (optional)
     * @param  int|null $limit Amount of items to return (optional, mininum is 1, maximum is 100000, default value is 100, if the parameter is used then every 100 output items are counted as one request) (optional, default to 100)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'] to see the possible values for this operation
     *
     * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \OpenAPI\Client\Model\V1ExchangeRatesTimeseriesItem[], HTTP status code, HTTP response headers (array of strings)
     */
    public function v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetWithHttpInfo($asset_id_base, $asset_id_quote, $period_id = null, $time_start = null, $time_end = null, $limit = 100, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'][0])
    {
        $request = $this->v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetRequest($asset_id_base, $asset_id_quote, $period_id, $time_start, $time_end, $limit, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        '\OpenAPI\Client\Model\V1ExchangeRatesTimeseriesItem[]',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                '\OpenAPI\Client\Model\V1ExchangeRatesTimeseriesItem[]',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 200:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        '\OpenAPI\Client\Model\V1ExchangeRatesTimeseriesItem[]',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetAsync
     *
     * Timeseries data
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $period_id Identifier of requested timeseries period (required, e.g. &#x60;5SEC&#x60; or &#x60;1HRS&#x60;) (optional)
     * @param  string|null $time_start Timeseries starting time in ISO 8601 (required) (optional)
     * @param  string|null $time_end Timeseries ending time in ISO 8601 (required) (optional)
     * @param  int|null $limit Amount of items to return (optional, mininum is 1, maximum is 100000, default value is 100, if the parameter is used then every 100 output items are counted as one request) (optional, default to 100)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetAsync($asset_id_base, $asset_id_quote, $period_id = null, $time_start = null, $time_end = null, $limit = 100, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'][0])
    {
        return $this->v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetAsyncWithHttpInfo($asset_id_base, $asset_id_quote, $period_id, $time_start, $time_end, $limit, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetAsyncWithHttpInfo
     *
     * Timeseries data
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $period_id Identifier of requested timeseries period (required, e.g. &#x60;5SEC&#x60; or &#x60;1HRS&#x60;) (optional)
     * @param  string|null $time_start Timeseries starting time in ISO 8601 (required) (optional)
     * @param  string|null $time_end Timeseries ending time in ISO 8601 (required) (optional)
     * @param  int|null $limit Amount of items to return (optional, mininum is 1, maximum is 100000, default value is 100, if the parameter is used then every 100 output items are counted as one request) (optional, default to 100)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetAsyncWithHttpInfo($asset_id_base, $asset_id_quote, $period_id = null, $time_start = null, $time_end = null, $limit = 100, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'][0])
    {
        $returnType = '\OpenAPI\Client\Model\V1ExchangeRatesTimeseriesItem[]';
        $request = $this->v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetRequest($asset_id_base, $asset_id_quote, $period_id, $time_start, $time_end, $limit, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string $asset_id_quote Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $period_id Identifier of requested timeseries period (required, e.g. &#x60;5SEC&#x60; or &#x60;1HRS&#x60;) (optional)
     * @param  string|null $time_start Timeseries starting time in ISO 8601 (required) (optional)
     * @param  string|null $time_end Timeseries ending time in ISO 8601 (required) (optional)
     * @param  int|null $limit Amount of items to return (optional, mininum is 1, maximum is 100000, default value is 100, if the parameter is used then every 100 output items are counted as one request) (optional, default to 100)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGetRequest($asset_id_base, $asset_id_quote, $period_id = null, $time_start = null, $time_end = null, $limit = 100, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'][0])
    {

        // verify the required parameter 'asset_id_base' is set
        if ($asset_id_base === null || (is_array($asset_id_base) && count($asset_id_base) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $asset_id_base when calling v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'
            );
        }

        // verify the required parameter 'asset_id_quote' is set
        if ($asset_id_quote === null || (is_array($asset_id_quote) && count($asset_id_quote) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $asset_id_quote when calling v1ExchangerateAssetIdBaseAssetIdQuoteHistoryGet'
            );
        }






        $resourcePath = '/v1/exchangerate/{asset_id_base}/{asset_id_quote}/history';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $period_id,
            'period_id', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $time_start,
            'time_start', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $time_end,
            'time_end', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $limit,
            'limit', // param base name
            'integer', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);


        // path params
        if ($asset_id_base !== null) {
            $resourcePath = str_replace(
                '{' . 'asset_id_base' . '}',
                ObjectSerializer::toPathValue($asset_id_base),
                $resourcePath
            );
        }
        // path params
        if ($asset_id_quote !== null) {
            $resourcePath = str_replace(
                '{' . 'asset_id_quote' . '}',
                ObjectSerializer::toPathValue($asset_id_quote),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            ['text/plain', 'application/json', 'text/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires API key authentication
        $apiKey = $this->config->getApiKeyWithPrefix('X-CoinAPI-Key');
        if ($apiKey !== null) {
            $headers['X-CoinAPI-Key'] = $apiKey;
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'GET',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation v1ExchangerateAssetIdBaseGet
     *
     * Get all current rates
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $filter_asset_id Comma or semicolon delimited asset identifiers used to filter response (optional) (optional)
     * @param  bool|null $invert True will invert all the rates (optional, if true then rates will be calculated as &#x60;rate &#x3D; 1 / actual_rate&#x60; eg. &#x60;USD/BTC&#x60; as &#x60;BTC/USD&#x60;) (optional, default to false)
     * @param  string|null $time Time for historical rates (optional) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseGet'] to see the possible values for this operation
     *
     * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \OpenAPI\Client\Model\V1ExchangeRates
     */
    public function v1ExchangerateAssetIdBaseGet($asset_id_base, $filter_asset_id = null, $invert = false, $time = null, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseGet'][0])
    {
        list($response) = $this->v1ExchangerateAssetIdBaseGetWithHttpInfo($asset_id_base, $filter_asset_id, $invert, $time, $contentType);
        return $response;
    }

    /**
     * Operation v1ExchangerateAssetIdBaseGetWithHttpInfo
     *
     * Get all current rates
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $filter_asset_id Comma or semicolon delimited asset identifiers used to filter response (optional) (optional)
     * @param  bool|null $invert True will invert all the rates (optional, if true then rates will be calculated as &#x60;rate &#x3D; 1 / actual_rate&#x60; eg. &#x60;USD/BTC&#x60; as &#x60;BTC/USD&#x60;) (optional, default to false)
     * @param  string|null $time Time for historical rates (optional) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseGet'] to see the possible values for this operation
     *
     * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \OpenAPI\Client\Model\V1ExchangeRates, HTTP status code, HTTP response headers (array of strings)
     */
    public function v1ExchangerateAssetIdBaseGetWithHttpInfo($asset_id_base, $filter_asset_id = null, $invert = false, $time = null, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseGet'][0])
    {
        $request = $this->v1ExchangerateAssetIdBaseGetRequest($asset_id_base, $filter_asset_id, $invert, $time, $contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        '\OpenAPI\Client\Model\V1ExchangeRates',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                '\OpenAPI\Client\Model\V1ExchangeRates',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 200:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        '\OpenAPI\Client\Model\V1ExchangeRates',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation v1ExchangerateAssetIdBaseGetAsync
     *
     * Get all current rates
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $filter_asset_id Comma or semicolon delimited asset identifiers used to filter response (optional) (optional)
     * @param  bool|null $invert True will invert all the rates (optional, if true then rates will be calculated as &#x60;rate &#x3D; 1 / actual_rate&#x60; eg. &#x60;USD/BTC&#x60; as &#x60;BTC/USD&#x60;) (optional, default to false)
     * @param  string|null $time Time for historical rates (optional) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function v1ExchangerateAssetIdBaseGetAsync($asset_id_base, $filter_asset_id = null, $invert = false, $time = null, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseGet'][0])
    {
        return $this->v1ExchangerateAssetIdBaseGetAsyncWithHttpInfo($asset_id_base, $filter_asset_id, $invert, $time, $contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation v1ExchangerateAssetIdBaseGetAsyncWithHttpInfo
     *
     * Get all current rates
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $filter_asset_id Comma or semicolon delimited asset identifiers used to filter response (optional) (optional)
     * @param  bool|null $invert True will invert all the rates (optional, if true then rates will be calculated as &#x60;rate &#x3D; 1 / actual_rate&#x60; eg. &#x60;USD/BTC&#x60; as &#x60;BTC/USD&#x60;) (optional, default to false)
     * @param  string|null $time Time for historical rates (optional) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function v1ExchangerateAssetIdBaseGetAsyncWithHttpInfo($asset_id_base, $filter_asset_id = null, $invert = false, $time = null, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseGet'][0])
    {
        $returnType = '\OpenAPI\Client\Model\V1ExchangeRates';
        $request = $this->v1ExchangerateAssetIdBaseGetRequest($asset_id_base, $filter_asset_id, $invert, $time, $contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'v1ExchangerateAssetIdBaseGet'
     *
     * @param  string $asset_id_base Requested exchange rates base asset identifier (from the Metadata -&gt; Assets) (required)
     * @param  string|null $filter_asset_id Comma or semicolon delimited asset identifiers used to filter response (optional) (optional)
     * @param  bool|null $invert True will invert all the rates (optional, if true then rates will be calculated as &#x60;rate &#x3D; 1 / actual_rate&#x60; eg. &#x60;USD/BTC&#x60; as &#x60;BTC/USD&#x60;) (optional, default to false)
     * @param  string|null $time Time for historical rates (optional) (optional)
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateAssetIdBaseGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function v1ExchangerateAssetIdBaseGetRequest($asset_id_base, $filter_asset_id = null, $invert = false, $time = null, string $contentType = self::contentTypes['v1ExchangerateAssetIdBaseGet'][0])
    {

        // verify the required parameter 'asset_id_base' is set
        if ($asset_id_base === null || (is_array($asset_id_base) && count($asset_id_base) === 0)) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $asset_id_base when calling v1ExchangerateAssetIdBaseGet'
            );
        }





        $resourcePath = '/v1/exchangerate/{asset_id_base}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $filter_asset_id,
            'filter_asset_id', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $invert,
            'invert', // param base name
            'boolean', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $time,
            'time', // param base name
            'string', // openApiType
            'form', // style
            true, // explode
            false // required
        ) ?? []);


        // path params
        if ($asset_id_base !== null) {
            $resourcePath = str_replace(
                '{' . 'asset_id_base' . '}',
                ObjectSerializer::toPathValue($asset_id_base),
                $resourcePath
            );
        }


        $headers = $this->headerSelector->selectHeaders(
            ['text/plain', 'application/json', 'text/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires API key authentication
        $apiKey = $this->config->getApiKeyWithPrefix('X-CoinAPI-Key');
        if ($apiKey !== null) {
            $headers['X-CoinAPI-Key'] = $apiKey;
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'GET',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation v1ExchangerateHistoryPeriodsGet
     *
     * Timeseries periods
     *
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateHistoryPeriodsGet'] to see the possible values for this operation
     *
     * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return \OpenAPI\Client\Model\V1TimeseriesPeriod[]
     */
    public function v1ExchangerateHistoryPeriodsGet(string $contentType = self::contentTypes['v1ExchangerateHistoryPeriodsGet'][0])
    {
        list($response) = $this->v1ExchangerateHistoryPeriodsGetWithHttpInfo($contentType);
        return $response;
    }

    /**
     * Operation v1ExchangerateHistoryPeriodsGetWithHttpInfo
     *
     * Timeseries periods
     *
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateHistoryPeriodsGet'] to see the possible values for this operation
     *
     * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format
     * @throws \InvalidArgumentException
     * @return array of \OpenAPI\Client\Model\V1TimeseriesPeriod[], HTTP status code, HTTP response headers (array of strings)
     */
    public function v1ExchangerateHistoryPeriodsGetWithHttpInfo(string $contentType = self::contentTypes['v1ExchangerateHistoryPeriodsGet'][0])
    {
        $request = $this->v1ExchangerateHistoryPeriodsGetRequest($contentType);

        try {
            $options = $this->createHttpClientOption();
            try {
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();


            switch($statusCode) {
                case 200:
                    return $this->handleResponseWithDataType(
                        '\OpenAPI\Client\Model\V1TimeseriesPeriod[]',
                        $request,
                        $response,
                    );
            }

            

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }

            return $this->handleResponseWithDataType(
                '\OpenAPI\Client\Model\V1TimeseriesPeriod[]',
                $request,
                $response,
            );
        } catch (ApiException $e) {
            switch ($e->getCode()) {
                case 200:
                    $data = ObjectSerializer::deserialize(
                        $e->getResponseBody(),
                        '\OpenAPI\Client\Model\V1TimeseriesPeriod[]',
                        $e->getResponseHeaders()
                    );
                    $e->setResponseObject($data);
                    throw $e;
            }
        

            throw $e;
        }
    }

    /**
     * Operation v1ExchangerateHistoryPeriodsGetAsync
     *
     * Timeseries periods
     *
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateHistoryPeriodsGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function v1ExchangerateHistoryPeriodsGetAsync(string $contentType = self::contentTypes['v1ExchangerateHistoryPeriodsGet'][0])
    {
        return $this->v1ExchangerateHistoryPeriodsGetAsyncWithHttpInfo($contentType)
            ->then(
                function ($response) {
                    return $response[0];
                }
            );
    }

    /**
     * Operation v1ExchangerateHistoryPeriodsGetAsyncWithHttpInfo
     *
     * Timeseries periods
     *
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateHistoryPeriodsGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Promise\PromiseInterface
     */
    public function v1ExchangerateHistoryPeriodsGetAsyncWithHttpInfo(string $contentType = self::contentTypes['v1ExchangerateHistoryPeriodsGet'][0])
    {
        $returnType = '\OpenAPI\Client\Model\V1TimeseriesPeriod[]';
        $request = $this->v1ExchangerateHistoryPeriodsGetRequest($contentType);

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ($returnType === '\SplFileObject') {
                        $content = $response->getBody(); //stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ($returnType !== 'string') {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders()
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();
                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            );
    }

    /**
     * Create request for operation 'v1ExchangerateHistoryPeriodsGet'
     *
     * @param  string $contentType The value for the Content-Type header. Check self::contentTypes['v1ExchangerateHistoryPeriodsGet'] to see the possible values for this operation
     *
     * @throws \InvalidArgumentException
     * @return \GuzzleHttp\Psr7\Request
     */
    public function v1ExchangerateHistoryPeriodsGetRequest(string $contentType = self::contentTypes['v1ExchangerateHistoryPeriodsGet'][0])
    {


        $resourcePath = '/v1/exchangerate/history/periods';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;





        $headers = $this->headerSelector->selectHeaders(
            ['text/plain', 'application/json', 'text/json', ],
            $contentType,
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);

            } elseif (stripos($headers['Content-Type'], 'application/json') !== false) {
                # if Content-Type contains "application/json", json_encode the form parameters
                $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams);
            }
        }

        // this endpoint requires API key authentication
        $apiKey = $this->config->getApiKeyWithPrefix('X-CoinAPI-Key');
        if ($apiKey !== null) {
            $headers['X-CoinAPI-Key'] = $apiKey;
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $operationHost = $this->config->getHost();
        $query = ObjectSerializer::buildQuery($queryParams);
        return new Request(
            'GET',
            $operationHost . $resourcePath . ($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Create http client option
     *
     * @throws \RuntimeException on file opening failure
     * @return array of http client options
     */
    protected function createHttpClientOption()
    {
        $options = [];
        if ($this->config->getDebug()) {
            $options[RequestOptions::DEBUG] = fopen($this->config->getDebugFile(), 'a');
            if (!$options[RequestOptions::DEBUG]) {
                throw new \RuntimeException('Failed to open the debug file: ' . $this->config->getDebugFile());
            }
        }

        return $options;
    }

    private function handleResponseWithDataType(
        string $dataType,
        RequestInterface $request,
        ResponseInterface $response
    ): array {
        if ($dataType === '\SplFileObject') {
            $content = $response->getBody(); //stream goes to serializer
        } else {
            $content = (string) $response->getBody();
            if ($dataType !== 'string') {
                try {
                    $content = json_decode($content, false, 512, JSON_THROW_ON_ERROR);
                } catch (\JsonException $exception) {
                    throw new ApiException(
                        sprintf(
                            'Error JSON decoding server response (%s)',
                            $request->getUri()
                        ),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                        $content
                    );
                }
            }
        }

        return [
            ObjectSerializer::deserialize($content, $dataType, []),
            $response->getStatusCode(),
            $response->getHeaders()
        ];
    }

    private function responseWithinRangeCode(
        string $rangeCode,
        int $statusCode
    ): bool {
        $left = (int) ($rangeCode[0].'00');
        $right = (int) ($rangeCode[0].'99');

        return $statusCode >= $left && $statusCode <= $right;
    }
}
