/**************************************************************
 * 
 * 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.
 * 
 *************************************************************/



#ifndef _CONNECTIVITY_ADO_COLLECTION_HXX_
#define _CONNECTIVITY_ADO_COLLECTION_HXX_

#include <cppuhelper/implbase3.hxx>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include "ado/Awrapadox.hxx"
#include "ado/Aolevariant.hxx"
#include <com/sun/star/lang/XServiceInfo.hpp>

namespace connectivity
{
	namespace ado
	{
		namespace starcontainer	= ::com::sun::star::container;
		namespace starlang		= ::com::sun::star::lang;
		namespace staruno		= ::com::sun::star::uno;
		namespace starbeans		= ::com::sun::star::beans;

		typedef ::cppu::WeakImplHelper3< starcontainer::XNameAccess,
										 starcontainer::XIndexAccess,
										 starlang::XServiceInfo> OCollectionBase;

		//************************************************************
		//  OCollection	
		//************************************************************
		template <class T,class SimT,class OCl> class OCollection : public OCollectionBase
		{
		private:
			OCollection( const OCollection& );				// never implemented
			OCollection& operator=( const OCollection& );	// never implemented

		protected:	
			vector<OCl*>							m_aElements;
			::cppu::OWeakObject&					m_rParent;
			::osl::Mutex&							m_rMutex;		// mutex of the parent
			T*										m_pCollection;
			

		public:
			OCollection(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,T* _pCollection)
					 : m_rParent(_rParent)
					 ,m_rMutex(_rMutex)
					 ,m_pCollection(_pCollection)
			{
				m_pCollection->AddRef();
			}

			~OCollection()
			{
				m_pCollection->Release();
			}

			virtual ::rtl::OUString SAL_CALL getImplementationName(  ) throw (staruno::RuntimeException)
			{
				return ::rtl::OUString::createFromAscii("com.sun.star.sdbcx.ACollection");
			}
			virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& _rServiceName ) throw(staruno::RuntimeException)
			{
				staruno::Sequence< ::rtl::OUString > aSupported(getSupportedServiceNames());
				const ::rtl::OUString* pSupported = aSupported.getConstArray();
				for (sal_Int32 i=0; i<aSupported.getLength(); ++i, ++pSupported)
					if (pSupported->equals(_rServiceName))
						return sal_True;
			
				return sal_False;
			}
			virtual staruno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames(  ) throw(staruno::RuntimeException)
			{
				staruno::Sequence< ::rtl::OUString > aSupported(1);
				aSupported[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdbcx.Container");
				return aSupported;
			}

			// dispatch the refcounting to the parent
			virtual void SAL_CALL acquire() throw()
			{
				m_rParent.acquire();
			}
			virtual void SAL_CALL release() throw()
			{
				m_rParent.release();
			}

		// ::com::sun::star::container::XElementAccess
			virtual staruno::Type SAL_CALL getElementType(  ) throw(staruno::RuntimeException)
			{
				return::getCppuType(static_cast< staruno::Reference< starbeans::XPropertySet>*>(NULL));
			}
			
			virtual sal_Bool SAL_CALL hasElements(  ) throw(staruno::RuntimeException)
			{
				::osl::MutexGuard aGuard(m_rMutex);
				return getCount() > 0;
			}
			
		// starcontainer::XIndexAccess
			virtual sal_Int32 SAL_CALL getCount(  ) throw(staruno::RuntimeException)
			{
				::osl::MutexGuard aGuard(m_rMutex);
				sal_Int32 nCnt = 0;
				m_pCollection->get_Count(&nCnt);
				return nCnt;
			}

			virtual staruno::Any SAL_CALL getByIndex( sal_Int32 Index ) throw(starlang::IndexOutOfBoundsException, starlang::WrappedTargetException, staruno::RuntimeException)
			{
				::osl::MutexGuard aGuard(m_rMutex);
				if (Index < 0 || Index >= getCount())
					throw starlang::IndexOutOfBoundsException();
				SimT* pCol = NULL;
				m_pCollection->get_Item(OLEVariant(Index),&pCol);
				if(!pCol)
					throw starlang::IndexOutOfBoundsException();

				OCl* pIndex = new OCl(pCol);

				m_aElements.push_back(pIndex);

				return staruno::makeAny( staruno::Reference< starbeans::XPropertySet >(pIndex));
			}


		// starcontainer::XNameAccess
			virtual staruno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw(starcontainer::NoSuchElementException, starlang::WrappedTargetException, staruno::RuntimeException)
			{
				::osl::MutexGuard aGuard(m_rMutex);
				
				SimT* pCol = NULL;
				m_pCollection->get_Item(OLEVariant(aName),&pCol);
				if(!pCol)
					throw starlang::IndexOutOfBoundsException();

				OCl* pIndex = new OCl(pCol);

				m_aElements.push_back(pIndex);

				return staruno::makeAny( staruno::Reference< starbeans::XPropertySet >(pIndex));
			}
			virtual staruno::Sequence< ::rtl::OUString > SAL_CALL getElementNames(  ) throw(staruno::RuntimeException)
			{
				::osl::MutexGuard aGuard(m_rMutex);
				sal_Int32 nLen = getCount();
				staruno::Sequence< ::rtl::OUString > aNameList(nLen);

				::rtl::OUString* pStringArray = aNameList.getArray();
				OLEVariant aVar;
				for (sal_Int32 i=0;i<nLen;++i)
				{
					aVar.setInt32(i);
					SimT* pIdx = NULL;
					m_pCollection->get_Item(aVar,&pIdx);
					pIdx->AddRef();
					_bstr_t sBSTR; 
					pIdx->get_Name(&sBSTR);
					(*pStringArray) = (sal_Unicode*)sBSTR;
					pIdx->Release();
					++pStringArray;
				}
				return aNameList;
			}
			virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw(staruno::RuntimeException)
			{
				::osl::MutexGuard aGuard(m_rMutex);
				SimT* pCol = NULL;
				m_pCollection->get_Item(OLEVariant(aName),&pCol);
				return pCol != NULL;
			}

			void SAL_CALL disposing()
			{
				::osl::MutexGuard aGuard(m_rMutex);
				for (::std::vector<OCl*>::const_iterator i = m_aElements.begin(); i != m_aElements.end(); ++i)
				{
					(*i)->disposing();
					(*i)->release();
				}
				m_aElements.clear();
			}

		};

		class OIndex;
		class OKey;
		class OColumn;
		class OTable;
		class OView;
		class OGroup;
		class OUser;

		typedef OCollection< ADOIndexes,ADOIndex,OIndex>	OIndexes;
		typedef OCollection< ADOKeys,ADOKey,OKey>			OKeys;
		typedef OCollection< ADOColumns,ADOColumn,OColumn>	OColumns;
		typedef OCollection< ADOTables,ADOTable,OTable>		OTables;
		typedef OCollection< ADOViews,ADOView,OView>		OViews; 
		typedef OCollection< ADOGroups,ADOGroup,OGroup>		OGroups;
		typedef OCollection< ADOUsers,ADOUser,OUser>		OUsers; 

	}
}
#endif // _CONNECTIVITY_ADO_COLLECTION_HXX_