/*
   Copyright (C) 1999-2007 id Software, Inc. and contributors.
   For a list of contributors, see the accompanying CONTRIBUTORS file.

   This file is part of GtkRadiant.

   GtkRadiant is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   GtkRadiant is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GtkRadiant; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

//-----------------------------------------------------------------------------
//
// DESCRIPTION:
// implementation of isurfaceplugin-interface specifics

#include "stdafx.h"

void QERApp_GetTwoSelectedPatch( patchMesh_t **p1, patchMesh_t **p2 ){
	*p1 = NULL; *p2 = NULL;
	for ( brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next )
	{
		if ( pb->patchBrush ) {
			if ( !( *p1 ) ) {
				*p1 = pb->pPatch;
			}
			else if ( !( *p2 ) ) {
				*p2 = pb->pPatch;
				return;
			}
		}
	}
#ifdef _DEBUG
	Sys_Printf( "WARNING: QERApp_GetTwoSelectedPatch failed (did not find two patches)\n" );
#endif
	return;
}

// Nurail: The following functions are used by the Surface Inspector module

// Queries the number of faces from selected brushes
int SI_GetSelectedFaceCountfromBrushes( void ){
	face_t    *f;
	brush_t   *b;
	int num_of_faces = 0;

	if ( selected_brushes.next == &selected_brushes ) {
		return( 0 );
	}

	for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
		if ( !( b->patchBrush ) ) {
			for ( f = b->brush_faces; f ; f = f->next, num_of_faces++ ) ;
		}

	return num_of_faces;
}

void SI_GetSelFacesTexdef( texdef_to_face_t *allocd_block_texdef ){
	int i;
	face_t    *f;
	brush_t   *b;
	texdef_to_face_t *position, *prev_pos;
	brushprimit_texdef_t bp;

	if ( selected_brushes.next != &selected_brushes ) {
		prev_pos = position = allocd_block_texdef;
		for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
		{
			if ( !( b->patchBrush ) ) {
				for ( f = b->brush_faces; f ; f = f->next )
				{
					position->face = f;
					position->brush = b;
					position->texdef = f->texdef;
					if ( g_qeglobals.m_bBrushPrimitMode ) {
						ConvertTexMatWithQTexture( &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture(), &bp, NULL );
						TexMatToFakeTexCoords( bp.coords, position->texdef.shift, &position->texdef.rotate, position->texdef.scale );
						position->orig_bp_texdef = bp;
					}
					position->orig_texdef = position->texdef;
					prev_pos->next = position;
					prev_pos = position;
					position++;
				}
				prev_pos->next = NULL;
			}
		}
	}
	else if ( g_ptrSelectedFaces.GetSize() != 0 ) {
		f = (face_t *) g_ptrSelectedFaces.GetAt( 0 );
		b = (brush_t *) g_ptrSelectedFaceBrushes.GetAt( 0 );
		position = (texdef_to_face_t*) allocd_block_texdef;
		position->face = f;
		position->brush = b;
		position->texdef = f->texdef;
		if ( g_qeglobals.m_bBrushPrimitMode ) {
			ConvertTexMatWithQTexture( &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture(), &bp, NULL );
			TexMatToFakeTexCoords( bp.coords, position->texdef.shift, &position->texdef.rotate, position->texdef.scale );
			position->orig_bp_texdef = bp;
		}
		position->orig_texdef = position->texdef;
		prev_pos = position;
		for ( i = 1; i < g_ptrSelectedFaces.GetSize(); i++ )
		{
			f = (face_t *) g_ptrSelectedFaces.GetAt( i );
			b = (brush_t *) g_ptrSelectedFaceBrushes.GetAt( i );
			position = allocd_block_texdef + i;
			position->face = f;
			position->brush = b;
			position->texdef = f->texdef;
			if ( g_qeglobals.m_bBrushPrimitMode ) {
				ConvertTexMatWithQTexture( &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture(), &bp, NULL );
				TexMatToFakeTexCoords( bp.coords, position->texdef.shift, &position->texdef.rotate, position->texdef.scale );
				position->orig_bp_texdef = bp;
			}
			position->orig_texdef = position->texdef;
			prev_pos->next = position;
			prev_pos = position;
		}
		position->next = NULL;
	}

}

/*
   SetFaceTexdef_Q2

   This doesn't mess with CONTENTS_DETAIL needed for Quake2 content flag

 */
void SetFaceTexdef_Q2( face_t *f, texdef_t *texdef, bool bFitScale ){

	if ( strcmp( f->texdef.GetName(), texdef->GetName() ) != 0 ) { // set shader here instead of Brush_Build
		Face_SetShader( f, texdef->GetName() );
	}

	if ( bFitScale ) {
		f->texdef = *texdef;
		// fit the scaling of the texture on the actual plane
		vec3_t p1,p2,p3;     // absolute coordinates
		// compute absolute coordinates
		ComputeAbsolute( f,p1,p2,p3 );
		// compute the scale
		vec3_t vx,vy;
		VectorSubtract( p2,p1,vx );
		VectorNormalize( vx, vx );
		VectorSubtract( p3,p1,vy );
		VectorNormalize( vy, vy );
		// assign scale
		VectorScale( vx,texdef->scale[0],vx );
		VectorScale( vy,texdef->scale[1],vy );
		VectorAdd( p1,vx,p2 );
		VectorAdd( p1,vy,p3 );
		// compute back shift scale rot
		AbsoluteToLocal( f->plane,f,p1,p2,p3 );
	}
	else
	{
		f->texdef = *texdef;
	}
}



