#include "ModelStorage.h"


void Model_storage::pushVcoord(float x, float y, float z)
{
	this->v_coords.push_back(x);
	this->v_coords.push_back(y);
	this->v_coords.push_back(z);
}
void Model_storage::pushTcoord(float x, float y)
{
	this->t_coords.push_back(x);
	this->t_coords.push_back(y);
}
void Model_storage::pushNcoord(float x, float y, float z)
{
	this->n_coords.push_back(x);
	this->n_coords.push_back(y);
	this->n_coords.push_back(z);
}
void Model_storage::pushFcoord(const vector<int>& fvcoord, const vector<int>& fncoord, const vector<int>& ftcoord)
{
	this->fv_coords.push_back(fvcoord);
	this->fn_coords.push_back(fncoord);
	this->ft_coords.push_back(ftcoord);
}

vcoord_buffer&  Model_storage::getVcoordBuffer()
{
	return this->v_coords;
}
tcoord_buffer&  Model_storage::getTcoordBuffer()
{
	return this->t_coords;
}
ncoord_buffer&  Model_storage::getNcoordBuffer()
{
	return this->n_coords;
}
fv_coord_buffer& Model_storage::getFVcoordBuffer()
{
	return this->fv_coords;
}
fn_coord_buffer& Model_storage::getFNcoordBuffer()
{
	return this->fn_coords;
}
ft_coord_buffer& Model_storage::getFTcoordBuffer()
{
	return this->ft_coords;
}



//=======POMOCNE FCE==============
void getPolygonVcoords(const fv_coord_buffer& fv_coords, const vcoord_buffer& vcoords, int polygon_index, vcoord_buffer& dst_polygon_v)
{
	assert(polygon_index<fv_coords.size());

	
	for (int n=0; n<fv_coords[polygon_index].size();++n)
	{
		int index=fv_coords[polygon_index][n]-1; //obj indexuje facy od 1 ale ja je indexuji od 0

		dst_polygon_v.push_back(vcoords[index*3]);	// x coord
		dst_polygon_v.push_back(vcoords[index*3 +1]);	// y coord
		dst_polygon_v.push_back(vcoords[index*3 +2]);	// z coord
	}
}
void getPolygonTcoords(const ft_coord_buffer& ft_coords, const tcoord_buffer& tcoords, int polygon_index, tcoord_buffer& dst_polygon_t)
{
	assert(polygon_index<ft_coords.size());

	
	for (int n=0; n<ft_coords[polygon_index].size();++n)
	{
		int index=ft_coords[polygon_index][n]-1;//obj indexuje facy od 1 ale ja je indexuji od 0

		if (index*2+1>tcoords.size() || index<0)
		{
			//mimo rozsah...nastala nejaka chyba, zrejme chybna data v modelu
			assert(!"CHYBA pri zpracovani dat modelu - duvodem je pravdepodobne vadny .obj model");
		}
		else
		{
			dst_polygon_t.push_back(tcoords[index*2]);		// u coord
			dst_polygon_t.push_back(tcoords[index*2 +1]);	// v coord
		}

	
	}
}
void getPolygonNcoords(const fn_coord_buffer& fn_coords, const ncoord_buffer& ncoords, int polygon_index, ncoord_buffer& dst_polygon_n)
{
	assert(polygon_index<fn_coords.size());

	for (int n=0; n<fn_coords[polygon_index].size();++n)
	{
		int index=fn_coords[polygon_index][n]-1; //obj indexuje facy od 1 ale ja je indexuji od 0

		if (index*2+1>ncoords.size() || index<0)
		{
			//mimo rozsah...nastala nejaka chyba, zrejme chybna data v modelu
			assert(!"CHYBA pri zpracovani dat modelu - duvodem je pravdepodobne vadny .obj model");
		}
		else
		{
			dst_polygon_n.push_back(ncoords[index*3]);		// x coord
			dst_polygon_n.push_back(ncoords[index*3 +1]);	// y coord
			dst_polygon_n.push_back(ncoords[index*3 +2]);	// z coord
		}
	}
}

