/*
 * This file defines the class atc::RawIOBase and declares its methods.
 */

#pragma once

#include <cstdint>
#include <memory>
#include <vector>
#include <map>
#include <string>

#include "DataType.hpp"

namespace atc {
	
	/*
	 * Handles IO for raw data files/memory (original and decompressed data) and operations performed on this data with the original data type (like casting output)
	 * We use polymorphism to make the atc::Compressor class independent of the data type used, which leads to simpler explicit instantiation.
	 * We only access atc::RawIOBase externally using this high-level interface, so the cost of dynamic dispatch is negligible in practice.
	 */
	template<typename ftype>
	class RawIOBase {
	public:
		// Constructs the corresponding atc::RawIO object on the heap based on an atc::DataType and returns it as an std::unique_ptr.
		static std::unique_ptr<RawIOBase<ftype>> create(DataType dtype);
		// Constructs the corresponding atc::RawIO object on the heap based on an integer data type ID and returns it as an std::unique_ptr.
		static std::unique_ptr<RawIOBase<ftype>> create(uint8_t data_type_id);
		virtual ~RawIOBase() = default; // Virtual destructor needs to be provided in order to avoid memory leaks due to polymorphism.
		virtual uint8_t get_data_type_id() = 0; // Returns the integer ID of the data type of the underlying RawIO object.
		virtual size_t get_data_type_size() = 0; // Returns the size of the data type of the underlying RawIO object in bytes (i.e. sizeof(dtype)).
		virtual size_t get_stored_data_size() = 0; // Returns the size of the data buffer currently stored in case the data was read with store_data = true. If not, returns 0.
		// Sets a file target for reading. skip_bytes bytes at the start of the file will be skipped (e.g. can be used to skip headers).
		virtual void set_read_target(const std::string& data_file, size_t skip_bytes = 0) = 0;
		// Loads data from target, casts it and returns it
		// If store is true, the data will also be stored in its original datatype in the buffer
		virtual std::vector<ftype> read(const std::vector<size_t>& sizes, bool store_data = false) = 0;
		// Sets a file target for writing.
		virtual void set_write_target(const std::string& file) = 0;
		// Cast given data to dtype and save to file
		// If calculate_sse is true, calculates and returns the SSE
		virtual double write(const std::vector<ftype>& data, bool calculate_sse = false, size_t size = 0) = 0;
	};
	
}
