//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#include "cbase.h"
#include "vguitextwindow.h"
#include <networkstringtabledefs.h>
#include <cdll_client_int.h>
#include <clientmode_shared.h>

#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <filesystem.h>
#include <KeyValues.h>
#include <convar.h>
#include <vgui_controls/ImageList.h>

#include <vgui_controls/TextEntry.h>
#include <vgui_controls/Button.h>

#include <game/client/iviewport.h>

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

using namespace vgui;
extern INetworkStringTable *g_pStringTableInfoPanel;

#define TEMP_HTML_FILE	"textwindow_temp.html"

ConVar cl_disablehtmlmotd( "cl_disablehtmlmotd", "1", FCVAR_ARCHIVE, "Disable HTML motds." );

//=============================================================================
// HPE_BEGIN:
// [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
// of options.  Passing a command string is dangerous and allowed a server network
// message to run arbitrary commands on the client.
//=============================================================================
CON_COMMAND( showinfo, "Shows a info panel: <type> <title> <message> [<command number>]" )
{
	if ( !gViewPortInterface )
		return;
	
	if ( args.ArgC() < 4 )
		return;
		
	IViewPortPanel * panel = gViewPortInterface->FindPanelByName( PANEL_INFO );

	 if ( panel )
	 {
		 KeyValues *kv = new KeyValues("data");
		 kv->SetInt( "type", Q_atoi(args[ 1 ]) );
		 kv->SetString( "title", args[ 2 ] );
		 kv->SetString( "message", args[ 3 ] );

		 if ( args.ArgC() == 5 )
			 kv->SetString( "command", args[ 4 ] );

		 panel->SetData( kv );

		 gViewPortInterface->ShowPanel( panel, true );

		 kv->deleteThis();
	 }
	 else
	 {
		 Msg("Couldn't find info panel.\n" );
	 }
}
//=============================================================================
// HPE_END
//=============================================================================

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CTextWindow::CTextWindow(IViewPort *pViewPort) : Frame(NULL, PANEL_INFO	)
{
	// initialize dialog
	m_pViewPort = pViewPort;

//	SetTitle("", true);

	m_szTitle[0] = '\0';
	m_szMessage[0] = '\0';
	m_szMessageFallback[0] = '\0';
	m_nExitCommand = TEXTWINDOW_CMD_NONE;
	m_bShownURL = false;
	m_bUnloadOnDismissal = false;
	
	// load the new scheme early!!
	SetScheme("ClientScheme");
	SetMoveable(false);
	SetSizeable(false);
	SetProportional(true);

	// hide the system buttons
	SetTitleBarVisible( false );

	m_pTextMessage = new TextEntry( this, "TextMessage" );
	m_pHTMLMessage = new CMOTDHTML( this,"HTMLMessage" );
	m_pTitleLabel  = new Label( this, "MessageTitle", "Message Title" );
	m_pOK		   = new Button(this, "ok", "#PropertyDialog_OK");

	m_pOK->SetCommand("okay");
	m_pTextMessage->SetMultiline( true );
	m_nContentType = TYPE_TEXT;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTextWindow::ApplySchemeSettings( IScheme *pScheme )
{
	BaseClass::ApplySchemeSettings( pScheme );

	LoadControlSettings("Resource/UI/TextWindow.res");

	Reset();
}

//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CTextWindow::~CTextWindow()
{
	// remove temp file again
	if (g_pFullFileSystem->FileExists(TEMP_HTML_FILE))
		g_pFullFileSystem->RemoveFile( TEMP_HTML_FILE, "DEFAULT_WRITE_PATH" );
}

void CTextWindow::Reset( void )
{
	//=============================================================================
	// HPE_BEGIN:
	// [Forrest] Replace strange hard-coded default message with hard-coded error message.
	//=============================================================================
	V_strcpy_safe( m_szTitle, "Error loading info message." );
	V_strcpy_safe( m_szMessage, "" );
	V_strcpy_safe( m_szMessageFallback, "" );
	//=============================================================================
	// HPE_END
	//=============================================================================

	m_nExitCommand = TEXTWINDOW_CMD_NONE;
	m_nContentType = TYPE_TEXT;
	m_bShownURL = false;
	m_bUnloadOnDismissal = false;
	Update();
}

void CTextWindow::ShowText( const char *text )
{
	m_pTextMessage->SetVisible( true );
	m_pTextMessage->SetText( text );
	m_pTextMessage->GotoTextStart();
}

void CTextWindow::ShowURL( const char *URL, bool bAllowUserToDisable )
{
	#ifdef _DEBUG
		Msg( "CTextWindow::ShowURL( %s )\n", URL );
	#endif

	ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal();
	if ( ( bAllowUserToDisable && cl_disablehtmlmotd.GetBool() ) || !mode->IsHTMLInfoPanelAllowed() )
	{
		Warning( "Blocking HTML info panel '%s'; Using plaintext instead.\n", URL );

		// User has disabled HTML TextWindows. Show the fallback as text only.
		if ( g_pStringTableInfoPanel )
		{
			int index = g_pStringTableInfoPanel->FindStringIndex( "motd_text" );
			if ( index != ::INVALID_STRING_INDEX )
			{
				int length = 0;
				const char *data = (const char *)g_pStringTableInfoPanel->GetStringUserData( index, &length );
				if ( data && data[0] )
				{
					m_pHTMLMessage->SetVisible( false );
					ShowText( data );
				}
			}
		}
		return;
	} 

	m_pHTMLMessage->SetVisible( true );
	m_pHTMLMessage->OpenURL( URL, NULL );
	m_bShownURL = true;
}

void CTextWindow::ShowIndex( const char *entry )
{
	const char *data = NULL;
	int length = 0;

	if ( NULL == g_pStringTableInfoPanel )
		return;

	int index = g_pStringTableInfoPanel->FindStringIndex( m_szMessage );
		
	if ( index != ::INVALID_STRING_INDEX )
		data = (const char *)g_pStringTableInfoPanel->GetStringUserData( index, &length );

	if ( !data || !data[0] )
		return; // nothing to show

	// is this a web URL ?
	if ( !Q_strncmp( data, "http://", 7 ) || !Q_strncmp( data, "https://", 8 ) )
	{
		ShowURL( data );
		return;
	}

	// try to figure out if this is HTML or not
	if ( data[0] != '<' )
	{
		ShowText( data );
		return;
	}

	// data is a HTML, we have to write to a file and then load the file
	FileHandle_t hFile = g_pFullFileSystem->Open( TEMP_HTML_FILE, "wb", "DEFAULT_WRITE_PATH" );

	if ( hFile == FILESYSTEM_INVALID_HANDLE )
		return;

	g_pFullFileSystem->Write( data, length, hFile );
	g_pFullFileSystem->Close( hFile );

	if ( g_pFullFileSystem->Size( TEMP_HTML_FILE ) != (unsigned int)length )
		return; // something went wrong while writing

	ShowFile( TEMP_HTML_FILE );
}

void CTextWindow::ShowFile( const char *filename )
{
	if  ( Q_stristr( filename, ".htm" ) || Q_stristr( filename, ".html" ) )
	{
		// it's a local HTML file
		char localURL[ _MAX_PATH + 7 ];
		Q_strncpy( localURL, "file://", sizeof( localURL ) );
		
		char pPathData[ _MAX_PATH ];
		g_pFullFileSystem->GetLocalPath( filename, pPathData, sizeof(pPathData) );
		Q_strncat( localURL, pPathData, sizeof( localURL ), COPY_ALL_CHARACTERS );

		ShowURL( localURL );
	}
	else
	{
		// read from local text from file
		FileHandle_t f = g_pFullFileSystem->Open( m_szMessage, "rb", "GAME" );

		if ( !f )
			return;

		char buffer[2048];
			
		int size = MIN( g_pFullFileSystem->Size( f ), sizeof(buffer)-1 ); // just allow 2KB

		g_pFullFileSystem->Read( buffer, size, f );
		g_pFullFileSystem->Close( f );

		buffer[size]=0; //terminate string

		ShowText( buffer );
	}
}

void CTextWindow::Update( void )
{
	SetTitle( m_szTitle, false );

	m_pTitleLabel->SetText( m_szTitle );

	if ( m_pHTMLMessage )
		m_pHTMLMessage->SetVisible( false );
	m_pTextMessage->SetVisible( false );

	if ( m_nContentType == TYPE_INDEX )
	{
		ShowIndex( m_szMessage );
	}
	else if ( m_nContentType == TYPE_URL )
	{
		if ( !Q_strncmp( m_szMessage, "http://", 7 ) || !Q_strncmp( m_szMessage, "https://", 8 ) || !Q_stricmp( m_szMessage, "about:blank" ) )
		{
			ShowURL( m_szMessage );
		}
		else
		{
			// We should have trapped this at a higher level
			Assert( !"URL protocol is missing or blocked" );
		}
	}
	else if ( m_nContentType == TYPE_FILE )
	{
		ShowFile( m_szMessage );
	}
	else if ( m_nContentType == TYPE_TEXT )
	{
		ShowText( m_szMessage );
	}
	else
	{
		DevMsg("CTextWindow::Update: unknown content type %i\n", m_nContentType );
	}
}

void CTextWindow::OnCommand( const char *command )
{
	if (!Q_strcmp(command, "okay"))
	{
		//=============================================================================
		// HPE_BEGIN:
		// [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
		// of options.  Passing a command string is dangerous and allowed a server network
		// message to run arbitrary commands on the client.
		//=============================================================================
		const char *pszCommand = NULL;
		switch ( m_nExitCommand )
		{
			case TEXTWINDOW_CMD_NONE:
				break;

			case TEXTWINDOW_CMD_JOINGAME:
				pszCommand = "joingame";
				break;

			case TEXTWINDOW_CMD_CHANGETEAM:
				pszCommand = "changeteam";
				break;

			case TEXTWINDOW_CMD_IMPULSE101:
				pszCommand = "impulse 101";
				break;

			case TEXTWINDOW_CMD_MAPINFO:
				pszCommand = "mapinfo";
				break;

			case TEXTWINDOW_CMD_CLOSED_HTMLPAGE:
				pszCommand = "closed_htmlpage";
				break;

			case TEXTWINDOW_CMD_CHOOSETEAM:
				pszCommand = "chooseteam";
				break;

			default:
				DevMsg("CTextWindow::OnCommand: unknown exit command value %i\n", m_nExitCommand );
				break;
		}

		if ( pszCommand != NULL )
		{
			engine->ClientCmd_Unrestricted( pszCommand );
		}
		//=============================================================================
		// HPE_END
		//=============================================================================
		
		m_pViewPort->ShowPanel( this, false );
	}

	BaseClass::OnCommand(command);
}

void CTextWindow::OnKeyCodePressed( vgui::KeyCode code )
{
	if ( code == KEY_XBUTTON_A || code == KEY_XBUTTON_B || code == STEAMCONTROLLER_A || code == STEAMCONTROLLER_B )
	{
		OnCommand( "okay" );
		return;
	}

	BaseClass::OnKeyCodePressed(code);
}

void CTextWindow::SetData(KeyValues *data)
{
	SetData( data->GetInt( "type" ), data->GetString( "title" ), data->GetString( "msg" ), data->GetString( "msg_fallback" ), data->GetInt( "cmd" ), data->GetBool( "unload" ) );
}

void CTextWindow::SetData( int type, const char *title, const char *message, const char *message_fallback, int command, bool bUnload )
{
	Q_strncpy(  m_szTitle, title, sizeof( m_szTitle ) );
	Q_strncpy(  m_szMessage, message, sizeof( m_szMessage ) );
	Q_strncpy(  m_szMessageFallback, message_fallback, sizeof( m_szMessageFallback ) );

	m_nExitCommand = command;

	m_nContentType = type;
	m_bUnloadOnDismissal = bUnload;

	Update();
}

void CTextWindow::ShowPanel( bool bShow )
{
	if ( BaseClass::IsVisible() == bShow )
		return;

	m_pViewPort->ShowBackGround( bShow );

	if ( bShow )
	{
		Activate();
		SetMouseInputEnabled( true );
	}
	else
	{
		SetVisible( false );
		SetMouseInputEnabled( false );

		if ( m_bUnloadOnDismissal && m_bShownURL && m_pHTMLMessage )
		{
			m_pHTMLMessage->OpenURL( "about:blank", NULL );
			m_bShownURL = false;
		}
	}
}

bool CTextWindow::CMOTDHTML::OnStartRequest( const char *url, const char *target, const char *pchPostData, bool bIsRedirect )
{
	if ( Q_strstr( url, "steam://" ) )
		return false;

	return BaseClass::OnStartRequest( url, target, pchPostData, bIsRedirect );
}