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


#if defined( WIN32 ) && !defined( _X360 )
#include <windows.h> // SRC only!!
#endif

#include "OptionsSubMultiplayer.h"
#include "MultiplayerAdvancedDialog.h"
#include <stdio.h>

#include <vgui_controls/Button.h>
#include <vgui_controls/QueryBox.h>
#include <vgui_controls/CheckButton.h>
#include "tier1/KeyValues.h"
#include <vgui_controls/Label.h>
#include <vgui/ISystem.h>
#include <vgui/ISurface.h>
#include <vgui/Cursor.h>
#include <vgui_controls/RadioButton.h>
#include <vgui_controls/ComboBox.h>
#include <vgui_controls/ImagePanel.h>
#include <vgui_controls/FileOpenDialog.h>
#include <vgui_controls/MessageBox.h>
#include <vgui/IVGui.h>
#include <vgui/ILocalize.h>
#include <vgui/IPanel.h>
#include <vgui_controls/MessageBox.h>

#include "CvarTextEntry.h"
#include "CvarToggleCheckButton.h"
#include "cvarslider.h"
#include "LabeledCommandComboBox.h"
#include "filesystem.h"
#include "EngineInterface.h"
#include "BitmapImagePanel.h"
#include "tier1/utlbuffer.h"
#include "ModInfo.h"
#include "tier1/convar.h"
#include "tier0/icommandline.h"

#include "materialsystem/imaterial.h"
#include "materialsystem/imesh.h"
#include "materialsystem/imaterialvar.h"

// use the JPEGLIB_USE_STDIO define so that we can read in jpeg's from outside the game directory tree.  For Spray Import.
#define JPEGLIB_USE_STDIO
#include "jpeglib/jpeglib.h"
#undef JPEGLIB_USE_STDIO

#include <setjmp.h>

#include "bitmap/tgawriter.h"
#include "ivtex.h"
#ifdef WIN32
#include <io.h>
#endif

#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#endif

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

using namespace vgui;


#define DEFAULT_SUIT_HUE 30
#define DEFAULT_PLATE_HUE 6

void UpdateLogoWAD( void *hdib, int r, int g, int b );

struct ColorItem_t
{
	const char	*name;
	int			r, g, b;
};

static ColorItem_t itemlist[]=
{
	{ "#Valve_Orange", 255, 120, 24 },
	{ "#Valve_Yellow", 225, 180, 24 },
	{ "#Valve_Blue", 0, 60, 255 },
	{ "#Valve_Ltblue", 0, 167, 255 },
	{ "#Valve_Green", 0, 167, 0 },
	{ "#Valve_Red", 255, 43, 0 },
	{ "#Valve_Brown", 123, 73, 0 },
	{ "#Valve_Ltgray", 100, 100, 100 },
	{ "#Valve_Dkgray", 36, 36, 36 },
};

static ColorItem_t s_crosshairColors[] = 
{
	{ "#Valve_Green",	50,		250,	50 },
	{ "#Valve_Red",		250,	50,		50 },
	{ "#Valve_Blue",	50,		50,		250 },
	{ "#Valve_Yellow",	250,	250,	50 },
	{ "#Valve_Ltblue",	50,		250,	250 },
};
static const int NumCrosshairColors = ARRAYSIZE(s_crosshairColors);


//-----------------------------------------------------------------------------
class CrosshairImagePanelSimple : public CrosshairImagePanelBase
{
	DECLARE_CLASS_SIMPLE( CrosshairImagePanelSimple, CrosshairImagePanelBase );
public:
	CrosshairImagePanelSimple( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel );
	virtual void Paint();
	virtual void ResetData();
	virtual void ApplyChanges();
	static void DrawCrosshairRect( int x, int y, int w, int h, bool bAdditive );

protected:
	MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );

	void InitCrosshairColorEntries();
	void InitCrosshairSizeList();
	void UpdateCrosshair();

private:
	COptionsSubMultiplayer* m_pOptionsPanel;
	vgui::ComboBox *m_pCrosshairColorCombo;
	CLabeledCommandComboBox *m_pCrosshairSizeCombo;
	CCvarToggleCheckButton *m_pCrosshairTranslucencyCheckbox;
	int m_R, m_G, m_B;
	int m_barSize;
	int m_barGap;
	int m_iCrosshairTextureID;
};

//-----------------------------------------------------------------------------
CrosshairImagePanelSimple::CrosshairImagePanelSimple( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel ) : CrosshairImagePanelBase( parent, name )
{
	m_pOptionsPanel = pOptionsPanel;
	m_pCrosshairTranslucencyCheckbox = new CCvarToggleCheckButton(m_pOptionsPanel, "CrosshairTranslucencyCheckbox", "#GameUI_Translucent", "cl_crosshairusealpha");
	m_pCrosshairColorCombo = new ComboBox(m_pOptionsPanel, "CrosshairColorComboBox", 6, false);
	m_pCrosshairSizeCombo = new CLabeledCommandComboBox(m_pOptionsPanel, "CrosshairSizeComboBox");

	m_pCrosshairColorCombo->AddActionSignalTarget( this );
	m_pCrosshairSizeCombo->AddActionSignalTarget( this );

	m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID();
	vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, "vgui/white_additive" , true, false);

	InitCrosshairSizeList();
	InitCrosshairColorEntries();
	ResetData();
}

