/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: CHXClientSiteSupplier.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 "CHXClientSiteSupplier.h"
#include "CHXClientSite.h"
#include "CHXFlatArray.h"
#include "CHXClientDebug.h"

CHXClientSiteSupplier::~CHXClientSiteSupplier( void )
{
	CHXASSERT( !m_pSiteContainer ); // Why hasn't the site container been destroyed?
	CHXASSERT( !m_pSites );
}

CHXClientSiteSupplier::CHXClientSiteSupplier( IHXPlayer* pIHXPlayer, HXxWindow* pHXxWindow, void* userInfo, const HXClientCallbacks* pClientCallbacks )
	: m_lCount( 0 )
	, m_pIHXCorePlayer( pIHXPlayer )
	, m_pHXxWindow( pHXxWindow )
	, m_UserInfo( userInfo )
	, m_pClientCallbacks( pClientCallbacks )
	, m_pSiteContainer( NULL )
	, m_pSites( NULL )
	, m_HadVisualContent( false )
{
	m_IdealSize.cx = 0;
	m_IdealSize.cy = 0;
}

DEFINE_SINGLE_INTERFACE_COMPONENT( CHXClientSiteSupplier, IHXSiteSupplier, m_lCount )

STDMETHODIMP
CHXClientSiteSupplier::SitesNeeded( UINT32 uRequestID, IHXValues* pSiteProps )
{
	// Make sure we have some site properties or we can't provide a site. (It won't get hooked up correctly)
	if ( !pSiteProps ) return HXR_INVALID_PARAMETER;
	if ( !m_pHXxWindow ) return HXR_FAIL; // We need a HXxWindow managed by the caller?
	
	HX_RESULT result = HXR_FAIL;
		
	// If this is the first site we are creating we need to create the site container
	if ( !m_pSiteContainer )
	{
		m_pSiteContainer = new CHXClientSite( uRequestID, m_pIHXCorePlayer, NULL, this );
		m_pSiteContainer->AddRef();
		result = m_pSiteContainer->Create( m_pHXxWindow, pSiteProps );
		if ( SUCCEEDED( result ) )
		{
			if ( !m_HadVisualContent )
			{
				m_HadVisualContent = true;
				if ( m_pClientCallbacks->OnVisualStateChanged )
				{
					m_pClientCallbacks->OnVisualStateChanged( m_UserInfo, m_HadVisualContent );
				}
			}
		}
		else
		{
			m_pSiteContainer->Release();
			m_pSiteContainer = NULL;
		}
	}
	// XXXSEH: Does this section even get hit anymore? For what type of content?
	else
	{
		// Create the site object and if it is successfully created then add it to our map of sites.
		// This site is created as a child inside the site container
		CHXClientSite* pSite = new CHXClientSite( uRequestID, m_pIHXCorePlayer, m_pSiteContainer, this );
		pSite->AddRef();
		result = pSite->CreateChild( pSiteProps );
		if ( SUCCEEDED( result ) )
		{
			if ( !m_pSites )
			{
				m_pSites = new CHXFlatArray(sizeof(pSite));
			}
			if (  m_pSites )
			{
				m_pSites->Push( &pSite );
			}
			else
			{
				result = HXR_OUTOFMEMORY;
			}
		}
		if ( FAILED( result ) )
		{
			pSite->Release();
			pSite = NULL;
		}
	}
	return result;
}

STDMETHODIMP
CHXClientSiteSupplier::SitesNotNeeded( UINT32 uRequestID )
{
	if ( m_pSiteContainer && ( uRequestID == m_pSiteContainer->GetRequestID() ) )
	{
		m_pSiteContainer->Destroy();
		m_pSiteContainer->Release();
		m_pSiteContainer = NULL;
		m_IdealSize.cx = 0;
		m_IdealSize.cy = 0;
		
		// Don't notify callbacks of a visual state change yet. Wait until DoneChangeLayout()
		// in case we're transitioning between two pieces of visual content.
		return HXR_OK;
	}
	else
	{
		// Find the site object that matches this request id, remove it from the map, destroy it and release the memory
		if ( m_pSites )
		{
			UINT32 numOfSites = m_pSites->GetCount();
			for ( UINT32 index = 0; index < numOfSites; ++index )
			{
				CHXClientSite* pSite = NULL;
				m_pSites->GetAt( index, &pSite );
				CHXASSERT( pSite );
				if ( uRequestID == pSite->GetRequestID() )
				{
					m_pSites->Remove( index );
					if ( m_pSites->IsEmpty() )
					{
						delete m_pSites;
						m_pSites = NULL;
					}
					pSite->Destroy();
					pSite->Release();
					pSite = NULL;
					return HXR_OK;
				}
			}
		}
	}
	return HXR_INVALID_PARAMETER;
}

STDMETHODIMP
CHXClientSiteSupplier::BeginChangeLayout( void )
{
	return HXR_OK;
}

STDMETHODIMP
CHXClientSiteSupplier::DoneChangeLayout( void )
{
	bool hasVisualContent = ( NULL != m_pSiteContainer );
	if ( hasVisualContent != m_HadVisualContent )
	{
		m_HadVisualContent = hasVisualContent;
		if ( m_pClientCallbacks->OnVisualStateChanged )
		{
			m_pClientCallbacks->OnVisualStateChanged( m_UserInfo, m_HadVisualContent );
		}
	}
	return HXR_OK;
}

void
CHXClientSiteSupplier::OnChangedIdealSize( CHXClientSite* pSite, const HXxSize& newIdealSiteSize )
{
	if ( ( pSite == m_pSiteContainer ) &&
		 ( ( m_IdealSize.cx != newIdealSiteSize.cx ) || ( m_IdealSize.cy != newIdealSiteSize.cy ) ) )
	{
		m_IdealSize = newIdealSiteSize;
		if ( m_pClientCallbacks->OnIdealSizeChanged )
		{
			m_pClientCallbacks->OnIdealSizeChanged( m_UserInfo, m_IdealSize.cx, m_IdealSize.cy );
		}
	}
}

void
CHXClientSiteSupplier::SetSize( const HXxSize& siteSize )
{
	if ( m_pSiteContainer )
	{
		m_pSiteContainer->SetSize( siteSize );
	}
}

bool
CHXClientSiteSupplier::SetStatus( const char* pStatus )
{
	return m_pSiteContainer ? ( ( 0 != SUCCEEDED( m_pSiteContainer->SetStatus( pStatus ) ) ) ? true : false ) : false;
}

void
CHXClientSiteSupplier::DrawSite( const HXxRect& siteRect )
{
	if ( m_pSiteContainer )
	{
		m_pSiteContainer->Draw( siteRect );
	}
}

SPIHXVideoControl
CHXClientSiteSupplier::GetVideoControl( void ) const
{
	SPIHXVideoControl spVideoControl;
	if ( m_pSiteContainer )
	{
		spVideoControl = m_pSiteContainer->GetIHXSite().Ptr();
	}
	return spVideoControl;
}
