//	Darkstar Engine  (c) UnderWorld Interactive Studio (all coding by Svarog    2007-2008)
//
//      Данный файл является частью Darkstar Engine. Любое использование кода файла
//      без согласия компании, является нарушением закона об авторском праве (в слу-
//      чае если не оговорено обратное).
//
//      Имя файла: compiled_effect_file_common.hpp
//      Краткое описание: cross-platform part of loader and saver for compiled effect files 
//

#include <Darkstar/Graphic System/Effect/compiled_effect_file.hpp>
#include <Darkstar/Kernel/FileSystem/dfile.hpp>
#include <Darkstar/Kernel/logh.hpp>

using namespace gs;
using ker::Log;
using ker::Blob;

CompiledEffectFile::CompiledEffectFile()
{
	full_file_path = "";
	output = -1;
};

CompiledEffectFile::~CompiledEffectFile()
{
	if(output != - 1)
		_close(output);
};

void CompiledEffectFile::deleteFile() 
{
	if(full_file_path != "")
	{
		_close(output);
		DeleteFile(full_file_path.c_str());
	};
};

void CompiledEffectFile::openForWrite(const std::string& output_file_name)
{
	_sopen_s(&output, output_file_name.c_str(), _O_BINARY | _O_CREAT | _O_WRONLY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
	full_file_path = output_file_name;
};

void CompiledEffectFile::writeConstantTables(const shared_ptr<ConstantTable>& const_table, const std::vector<Blob>& vc_code, const std::vector<Blob>& pc_code)
{
	if(output == -1)
	{
		lwar << "File not open for writing";
		return;
	};

	ConstantTable::storage constants = const_table->getStorage();
	ConstantTable::storage::const_iterator cit;
	unsigned int ctable_size = (unsigned int)constants.size();
	_write(output, (char*)&ctable_size, sizeof(unsigned int));
	for(cit = constants.begin(); cit != constants.end(); ++cit)
	{
		unsigned short name_size = (unsigned short)cit->first.size();
		_write(output, (char*)&name_size, sizeof(unsigned short));
		_write(output, cit->first.c_str(), name_size);
		_write(output, (char*)&cit->second.register_index, sizeof(unsigned short));
		_write(output, (char*)&cit->second.type, sizeof(int));
	};
	unsigned int code_block_num = (unsigned int)vc_code.size();
	_write(output, (char*)&code_block_num, sizeof(unsigned int));
	for(unsigned int i = 0; i < vc_code.size(); ++i)
	{
		Blob vblob = vc_code[i];
		Blob pblob = pc_code[i];
		_write(output, (char*)&vblob.data_size, sizeof(unsigned int));
		_write(output, (char*)vblob.data, vblob.data_size);
		_write(output, (char*)&pblob.data_size, sizeof(unsigned int));
		_write(output, (char*)pblob.data, pblob.data_size);
	};
};

bool CompiledEffectFile::load(ker::DFile& input, const std::list<_Technique>& _tech, shared_ptr<Effect>& effect)
{
	if(!input.getIsLoaded())
	{
		lwar << "Cannot load file " << input.getFilename();
		return false;
	};

	std::list<_Technique>::const_iterator lit;
	for(lit = _tech.begin(); lit != _tech.end(); ++lit)
	{
		unsigned int size = static_cast<unsigned int>(lit->tech->macros.size());
		std::vector<short> cur_values(size);
		ConstantTable::storage stor;
		CONSTANT_TYPE type;
		shared_array<char> name;
		unsigned short name_size;
		unsigned short reg_index;
		unsigned int stor_size;
		input.read(sizeof(unsigned int), &stor_size);
		for(unsigned int i = 0; i < stor_size; ++i)
		{
			input.read(sizeof(unsigned short), &name_size);
			name.reset(new char[name_size+1]);
			name[name_size] = '\0';
			input.read(name_size, name.get());
			input.read(sizeof(unsigned short), &reg_index);
			int ctype;
			input.read(sizeof(int), &ctype);
			type = (CONSTANT_TYPE)ctype;
			Constant new_const;
			new_const.register_index = reg_index;
			new_const.type = type;
			stor.insert(std::pair<std::string, Constant>(name.get(), new_const));
		};
		lit->tech->const_table.reset(new ConstantTable);
		lit->tech->const_table->setNewStorage(stor);
		unsigned int number_of_block;
		input.read(sizeof(unsigned int), &number_of_block);
		for(unsigned int i = 0; i < number_of_block; ++i)
		{
			shared_array<char> code;
			unsigned int code_size;
			// vertex shader
			input.read(sizeof(unsigned int), &code_size);
			code.reset(new char[code_size]);
			input.read(code_size, code.get());
			shared_ptr<VertexShader> vertex_shader(new VertexShader);
			if(!vertex_shader->create(code.get(), code_size))
			{
				lwar << "Error in compiled effect file. Cannot create vertex shader";
				return false;
			};
			// pixel shader
			input.read(sizeof(unsigned int), &code_size);
			code.reset(new char[code_size]);
			input.read(code_size, code.get());
			shared_ptr<PixelShader> pixel_shader(new PixelShader);
			if(!pixel_shader->create(code.get(), code_size))
			{
				lwar << "Error in compiled effect file. Cannot create pixel shader";
				return false;
			};
			ConcreteEffect new_ce;
			new_ce.ps = pixel_shader;
			new_ce.vs = vertex_shader;
			lit->tech->ce.push_back(new_ce);
		};
		effect->addNewTechnique(lit->tech_name, lit->tech);
	};
	_loadInputSignature(input, effect);
	return true;
};