void SI_SetTexdef_FaceList( texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale ){
	texdef_to_face_t* texdef_to_face;
	bool b_isQuake2;

	if ( g_pGameDescription->quake2 ) {
		b_isQuake2 = true;
	}
	else{
		b_isQuake2 = false;
	}

	if ( !texdef_face_list ) {
		return;
	}

	if ( b_SetUndoPoint ) {
		if ( g_ptrSelectedFaces.GetSize() > 1 ) {
			Sys_FPrintf( SYS_WRN, "WARNING: Undo NOT supported for multiple face selections\n" );
		}
		else if ( ( selected_brushes.next != &selected_brushes ) || ( g_ptrSelectedFaces.GetSize() == 1 ) ) {
			// Give something to undo to
			for ( texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next )
				if ( b_isQuake2 ) {
					SetFaceTexdef_Q2( texdef_to_face->face, &texdef_to_face->orig_texdef, bFit_to_Scale );
				}
				else{
					SetFaceTexdef( texdef_to_face->face, &texdef_to_face->orig_texdef, &texdef_to_face->orig_bp_texdef, bFit_to_Scale );
				}

			Undo_Start( "set facelist texdefs" );

			if ( selected_brushes.next != &selected_brushes ) {
				Undo_AddBrushList( &selected_brushes );
			}
			else{
				Undo_AddBrush( texdef_face_list->brush );
			}

		}
	}

	for ( texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next )
	{
		if ( b_isQuake2 ) {
			SetFaceTexdef_Q2( texdef_to_face->face, &texdef_to_face->texdef,  bFit_to_Scale );
		}
		else
		{
			brushprimit_texdef_t brushprimit_texdef;
			FakeTexCoordsToTexMat( texdef_to_face->texdef.shift, texdef_to_face->texdef.rotate, texdef_to_face->texdef.scale, brushprimit_texdef.coords );
			SetFaceTexdef( texdef_to_face->face, &texdef_to_face->texdef, &brushprimit_texdef, bFit_to_Scale );
		}
		Brush_Build( texdef_to_face->brush );
		if ( bFit_to_Scale ) {
			texdef_to_face->texdef = texdef_to_face->face->texdef;
		}
	}

	if ( b_SetUndoPoint ) {
		if ( ( selected_brushes.next != &selected_brushes ) || ( g_ptrSelectedFaces.GetSize() == 1 ) ) {
			if ( selected_brushes.next != &selected_brushes ) {
				Undo_EndBrushList( &selected_brushes );
			}
			else{
				Undo_EndBrush( texdef_face_list->brush );
			}

			Undo_End();
			// Over-write the orig_texdef list, cementing the change.
			for ( texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next )
			{
				texdef_to_face->orig_texdef = texdef_to_face->texdef;
				texdef_to_face->orig_bp_texdef = texdef_to_face->face->brushprimit_texdef;
			}
		}
	}

	Sys_UpdateWindows( W_ALL );
}

void SI_FaceList_FitTexture( texdef_to_face_t* si_texdef_face_list, int nHeight, int nWidth ){
	texdef_to_face_t* temp_texdef_face_list;
	brushprimit_texdef_t bp;

	if ( !si_texdef_face_list ) {
		return;
	}

	for ( temp_texdef_face_list = si_texdef_face_list; temp_texdef_face_list; temp_texdef_face_list = temp_texdef_face_list->next )
	{
		Face_FitTexture( temp_texdef_face_list->face, nHeight, nWidth );
		Brush_Build( temp_texdef_face_list->brush,true,true,false,false );
		// Write changes to our working Texdef list

		if ( g_qeglobals.m_bBrushPrimitMode ) {
			ConvertTexMatWithQTexture( &temp_texdef_face_list->face->brushprimit_texdef, QERApp_Shader_ForName( temp_texdef_face_list->face->texdef.GetName() )->getTexture(), &bp, NULL );
			TexMatToFakeTexCoords( bp.coords, temp_texdef_face_list->face->texdef.shift, &temp_texdef_face_list->face->texdef.rotate, temp_texdef_face_list->face->texdef.scale );
		}
		temp_texdef_face_list->texdef = temp_texdef_face_list->face->texdef;
	}

	Sys_UpdateWindows( W_CAMERA );

}

GtkWindow* SI_GetMainWindow( void ){
	return GTK_WINDOW( g_qeglobals_gui.d_main_window );
}

void SI_SetWinPos_from_Prefs( GtkWidget *win ){
	load_window_pos( win, g_PrefsDlg.mWindowInfo.posSurfaceWnd );
}
