/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



//____________________________________________________________________________________________________________
//	my own includes
//____________________________________________________________________________________________________________

#include "basecontainercontrol.hxx"

//____________________________________________________________________________________________________________
//	includes of other projects
//____________________________________________________________________________________________________________
#include <cppuhelper/typeprovider.hxx>

//____________________________________________________________________________________________________________
//	includes of my own project
//____________________________________________________________________________________________________________

//____________________________________________________________________________________________________________
//	namespaces
//____________________________________________________________________________________________________________

using namespace ::cppu						;
using namespace ::osl						;
using namespace ::rtl						;
using namespace ::com::sun::star::uno		;
using namespace ::com::sun::star::lang		;
using namespace ::com::sun::star::awt		;
using namespace ::com::sun::star::container	;

namespace unocontrols{

//____________________________________________________________________________________________________________
//	construct/destruct
//____________________________________________________________________________________________________________

BaseContainerControl::BaseContainerControl( const Reference< XMultiServiceFactory >& xFactory )
	: BaseControl	( xFactory	)
	, m_aListeners	( m_aMutex	)
{
	// initialize info list for controls
	m_pControlInfoList = new IMPL_ControlInfoList ;
}

BaseContainerControl::~BaseContainerControl()
{
	impl_cleanMemory();
}

//____________________________________________________________________________________________________________
//	XInterface
//____________________________________________________________________________________________________________

Any SAL_CALL BaseContainerControl::queryInterface( const Type& rType ) throw( RuntimeException )
{
	// Attention:
	//	Don't use mutex or guard in this method!!! Is a method of XInterface.
	Any aReturn ;
	Reference< XInterface > xDel = BaseControl::impl_getDelegator();
	if ( xDel.is() == sal_True )
	{
		// If an delegator exist, forward question to his queryInterface.
		// Delegator will ask his own queryAggregation!
		aReturn = xDel->queryInterface( rType );
	}
	else
	{
		// If an delegator unknown, forward question to own queryAggregation.
		aReturn = queryAggregation( rType );
	}

	return aReturn ;
}

//____________________________________________________________________________________________________________
//	XTypeProvider
//____________________________________________________________________________________________________________

Sequence< Type > SAL_CALL BaseContainerControl::getTypes() throw( RuntimeException )
{
	// Optimize this method !
	// We initialize a static variable only one time. And we don't must use a mutex at every call!
	// For the first call; pTypeCollection is NULL - for the second call pTypeCollection is different from NULL!
	static OTypeCollection* pTypeCollection = NULL ;

	if ( pTypeCollection == NULL )
	{
		// Ready for multithreading; get global mutex for first call of this method only! see before
		MutexGuard aGuard( Mutex::getGlobalMutex() );

		// Control these pointer again ... it can be, that another instance will be faster then these!
		if ( pTypeCollection == NULL )
		{
			// Create a static typecollection ...
			static OTypeCollection aTypeCollection	(	::getCppuType(( const Reference< XControlModel		>*)NULL )	,
												  		::getCppuType(( const Reference< XControlContainer	>*)NULL )	,
														BaseControl::getTypes()
													);
			// ... and set his address to static pointer!
			pTypeCollection = &aTypeCollection ;
		}
	}

	return pTypeCollection->getTypes();
}

//____________________________________________________________________________________________________________
//	XAggregation
//____________________________________________________________________________________________________________

Any SAL_CALL BaseContainerControl::queryAggregation( const Type& aType ) throw( RuntimeException )
{
	// Ask for my own supported interfaces ...
	// Attention: XTypeProvider and XInterface are supported by OComponentHelper!
	Any aReturn	( ::cppu::queryInterface(	aType										,
									   		static_cast< XControlModel*		> ( this )	,
									   		static_cast< XControlContainer*	> ( this )
										)
				);

	// If searched interface supported by this class ...
	if ( aReturn.hasValue() == sal_True )
	{
		// ... return this information.
		return aReturn ;
	}
	else
	{
		// Else; ... ask baseclass for interfaces!
		return BaseControl::queryAggregation( aType );
	}
}

//____________________________________________________________________________________________________________
//	XControl
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::createPeer(	const	Reference< XToolkit >&		xToolkit	,
												const	Reference< XWindowPeer >&	xParent		) throw( RuntimeException )
{
	if ( getPeer().is() == sal_False )
	{
		// create own peer
		BaseControl::createPeer( xToolkit, xParent );

		// create peers at all childs
		Sequence< Reference< XControl > >	seqControlList	= getControls();
		sal_uInt32							nControls		= seqControlList.getLength();

		for ( sal_uInt32 n=0; n<nControls; n++ )
		{
			seqControlList.getArray()[n]->createPeer( xToolkit, getPeer() );
		}

		// activate new tab order
		impl_activateTabControllers();

/*
		Reference< XVclContainerPeer > xC;
		mxPeer->queryInterface( ::getCppuType((const Reference< XVclContainerPeer >*)0), xC );
		xC->enableDialogControl( sal_True );
*/

	}
}

//____________________________________________________________________________________________________________
//	XControl
//____________________________________________________________________________________________________________

sal_Bool SAL_CALL BaseContainerControl::setModel( const Reference< XControlModel >& ) throw( RuntimeException )
{
	// This object has NO model.
	return sal_False ;
}

//____________________________________________________________________________________________________________
//	XControl
//____________________________________________________________________________________________________________

Reference< XControlModel > SAL_CALL BaseContainerControl::getModel() throw( RuntimeException )
{
	// This object has NO model.
	// return (XControlModel*)this ;
	return Reference< XControlModel >();
}

//____________________________________________________________________________________________________________
//	XComponent
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::dispose() throw( RuntimeException )
{
	// Zuerst der Welt mitteilen, da� der Container wegfliegt. Dieses ist um einiges
	// schneller wenn die Welt sowohl an den Controls als auch am Container horcht

	// Ready for multithreading
	MutexGuard aGuard( m_aMutex );

	// remove listeners
	EventObject	aObject ;

	aObject.Source = Reference< XComponent > ( (XControlContainer*)this, UNO_QUERY );
	m_aListeners.disposeAndClear( aObject );

	// remove controls
	Sequence< Reference< XControl > >	seqCtrls	=	getControls();
	Reference< XControl > *				pCtrls		=	seqCtrls.getArray();
	sal_uInt32							nCtrls		=	seqCtrls.getLength();
	sal_uInt32							nMaxCount	=	m_pControlInfoList->Count();
	sal_uInt32							nCount		=	0;

	for ( nCount = 0; nCount < nMaxCount; ++nCount )
	{
		delete m_pControlInfoList->GetObject( 0 );
	}
	m_pControlInfoList->Clear();


	for ( nCount = 0; nCount < nCtrls; ++nCount )
	{
		pCtrls [ nCount ] -> removeEventListener	( static_cast< XEventListener* >( static_cast< XWindowListener* >( this ) )	) ;
		pCtrls [ nCount ] -> dispose				(		) ;
	}

	// call baseclass
	BaseControl::dispose();
}

//____________________________________________________________________________________________________________
//	XEventListener
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::disposing( const EventObject& rEvent ) throw( RuntimeException )
{
	Reference< XControl > xControl( rEvent.Source, UNO_QUERY );

	// "removeControl" remove only, when control is an active control
	removeControl( xControl );
}

//____________________________________________________________________________________________________________
//	XControlContainer
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::addControl ( const OUString& rName, const Reference< XControl > & rControl ) throw( RuntimeException )
{
	if ( !rControl.is () )
        return;

	// take memory for new item
	IMPL_ControlInfo* pNewControl = new IMPL_ControlInfo ;

	if (pNewControl!=(IMPL_ControlInfo*)0)
	{
		// Ready for multithreading
		MutexGuard aGuard (m_aMutex) ;

		// set control
		pNewControl->sName		= rName 	;
		pNewControl->xControl	= rControl	;

		// and insert in list
		m_pControlInfoList->Insert ( pNewControl, LIST_APPEND ) ;

		// initialize new control
		pNewControl->xControl->setContext		( (OWeakObject*)this	) ;
		pNewControl->xControl->addEventListener	( static_cast< XEventListener* >( static_cast< XWindowListener* >( this ) ) ) ;

		// when container has a peer ...
		if (getPeer().is())
		{
			// .. then create a peer on child
			pNewControl->xControl->createPeer ( getPeer()->getToolkit(), getPeer() ) ;
			impl_activateTabControllers () ;
		}

		// Send message to all listener
		OInterfaceContainerHelper* pInterfaceContainer = m_aListeners.getContainer( ::getCppuType((const Reference< XContainerListener >*)0) ) ;

		if (pInterfaceContainer)
		{
			// Build event
			ContainerEvent	aEvent ;

			aEvent.Source	= *this		;
			aEvent.Element <<= rControl ;

			// Get all listener
			OInterfaceIteratorHelper	aIterator (*pInterfaceContainer) ;

			// Send event
			while ( aIterator.hasMoreElements() )
			{
				((XContainerListener*)aIterator.next())->elementInserted (aEvent) ;
			}
		}
	}
}

//____________________________________________________________________________________________________________
//	XControlContainer
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::addContainerListener ( const Reference< XContainerListener > & rListener ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	m_aListeners.addInterface ( ::getCppuType((const Reference< XContainerListener >*)0), rListener ) ;
}

//____________________________________________________________________________________________________________
//	XControlContainer
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::removeControl ( const Reference< XControl > & rControl ) throw( RuntimeException )
{
	if ( rControl.is() )
	{
		// Ready for multithreading
		MutexGuard aGuard (m_aMutex) ;

		sal_uInt32 nControls = m_pControlInfoList->Count () ;

		for ( sal_uInt32 n=0; n<nControls; n++ )
		{
			// Search for right control
			IMPL_ControlInfo* pControl = m_pControlInfoList->GetObject (n) ;
			if ( rControl == pControl->xControl )
			{
				//.is it found ... remove listener from control
				pControl->xControl->removeEventListener	(static_cast< XEventListener* >( static_cast< XWindowListener* >( this ) )) ;
				pControl->xControl->setContext			( Reference< XInterface >  ()	) ;

				// ... free memory
				delete pControl ;
				m_pControlInfoList->Remove (n) ;

				// Send message to all other listener
				OInterfaceContainerHelper * pInterfaceContainer = m_aListeners.getContainer( ::getCppuType((const Reference< XContainerListener >*)0) ) ;

				if (pInterfaceContainer)
				{
					ContainerEvent	aEvent ;

					aEvent.Source	 = *this	;
					aEvent.Element <<= rControl	;

					OInterfaceIteratorHelper	aIterator (*pInterfaceContainer) ;

					while ( aIterator.hasMoreElements() )
					{
						((XContainerListener*)aIterator.next())->elementRemoved (aEvent) ;
					}
				}
				// Break "for" !
				break ;
			}
		}
	}
}

//____________________________________________________________________________________________________________
//	XControlContainer
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::removeContainerListener ( const Reference< XContainerListener > & rListener ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	m_aListeners.removeInterface ( ::getCppuType((const Reference< XContainerListener >*)0), rListener ) ;
}

//____________________________________________________________________________________________________________
//	XControlContainer
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::setStatusText ( const OUString& rStatusText ) throw( RuntimeException )
{
	// go down to each parent
	Reference< XControlContainer > 	xContainer ( getContext(), UNO_QUERY ) ;

	if ( xContainer.is () )
	{
		xContainer->setStatusText ( rStatusText ) ;
	}
}

//____________________________________________________________________________________________________________
//	XControlContainer
//____________________________________________________________________________________________________________

Reference< XControl > SAL_CALL BaseContainerControl::getControl ( const OUString& rName	) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard	aGuard ( Mutex::getGlobalMutex() ) ;

