/**
 * Copyright 2020 German Tischler-Höhle
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **/
#if ! defined(LIBSECRECY_GCMOUTPUTSTREAM_HPP)
#define LIBSECRECY_GCMOUTPUTSTREAM_HPP

#include <libsecrecy/GCMOutputStreamBuffer.hpp>
#include <libsecrecy/GCMEncrypter.hpp>

namespace libsecrecy
{
	/**
	 * output stream for write libsecrecy encryped files. Seeking inside the
	 * is not supported
	 **/
	struct GCMOutputStream : std::shared_ptr<GCMEncrypterInterface>, public GCMOutputStreamBuffer, public std::ostream
	{
		private:
		std::shared_ptr<GCMEncrypterInterface> interface;

		public:
		/**
		 * constructor
		 *
		 * @param rout output stream encrypted data will be written to
		 * @param scipher name of cipher to be used (AES128 or AES256)
		 * @param hexhash hexadecimal hash code representing the key
		 *        to be used (output of secrecy createKey scipher)
		 * @param rbuffersize output buffer size used
		 * @param l_authdata length of auth data used for
		 *        authenticating each output block
		 **/
		GCMOutputStream(
			std::ostream & rout,
			std::string const & hexhash,
			uint64_t const rbuffersize = getDefaultBlockSize(),
			::std::size_t const l_authdata = getDefaultAuthDataSize(),
			RawKeyBaseCacheInterface * cache = nullptr
		)
		: std::shared_ptr<GCMEncrypterInterface>(GCMEncrypterFactory::construct(
			rout,
			hexhash,
			l_authdata,
			0 /* countershift */,
			rbuffersize,
			cache
		  )),
		  GCMOutputStreamBuffer(rout,static_cast<std::shared_ptr<GCMEncrypterInterface> >(*this),rbuffersize),
		  std::ostream(this)
		{
		}

		~GCMOutputStream()
		{
			flush();
		}

		static std::size_t getDefaultAuthDataSize()
		{
			return GCM_DIGEST_SIZE;
		}

		static std::size_t getDefaultBlockSize()
		{
			return 64*1024;
		}
	};
}
#endif