//-----------------------------------------------------------------------------
// Purpose: initialize the crosshair size list.
//-----------------------------------------------------------------------------
void CrosshairImagePanelSimple::InitCrosshairSizeList()
{
	// add in the auto, small, medium, and large size selections.
	m_pCrosshairSizeCombo->AddItem("#GameUI_Auto", "cl_crosshairscale 0");
	m_pCrosshairSizeCombo->AddItem("#GameUI_Small", "cl_crosshairscale 1200");
	m_pCrosshairSizeCombo->AddItem("#GameUI_Medium", "cl_crosshairscale 768");
	m_pCrosshairSizeCombo->AddItem("#GameUI_Large", "cl_crosshairscale 600");
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CrosshairImagePanelSimple::InitCrosshairColorEntries()
{
	if (m_pCrosshairColorCombo != NULL)
	{
		KeyValues *data = new KeyValues("data");

		// add in the "Default" selection
		data->Clear();

		// add in the colors for the color list
		for ( int i = 0; i < NumCrosshairColors; i++ )
		{
			data->SetInt("color", i);
			m_pCrosshairColorCombo->AddItem( s_crosshairColors[ i ].name, data);
		}

		data->deleteThis();
	}
}


//-----------------------------------------------------------------------------
void CrosshairImagePanelSimple::DrawCrosshairRect( int x0, int y0, int x1, int y1, bool bAdditive )
{
	if ( bAdditive )
		vgui::surface()->DrawTexturedRect( x0, y0, x1, y1 );
	else
		vgui::surface()->DrawFilledRect( x0, y0, x1, y1 );
}

//-----------------------------------------------------------------------------
void CrosshairImagePanelSimple::Paint()
{
	int screenWide, screenTall;
	surface()->GetScreenSize( screenWide, screenTall );;

	BaseClass::Paint();

	if ( !m_pCrosshairTranslucencyCheckbox )
		return;

	int wide, tall;
	GetSize( wide, tall );

	bool bAdditive = !m_pCrosshairTranslucencyCheckbox->IsSelected();

	int a = 200;
	ConVarRef cl_crosshairalpha( "cl_crosshairalpha", true );
	if ( !bAdditive && cl_crosshairalpha.IsValid() )
	{
		a = clamp( cl_crosshairalpha.GetInt(), 0, 255 );
	}
	vgui::surface()->DrawSetColor( m_R, m_G, m_B, a );

	if ( bAdditive )
	{
		vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
	}

	int centerX = wide / 2;
	int centerY = tall / 2;
	int iCrosshairDistance = m_barGap;

	int iBarThickness = 1;
	int iBarSize = m_barSize;

	// draw horizontal crosshair lines
	int iInnerLeft	= centerX - iCrosshairDistance - iBarThickness / 2;
	int iInnerRight	= iInnerLeft + 2 * iCrosshairDistance + iBarThickness;
	int iOuterLeft	= iInnerLeft - iBarSize;
	int iOuterRight	= iInnerRight + iBarSize;
	int y0 = centerY - iBarThickness / 2;
	int y1 = y0 + iBarThickness;
	DrawCrosshairRect( iOuterLeft, y0, iInnerLeft, y1, bAdditive );
	DrawCrosshairRect( iInnerRight, y0, iOuterRight, y1, bAdditive );

	// draw vertical crosshair lines
	int iInnerTop		= centerY - iCrosshairDistance - iBarThickness / 2;
	int iInnerBottom	= iInnerTop + 2 * iCrosshairDistance + iBarThickness;
	int iOuterTop		= iInnerTop - iBarSize;
	int iOuterBottom	= iInnerBottom + iBarSize;
	int x0 = centerX - iBarThickness / 2;
	int x1 = x0 + iBarThickness;
	DrawCrosshairRect( x0, iOuterTop, x1, iInnerTop, bAdditive );
	DrawCrosshairRect( x0, iInnerBottom, x1, iOuterBottom, bAdditive );
}


//-----------------------------------------------------------------------------
// Purpose: takes the settings from the crosshair settings combo boxes and sliders
//          and apply it to the crosshair illustrations.
//-----------------------------------------------------------------------------
void CrosshairImagePanelSimple::UpdateCrosshair()
{
	// get the color selected in the combo box.
	KeyValues *data = m_pCrosshairColorCombo->GetActiveItemUserData();
	int colorIndex = data->GetInt("color");
	colorIndex = clamp( colorIndex, 0, NumCrosshairColors );

	int selectedColor = 0;
	int actualVal = 0;
	if (m_pCrosshairColorCombo != NULL)
	{
		selectedColor = m_pCrosshairColorCombo->GetActiveItem();
	}

	ConVarRef cl_crosshaircolor( "cl_crosshaircolor", true );
	if ( cl_crosshaircolor.IsValid() )
	{
		actualVal = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors );
	}

	m_R = s_crosshairColors[selectedColor].r;
	m_G = s_crosshairColors[selectedColor].g;
	m_B = s_crosshairColors[selectedColor].b;

	if ( m_pCrosshairSizeCombo )
	{
		int size = m_pCrosshairSizeCombo->GetActiveItem();

		if ( size == 0 )
		{
			int screenWide, screenTall;
			surface()->GetScreenSize( screenWide, screenTall );
			if ( screenTall <= 600 )
			{
				// if the screen height is 600 or less, set the crosshair num to 3 (large)
				size = 3;
			}
			else if ( screenTall <= 768 )
			{
				// if the screen height is between 600 and 768, set the crosshair num to 2 (medium)
				size = 2;
			}
			else
			{
				// if the screen height is greater than 768, set the crosshair num to 1 (small)
				size = 1;
			}
		}

		int scaleBase;
		switch( size )
		{
		case 1:
			scaleBase = 1200;
			break;
		case 2:
			scaleBase = 768;
			break;
		case 3:
			scaleBase = 600;
			break;
		default:
			scaleBase = 1200;
			break;
		}

		m_barSize = (int) 9 * 1200 / scaleBase;
		m_barGap = (int) 5 * 1200 / scaleBase;
	}
}


//-----------------------------------------------------------------------------
// Purpose: Called whenever color combo changes
//-----------------------------------------------------------------------------
void CrosshairImagePanelSimple::OnTextChanged(vgui::Panel *panel)
{
	m_pOptionsPanel->OnControlModified();
	UpdateCrosshair();
}


void CrosshairImagePanelSimple::ResetData()
{
	m_pCrosshairTranslucencyCheckbox->Reset();

	// parse out the size value from the cvar and set the initial value.
	int initialScale = 0;
	ConVarRef cl_crosshairscale( "cl_crosshairscale", true );
	if ( cl_crosshairscale.IsValid() )
	{
		initialScale = cl_crosshairscale.GetInt();
		if ( initialScale <= 0 )
		{
			initialScale = 0;
		}
		else if ( initialScale <= 600 )
		{
			initialScale = 3;
		}
		else if ( initialScale <= 768 )
		{
			initialScale = 2;
		}
		else
		{
			initialScale = 1;
		}
	}
	m_pCrosshairSizeCombo->SetInitialItem( initialScale );

	// parse the string for the custom color settings and get the initial settings.
	ConVarRef cl_crosshaircolor( "cl_crosshaircolor", true );
	int index = 0;
	if ( cl_crosshaircolor.IsValid() )
	{
		index = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors );
	}
	m_pCrosshairColorCombo->ActivateItemByRow(index);

	UpdateCrosshair();
}

void CrosshairImagePanelSimple::ApplyChanges()
{
	m_pCrosshairTranslucencyCheckbox->ApplyChanges();

	char cmd[256];
	cmd[0] = 0;

	if (m_pCrosshairColorCombo != NULL)
	{
		int val = m_pCrosshairColorCombo->GetActiveItem();
		Q_snprintf( cmd, sizeof(cmd), "cl_crosshaircolor %d\n", val );
		engine->ClientCmd_Unrestricted( cmd );
	}
}


//-----------------------------------------------------------------------------
class CrosshairImagePanelCS : public CrosshairImagePanelBase
{
	DECLARE_CLASS_SIMPLE( CrosshairImagePanelCS, CrosshairImagePanelBase );

public:
	CrosshairImagePanelCS( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel );
	virtual void ResetData();
	virtual void ApplyChanges();

protected:
	MESSAGE_FUNC_PARAMS( OnSliderMoved, "SliderMoved", data );
	MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
	MESSAGE_FUNC( OnCheckButtonChecked, "CheckButtonChecked" );

	virtual void Paint();
	static void DrawCrosshairRect( int x, int y, int w, int h, bool bAdditive );
	void InitCrosshairColorEntries();
	void UpdateCrosshair();

private:
	COptionsSubMultiplayer* m_pOptionsPanel;
	vgui::ComboBox *m_pColorComboBox;
	CCvarToggleCheckButton *m_pAlphaCheckbox;
	CCvarToggleCheckButton *m_pDynamicCheckbox;
	CCvarToggleCheckButton *m_pDotCheckbox;
	CCvarSlider *m_pColorAlphaSlider;
	CCvarSlider *m_pColorRSlider;
	CCvarSlider *m_pColorGSlider;
	CCvarSlider *m_pColorBSlider;
	CCvarSlider *m_pSizeSlider;
	CCvarSlider *m_pThicknessSlider;
	int m_R, m_G, m_B;
	float m_barSize;
	float m_barThickness;
	int m_iCrosshairTextureID;
};

