//! \~\file pihttpclient.h
//! \~\ingroup HTTPClient
//! \~\brief
//! \~english Public HTTP client request API
//! \~russian Публичный API HTTP-клиента для выполнения запросов
/*
	PIP - Platform Independent Primitives
	Public HTTP client request API
	Ivan Pelipenko peri4ko@yandex.ru

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef pihttpclient_h
#define pihttpclient_h

#include "pihttptypes.h"
#include "pip_http_client_export.h"
#include "pistringlist.h"


class PIHTTPClientBase {
public:
	int __infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow);
	int __debugFunc(int type, char * data, size_t size);
};


//! \~\ingroup HTTPClient
//! \~\brief
//! \~english Asynchronous HTTP client request with completion callbacks.
//! \~russian Асинхронный HTTP-запрос клиента с callback-ами завершения.
class PIP_HTTP_CLIENT_EXPORT PIHTTPClient: private PIHTTPClientBase {
	friend class PIHTTPClientBase;
	friend class CurlThreadPool;


public:
	//! \~english Creates a request object for the specified URL, method and initial message data.
	//! \~russian Создает объект запроса для указанного URL, метода и начальных данных сообщения.
	static PIHTTPClient * create(const PIString & url, PIHTTP::Method method = PIHTTP::Method::Get, const PIHTTP::MessageConst & req = {});


	//! \~english Sets a callback invoked when the transfer completes successfully.
	//! \~russian Устанавливает callback, вызываемый при успешном завершении передачи.
	PIHTTPClient * onFinish(std::function<void()> f);

	//! \~english Sets a callback invoked when the transfer completes successfully and provides the parsed reply.
	//! \~russian Устанавливает callback, вызываемый при успешном завершении передачи, и передает разобранный ответ.
	PIHTTPClient * onFinish(std::function<void(const PIHTTP::MessageConst &)> f);

	//! \~english Sets a callback invoked when the transfer fails with a transport-level error.
	//! \~russian Устанавливает callback, вызываемый при ошибке передачи на транспортном уровне.
	PIHTTPClient * onError(std::function<void()> f);

	//! \~english Sets a callback invoked when the transfer fails with a transport-level error and provides the partial reply state.
	//! \~russian Устанавливает callback, вызываемый при ошибке передачи на транспортном уровне, и передает текущее состояние ответа.
	PIHTTPClient * onError(std::function<void(const PIHTTP::MessageConst &)> f);

	//! \~english Sets a callback invoked when the request is aborted.
	//! \~russian Устанавливает callback, вызываемый при прерывании запроса.
	PIHTTPClient * onAbort(std::function<void()> f);

	//! \~english Sets a callback invoked when the request is aborted and provides the current reply state.
	//! \~russian Устанавливает callback, вызываемый при прерывании запроса, и передает текущее состояние ответа.
	PIHTTPClient * onAbort(std::function<void(const PIHTTP::MessageConst &)> f);


	//! \~english Disables SSL verification checks for this request. Call \b before \a start().
	//! \~russian Отключает проверки SSL для этого запроса. Вызывайте \b до \a start().
	PIHTTPClient * ignoreSSLErrors();


	//! \~english Queues the request for asynchronous execution.
	//! \~russian Ставит запрос в очередь на асинхронное выполнение.
	void start();

	//! \~english Requests cancellation of the running transfer.
	//! \~russian Запрашивает отмену выполняющейся передачи.
	void abort();


	//! \~english Returns the last transport error message.
	//! \~russian Возвращает последнее сообщение об ошибке транспортного уровня.
	PIString lastError() const { return last_error; }


private:
	NO_COPY_CLASS(PIHTTPClient)
	PIHTTPClient();
	virtual ~PIHTTPClient();

	PRIVATE_DECLARATION(PIP_HTTP_CLIENT_EXPORT)

	bool init();
	void perform();
	void procHeaderLine(PIString & line);

	static size_t writeMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr);
	static size_t readMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr);
	static size_t headerFunc(char * contents, size_t size, size_t nmemb, void * ptr);
	int infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow);
	int debugFunc(int type, char * data, size_t size);

	PIString url;
	PIString last_error;
	PIStringList headers;
	PIByteArray buffer_out;
	PIHTTP::MessageMutable request, reply;
	std::atomic_bool is_cancel = {false};
	bool ignore_ssl_errors     = false;
	ssize_t read_pos           = 0;
	std::function<void(const PIHTTP::MessageConst &)> on_finish, on_error, on_abort;
};


#endif
