#pragma once
#include <stdint.h>
#include <string>
#include <map>
#include "mmap.h"

namespace M3D
{
const uint16_t M3DML_VER_MAGIC = 1;
const char M3DML_SIGNATURE[] = "M3DML";

enum M3DML_BLOCK_TYPE
{
    M3DML_NOBLOCK = 0x0,
    M3DML_DIFFUSE = 0x01,
    M3DML_AMBIENT = 0x02,
    M3DML_SHININESS = 0x04,
    M3DML_SPECULAR = 0x08,
    M3DML_EMISSION = 0x10,
    M3DML_NORMAL_MAP = 0x20,
    M3DML_BUMP_MAP = 0x40,
    M3DML_ROUGHNESS = 0x80
};
enum M3DML_BLOCK_DATA_TYPE
{
    M3DML_TEXTURE = 0x00,
    M3DML_COLOR = 0x01,
    M3DML_FLOAT = 0x02
};
#pragma pack(push, 1)
struct M3DML_Header
{
	char signature[ 5 ];
	uint16_t version;
	uint8_t layers_number;
	uint16_t shader_path_length;
	uint32_t data_offset;
	uint32_t shader_path_offset;
};
struct M3DML_Data_Block
{
	uint16_t block_type;
	uint32_t block_offset;
	uint8_t block_data_type;
};
struct M3DML_Color_Block
{
	float r;
	float g;
	float b;
	float a;
};
struct M3DML_Texture_Block
{
	uint16_t texture_path_length;
};
struct M3DML_Float_Block
{
	float data;
};
#pragma pack(pop)
struct M3DML_Layer
{
	M3DML_Data_Block *data_block;
	M3DML_Color_Block *color_block;
	M3DML_Texture_Block *texture_block;
	char *texture_path;
	M3DML_Float_Block *float_block;
	M3DML_Layer() : data_block( 0 ), color_block( 0 ), texture_block( 0 ), float_block( 0 ) {}}
;
/**
 * @author Denis A. Biryukov <denis.birukov@gmail.com>
 */
class M3DML
{
	public:
		M3DML();
		~M3DML();
		/**
		 * Производит загрузку указанного файла в память.
		 * @param fname имя файла для загрузки.
		 */
		void load ( std::string fname );

		/**
		 * Производит сохранение данных в указанный файл. 
		 * Если такой файл уже существует то он заменяется. 
		 * При сохранении производится пересчет всех смещений 
		 * @param fname имя файла для сохранения данных
		 */
		void save ( std::string fname );

		/**
		 * Устанавливает данные соответствующего слоя
		 * @param layer слой
		 * @param layer_data даные о соответствующих слоях
		 */
		void set_layer_data ( M3DML_BLOCK_TYPE layer, const M3DML_Layer &layer_data );
		/**
		* Получение информации о слое
		* @param layer слой
		* @return константная ссылка на данные о запрошенном слое
		 */
		const M3DML_Layer* get_layer_data ( M3DML_BLOCK_TYPE layer ) const;

		/**
		* Производит установку информации для заголовка файла. Информация о кол-ве слоевавтоматически обновляется при каждом добавлении нового слоя
		* @param value заголовок
		 */
		void set_header_ ( M3DML_Header* value );
		/**
		* Получение информации из заголовка файла.
		* @return константный указатель на заголовок
		*/
		const M3DML_Header* get_header() const { return _header_;};
		
		/**
		 * Сохранение пути к шейдеру
		 * @param path путь к шейдеру
		 */
		void set_shader_path ( char* path ) { _shader_path_ = path;}
		/**
		 * Получение пути к шейдеру
		 * @return константный указатель на путь к шейдеру
		 */
		const char*  get_shader_path () const { return _shader_path_;}
		/**
		 * Возвращает итератор на первый блок данных
		 * @return итератор на первый блок данных
		 */
		std::map<M3DML_BLOCK_TYPE, M3DML_Layer>::const_iterator data_begin() { return _layer_data_.begin();}
		/**
		 * Возвращает итератор на конец блока данных
		 * @return итератор на конец блока данных
		 */
		std::map<M3DML_BLOCK_TYPE, M3DML_Layer>::const_iterator data_end() { return _layer_data_.end();}
		
	private:
		M3DML_Header *_header_;
		std::map<M3DML_BLOCK_TYPE, M3DML_Layer> _layer_data_;
		typedef std::map<M3DML_BLOCK_TYPE, M3DML_Layer> LAYER_MAP;
		char *_shader_path_;
		MMAP _mapped_file_;
};

}


