#pragma once

#include "common.h"
#include "util.h"

struct SeekMode
{
	enum Enum
	{
		kBEGIN,
		kCURRENT,
		kEND,
	};
};

class IStream
{
public:
	virtual ~IStream()
	{
	}

	virtual bool read(void* const data, const uint32_t size, uint32_t* const num_read = nullptr) = 0;
	virtual bool write(const void* const data, const uint32_t size, uint32_t* const num_written = nullptr) = 0;

	virtual bool seek(const uint64_t offset, const SeekMode::Enum mode = SeekMode::kBEGIN, uint64_t* const position = nullptr) = 0;

	inline uint64_t tell()
	{
		uint64_t pos;
		if (!seek(0, SeekMode::kCURRENT, &pos))
			return 0;
		return pos;
	}

	template<typename T>
	inline typename std::enable_if<std::is_arithmetic<T>::value, bool>::type read_le(T& data)
	{
		if (!read(&data, sizeof(data)))
			return false;
		data = host_to_little(data);
		return true;
	}

	template<typename T>
	inline typename std::enable_if<std::is_arithmetic<T>::value, bool>::type read_be(T& data)
	{
		if (!read(&data, sizeof(data)))
			return false;
		data = host_to_big(data);
		return true;
	}

	template<typename T>
	inline typename std::enable_if<std::is_arithmetic<T>::value, bool>::type write_le(T data)
	{
		data = little_to_host(data);
		if (!write(&data, sizeof(data)))
			return false;
		return true;
	}

	template<typename T>
	inline typename std::enable_if<std::is_arithmetic<T>::value, bool>::type write_be(T data)
	{
		data = big_to_host(data);
		if (!write(&data, sizeof(data)))
			return false;
		return true;
	}
};
