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


#include <hash_map>

#include <osl/conditn.h>

#include <rtl/byteseq.hxx>

#include <boost/shared_ptr.hpp>

#include "jobqueue.hxx"


using namespace ::rtl;
namespace cppu_threadpool {
	class ORequestThread;

	struct EqualThreadId
	{
		sal_Int32 operator () ( const ::rtl::ByteSequence &a , const ::rtl::ByteSequence &b ) const
			{
				return a == b;
			}
	};

	struct HashThreadId
	{
		sal_Int32 operator () ( const ::rtl::ByteSequence &a  )  const 
			{
				if( a.getLength() >= 4 )
				{
					return *(sal_Int32 *)a.getConstArray();
				}
				return 0;
			}
	};

	typedef	::std::hash_map
	<
	    ByteSequence, // ThreadID 
		::std::pair < JobQueue * , JobQueue * >,
		HashThreadId,
		EqualThreadId
	> ThreadIdHashMap;

	typedef	::std::list	< sal_Int64 > DisposedCallerList;

	
	struct WaitingThread
	{
		oslCondition condition;
		ORequestThread *thread;
	};
	
	typedef	::std::list	< struct ::cppu_threadpool::WaitingThread * > WaitingThreadList;

	class DisposedCallerAdmin;
	typedef boost::shared_ptr<DisposedCallerAdmin> DisposedCallerAdminHolder;
	
	class DisposedCallerAdmin
	{
	public:
		~DisposedCallerAdmin();
		
		static DisposedCallerAdminHolder getInstance();

		void dispose( sal_Int64 nDisposeId );
		void stopDisposing( sal_Int64 nDisposeId );
		sal_Bool isDisposed( sal_Int64 nDisposeId );

	private:
		::osl::Mutex m_mutex;
		DisposedCallerList m_lst;
	};

	class ThreadPool;
	typedef boost::shared_ptr<ThreadPool> ThreadPoolHolder;

	class ThreadPool
	{
	public:
		ThreadPool();
		~ThreadPool();
		static ThreadPoolHolder getInstance();
		
		void dispose( sal_Int64 nDisposeId );
		void stopDisposing( sal_Int64 nDisposeId );
		
		void addJob( const ByteSequence &aThreadId,
					 sal_Bool bAsynchron,
					 void *pThreadSpecificData,
					 RequestFun * doRequest );

		void prepare( const ByteSequence &aThreadId );
		void * enter( const ByteSequence &aThreadId, sal_Int64 nDisposeId );

		/********
		 * @return true, if queue could be succesfully revoked.
		 ********/
		sal_Bool revokeQueue( const ByteSequence & aThreadId , sal_Bool bAsynchron );
		
		void waitInPool( ORequestThread *pThread );
	private:
		void createThread( JobQueue *pQueue, const ByteSequence &aThreadId,	sal_Bool bAsynchron);

		
		ThreadIdHashMap m_mapQueue;
		::osl::Mutex m_mutex;
		
		::osl::Mutex m_mutexWaitingThreadList;
		WaitingThreadList m_lstThreads;

		DisposedCallerAdminHolder m_DisposedCallerAdmin;
	};

} // end namespace cppu_threadpool
