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

#include "clipboardmanager.h"
#include "datamodel.h"
#include "tier1/KeyValues.h"

#ifdef _WIN32
#define USE_WINDOWS_CLIPBOARD
#endif

#if defined( USE_WINDOWS_CLIPBOARD )
#include <windows.h>
#endif

CClipboardManager::CClipboardManager( ) :
	m_pfnCleanup( NULL )
{
}

CClipboardManager::~CClipboardManager()
{
	EmptyClipboard( false );
}

void CClipboardManager::EmptyClipboard( bool bClearWindowsClipboard )
{
	// Call optional cleanup function if there is one...
	if ( m_pfnCleanup )
	{
		m_pfnCleanup->ReleaseClipboardData( m_Data );
	}
	int c = m_Data.Count();
	for ( int i = 0; i < c; ++i )
	{
		m_Data[ i ]->deleteThis();
	}
	m_Data.RemoveAll();
	m_pfnCleanup = NULL;

#if defined( USE_WINDOWS_CLIPBOARD )
	if ( bClearWindowsClipboard )
	{
		if ( ::OpenClipboard( ::GetDesktopWindow() ) )
		{
			::EmptyClipboard();
			::CloseClipboard();
		}
	}
#endif
}

void CClipboardManager::SetClipboardData( CUtlVector< KeyValues * >& data, IClipboardCleanup *pfnOptionalCleanuFunction )
{
	EmptyClipboard( true );
	m_Data = data;
	m_pfnCleanup = pfnOptionalCleanuFunction;

#if defined( USE_WINDOWS_CLIPBOARD )
	if ( m_Data.Count() >= 0 )
	{
		// Only stick the first item's data into the clipboard
		char const *text = m_Data[ 0 ]->GetString( "text", "" );
		if ( text && text[ 0 ] )
		{
			int textLen = Q_strlen( text );

			if ( ::OpenClipboard( ::GetDesktopWindow() ) )
			{
				HANDLE hmem = ::GlobalAlloc(GMEM_MOVEABLE, textLen + 1);
				if (hmem)
				{
					void *ptr = ::GlobalLock( hmem );
					if ( ptr  )
					{
						Q_memset( ptr, 0, textLen + 1 );
						Q_memcpy( ptr, text, textLen );
						::GlobalUnlock( hmem );

						::SetClipboardData( CF_TEXT, hmem );
					}
				}
				::CloseClipboard();
			}
		}
	}
#endif
}

void CClipboardManager::AddToClipboardData( KeyValues *add )
{
	m_Data.AddToTail( add );
#if defined( USE_WINDOWS_CLIPBOARD )
	if ( m_Data.Count() >= 0 )
	{
		// Only stick the first item's data into the clipboard
		char const *text = m_Data[ 0 ]->GetString( "text", "" );
		if ( text && text[ 0 ] )
		{
			int textLen = Q_strlen( text );


			if ( ::OpenClipboard( ::GetDesktopWindow() ) )
			{
				::EmptyClipboard();

				HANDLE hmem = ::GlobalAlloc(GMEM_MOVEABLE, textLen + 1);
				if (hmem)
				{
					void *ptr = ::GlobalLock( hmem );
					if ( ptr  )
					{
						Q_memset( ptr, 0, textLen + 1 );
						Q_memcpy( ptr, text, textLen );
						::GlobalUnlock( hmem );

						::SetClipboardData( CF_TEXT, hmem );
					}
				}
				::CloseClipboard();
			}
		}
	}
#endif
}

void CClipboardManager::GetClipboardData( CUtlVector< KeyValues * >& data )
{
	data.RemoveAll();
	data = m_Data;
#if defined( USE_WINDOWS_CLIPBOARD )
	if ( data.Count() == 0 )
	{
		// See if windows has some text since we didn't have any internally
		if ( ::OpenClipboard( ::GetDesktopWindow() ) )
		{
			HANDLE hmem = ::GetClipboardData( CF_TEXT );
			if ( hmem )
			{
				int len = GlobalSize( hmem );
				if ( len > 0 )
				{
					void *ptr = GlobalLock(hmem);
					if ( ptr )
					{
						char buf[ 8192 ];
						len = min( len, 8191 );
						Q_memcpy( buf, ( char * )ptr, len );
						buf[ 8191 ] = 0;
						GlobalUnlock(hmem);

						KeyValues *newData = new KeyValues( "ClipBoard", "text", buf );
						data.AddToTail( newData );
					}
				}
			}
			::CloseClipboard();
		}
	}
#endif
}

bool CClipboardManager::HasClipboardData() const
{
	return m_Data.Count() > 0 ? true : false;
}