//-----------------------------------------------------------------------------
CrosshairImagePanelCS::CrosshairImagePanelCS( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel ) : CrosshairImagePanelBase( parent, name )
{
	m_pOptionsPanel = pOptionsPanel;
	m_pColorComboBox = new ComboBox(m_pOptionsPanel, "CrosshairColorComboBox", 6, false);
	m_pAlphaCheckbox = new CCvarToggleCheckButton(m_pOptionsPanel, "CrosshairTranslucencyCheckbox", "#GameUI_Crosshair_Blend", "cl_crosshairusealpha");
	m_pDynamicCheckbox = new CCvarToggleCheckButton(m_pOptionsPanel, "CrosshairDynamicCheckbox", "#GameUI_CrosshairDynamic", "cl_dynamiccrosshair");
	m_pDotCheckbox = new CCvarToggleCheckButton(m_pOptionsPanel, "CrosshairDotCheckbox", "#GameUI_CrosshairDot", "cl_crosshairdot");
	m_pColorAlphaSlider = new CCvarSlider( m_pOptionsPanel, "Alpha Slider", "#GameUI_CrosshairColor_Alpha",
		0.0f, 255.0f, "cl_crosshairalpha" );
	m_pColorRSlider = new CCvarSlider( m_pOptionsPanel, "Red Color Slider", "#GameUI_CrosshairColor_Red",
		0.0f, 255.0f, "cl_crosshaircolor_r" );
	m_pColorGSlider = new CCvarSlider( m_pOptionsPanel, "Green Color Slider", "#GameUI_CrosshairColor_Green",
		0.0f, 255.0f, "cl_crosshaircolor_g" );
	m_pColorBSlider = new CCvarSlider( m_pOptionsPanel, "Blue Color Slider", "#GameUI_CrosshairColor_Blue",
		0.0f, 255.0f, "cl_crosshaircolor_b" );
	m_pSizeSlider = new CCvarSlider( m_pOptionsPanel, "Size Slider", "#GameUI_Crosshair_Size",
		0.0f, 12.0f, "cl_crosshairsize" );
	m_pThicknessSlider = new CCvarSlider( m_pOptionsPanel, "Thickness Slider", "#GameUI_Crosshair_Thickness",
		0.0f, 3.0f, "cl_crosshairthickness" );

	m_pColorAlphaSlider->SetTickCaptions("", "");
	m_pColorRSlider->SetTickCaptions("", "");
	m_pColorGSlider->SetTickCaptions("", "");
	m_pColorBSlider->SetTickCaptions("", "");
	m_pSizeSlider->SetTickCaptions("", "");
	m_pThicknessSlider->SetTickCaptions("", "");

	m_pAlphaCheckbox->AddActionSignalTarget(this);
	m_pDynamicCheckbox->AddActionSignalTarget(this);
	m_pDotCheckbox->AddActionSignalTarget(this);
	m_pColorComboBox->AddActionSignalTarget( this );
	m_pColorAlphaSlider->AddActionSignalTarget( this );
	m_pColorRSlider->AddActionSignalTarget( this );
	m_pColorGSlider->AddActionSignalTarget( this );
	m_pColorBSlider->AddActionSignalTarget( this );
	m_pSizeSlider->AddActionSignalTarget( this );
	m_pThicknessSlider->AddActionSignalTarget( this );

	InitCrosshairColorEntries();

	m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID();
	vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, "vgui/white_additive" , true, false);

	ResetData();
}

void CrosshairImagePanelCS::InitCrosshairColorEntries()
{
	if (m_pColorComboBox != NULL)
	{
		KeyValues *data = new KeyValues("data");

		// add in the "Default" selection
		data->Clear();

		// add in the colors for the color list
		for ( int i = 0; i < NumCrosshairColors; i++ )
		{
			data->SetInt("color", i);
			m_pColorComboBox->AddItem( s_crosshairColors[ i ].name, data);
		}

		data->SetInt("color", NumCrosshairColors);
		m_pColorComboBox->AddItem( "Custom", data);

		data->deleteThis();
	}
}

//-----------------------------------------------------------------------------
void CrosshairImagePanelCS::DrawCrosshairRect( int x0, int y0, int x1, int y1, bool bAdditive )
{
	if ( bAdditive )
		vgui::surface()->DrawTexturedRect( x0, y0, x1, y1 );
	else
		vgui::surface()->DrawFilledRect( x0, y0, x1, y1 );
}

//-----------------------------------------------------------------------------
void CrosshairImagePanelCS::Paint()
{
	int screenWide, screenTall;
	surface()->GetScreenSize( screenWide, screenTall );;

	BaseClass::Paint();

	int wide, tall;
	GetSize( wide, tall );

	bool bAdditive = !m_pAlphaCheckbox->IsSelected();
	bool bDynamic = m_pDynamicCheckbox->IsSelected();

	int a = 255;
	if ( !bAdditive )
		a = m_pColorAlphaSlider->GetSliderValue();

	vgui::surface()->DrawSetColor( m_R, m_G, m_B, a );

	if ( bAdditive )
	{
		vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
	}

	int centerX = wide / 2;
	int centerY = tall / 2;

	int iBarSize = RoundFloatToInt(m_barSize * screenTall / 480.0f);
	int iBarThickness = max(1, RoundFloatToInt(m_barThickness * (float)screenTall / 480.0f));

	float fBarGap = 4.0f;
	if ( bDynamic )
	{
		float curtime = system()->GetFrameTime();
		fBarGap *= (1.0f + cosf(curtime * 1.5f) * 0.5f);
	}

	int iBarGap = RoundFloatToInt(fBarGap * screenTall / 480.0f);

	// draw horizontal crosshair lines
	int iInnerLeft	= centerX - iBarGap - iBarThickness / 2;
	int iInnerRight	= iInnerLeft + 2 * iBarGap + iBarThickness;
	int iOuterLeft	= iInnerLeft - iBarSize;
	int iOuterRight	= iInnerRight + iBarSize;
	int y0 = centerY - iBarThickness / 2;
	int y1 = y0 + iBarThickness;
	DrawCrosshairRect( iOuterLeft, y0, iInnerLeft, y1, bAdditive );
	DrawCrosshairRect( iInnerRight, y0, iOuterRight, y1, bAdditive );

	// draw vertical crosshair lines
	int iInnerTop		= centerY - iBarGap - iBarThickness / 2;
	int iInnerBottom	= iInnerTop + 2 * iBarGap + iBarThickness;
	int iOuterTop		= iInnerTop - iBarSize;
	int iOuterBottom	= iInnerBottom + iBarSize;
	int x0 = centerX - iBarThickness / 2;
	int x1 = x0 + iBarThickness;
	DrawCrosshairRect( x0, iOuterTop, x1, iInnerTop, bAdditive );
	DrawCrosshairRect( x0, iInnerBottom, x1, iOuterBottom, bAdditive );

	// draw dot
	if ( m_pDotCheckbox->IsSelected() )
	{
		x0 = centerX - iBarThickness / 2;
		x1 = x0 + iBarThickness;
		y0 = centerY - iBarThickness / 2;
		y1 = y0 + iBarThickness;
		DrawCrosshairRect( x0, y0, x1, y1, bAdditive );
	}
}


//-----------------------------------------------------------------------------
// Purpose: takes the settings from the crosshair settings combo boxes and sliders
//          and apply it to the crosshair illustrations.
//-----------------------------------------------------------------------------
void CrosshairImagePanelCS::UpdateCrosshair()
{
	// get the color selected in the combo box.
	KeyValues *data = m_pColorComboBox->GetActiveItemUserData();
	int colorIndex = data->GetInt("color");
	colorIndex = clamp( colorIndex, 0, NumCrosshairColors + 1 );

	int actualVal = 0;
	int selectedColor = m_pColorComboBox->GetActiveItem();

	ConVarRef cl_crosshaircolor( "cl_crosshaircolor", true );
	if ( cl_crosshaircolor.IsValid() )
	{
		actualVal = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors + 1 );
	}

	if ( selectedColor != NumCrosshairColors )	// not custom
	{
		m_R = s_crosshairColors[selectedColor].r;
		m_G = s_crosshairColors[selectedColor].g;
		m_B = s_crosshairColors[selectedColor].b;
		m_pColorRSlider->SetSliderValue(m_R);
		m_pColorGSlider->SetSliderValue(m_G);
		m_pColorBSlider->SetSliderValue(m_B);
	}
	else
	{
		m_R = clamp( m_pColorRSlider->GetSliderValue(), 0, 255 );
		m_G = clamp( m_pColorGSlider->GetSliderValue(), 0, 255 );
		m_B = clamp( m_pColorBSlider->GetSliderValue(), 0, 255 );
	}

	m_barSize = m_pSizeSlider->GetSliderValue();
	m_barThickness = m_pThicknessSlider->GetSliderValue();
}


void CrosshairImagePanelCS::OnSliderMoved(KeyValues *data)
{
	vgui::Panel* pPanel = static_cast<vgui::Panel*>(data->GetPtr("panel"));

	if ( pPanel == m_pColorRSlider || pPanel == m_pColorGSlider || pPanel == m_pColorBSlider )
	{
		m_pColorComboBox->ActivateItem(NumCrosshairColors);
	}
	m_pOptionsPanel->OnControlModified();

	UpdateCrosshair();
}


//-----------------------------------------------------------------------------
// Purpose: Called whenever color combo changes
//-----------------------------------------------------------------------------
void CrosshairImagePanelCS::OnTextChanged(vgui::Panel *panel)
{
	m_pOptionsPanel->OnControlModified();
	UpdateCrosshair();
}