	Reference< XControl >  xRetControl	=	Reference< XControl >  		() ;
	sal_uInt32				nControls	=	m_pControlInfoList->Count	() ;

	// Search for right control
	for( sal_uInt32 nCount = 0; nCount < nControls; ++nCount )
	{
		IMPL_ControlInfo* pSearchControl = m_pControlInfoList->GetObject ( nCount ) ;

		if ( pSearchControl->sName == rName )
		{
			// We have found it ...
			// Break operation and return.
			return pSearchControl->xControl ;
		}
	}

	// We have not found it ... return NULL.
	return Reference< XControl >  () ;
}

//____________________________________________________________________________________________________________
//	XControlContainer
//____________________________________________________________________________________________________________

Sequence< Reference< XControl > > SAL_CALL BaseContainerControl::getControls () throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard	aGuard ( Mutex::getGlobalMutex() ) ;

	sal_uInt32							nControls		= m_pControlInfoList->Count ()	;
	Sequence< Reference< XControl > >	aDescriptor		( nControls )					;
	Reference< XControl > *				pDestination	= aDescriptor.getArray ()		;
	sal_uInt32							nCount			= 0								;

	// Copy controls to sequence
	for( nCount = 0; nCount < nControls; ++nCount )
	{
		IMPL_ControlInfo* pCopyControl = m_pControlInfoList->GetObject ( nCount ) ;
		pDestination [ nCount ] = pCopyControl->xControl ;
	}

	// Return sequence
	return aDescriptor ;
}

