#pragma once

#include <vector>
#include <string>
#include <limits>

#undef max
#undef min



class CVideoAdvListCtrl;
class CSystemConfiguration;

struct SCVar
{
	enum EDataType
	{
		STRING,
		INT,
		DOUBLE
	};



	class CDataValidator 
	{	
	public:
		CDataValidator() {}
		virtual ~CDataValidator() = 0 {} 
		virtual EDataType GetType() const = 0;
		virtual bool Validate( CString& strValue ) const = 0;
	};

	class CStringValidator : public CDataValidator
	{
	public:
		CStringValidator() : CDataValidator() 
		{
		}		
		
		virtual ~CStringValidator() 
		{
		}		
		
		virtual EDataType GetType() const
		{
			return( STRING );
		}

		virtual bool Validate( CString& strValue ) const
		{
			return( true );
		}
	};

	class CIntValidator : public CDataValidator
	{
	public:
		CIntValidator( int iLowerBound = -std::numeric_limits< int >::min(), int iUpperBound = std::numeric_limits< int >::max() ) 
		: CDataValidator()
		, m_iLowerBound( iLowerBound ) 
		, m_iUpperBound( iUpperBound ) 
		{
			ASSERT( m_iLowerBound <= m_iUpperBound );
		}		
		
		virtual ~CIntValidator()
		{
		}		
		
		virtual EDataType GetType() const
		{
			return( INT );
		}

		virtual bool Validate( CString& strValue ) const
		{
			bool bRet( false );
			int iVal;
			if( 1 == _stscanf( strValue, _T( "%d" ), &iVal ) )
			{
				if( iVal >= m_iLowerBound && iVal <= m_iUpperBound )
				{
					strValue.Format( _T( "%d" ), iVal );
					bRet = true;
				}
			}
			return( bRet );
		}

	private:
		int m_iLowerBound;
		int m_iUpperBound;
	};

	class CDoubleValidator : public CDataValidator
	{
	public:
		CDoubleValidator( double dLowerBound = -std::numeric_limits< double >::max(), double dUpperBound = std::numeric_limits< double >::max() ) 
		: CDataValidator()
		, m_dLowerBound( dLowerBound ) 
		, m_dUpperBound( dUpperBound ) 
		{
			ASSERT( m_dLowerBound <= m_dUpperBound );
		}		

		virtual ~CDoubleValidator()
		{
		}		

		virtual EDataType GetType() const
		{
			return( DOUBLE );
		}

		virtual bool Validate( CString& strValue ) const
		{
			bool bRet( false );
			double dVal;
			if( 1 == _stscanf( strValue, _T( "%lf" ), &dVal ) )
			{
				if( dVal >= m_dLowerBound && dVal <= m_dUpperBound )
				{
					strValue.Format( _T( "%lf" ), dVal );
					bRet = true;
				}
			}
			return( bRet );
		}

	private:
		double m_dLowerBound;
		double m_dUpperBound;
	};



	SCVar()
	: m_strKey()
	, m_strValue()
	, m_uiHelpID( 0 )
	, m_pkDataValidator( 0 )
	{
	}

	SCVar( const std::string& strKey, const std::string& strValue, CDataValidator* pkDataValidator, unsigned int uiHelpID = 0 )
	: m_strKey( strKey )
	, m_strValue( strValue )
	, m_uiHelpID( uiHelpID )
	, m_pkDataValidator( pkDataValidator )
	{
	}

	std::string m_strKey;
	std::string m_strValue;
	unsigned int m_uiHelpID;
	CDataValidator* m_pkDataValidator;
};

typedef std::vector< SCVar > CVarVector;



class CInplaceEdit : public CEdit
{
public:
	CInplaceEdit();
	virtual ~CInplaceEdit();

	void SetInplaceInfo( SCVar* pCVar, int iToEdit );
	void SetParentListCtrl( CVideoAdvListCtrl* pkParent );

protected:
	DECLARE_MESSAGE_MAP()

	afx_msg void OnEnKillFocus();
	afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );
	afx_msg UINT OnGetDlgCode();
	afx_msg void OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags );

private:
	void DoEditValidation();

	DECLARE_DYNAMIC( CInplaceEdit )

private:
	SCVar* m_pCVar;
	int m_iToEdit;
	CVideoAdvListCtrl* m_pkVideoAdvListCtrl;
};



class CVideoAdvListCtrl : public CListCtrl
{
public:
	CVideoAdvListCtrl( const CVarVector& colCVars, CSystemConfiguration& kSysConfig, CEdit& kHelpEditCtrl );
	virtual ~CVideoAdvListCtrl();

	virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );

	void Initialize();
	void UpdateSystemConfig();

protected:
	DECLARE_MESSAGE_MAP()
	afx_msg void OnNMDblclk( NMHDR *pNMHDR, LRESULT *pResult );
	afx_msg void OnNMClick( NMHDR *pNMHDR, LRESULT *pResult );
	afx_msg void OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);

private:
	void PrepareDC( CDC* pDC, bool bSelected, SCVar::EDataType eDataType );
	void DrawCVarKeyColumn( CDC *pDC, int iItem );
	void DrawCVarValueColumn( CDC *pDC, int iItem );

	void EditInplace( int iItem, int iSubItem );
	void UpdateHelp( int iItem );

	DECLARE_DYNAMIC( CVideoAdvListCtrl )

private:
    CInplaceEdit m_kInplaceEdit;   
	CVarVector m_colCVars;
	CSystemConfiguration& m_kSysConfig;
	CEdit& m_kHelpEditCtrl;
};


