/*
    libmaus2
    Copyright (C) 2020 German Tischler-Höhle

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU 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 General Public License for more details.

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

bool libmaus2::network::CurlObjectReader::startsWith(std::string const & url, std::string const & prefix)
{
	return url.size() >= prefix.size() && url.substr(0,prefix.size()) == prefix;
}

libmaus2::network::CurlResponseAcceptor::unique_ptr_type libmaus2::network::CurlObjectReader::constructAcceptor(std::string const & url)
{
	if ( startsWith(url,"http:") || startsWith(url,"https:") )
	{
		libmaus2::network::CurlResponseAcceptor::unique_ptr_type pacceptor(
			new libmaus2::network::HttpCurlResponseAcceptor
		);
		return pacceptor;
	}
	else if ( startsWith(url,"ftp:") )
	{
		libmaus2::network::CurlResponseAcceptor::unique_ptr_type pacceptor(
			new libmaus2::network::FtpCurlResponseAcceptor
		);
		return pacceptor;
	}
	else
	{
		libmaus2::exception::LibMausException lme;
		lme.getStream() << "CurlObjectReader::CurlObjectReader: unsupported protocol in " << url << std::endl;
		lme.finish();
		throw lme;
	}
}

libmaus2::network::CurlObjectReader::CurlObjectReader(std::string const & rurl, std::size_t const freelistsize)
: url(rurl), pacceptor(constructAcceptor(url)), obj(url,pacceptor.get(),freelistsize),
  pcall(new libmaus2::network::CurlObjectThreadCallable(obj)),
  thread(pcall),
  callable(dynamic_cast<libmaus2::network::CurlObjectThreadCallable &>(thread.getCallable()))
{
	thread.start();
}

std::size_t libmaus2::network::CurlObjectReader::read(char * p, std::size_t n)
{
	std::size_t const r = obj.read(p,n);

	if ( r )
		return r;

	thread.join();

	if ( callable.getCode() != 0 )
	{
		if (
			(callable.getLastResponse() < 0)
			||
			(*pacceptor)(callable.getLastResponse())
		)
		{
			libmaus2::exception::LibMausException lme;
			lme.getStream() << "[E] CurlObjectReader::read failed: " << callable.getErrorString() << " on " << url << std::endl;
			lme.finish();
			throw lme;
		}
		else
		{
			libmaus2::exception::LibMausException lme;
			lme.getStream() << "[E] CurlObjectReader::read failed: response code " << callable.getLastResponse() << " on " << url << std::endl;
			lme.finish();
			throw lme;
		}
	}
	else if ( ! (*pacceptor)(callable.getLastResponse()) )
	{
		libmaus2::exception::LibMausException lme;
		lme.getStream() << "[E] CurlObjectReader::read failed: " << callable.getErrorString() << " on " << url << std::endl;
		lme.finish();
		throw lme;

	}
	else
	{
		return 0;
	}
}