//____________________________________________________________________________________________________________
//	XUnoControlContainer
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::addTabController ( const Reference< XTabController > & rTabController ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard (m_aMutex) ;

	sal_uInt32									nOldCount	= m_xTabControllerList.getLength () ;
	Sequence< Reference< XTabController >  >	aNewList	( nOldCount + 1 ) 					;
	sal_uInt32									nCount		= 0									;

	// Copy old elements of sequence to new list.
	for ( nCount = 0; nCount < nOldCount; ++nCount )
	{
		aNewList.getArray () [nCount] = m_xTabControllerList.getConstArray () [nCount] ;
	}

	// Add new controller
	aNewList.getArray () [nOldCount] = rTabController ;

	// change old and new list
	m_xTabControllerList = aNewList ;
}

//____________________________________________________________________________________________________________
//	XUnoControlContainer
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::removeTabController ( const Reference< XTabController > & rTabController ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard (m_aMutex) ;

	sal_uInt32	nMaxCount	= m_xTabControllerList.getLength ()	;
	sal_uInt32	nCount		= 0									;

	// Search right tabcontroller ...
	for ( nCount = 0; nCount < nMaxCount; ++nCount )
	{
		if ( m_xTabControllerList.getConstArray () [nCount] == rTabController )
		{
			// ... if is it found ... remove it from list.
			m_xTabControllerList.getArray()[ nCount ] = Reference< XTabController >() ;
			break ;
		}
	}
}