void CrosshairImagePanelCS::OnCheckButtonChecked()
{
	m_pColorAlphaSlider->SetEnabled(m_pAlphaCheckbox->IsSelected());
	m_pOptionsPanel->OnControlModified();
	UpdateCrosshair();
}

void CrosshairImagePanelCS::ResetData()
{
	// parse the string for the custom color settings and get the initial settings.
	ConVarRef cl_crosshaircolor( "cl_crosshaircolor", true );
	int index = 0;
	if ( cl_crosshaircolor.IsValid() )
	{
		index = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors + 1);
	}
	m_pColorComboBox->ActivateItemByRow(index);

	m_pAlphaCheckbox->Reset();
	m_pDynamicCheckbox->Reset();
	m_pDotCheckbox->Reset();
	m_pColorRSlider->Reset();
	m_pColorGSlider->Reset();
	m_pColorBSlider->Reset();
	m_pColorAlphaSlider->Reset();
	m_pSizeSlider->Reset();
	m_pThicknessSlider->Reset();

	UpdateCrosshair();
}

void CrosshairImagePanelCS::ApplyChanges()
{
	m_pAlphaCheckbox->ApplyChanges();
	m_pDynamicCheckbox->ApplyChanges();
	m_pDotCheckbox->ApplyChanges();
	m_pColorRSlider->ApplyChanges();
	m_pColorGSlider->ApplyChanges();
 	m_pColorBSlider->ApplyChanges();
	m_pColorAlphaSlider->ApplyChanges();
	m_pSizeSlider->ApplyChanges();
	m_pThicknessSlider->ApplyChanges();

	char cmd[256];
	cmd[0] = 0;

	if (m_pColorComboBox != NULL)
	{
		int val = m_pColorComboBox->GetActiveItem();
		Q_snprintf( cmd, sizeof(cmd), "cl_crosshaircolor %d\n", val );
		engine->ClientCmd_Unrestricted( cmd );
	}
}

//-----------------------------------------------------------------------------
class CrosshairImagePanelAdvanced : public CrosshairImagePanelBase
{
	DECLARE_CLASS_SIMPLE( CrosshairImagePanelAdvanced, CrosshairImagePanelBase );
public:
	CrosshairImagePanelAdvanced( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel );
	virtual ~CrosshairImagePanelAdvanced();

	virtual void ResetData();
	virtual void ApplyChanges();
	virtual void UpdateVisibility();

protected:
	MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
	MESSAGE_FUNC_PARAMS( OnSliderMoved, "SliderMoved", data );

	virtual void Paint();
	static void DrawCrosshairRect( int x, int y, int w, int h, bool bAdditive );
	void InitAdvCrosshairStyleList();
	void SetCrosshairTexture( const char *crosshairname );
	void UpdateCrosshair();

private:
	COptionsSubMultiplayer* m_pOptionsPanel;

	// --- advanced crosshair controls
	CCvarSlider *m_pAdvCrosshairRedSlider;		
	CCvarSlider *m_pAdvCrosshairBlueSlider;
	CCvarSlider *m_pAdvCrosshairGreenSlider;
	CCvarSlider *m_pAdvCrosshairScaleSlider;

	CLabeledCommandComboBox *m_pAdvCrosshairStyle;

	int m_R, m_G, m_B;
	float m_flScale;

	// material
	int				m_iCrosshairTextureID;
	IVguiMatInfo	*m_pAdvCrosshairMaterial;

	// animation
	IVguiMatInfoVar	*m_pFrameVar;
	float			m_flNextFrameChange;
	int				m_nNumFrames;
	bool			m_bAscending;	// animating forward or in reverse?
};

//-----------------------------------------------------------------------------
CrosshairImagePanelAdvanced::CrosshairImagePanelAdvanced( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel ) : CrosshairImagePanelBase( parent, name )
{
	m_pOptionsPanel = pOptionsPanel;
	m_pAdvCrosshairMaterial = NULL;
	m_pFrameVar = NULL;

	m_pAdvCrosshairRedSlider = new CCvarSlider( pOptionsPanel, "Red Color Slider", "#GameUI_CrosshairColor_Red",
		0.0f, 255.0f, "cl_crosshair_red" );
	m_pAdvCrosshairGreenSlider = new CCvarSlider( pOptionsPanel, "Green Color Slider", "#GameUI_CrosshairColor_Green",
		0.0f, 255.0f, "cl_crosshair_green" );
	m_pAdvCrosshairBlueSlider = new CCvarSlider( pOptionsPanel, "Blue Color Slider", "#GameUI_CrosshairColor_Blue",
		0.0f, 255.0f, "cl_crosshair_blue" );

	m_pAdvCrosshairRedSlider->SetTickCaptions("", "");
	m_pAdvCrosshairGreenSlider->SetTickCaptions("", "");
	m_pAdvCrosshairBlueSlider->SetTickCaptions("", "");

	m_pAdvCrosshairScaleSlider = new CCvarSlider( pOptionsPanel, "Scale Slider", "#GameUI_CrosshairScale",
		16.0f, 48.0f, "cl_crosshair_scale" );

	m_pAdvCrosshairStyle = new CLabeledCommandComboBox( pOptionsPanel, "AdvCrosshairList" );

	m_pAdvCrosshairRedSlider->AddActionSignalTarget( this );
	m_pAdvCrosshairGreenSlider->AddActionSignalTarget( this );
	m_pAdvCrosshairBlueSlider->AddActionSignalTarget( this );
	m_pAdvCrosshairScaleSlider->AddActionSignalTarget( this );
	m_pAdvCrosshairStyle->AddActionSignalTarget(this);

	InitAdvCrosshairStyleList();

	m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID();
	SetCrosshairTexture("vgui/crosshairs/crosshair1");

	UpdateCrosshair();
}

CrosshairImagePanelAdvanced::~CrosshairImagePanelAdvanced()
{
	if ( m_pFrameVar )
	{
		delete m_pFrameVar;
		m_pFrameVar = NULL;
	}

	if ( m_pAdvCrosshairMaterial )
	{
		delete m_pAdvCrosshairMaterial;
		m_pAdvCrosshairMaterial = NULL;
	}
}

//-----------------------------------------------------------------------------
void CrosshairImagePanelAdvanced::SetCrosshairTexture( const char *crosshairname )
{
	if ( !crosshairname || !crosshairname[0] )
	{
		SetVisible( false );
		return;
	}

	SetVisible( true );

	vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, crosshairname, true, false );

	if ( m_pAdvCrosshairMaterial )
	{
		delete m_pAdvCrosshairMaterial;
	}

	m_pAdvCrosshairMaterial = vgui::surface()->DrawGetTextureMatInfoFactory( m_iCrosshairTextureID );

	Assert(m_pAdvCrosshairMaterial);

	m_pFrameVar = m_pAdvCrosshairMaterial->FindVarFactory( "$frame", NULL );
	m_nNumFrames = m_pAdvCrosshairMaterial->GetNumAnimationFrames();

	m_flNextFrameChange = system()->GetFrameTime() + 0.2;
	m_bAscending = true;
}

//-----------------------------------------------------------------------------
void CrosshairImagePanelAdvanced::Paint()
{
	BaseClass::Paint();

	int wide, tall;
	GetSize( wide, tall );

	int iClipX0, iClipY0, iClipX1, iClipY1;
	ipanel()->GetClipRect(GetVPanel(), iClipX0, iClipY0, iClipX1, iClipY1 );

	// scroll through all frames
	if ( m_pFrameVar )
	{	
		float curtime = system()->GetFrameTime();

		if ( curtime >= m_flNextFrameChange )
		{
			m_flNextFrameChange = curtime + 0.2;

			int frame = m_pFrameVar->GetIntValue();

			if ( m_bAscending )
			{
				frame++;
				if ( frame >= m_nNumFrames )
				{
					m_bAscending = !m_bAscending;
					frame--;
				}
			}
			else
			{
				frame--;
				if ( frame < 0 )
				{
					m_bAscending = !m_bAscending;
					frame++;
				}
			}

			m_pFrameVar->SetIntValue(frame);
		}
	}

	float x, y;

	// assume square
	float flDrawWidth = ( m_flScale/48.0 ) * (float)wide;	
	int flHalfWidth = (int)( flDrawWidth / 2 );

	x = wide/2 - flHalfWidth;
	y = tall/2 - flHalfWidth;

	vgui::surface()->DrawSetColor( m_R, m_G, m_B, 255 );
	vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
	vgui::surface()->DrawTexturedRect( x, y, x+flDrawWidth, y+flDrawWidth );
	vgui::surface()->DrawSetTexture(0);
}

