#include "ElementProxyHeaders.hpp"

#include <MLR\MLRTexture.hpp>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ApplyDetailTexturesProcess::ApplyDetailTexturesProcess(
	Stuff::NotationFile *tron_file
)
{
	tronFile = tron_file;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ApplyDetailTexturesProcess::ApplyDetailTexturesProcess(
	Stuff::NotationFile *tron_file,
	Stuff::NotationFile *config_file
):
	Process(config_file)
{
	tronFile = tron_file;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ApplyDetailTexturesProcess::~ApplyDetailTexturesProcess()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementPolygonMeshProxy::ApplyDetailTextures(ApplyDetailTexturesProcess *process)
{
	Check_Object(this);
	Check_Object(process);

	//
	//------------------------------------------------------------
	// Make sure that the process says its OK to check the texture
	//------------------------------------------------------------
	//
	process->ApplyDetailTexturesCallback(this);
	if (!process->continueProcess)
		return;

	//
	//------------------------------------------------------------------------
	// Get the state arrays for this mesh and make sure that they have already
	// been split
	//------------------------------------------------------------------------
	//
	DynamicArrayOf<PolygonProxy*> polygons;
	unsigned polygon_count = UsePolygonArray(&polygons);
	if (!polygon_count)
		return;
	DynamicArrayOf<MultiState*> states;
	DynamicArrayOf<unsigned> index;
	DynamicArrayOf<unsigned> count;
	#if defined(_ARMOR)
		unsigned unique_states =
	#endif
		UseMultiStateArray(&states, &index, &count, polygons);
	Verify(unique_states==1 && count[0]==polygon_count);

	//
	//----------------------------------------------------------------------
	// If this mesh is not textured, we can just return.  Otherwise, get the
	// texture name and size
	//----------------------------------------------------------------------
	//
	Check_Object(states[0]);
	unsigned state_count = states[0]->GetLength();
	Check_Object(process->tronFile);
	for(unsigned state_loop=0;state_loop<state_count;++state_loop)
	{
		TextureProxy *texture = (*states[0])[state_loop]->UseTextureProxy();
		if (!texture)
			break;

		MString name;
		texture->GetName(&name);
		Vector2DOf<int> texture_size;
		texture->GetImageSize(&texture_size);
		texture->DetachReference();

		//
		//---------------------------------------------------------------------
		// See if there is a detail texture for this texture.  If so, parse the
		// info
		//---------------------------------------------------------------------
		//
		const char *detail_info = NULL;
		Page *page = process->tronFile->FindPage(name);
		if (!page)
			continue;
		if (!page->GetEntry("DetailTexture", &detail_info))
			continue;
		Check_Pointer(detail_info);
		char detail_name[80];
		Vector2DOf<Scalar>
			detail_offset,
			detail_scale;
		#if defined(_ARMOR)
			int count =
		#endif
		sscanf(
			detail_info,
			"%s %f %f %f %f",
			detail_name,
			&detail_offset.x,
			&detail_offset.y,
			&detail_scale.x,
			&detail_scale.y
		);
		Verify(count == 5);
		Verify(strlen(detail_name)>0);

		//
		//-----------------------------------------------------------------------
		// Now, get the detail tron from the library.  If it isn't already there,
		// an empty one will be created
		//-----------------------------------------------------------------------
		//
		SceneProxy *scene = GetSceneProxy();
		Check_Object(scene);
		StateLibrary *state_library = scene->GetStateLibrary();
		Check_Object(state_library);
		TextureLibrary *textures = state_library->GetTextureLibrary();
		Check_Object(textures);
		texture = textures->UseTextureProxy(detail_name);
		Check_Object(texture);
		MLRTexture *mlr_texture =
			Cast_Object(MLRTextureProxy*, texture)->GetMLRTexture();
		Check_Object(mlr_texture);
		int detail_handle = mlr_texture->GetTextureHandle();

		//
		//------------------------------------------------
		// Loop over the primitives within the shape proxy
		//------------------------------------------------
		//
		unsigned i;
		unsigned primitive_count = primitiveArray.GetLength();
		for (i=0; i<primitive_count; ++i)
		{
			MLR_I_PMesh *primitive = primitiveArray[i];
			Check_Object(primitive);

			//
			//--------------------------------------------------------------------
			// Create the detail state from the primitive state and detail texture
			//--------------------------------------------------------------------
			//
			MLRState detail_state = primitive->GetReferenceState();
			detail_state.SetTextureHandle(detail_handle);
			detail_state.SetAlphaMode(MLRState::OneOneMode);
			detail_state.SetPriority(detail_state.GetPriority()+1);

			//
			//----------------------------------------------------------------
			// Determine the type of primitive (non-colored, colored, and lit)
			//----------------------------------------------------------------
			//
			STOP(("Not implemented"));

			//
			//-----------------------------------------------------------------
			// Create a new detail primitive out of the primitive given the new
			// state and offset parameters
			//-----------------------------------------------------------------
			//
			STOP(("Not implemented"));

			//
			//----------------------------------------
			// Replace the old primitive with this one
			//----------------------------------------
			//
			STOP(("Not implemented"));
		}

		//
		//------------------------------------
		// Clean up and move to the next state
		//------------------------------------
		//
		texture->DetachReference();
	}
	DetachArrayReferences(&states);
	DetachArrayReferences(&polygons);
	SetToMatchMultiState(states[0]);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementSceneProxy::ApplyDetailTextures(ApplyDetailTexturesProcess *process)
{
	Check_Object(this);
	Check_Object(process);

	//
	//---------------------------------------
	// Make sure that the process says its OK
	//---------------------------------------
	//
	process->ApplyDetailTexturesCallback(this);
	if (!process->continueProcess)
		return;

	//
	//--------------------------------------------------------------------
	// Apply details to all the children.  At this point, they must all be
	// flattened
	//--------------------------------------------------------------------
	//
	unsigned child_count = GetChildCount();
	ChildProxy *child = UseFirstChildProxy();
	for (unsigned i=0; i<child_count; ++i)
	{
		Check_Object(child);
		ChildProxy *next = child->UseNextSiblingProxy();
		ElementPolygonMeshProxy *mesh =
			Cast_Object(ElementPolygonMeshProxy*, child);
		mesh->ApplyDetailTextures(process);
		child->DetachReference();
		child = next;
		if (!process->continueProcess)
		{
			if (child)
				child->DetachReference();
			break;
		}
	}

	//
	//-------------------------------------------
	// Make sure to discard any remaining proxies
	//-------------------------------------------
	//
	if (child)
		child->DetachReference();
}