//____________________________________________________________________________________________________________
//	XUnoControlContainer
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::setTabControllers ( const Sequence< Reference< XTabController >  >& rTabControllers ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard (m_aMutex) ;

	m_xTabControllerList = rTabControllers ;
}

Sequence<Reference< XTabController > > SAL_CALL BaseContainerControl::getTabControllers () throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard (m_aMutex) ;

	return m_xTabControllerList ;
}

//____________________________________________________________________________________________________________
//	XWindow
//____________________________________________________________________________________________________________

void SAL_CALL BaseContainerControl::setVisible ( sal_Bool bVisible ) throw( RuntimeException )
{
	// override baseclass definition
	BaseControl::setVisible ( bVisible ) ;

	// is it a top window ?
	if ( !getContext().is() && bVisible )
	{
		// then show it automaticly
		createPeer ( Reference< XToolkit > (), Reference< XWindowPeer > () ) ;
	}
}

//____________________________________________________________________________________________________________
//	protected method
//____________________________________________________________________________________________________________

WindowDescriptor* BaseContainerControl::impl_getWindowDescriptor ( const Reference< XWindowPeer > & rParentPeer )
{
	// - used from "createPeer()" to set the values of an WindowDescriptor !!!
	// - if you will change the descriptor-values, you must override thid virtuell function
	// - the caller must release the memory for this dynamical descriptor !!!

	WindowDescriptor	*	aDescriptor	= new WindowDescriptor ;

	aDescriptor->Type				= WindowClass_CONTAINER								;
	aDescriptor->WindowServiceName	= OUString(RTL_CONSTASCII_USTRINGPARAM("window"))	;
	aDescriptor->ParentIndex		= -1												;
	aDescriptor->Parent				= rParentPeer										;
	aDescriptor->Bounds				= getPosSize ()										;
	aDescriptor->WindowAttributes	= 0													;

	return aDescriptor ;
}

//____________________________________________________________________________________________________________
//	protected method
//____________________________________________________________________________________________________________

void BaseContainerControl::impl_paint ( sal_Int32 /*nX*/, sal_Int32 /*nY*/, const Reference< XGraphics > & /*rGraphics*/ )
{
/*
	if (rGraphics.is())
	{
		for ( sal_uInt32 n=m_pControlInfoList->Count(); n; )
		{
			ControlInfo* pSearchControl = m_pControlInfoList->GetObject (--n) ;

			pSearchControl->xControl->paint ( nX, nY, rGraphics ) ;
		}
	}
*/
}

//____________________________________________________________________________________________________________
//	private method
//____________________________________________________________________________________________________________

void BaseContainerControl::impl_activateTabControllers ()
{
	// Ready for multithreading
	MutexGuard aGuard (m_aMutex) ;

	sal_uInt32	nMaxCount	=	m_xTabControllerList.getLength ()	;
	sal_uInt32	nCount		=	0									;

	for ( nCount = 0; nCount < nMaxCount; ++nCount )
	{
 		m_xTabControllerList.getArray () [nCount]->setContainer		( this	) ;
 		m_xTabControllerList.getArray () [nCount]->activateTabOrder	(		) ;
	}
}

//____________________________________________________________________________________________________________
//	private method
//____________________________________________________________________________________________________________

void BaseContainerControl::impl_cleanMemory ()
{
	// Get count of listitems.
	sal_uInt32	nMaxCount	=	m_pControlInfoList->Count ()	;
	sal_uInt32	nCount		=	0								;

	// Delete all items.
	for ( nCount = 0; nCount < nMaxCount; ++nCount )
	{
		// Delete everytime first element of list!
		// We count from 0 to MAX, where "MAX=count of items" BEFORE we delete some elements!
		// If we use "GetObject ( nCount )" ... it can be, that we have an index greater then count of current elements!

		IMPL_ControlInfo* pSearchControl = m_pControlInfoList->GetObject ( 0 ) ;
		delete pSearchControl ;
	}

	// Delete list himself.
	m_pControlInfoList->Clear () ;
	delete m_pControlInfoList ;
}

} // namespace unocontrols