/*
    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/aio/SecrecyOutputStreamFactory.hpp>

#if defined(LIBMAUS2_HAVE_LIBSECRECY)
#include <libmaus2/aio/OutputStreamInstance.hpp>
#include <libmaus2/aio/SecrecyCache.hpp>
#include <libsecrecy/GCMOutputStream.hpp>
#include <libmaus2/exception/LibMausException.hpp>
#include <libmaus2/aio/OutputStreamFactoryContainer.hpp>
#include <libmaus2/aio/FileRemoval.hpp>

namespace libmaus2
{
	namespace aio
	{
		struct SecrecyOutputStreamInstanceWrapper
		{
			protected:
			OutputStreamInstance OSI;

			public:
			SecrecyOutputStreamInstanceWrapper(std::string const & fn) : OSI(fn) {}
		};
	}
}

namespace libmaus2
{
	namespace aio
	{
		struct SecrecyOutputStream : public SecrecyOutputStreamInstanceWrapper, public libsecrecy::GCMOutputStream
		{
			SecrecyOutputStream(std::string const & fn, std::string const & hexhash)
			:
				SecrecyOutputStreamInstanceWrapper(fn),
				libsecrecy::GCMOutputStream(
					SecrecyOutputStreamInstanceWrapper::OSI, hexhash,
					libsecrecy::GCMOutputStream::getDefaultBlockSize(),
					libsecrecy::GCMOutputStream::getDefaultAuthDataSize(),
					&libmaus2::aio::SecrecyCache::secrecyCache
				)
			{}
		};
	}
}

libmaus2::aio::SecrecyOutputStreamFactory::~SecrecyOutputStreamFactory() {}

libmaus2::aio::OutputStream::unique_ptr_type libmaus2::aio::SecrecyOutputStreamFactory::constructUnique(std::string const & filename, std::string const & params)
{
	std::shared_ptr<std::ostream> iptr(new SecrecyOutputStream(filename,params));
	libmaus2::aio::OutputStream::unique_ptr_type istr(new libmaus2::aio::OutputStream(iptr));
	return istr;
}

libmaus2::aio::OutputStream::unique_ptr_type libmaus2::aio::SecrecyOutputStreamFactory::constructUnique(std::string const & filename)
{
	libmaus2::aio::OutputStream::unique_ptr_type ptr(constructUnique(filename,std::string()));
	return ptr;
}

libmaus2::aio::OutputStream::shared_ptr_type libmaus2::aio::SecrecyOutputStreamFactory::constructShared(std::string const & filename, std::string const & params)
{
	std::shared_ptr<std::ostream> iptr(new SecrecyOutputStream(filename,params));
	libmaus2::aio::OutputStream::shared_ptr_type istr(new libmaus2::aio::OutputStream(iptr));
	return istr;
}

libmaus2::aio::OutputStream::shared_ptr_type libmaus2::aio::SecrecyOutputStreamFactory::constructShared(std::string const & filename)
{
	return constructShared(filename);
}

void libmaus2::aio::SecrecyOutputStreamFactory::rename(std::string const & from, std::string const & to)
{
	libmaus2::aio::URLObject Ufrom(from);
	libmaus2::aio::URLObject Uto(from);

	if ( Ufrom.protocol != "libsecrecy" )
	{
		libmaus2::exception::LibMausException lme;
		lme.getStream() << "SecrecyOutputStreamFactory::mkdir: protocol mismatch in " << from << std::endl;
		lme.finish();
		throw lme;
	}

	if ( Uto.protocol != "libsecrecy" )
	{
		libmaus2::exception::LibMausException lme;
		lme.getStream() << "SecrecyOutputStreamFactory::mkdir: protocol mismatch in " << to << std::endl;
		lme.finish();
		throw lme;
	}

	libmaus2::aio::OutputStreamFactoryContainer::rename(Ufrom.path,Uto.path);
}

void libmaus2::aio::SecrecyOutputStreamFactory::mkdir(std::string const & name, uint64_t const mode)
{
	libmaus2::aio::URLObject U(name);

	if ( U.protocol != "libsecrecy" )
	{
		libmaus2::exception::LibMausException lme;
		lme.getStream() << "SecrecyOutputStreamFactory::mkdir: protocol mismatch in " << name << std::endl;
		lme.finish();
		throw lme;
	}

	libmaus2::aio::OutputStreamFactoryContainer::mkdir(U.path,mode);
}

#endif
