/*
    libmaus2
    Copyright (C) 2009-2014 German Tischler
    Copyright (C) 2011-2014 Genome Research Limited

    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/>.
*/
#if ! defined(LIBMAUS2_AIO_POSIXFDINPUT_HPP)
#define LIBMAUS2_AIO_POSIXFDINPUT_HPP

#include <libmaus2/LibMausConfig.hpp>
#include <libmaus2/aio/StreamLock.hpp>
#include <libmaus2/exception/LibMausException.hpp>
#include <libmaus2/posix/PosixFunctions.hpp>
#include <libmaus2/lz/StreamWrapper.hpp>
#include <libmaus2/parallel/StdSpinLock.hpp>

#include <cerrno>
#include <cstring>
#include <ctime>
#include <cmath>

#if \
	defined(LIBMAUS2_HAVE_OPEN_2) && \
	defined(LIBMAUS2_HAVE_READ) && \
	defined(LIBMAUS2_HAVE_LSEEK) && \
	defined(LIBMAUS2_HAVE_CLOSE) && \
	defined(LIBMAUS2_HAVE_O_RDONLY)
#define LIBMAUS2_AIO_POSIXFDINPUT_SUPPORTED
#endif

namespace libmaus2
{
	namespace aio
	{
		struct PosixFdInput
		{
			public:
			typedef PosixFdInput this_type;
			typedef std::unique_ptr<this_type> unique_ptr_type;
			typedef std::shared_ptr<this_type> shared_ptr_type;

			private:
			std::string filename;
			int fd;
			::libmaus2::ssize_t gcnt;
			bool const closeOnDeconstruct;

			static std::atomic<uint64_t> totalin;
			static libmaus2::parallel::StdSpinLock totalinlock;

			static std::time_t const warnThreshold;

			static std::map<std::string,uint64_t> const blocksizeoverride;

			static std::time_t getTime();
			static void printWarning(char const * const functionname, std::time_t const time, std::string const & filename, int const fd);
			static void printWarningRead(char const * const functionname, std::time_t const time, std::string const & filename, int const fd, uint64_t const size);

			public:
			static int getDefaultFlags();

			~PosixFdInput();

			static bool tryOpen(std::string const & filename, int const rflags = getDefaultFlags());

			PosixFdInput(int const rfd);
			PosixFdInput(std::string const & rfilename, int const rflags = getDefaultFlags());

			::libmaus2::ssize_t read(char * const buffer, uint64_t n);
			int64_t lseek(uint64_t const n);
			::libmaus2::ssize_t gcount() const;
			void close();
			uint64_t size();
			int64_t sizeChecked();
			int64_t getOptimalIOBlockSize();
			static int64_t getOptimalIOBlockSize(int const fd, std::string const & filename);
			static uint64_t getTotalIn();
		};
	}
}
#endif