void convertCoordsToUnionIndices(const fv_coord_buffer& fv_coords, const vcoord_buffer& vcoords, 
	const fn_coord_buffer& fn_coords, const ncoord_buffer& ncoords, 
	const ft_coord_buffer& ft_coords, const tcoord_buffer& tcoords, 
	vcoord_buffer& dst_union_vcoords, ncoord_buffer& dst_union_ncoords, tcoord_buffer& dst_union_tcoords, funion_coord_buffer& union_indices)
{
	dst_union_vcoords.clear();
	dst_union_ncoords.clear();
	dst_union_tcoords.clear();
	union_indices.clear();

	size_t index=0;
	for (int i=0; i<fv_coords.size(); ++i)
	{
		getPolygonVcoords(fv_coords,vcoords,i, dst_union_vcoords);
		getPolygonNcoords(fn_coords,ncoords,i, dst_union_ncoords);
		getPolygonTcoords(ft_coords,tcoords,i, dst_union_tcoords);
		

		//######################################
		/*
			We have to have the same number of vertex indices, texture indices and normal indices 
			if we want convert to union faces
		*/

		//FIXME: this is very uneffective -> OPTIMALIZATION TIP ( GPU memory can be much lower for untextured objects )
		
		//nCoords have to corresponds to vCoords to be able to use union face indices
		/*
			if ncoords.size() == 0 than it mean that the model doesnt have normals at all
			and in this case no normal buffer array will be created when VBO initialization
			is called
		*/
		while ( dst_union_ncoords.size() != dst_union_vcoords.size() && ncoords.size()!=0 )
		{
			dst_union_ncoords.push_back( 0 );
		}

		//tCoords have to corresponds to vCoords to be able to use union face indices
		/*
			if tcoords.size() == 0 than it mean that the model doesnt have tex. coords at all
			and in this case no normal buffer array will be created when VBO initialization
			is called
		*/
		while ( dst_union_tcoords.size()*3 != dst_union_vcoords.size()*2 && tcoords.size()!=0  )	 // vCoords consist of X,Y,Z but tCoord consist of X,Y -> GCD(3,2) = 6
		{
			dst_union_tcoords.push_back( 0 );
		}
		//#####################################

		vector<int> indices;
		for (int n=0; n<fv_coords[i].size(); ++n)
		{
			indices.push_back(index);
			++index;
		}

		union_indices.push_back(indices);
	}
}


void convertIndicesToArray1D(const vector<vector<int>>& src_indices, vector<int>& dst_array)
{
	for (size_t i=0; i<src_indices.size(); ++i)
	{
		for (size_t n=0; n<src_indices[i].size(); ++n)
		{
			dst_array.push_back(src_indices[i][n]);
		}
	}
}


bool convertToTriangularFaces(const vector<vector<int>>& polygon_indices)
{
	for (int i=0; i<polygon_indices.size(); ++i)
	{
		if (polygon_indices[i].size()!=3)
		{
			return false;
		}
	}

	return true;
}
bool convertPolygonToTriangles(vector<int>& polygon_indices, vector<vector<int>>& dst_triangles_indices)
{
	if (polygon_indices.size()<3) return false; //nelze prevest na trojuhelnik

	if (polygon_indices.size()==3)	//jiz je trojuhelnik
	{
		dst_triangles_indices.push_back(polygon_indices);
		return true;
	}

	int first_index=polygon_indices[0];
	int prev_index=polygon_indices[1];

	for (int i=2; i<polygon_indices.size(); ++i)
	{
		vector<int> triangle_indices;
		triangle_indices.push_back(first_index);
		triangle_indices.push_back(prev_index);
		triangle_indices.push_back(polygon_indices[i]);

		prev_index=polygon_indices[i];

		dst_triangles_indices.push_back(triangle_indices);
	}

	return true;
}

void convertPolygonsToTriangles( vector<vector<int>>& src_indices, vector<vector<int>>& dst_indices)
{
	//POZOR dst_fv_coords!=fv_coords ...jinak nebude fungovat!!!

	for (int i=0; i<src_indices.size(); ++i)
	{
		convertPolygonToTriangles(src_indices[i],dst_indices);
	}
}


void convertPolygonsToTriangles( vector<vector<int>>& src_indices,unsigned int from, unsigned int to, vector<vector<int>>& dst_indices)
{
	//WARNING srcIndices and dstIndices cannot have the same address!!!
	assert( (&src_indices)!=(&dst_indices));

	for (int i=from; i<to; ++i)
	{
		convertPolygonToTriangles(src_indices[i],dst_indices);
	}
}