void CrosshairImagePanelAdvanced::UpdateCrosshair()
{
	// get the color selected in the combo box.
	m_R = clamp( m_pAdvCrosshairRedSlider->GetSliderValue(), 0, 255 );
	m_G = clamp( m_pAdvCrosshairGreenSlider->GetSliderValue(), 0, 255 );
	m_B = clamp( m_pAdvCrosshairBlueSlider->GetSliderValue(), 0, 255 );

	m_flScale = m_pAdvCrosshairScaleSlider->GetSliderValue();

	if ( m_pAdvCrosshairStyle )
	{
		char crosshairname[256];
		m_pAdvCrosshairStyle->GetText( crosshairname, sizeof(crosshairname)	);

		if ( ModInfo().AdvCrosshairLevel() == 1 && m_pAdvCrosshairStyle->GetActiveItem() == 0 ) // this is the "none" selection
		{
			SetCrosshairTexture(NULL);
		}
		else
		{
			char texture[ 256 ];
			Q_snprintf ( texture, sizeof( texture ), "vgui/crosshairs/%s", crosshairname );
			SetCrosshairTexture( texture );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: initialize the crosshair style list
//-----------------------------------------------------------------------------
void CrosshairImagePanelAdvanced::InitAdvCrosshairStyleList()
{
	// Find out images
	FileFindHandle_t fh;
	char directory[ 512 ];

	ConVarRef cl_crosshair_file( "cl_crosshair_file", true );
	if ( !cl_crosshair_file.IsValid() )
		return;

	m_pAdvCrosshairStyle->DeleteAllItems();

	if ( ModInfo().AdvCrosshairLevel() == 1 )
	{
		m_pAdvCrosshairStyle->AddItem( "#GameUI_None", "" );
	}

	char crosshairfile[256];
	Q_snprintf( crosshairfile, sizeof(crosshairfile), "materials/vgui/crosshairs/%s.vtf", cl_crosshair_file.GetString() );

	Q_snprintf( directory, sizeof( directory ), "materials/vgui/crosshairs/*.vtf" );
	const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
	int i = 0, initialItem = 0; 
	while (fn)
	{
		char filename[ 512 ];
		Q_snprintf( filename, sizeof(filename), "materials/vgui/crosshairs/%s", fn );
		if ( strlen( filename ) >= 4 )
		{
			filename[ strlen( filename ) - 4 ] = 0;
			Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
			if ( g_pFullFileSystem->FileExists( filename ) )
			{
				// strip off the extension
				Q_strncpy( filename, fn, sizeof( filename ) );
				filename[ strlen( filename ) - 4 ] = 0;
				m_pAdvCrosshairStyle->AddItem( filename, "" );

				// check to see if this is the one we have set
				if ( crosshairfile[0] )
				{
					Q_snprintf( filename, sizeof(filename), "materials/vgui/crosshairs/%s", fn );
					if (!stricmp(filename, crosshairfile))
					{
						if ( ModInfo().AdvCrosshairLevel() == 1 )
						{
							initialItem = i+1;
						}
						else
						{
							initialItem = i;
						}
					}
				}

				++i;
			}
		}

		fn = g_pFullFileSystem->FindNext( fh );
	}

	g_pFullFileSystem->FindClose( fh );
	m_pAdvCrosshairStyle->SetInitialItem(initialItem);
}


//-----------------------------------------------------------------------------
// Purpose: Called whenever style combo changes
//-----------------------------------------------------------------------------
void CrosshairImagePanelAdvanced::OnTextChanged(vgui::Panel *panel)
{
	m_pOptionsPanel->OnControlModified();
	UpdateCrosshair();
}

//-----------------------------------------------------------------------------
// Purpose: Called whenever one of the color or scale sliders move
//-----------------------------------------------------------------------------
void CrosshairImagePanelAdvanced::OnSliderMoved(KeyValues *data)
{
	m_pOptionsPanel->OnControlModified();
	UpdateCrosshair();
}

void CrosshairImagePanelAdvanced::ResetData()
{
	m_pAdvCrosshairRedSlider->Reset();
	m_pAdvCrosshairGreenSlider->Reset();
	m_pAdvCrosshairBlueSlider->Reset();
	m_pAdvCrosshairScaleSlider->Reset();

	// TODO: update style combo from cvar
}

void CrosshairImagePanelAdvanced::ApplyChanges()
{
	m_pAdvCrosshairRedSlider->ApplyChanges();
	m_pAdvCrosshairGreenSlider->ApplyChanges();
	m_pAdvCrosshairBlueSlider->ApplyChanges();
	m_pAdvCrosshairScaleSlider->ApplyChanges();

	// save the crosshair
	char cmd[512];
	char crosshair[256];
	m_pAdvCrosshairStyle->GetText(crosshair, sizeof(crosshair));

	if ( ModInfo().AdvCrosshairLevel() == 1 && m_pAdvCrosshairStyle->GetActiveItem() == 0 ) // this is the "none" selection
	{
		engine->ClientCmd_Unrestricted("cl_crosshair_file \"\"");
	}
	else
	{
		Q_snprintf(cmd, sizeof(cmd), "cl_crosshair_file %s\n", crosshair);
		engine->ClientCmd_Unrestricted(cmd);
	}
}

void CrosshairImagePanelAdvanced::UpdateVisibility()
{
	SetVisible(true);
	m_pAdvCrosshairRedSlider->SetVisible(true);
	m_pAdvCrosshairBlueSlider->SetVisible(true);
	m_pAdvCrosshairGreenSlider->SetVisible(true);
	m_pAdvCrosshairScaleSlider->SetVisible(true);
	m_pAdvCrosshairStyle->SetVisible(true);

	if ( ModInfo().NoCrosshair() )
	{
		Panel *pTempPanel = NULL;

		pTempPanel = FindSiblingByName( "CrosshairImage" );
		pTempPanel->SetVisible( false );

		pTempPanel = FindSiblingByName( "CrosshairLabel" );
		if ( pTempPanel )
			pTempPanel->SetVisible( false );
	}
}


//-----------------------------------------------------------------------------
// Purpose: Basic help dialog
//-----------------------------------------------------------------------------
COptionsSubMultiplayer::COptionsSubMultiplayer(vgui::Panel *parent) : vgui::PropertyPage(parent, "OptionsSubMultiplayer") 
{
	Button *cancel = new Button( this, "Cancel", "#GameUI_Cancel" );
	cancel->SetCommand( "Close" );

	Button *ok = new Button( this, "OK", "#GameUI_OK" );
	ok->SetCommand( "Ok" );

	Button *apply = new Button( this, "Apply", "#GameUI_Apply" );
	apply->SetCommand( "Apply" );

	Button *advanced = new Button( this, "Advanced", "#GameUI_AdvancedEllipsis" );
	advanced->SetCommand( "Advanced" );

	Button *importSprayImage = new Button( this, "ImportSprayImage", "#GameUI_ImportSprayEllipsis" );
	importSprayImage->SetCommand("ImportSprayImage");

	m_hImportSprayDialog = NULL;

	m_pPrimaryColorSlider = new CCvarSlider( this, "Primary Color Slider", "#GameUI_PrimaryColor",
		0.0f, 255.0f, "topcolor" );

	m_pSecondaryColorSlider = new CCvarSlider( this, "Secondary Color Slider", "#GameUI_SecondaryColor",
		0.0f, 255.0f, "bottomcolor" );

	m_pHighQualityModelCheckBox = new CCvarToggleCheckButton( this, "High Quality Models", "#GameUI_HighModels", "cl_himodels" );

	m_pModelList = new CLabeledCommandComboBox( this, "Player model" );
	m_ModelName[0] = 0;
	InitModelList( m_pModelList );

	m_pLogoList = new CLabeledCommandComboBox( this, "SpraypaintList" );
    m_LogoName[0] = 0;
	InitLogoList( m_pLogoList );

	m_pModelImage = new CBitmapImagePanel( this, "ModelImage", NULL );
	m_pModelImage->AddActionSignalTarget( this );

	m_pLogoImage = new ImagePanel( this, "LogoImage" );
	m_pLogoImage->AddActionSignalTarget( this );

	m_nLogoR = 255;
	m_nLogoG = 255;
	m_nLogoB = 255;

	m_pCrosshairImage = NULL;
	switch ( ModInfo().AdvCrosshairLevel() )
	{
	case 0:
		if ( !ModInfo().NoCrosshair() )
			m_pCrosshairImage = new CrosshairImagePanelSimple( this, "CrosshairImage", this );
		break;

	case 1:	// TF
	case 2:	// DOD
		m_pCrosshairImage = new CrosshairImagePanelAdvanced( this, "AdvCrosshairImage", this );
		break;

	case 3:	// Counter-Strike
		m_pCrosshairImage = new CrosshairImagePanelCS( this, "CrosshairImage", this );
		break;

	}

	m_pLockRadarRotationCheckbox = new CCvarToggleCheckButton( this, "LockRadarRotationCheckbox", "#Cstrike_RadarLocked", "cl_radar_locked" );

	m_pDownloadFilterCombo = new ComboBox( this, "DownloadFilterCheck", 4, false );
	m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_ALL", NULL );
	m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_NoSounds", NULL );
	m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_MapsOnly", NULL );
	m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_None", NULL );

	//=========

	LoadControlSettings("Resource/OptionsSubMultiplayer.res");

	// this is necessary because some of the game .res files don't have visiblity flags set up correctly for their controls
	if ( m_pCrosshairImage )
		m_pCrosshairImage->UpdateVisibility();

	// turn off model selection stuff if the mod specifies "nomodels" in the gameinfo.txt file
	if ( ModInfo().NoModels() )
	{
		Panel *pTempPanel = NULL;

		if ( m_pModelImage )
		{
			m_pModelImage->SetVisible( false );
		}

		if ( m_pModelList )
		{
			m_pModelList->SetVisible( false );
		}

		if ( m_pPrimaryColorSlider )
		{
			m_pPrimaryColorSlider->SetVisible( false );
		}

		if ( m_pSecondaryColorSlider )
		{
			m_pSecondaryColorSlider->SetVisible( false );
		}

		// #GameUI_PlayerModel (from "Resource/OptionsSubMultiplayer.res")
		pTempPanel = FindChildByName( "Label1" );

		if ( pTempPanel )
		{
			pTempPanel->SetVisible( false );
		}

		// #GameUI_ColorSliders (from "Resource/OptionsSubMultiplayer.res")
		pTempPanel = FindChildByName( "Colors" );

		if ( pTempPanel )
		{
			pTempPanel->SetVisible( false );
		}
	}

	// turn off the himodel stuff if the mod specifies "nohimodel" in the gameinfo.txt file
	if ( ModInfo().NoHiModel() )
	{
		if ( m_pHighQualityModelCheckBox )
		{
			m_pHighQualityModelCheckBox->SetVisible( false );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
COptionsSubMultiplayer::~COptionsSubMultiplayer()
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::OnCommand( const char *command )
{
	if ( !stricmp( command, "Advanced" ) )
	{
#ifndef _XBOX
		if (!m_hMultiplayerAdvancedDialog.Get())
		{
			m_hMultiplayerAdvancedDialog = new CMultiplayerAdvancedDialog( this );
		}
		m_hMultiplayerAdvancedDialog->Activate();
#endif
	}
	else if (!stricmp( command, "ImportSprayImage" ) )
	{
		if (m_hImportSprayDialog == NULL)
		{
			m_hImportSprayDialog = new FileOpenDialog(NULL, "#GameUI_ImportSprayImage", true);
#ifdef WIN32
			m_hImportSprayDialog->AddFilter("*.tga,*.jpg,*.bmp,*.vtf", "#GameUI_All_Images", true);
#else
			m_hImportSprayDialog->AddFilter("*.tga,*.jpg,*.vtf", "#GameUI_All_ImagesNoBmp", true);
#endif
			m_hImportSprayDialog->AddFilter("*.tga", "#GameUI_TGA_Images", false);
			m_hImportSprayDialog->AddFilter("*.jpg", "#GameUI_JPEG_Images", false);
#ifdef WIN32
			m_hImportSprayDialog->AddFilter("*.bmp", "#GameUI_BMP_Images", false);
#endif
			m_hImportSprayDialog->AddFilter("*.vtf", "#GameUI_VTF_Images", false);
			m_hImportSprayDialog->AddActionSignalTarget(this);
		}
		m_hImportSprayDialog->DoModal(false);
		m_hImportSprayDialog->Activate();
	}

	else if ( !stricmp( command, "ResetStats" ) )
	{
		QueryBox *box = new QueryBox("#GameUI_ConfirmResetStatsTitle", "#GameUI_ConfirmResetStatsText", this);
		box->SetOKButtonText("#GameUI_Reset");
		box->SetOKCommand(new KeyValues("Command", "command", "ResetStats_NoConfirm"));
		box->SetCancelCommand(new KeyValues("Command", "command", "ReleaseModalWindow"));
		box->AddActionSignalTarget(this);
		box->DoModal();
	}

	else if ( !stricmp( command, "ResetStats_NoConfirm" ) )
	{
		engine->ClientCmd_Unrestricted("stats_reset");
	}

	BaseClass::OnCommand( command );
}

void COptionsSubMultiplayer::ConversionError( ConversionErrorType nError )
{
	const char *pErrorText = NULL;

	switch ( nError )
	{
	case CE_MEMORY_ERROR:
		pErrorText = "#GameUI_Spray_Import_Error_Memory";
		break;

	case CE_CANT_OPEN_SOURCE_FILE:
		pErrorText = "#GameUI_Spray_Import_Error_Reading_Image";
		break;

	case CE_ERROR_PARSING_SOURCE:
		pErrorText = "#GameUI_Spray_Import_Error_Image_File_Corrupt";
		break;

	case CE_SOURCE_FILE_SIZE_NOT_SUPPORTED:
		pErrorText = "#GameUI_Spray_Import_Image_Wrong_Size";
		break;

	case CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED:
		pErrorText = "#GameUI_Spray_Import_Image_Wrong_Size";
		break;

	case CE_SOURCE_FILE_TGA_FORMAT_NOT_SUPPORTED:
		pErrorText = "#GameUI_Spray_Import_Error_TGA_Format_Not_Supported";
		break;

	case CE_SOURCE_FILE_BMP_FORMAT_NOT_SUPPORTED:
		pErrorText = "#GameUI_Spray_Import_Error_BMP_Format_Not_Supported";
		break;

	case CE_ERROR_WRITING_OUTPUT_FILE:
		pErrorText = "#GameUI_Spray_Import_Error_Writing_Temp_Output";
		break;

	case CE_ERROR_LOADING_DLL:
		pErrorText = "#GameUI_Spray_Import_Error_Cant_Load_VTEX_DLL";
		break;
	}

	if ( pErrorText )
	{
		// Create the dialog
		vgui::MessageBox *pErrorDlg = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", pErrorText );	Assert( pErrorDlg );

		// Display
		if ( pErrorDlg )	// Check for a NULL just to be extra cautious...
		{
			pErrorDlg->DoModal();
		}
	}
}

void COptionsSubMultiplayer::OnFileSelected(const char *fullpath)
{
#ifndef _XBOX
	// this can take a while, put up a waiting cursor
	surface()->SetCursor(dc_hourglass);

	ConversionErrorType nErrorCode = ImgUtl_ConvertToVTFAndDumpVMT( fullpath, IsPosix() ? "/vgui/logos" : "\\vgui\\logos", 256, 256 );
	if ( nErrorCode == CE_SUCCESS )
	{
		// refresh the logo list so the new spray shows up.
		InitLogoList(m_pLogoList);

		// Get the filename
		char szRootFilename[MAX_PATH];
		V_FileBase( fullpath, szRootFilename, sizeof( szRootFilename ) );

		// automatically select the logo that was just imported.
		SelectLogo(szRootFilename);
	}
	else
	{
		ConversionError( nErrorCode );
	}

	// change the cursor back to normal
	surface()->SetCursor(dc_user);
#endif
}

struct ValveJpegErrorHandler_t 
{
	// The default manager
	struct jpeg_error_mgr	m_Base;
	// For handling any errors
	jmp_buf					m_ErrorContext;
};

//-----------------------------------------------------------------------------
// Purpose: We'll override the default error handler so we can deal with errors without having to exit the engine
//-----------------------------------------------------------------------------
static void ValveJpegErrorHandler( j_common_ptr cinfo )
{
	ValveJpegErrorHandler_t *pError = reinterpret_cast< ValveJpegErrorHandler_t * >( cinfo->err );

	char buffer[ JMSG_LENGTH_MAX ];

	/* Create the message */
	( *cinfo->err->format_message )( cinfo, buffer );

	Warning( "%s\n", buffer );

	// Bail
	longjmp( pError->m_ErrorContext, 1 );
}

//-----------------------------------------------------------------------------
// Purpose: Builds the list of logos
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::InitLogoList( CLabeledCommandComboBox *cb )
{
	// Find out images
	FileFindHandle_t fh;
	char directory[ 512 ];

	ConVarRef cl_logofile( "cl_logofile", true );
	if ( !cl_logofile.IsValid() )
		return;

	cb->DeleteAllItems();

	const char *logofile = cl_logofile.GetString();
	Q_snprintf( directory, sizeof( directory ), "materials/vgui/logos/*.vtf" );
	const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
	int i = 0, initialItem = 0; 
	while (fn)
	{
		char filename[ 512 ];
		Q_snprintf( filename, sizeof(filename), "materials/vgui/logos/%s", fn );
		if ( strlen( filename ) >= 4 )
		{
			filename[ strlen( filename ) - 4 ] = 0;
			Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
			if ( g_pFullFileSystem->FileExists( filename ) )
			{
				// strip off the extension
				Q_strncpy( filename, fn, sizeof( filename ) );
				filename[ strlen( filename ) - 4 ] = 0;
				cb->AddItem( filename, "" );

				// check to see if this is the one we have set
				Q_snprintf( filename, sizeof(filename), "materials/vgui/logos/%s", fn );
				if (!Q_stricmp(filename, logofile))
				{
					initialItem = i;
				}

				++i;
			}
		}

		fn = g_pFullFileSystem->FindNext( fh );
	}

	g_pFullFileSystem->FindClose( fh );
	cb->SetInitialItem(initialItem);
}


//-----------------------------------------------------------------------------
// Purpose: Selects the given logo in the logo list.
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::SelectLogo(const char *logoName)
{
	int numEntries = m_pLogoList->GetItemCount();
	int index;
	wchar_t itemText[MAX_PATH];
	wchar_t itemToSelectText[MAX_PATH];

	// convert the logo filename to unicode
	g_pVGuiLocalize->ConvertANSIToUnicode(logoName, itemToSelectText, sizeof(itemToSelectText));

	// find the index of the spray we want.
	for (index = 0; index < numEntries; ++index)
	{
		m_pLogoList->GetItemText(index, itemText, sizeof(itemText));
		if (!wcscmp(itemText, itemToSelectText))
		{
			break;
		}
	}

	if (index < numEntries)
	{
		// select the logo.
		m_pLogoList->ActivateItem(index);
	}
}

#define MODEL_MATERIAL_BASE_FOLDER "materials/vgui/playermodels/"


void StripStringOutOfString( const char *pPattern, const char *pIn, char *pOut )
{
	int iLengthBase = strlen( pPattern );
	int iLengthString = strlen( pIn );

	int k = 0;

	for ( int j = iLengthBase; j < iLengthString; j++ )
	{
		pOut[k] = pIn[j];
		k++;
	}

	pOut[k] = 0;
}

void FindVMTFilesInFolder( const char *pFolder, const char *pFolderName, CLabeledCommandComboBox *cb, int &iCount, int &iInitialItem )
{
	ConVarRef cl_modelfile( "cl_playermodel", true );
	if ( !cl_modelfile.IsValid() )
		return;

	char directory[ 512 ];
	Q_snprintf( directory, sizeof( directory ), "%s/*.*", pFolder );

	FileFindHandle_t fh;

	const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
	const char *modelfile = cl_modelfile.GetString();

	while ( fn )
	{
		if ( !stricmp( fn, ".") || !stricmp( fn, "..") )
		{
			fn = g_pFullFileSystem->FindNext( fh );
			continue;
		}

		if ( g_pFullFileSystem->FindIsDirectory( fh ) )
		{
			char folderpath[512];

			Q_snprintf( folderpath, sizeof( folderpath ), "%s/%s", pFolder, fn );

			FindVMTFilesInFolder( folderpath, fn, cb, iCount, iInitialItem );
			fn = g_pFullFileSystem->FindNext( fh );
			continue;
		}

		if ( !strstr( fn, ".vmt" ) )
		{
			fn = g_pFullFileSystem->FindNext( fh );
			continue;
		}


		char filename[ 512 ];
		Q_snprintf( filename, sizeof(filename), "%s/%s", pFolder, fn );
		if ( strlen( filename ) >= 4 )
		{
			filename[ strlen( filename ) - 4 ] = 0;
			Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
			if ( g_pFullFileSystem->FileExists( filename ) )
			{
				char displayname[ 512 ];
				char texturepath[ 512 ];
				// strip off the extension
				Q_strncpy( displayname, fn, sizeof( displayname ) );
				StripStringOutOfString( MODEL_MATERIAL_BASE_FOLDER, filename, texturepath );
				
				displayname[ strlen( displayname ) - 4 ] = 0;
				
				if ( CORRECT_PATH_SEPARATOR == texturepath[0] )
				    cb->AddItem( displayname, texturepath + 1 ); // ignore the initial "/" in texture path
				else
				    cb->AddItem( displayname, texturepath );


				char realname[ 512 ];
				Q_FileBase( modelfile, realname, sizeof( realname ) );
				Q_FileBase( filename, filename, sizeof( filename ) );
				
				if (!stricmp(filename, realname))
				{
					iInitialItem = iCount;
				}

				++iCount;
			}
		}

		fn = g_pFullFileSystem->FindNext( fh );
	}
}

//-----------------------------------------------------------------------------
// Purpose: Builds model list
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::InitModelList( CLabeledCommandComboBox *cb )
{
	// Find out images
	int i = 0, initialItem = 0;

	cb->DeleteAllItems();
	FindVMTFilesInFolder( MODEL_MATERIAL_BASE_FOLDER, "", cb, i, initialItem );
	cb->SetInitialItem( initialItem );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::RemapLogo()
{
	char logoname[256];

	m_pLogoList->GetText( logoname, sizeof( logoname ) );
	if( !logoname[ 0 ] )
		return;

	char fullLogoName[512];

	// make sure there is a version with the proper shader
	g_pFullFileSystem->CreateDirHierarchy( "materials/VGUI/logos/UI", "GAME" );
	Q_snprintf( fullLogoName, sizeof( fullLogoName ), "materials/VGUI/logos/UI/%s.vmt", logoname );
	if ( !g_pFullFileSystem->FileExists( fullLogoName ) )
	{
		FileHandle_t fp = g_pFullFileSystem->Open( fullLogoName, "wb" );
		if ( !fp )
			return;

		char data[1024];
		Q_snprintf( data, sizeof( data ), "\"UnlitGeneric\"\n\
{\n\
	// Original shader: BaseTimesVertexColorAlphaBlendNoOverbright\n\
	\"$translucent\" 1\n\
	\"$basetexture\" \"VGUI/logos/%s\"\n\
	\"$vertexcolor\" 1\n\
	\"$vertexalpha\" 1\n\
	\"$no_fullbright\" 1\n\
	\"$ignorez\" 1\n\
}\n\
", logoname );

		g_pFullFileSystem->Write( data, strlen( data ), fp );
		g_pFullFileSystem->Close( fp );
	}

	Q_snprintf( fullLogoName, sizeof( fullLogoName ), "logos/UI/%s", logoname );
	m_pLogoImage->SetImage( fullLogoName );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::RemapModel()
{
	const char *pModelName = m_pModelList->GetActiveItemCommand();
	
	if( pModelName == NULL )
		return;

	char texture[ 256 ];
	Q_snprintf ( texture, sizeof( texture ), "vgui/playermodels/%s", pModelName );
	texture[ strlen( texture ) - 4 ] = 0;

	m_pModelImage->setTexture( texture );
}


//-----------------------------------------------------------------------------
// Purpose: Called whenever model name changes
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::OnTextChanged(vgui::Panel *panel)
{
	RemapModel();
	RemapLogo();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::OnControlModified()
{
	PostMessage(GetParent(), new KeyValues("ApplyButtonEnable"));
	InvalidateLayout();
}

#define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B')
#define SUIT_HUE_START 192
#define SUIT_HUE_END 223
#define PLATE_HUE_START 160
#define PLATE_HUE_END 191

#ifdef POSIX 
typedef struct tagRGBQUAD { 
  uint8 rgbBlue;
  uint8 rgbGreen;
  uint8 rgbRed;
  uint8 rgbReserved;
} RGBQUAD;
#endif

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
static void PaletteHueReplace( RGBQUAD *palSrc, int newHue, int Start, int end )
{
	int i;
	float r, b, g;
	float maxcol, mincol;
	float hue, val, sat;

	hue = (float)(newHue * (360.0 / 255));

	for (i = Start; i <= end; i++)
	{
		b = palSrc[ i ].rgbBlue;
		g = palSrc[ i ].rgbGreen;
		r = palSrc[ i ].rgbRed;
		
		maxcol = max( max( r, g ), b ) / 255.0f;
		mincol = min( min( r, g ), b ) / 255.0f;
		
		val = maxcol;
		sat = (maxcol - mincol) / maxcol;

		mincol = val * (1.0f - sat);

		if (hue <= 120)
		{
			b = mincol;
			if (hue < 60)
			{
				r = val;
				g = mincol + hue * (val - mincol)/(120 - hue);
			}
			else
			{
				g = val;
				r = mincol + (120 - hue)*(val-mincol)/hue;
			}
		}
		else if (hue <= 240)
		{
			r = mincol;
			if (hue < 180)
			{
				g = val;
				b = mincol + (hue - 120)*(val-mincol)/(240 - hue);
			}
			else
			{
				b = val;
				g = mincol + (240 - hue)*(val-mincol)/(hue - 120);
			}
		}
		else
		{
			g = mincol;
			if (hue < 300)
			{
				b = val;
				r = mincol + (hue - 240)*(val-mincol)/(360 - hue);
			}
			else
			{
				r = val;
				b = mincol + (360 - hue)*(val-mincol)/(hue - 240);
			}
		}

		palSrc[ i ].rgbBlue = (unsigned char)(b * 255);
		palSrc[ i ].rgbGreen = (unsigned char)(g * 255);
		palSrc[ i ].rgbRed = (unsigned char)(r * 255);
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::ColorForName( char const *pszColorName, int&r, int&g, int&b )
{
	r = g = b = 0;
	
	int count = sizeof( itemlist ) / sizeof( itemlist[0] );

	for ( int i = 0; i < count; i++ )
	{
		if (!Q_strnicmp(pszColorName, itemlist[ i ].name, strlen(itemlist[ i ].name)))
		{
			r = itemlist[ i ].r;
			g = itemlist[ i ].g;
			b = itemlist[ i ].b;
			return;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::OnResetData()
{
	// reset the DownloadFilter combo box
	if ( m_pDownloadFilterCombo )
	{
		// cl_downloadfilter
		ConVarRef cl_downloadfilter( "cl_downloadfilter");

		if ( Q_stricmp( cl_downloadfilter.GetString(), "none" ) == 0 )
		{
			m_pDownloadFilterCombo->ActivateItem( 3 );
		}
		else if ( Q_stricmp( cl_downloadfilter.GetString(), "nosounds" ) == 0 )
		{
			m_pDownloadFilterCombo->ActivateItem( 1 );
		}
		else if ( Q_stricmp( cl_downloadfilter.GetString(), "mapsonly" ) == 0 )
		{
			m_pDownloadFilterCombo->ActivateItem( 2 );
		}
		else
		{
			m_pDownloadFilterCombo->ActivateItem( 0 );
		}
	}

	if ( m_pCrosshairImage )
		m_pCrosshairImage->ResetData();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void COptionsSubMultiplayer::OnApplyChanges()
{
	m_pPrimaryColorSlider->ApplyChanges();
	m_pSecondaryColorSlider->ApplyChanges();
//	m_pModelList->ApplyChanges();
	m_pLogoList->ApplyChanges();
    m_pLogoList->GetText(m_LogoName, sizeof(m_LogoName));
	m_pHighQualityModelCheckBox->ApplyChanges();

	for ( int i=0; i<m_cvarToggleCheckButtons.GetCount(); ++i )
	{
		CCvarToggleCheckButton *toggleButton = m_cvarToggleCheckButtons[i];
		if( toggleButton->IsVisible() && toggleButton->IsEnabled() )
		{
			toggleButton->ApplyChanges();
		}
	}

	if ( m_pLockRadarRotationCheckbox != NULL )
	{
		m_pLockRadarRotationCheckbox->ApplyChanges();
	}

	if ( m_pCrosshairImage != NULL )
		m_pCrosshairImage->ApplyChanges();

	// save the logo name
	char cmd[512];
	if ( m_LogoName[ 0 ] )
	{
		Q_snprintf(cmd, sizeof(cmd), "cl_logofile materials/vgui/logos/%s.vtf\n", m_LogoName);
	}
	else
	{
		Q_strncpy( cmd, "cl_logofile \"\"\n", sizeof( cmd ) );
	}
	engine->ClientCmd_Unrestricted(cmd);

	if ( m_pModelList && m_pModelList->IsVisible() && m_pModelList->GetActiveItemCommand() )
	{
		Q_strncpy( m_ModelName, m_pModelList->GetActiveItemCommand(), sizeof( m_ModelName ) );
		Q_StripExtension( m_ModelName, m_ModelName, sizeof ( m_ModelName ) );
		
		// save the player model name
		Q_snprintf(cmd, sizeof(cmd), "cl_playermodel models/%s.mdl\n", m_ModelName );
		engine->ClientCmd_Unrestricted(cmd);
	}
	else
	{
		m_ModelName[0] = 0;
	}

	// set the DownloadFilter cvar
	if ( m_pDownloadFilterCombo )
	{
		ConVarRef  cl_downloadfilter( "cl_downloadfilter" );
		
		switch ( m_pDownloadFilterCombo->GetActiveItem() )
		{
		default:
		case 0:
			cl_downloadfilter.SetValue( "all" );
			break;
		case 1:
			cl_downloadfilter.SetValue( "nosounds" );
			break;
		case 2:
			cl_downloadfilter.SetValue( "mapsonly" );
			break;
		case 3:
			cl_downloadfilter.SetValue( "none" );
			break;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Allow the res file to create controls on per-mod basis
//-----------------------------------------------------------------------------
Panel *COptionsSubMultiplayer::CreateControlByName( const char *controlName )
{
	if( !Q_stricmp( "CCvarToggleCheckButton", controlName ) )
	{
		CCvarToggleCheckButton *newButton = new CCvarToggleCheckButton( this, controlName, "", "" );
		m_cvarToggleCheckButtons.AddElement( newButton );
		return newButton;
	}
	else
	{
		return BaseClass::CreateControlByName( controlName );
	}
}