/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: CHXClientSite.cpp,v 1.9.2.3 2004/07/09 01:49:47 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#include "CHXClientSite.h"

#include "enter_hx_headers.h"
#include "hxcore.h"
#include "hxwintyp.h" /* Required for hxsite2.h */
#include "hxsite2.h"
#include "hxwin.h" // IHXStatusMessage
#include "ihxpckts.h"

#include "hxsmartptr.h"
HX_SMART_POINTER_INLINE( SPIHXSiteWindowed, IHXSiteWindowed );
HX_SMART_POINTER_INLINE( SPIHXSite2, IHXSite2 );
HX_SMART_POINTER_INLINE( SPIHXSiteTreeNavigation, IHXSiteTreeNavigation );
HX_SMART_POINTER_INLINE( SPIHXBuffer, IHXBuffer );
HX_SMART_POINTER_INLINE( SPIHXValues, IHXValues );
HX_SMART_POINTER_INLINE( SPIHXCommonClassFactory, IHXCommonClassFactory );
HX_SMART_POINTER_INLINE( SPIHXStatusMessage, IHXStatusMessage );
#include "exit_hx_headers.h"

#include "CHXClientSiteSupplier.h"
#include "CHXClientDebug.h"

CHXClientSite::CHXClientSite( UINT32 uRequestID, IHXPlayer* pIHXPlayer, CHXClientSite* pParentSite, CHXClientSiteSupplier* pSiteSupplier )
	: m_lCount( 0 )
	, m_RequestID( uRequestID )
	, m_pIHXCorePlayer( pIHXPlayer )
	, m_spISiteManager( pIHXPlayer )
	, m_pParentSite( pParentSite )
	, m_pSiteSupplier( pSiteSupplier )
	, m_IsInChangingSize( 0 )
	, m_IsInSetSize( 0 )
{
	CHXASSERT( m_spISiteManager.IsValid() ); // IHXPlayer must support IHXSiteManager.
	if ( m_pParentSite )
	{
		// Make sure this sticks around until we're destroyed. Helix cannot be relied up to destroy child sites before parents.
		m_pParentSite->AddRef();
	}
}

CHXClientSite::~CHXClientSite( void )
{
	if ( m_pParentSite )
	{
		m_pParentSite->Release();
		m_pParentSite = NULL;
	}
}

DEFINE_SINGLE_INTERFACE_COMPONENT( CHXClientSite, IHXSiteWatcher, m_lCount )

STDMETHODIMP
CHXClientSite::AttachSite( IHXSite* pSite )
{
	return HXR_OK;
}

STDMETHODIMP
CHXClientSite::DetachSite( void )
{
	return HXR_OK;
}

STDMETHODIMP
CHXClientSite::ChangingPosition( HXxPoint posOld, REF( HXxPoint ) posNew )
{
	HXxWindow* pHXxWindow = m_pSiteSupplier->GetHXxWindow();
	posNew.x = pHXxWindow->x;
	posNew.y = pHXxWindow->y;

    return HXR_OK;
}

STDMETHODIMP
CHXClientSite::ChangingSize( HXxSize sizeOld, REF( HXxSize ) sizeNew )
{
	if ( !m_IsInSetSize )
	{
		m_IsInChangingSize++;
		m_pSiteSupplier->OnChangedIdealSize( this, sizeNew );
		m_IsInChangingSize--;
	}
	HXxWindow* pHXxWindow = m_pSiteSupplier->GetHXxWindow();
	sizeNew.cx = pHXxWindow->width;
	sizeNew.cy = pHXxWindow->height;

	return HXR_OK;
}

void
CHXClientSite::TranslateSiteProperties( IHXValues* pFromSiteProps, IHXValues* pToSiteProps )
{
	if ( pFromSiteProps && pToSiteProps )
	{
		SPIHXBuffer spValue;
		if ( SUCCEEDED( pFromSiteProps->GetPropertyCString( "playto", *spValue.AsInOutParam() ) ) )
		{
			pToSiteProps->SetPropertyCString( "channel", spValue.Ptr() );
		}
		else if ( SUCCEEDED( pFromSiteProps->GetPropertyCString( "name", *spValue.AsInOutParam() ) ) )
		{
			pToSiteProps->SetPropertyCString( "LayoutGroup", spValue.Ptr() );
		}
	}
}

HX_RESULT
CHXClientSite::Create( HXxWindow* window, IHXValues* pSiteProps )
{
	HX_RESULT result = HXR_FAIL;
	
	CHXASSERT( !m_spISite.IsValid() ); // Destroy wasn't called.
	
	// Get the site windowed interface used to create/destroy or attach/detach windows to the site
	SPIHXCommonClassFactory spICCF = m_pIHXCorePlayer;
	CHXASSERT( spICCF.IsValid() ); // Where's our CommonClassFactory?
	SPIHXSiteWindowed spISiteWindowed( spICCF.Ptr(), CLSID_IHXSiteWindowed );
	CHXASSERT( spISiteWindowed.IsValid() ); // Where's our Site?
	if ( spISiteWindowed.IsValid() )
	{
		SPIHXValues spNewSiteProps = spISiteWindowed.Ptr();
		TranslateSiteProperties( pSiteProps, spNewSiteProps.Ptr() );
		if ( SUCCEEDED( spISiteWindowed->AttachWindow( window ) ) )
		{
			m_spISite = spISiteWindowed.Ptr();
			if ( m_spISite.IsValid() )
			{
				// Attach ourselves as a site user for the site container so we can handle events
				result = m_spISite->AttachWatcher( this );
				if ( SUCCEEDED( result ) )
				{
					result = m_spISiteManager->AddSite( m_spISite.Ptr() );
					if ( SUCCEEDED( result ) )
					{
						ShowSite( TRUE );
					}
				}
			}
		}
	}
	return result;
}

HX_RESULT
CHXClientSite::CreateChild( IHXValues* pSiteProps )
{
	HX_RESULT result = HXR_FAIL;
	if ( m_pParentSite && !m_spISite.IsValid() )
	{
		SPIHXSite spIParentSite = m_pParentSite->GetIHXSite();
		if ( spIParentSite.IsValid() )
		{
			result = spIParentSite->CreateChild( *m_spISite.AsInOutParam() );
			CHXASSERT( SUCCEEDED( result ) );
			
			// This code takes the site properties and transfers them to the new site with the appropriate names,
			// so the site will get hooked up to the renderers correctly.
			if ( m_spISite.IsValid() )
			{
				SPIHXValues spNewSiteProps = m_spISite.Ptr();
				TranslateSiteProperties( pSiteProps, spNewSiteProps.Ptr() );
				result = m_spISiteManager->AddSite( m_spISite.Ptr() );
				CHXASSERT( SUCCEEDED( result ) );
			}
		}
	}
	return result;
}

void
CHXClientSite::Destroy( void )
{
	if ( m_spISite.IsValid() )
	{
		HX_RESULT result;
		result = m_spISiteManager->RemoveSite( m_spISite.Ptr() );
		CHXASSERT( SUCCEEDED( result ) );
		if ( m_pParentSite )
		{
			SPIHXSite spIParentSite = m_pParentSite->GetIHXSite();
			if ( spIParentSite.IsValid() )
			{
				result = spIParentSite->DestroyChild( m_spISite.Ptr() );
				CHXASSERT( SUCCEEDED( result ) );
			}
		}
		else
		{
			m_spISite->DetachWatcher();
			SPIHXSiteWindowed spISiteWindowed = m_spISite.Ptr();
			if ( spISiteWindowed.IsValid() )
			{
				result = spISiteWindowed->DetachWindow(); // XXXSEH: Should we call Destroy() instead?
				CHXASSERT( SUCCEEDED( result ) );
			}
		}
		m_spISite.Clear();
	}
}

HX_RESULT
CHXClientSite::SetSize( const HXxSize& size )
{
	if ( m_IsInChangingSize ) return HXR_OK;
	
	HX_RESULT result = HXR_FAIL;
	if ( m_spISite.IsValid() )
	{
		m_IsInSetSize++;
		result = m_spISite->SetSize( size );
		m_IsInSetSize--;
		CHXASSERT( SUCCEEDED( result ) );
	}
	return result;
}

HX_RESULT
CHXClientSite::ShowSite( bool bShow )
{
	SPIHXSite2 spISite2 = m_spISite.Ptr();
	HX_RESULT result = spISite2.IsValid() ? spISite2->ShowSite( bShow ? 1 : 0 ) : HXR_FAIL;
	CHXASSERT( SUCCEEDED( result ) );
	return result;
}

HX_RESULT
CHXClientSite::SetStatus( const char* pStatus )
{
	HX_RESULT result = HXR_FAIL;
	if ( m_spISite.IsValid() )
	{
		SPIHXStatusMessage spIStatusMessage = m_spISite.Ptr();
		if ( spIStatusMessage.IsValid() )
		{
			result = spIStatusMessage->SetStatus( pStatus );
		}
	}
	return result;
}

void
CHXClientSite::ReDrawSite( IHXSite* pISite, const HXxRect& siteRect )
{
	CHXASSERT( pISite );
	
	SPIHXSiteTreeNavigation spISiteTreeNavigator = pISite;
	if ( spISiteTreeNavigator.IsValid() )
	{
		UINT32 numOfChildren = spISiteTreeNavigator->GetNumberOfChildSites();
		for ( UINT32 i = 0; i < numOfChildren; ++i )
		{
			SPIHXSite spIChildSite;
			if ( SUCCEEDED( spISiteTreeNavigator->GetNthChildSite( i, *spIChildSite.AsInOutParam() ) ) && spIChildSite.IsValid() )
			{
				ReDrawSite( spIChildSite.Ptr(), siteRect );
			}
		}
	}
	pISite->DamageRect( siteRect );
	pISite->ForceRedraw();
}

void
CHXClientSite::Draw( const HXxRect& siteRect )
{
	if ( m_spISite.IsValid() )
	{
		ReDrawSite( m_spISite.Ptr(), siteRect );
	}
}
