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



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_cppu.hxx"
#include "jobqueue.hxx"
#include "threadpool.hxx"

#include <osl/diagnose.h>

using namespace ::osl;

namespace cppu_threadpool {
	
	JobQueue::JobQueue() :
		m_nToDo( 0 ),
		m_bSuspended( sal_False ),
		m_cndWait( osl_createCondition() )
	{
		osl_resetCondition( m_cndWait );		
		m_DisposedCallerAdmin = DisposedCallerAdmin::getInstance();
	}
	
	JobQueue::~JobQueue()
	{
		osl_destroyCondition( m_cndWait );
	}
		
		
	void JobQueue::add( void *pThreadSpecificData, RequestFun * doRequest )
	{
		MutexGuard guard( m_mutex );
		Job job = { pThreadSpecificData , doRequest };
		m_lstJob.push_back( job );
		if( ! m_bSuspended )
		{
			osl_setCondition( m_cndWait );
		}
		m_nToDo ++;
	}
		
	void *JobQueue::enter( sal_Int64 nDisposeId , sal_Bool bReturnWhenNoJob )
	{
		void *pReturn = 0;
		{
			// synchronize with the dispose calls
			MutexGuard guard( m_mutex );
			if( m_DisposedCallerAdmin->isDisposed( nDisposeId ) )
			{
				return 0;
			}
			m_lstCallstack.push_front( nDisposeId );
		}

		
		while( sal_True )
		{
			if( bReturnWhenNoJob )
			{
				MutexGuard guard( m_mutex );
				if( m_lstJob.empty() )
				{
					break;
				}
			}

			osl_waitCondition( m_cndWait , 0 );
			
			struct Job job={0,0};
			{
				// synchronize with add and dispose calls
				MutexGuard guard( m_mutex );

				if( 0 == m_lstCallstack.front() )
				{
					// disposed !
                    if( m_lstJob.empty() )
                    {
                        osl_resetCondition( m_cndWait );
                    }
					break;
				}

				OSL_ASSERT( ! m_lstJob.empty() );
				if( ! m_lstJob.empty() )
				{
					job = m_lstJob.front();
					m_lstJob.pop_front();
				}
				if( m_lstJob.empty() )
				{
					osl_resetCondition( m_cndWait );
				}
			}

			if( job.doRequest )
			{
				job.doRequest( job.pThreadSpecificData );
				m_nToDo --;
			}
			else
			{
				m_nToDo --;
				pReturn = job.pThreadSpecificData;
				break;
			}
		}

		{
			// synchronize with the dispose calls
			MutexGuard guard( m_mutex );
			m_lstCallstack.pop_front();
		}
		
		return pReturn;
	}
	
	void JobQueue::dispose( sal_Int64 nDisposeId )
	{
		MutexGuard guard( m_mutex );
		for( CallStackList::iterator ii = m_lstCallstack.begin() ;
			 ii != m_lstCallstack.end() ;
			 ++ii )
		{
			if( (*ii) == nDisposeId )
			{
				(*ii) = 0;
			}
		}

		if( !m_lstCallstack.empty()  && ! m_lstCallstack.front() )
		{
			// The thread is waiting for a disposed pCallerId, let it go
			osl_setCondition( m_cndWait );
		}
	}
		
	void JobQueue::suspend()
	{
		MutexGuard guard( m_mutex );
		m_bSuspended = sal_True;
	}

	void JobQueue::resume()
	{
		MutexGuard guard( m_mutex );
		m_bSuspended = sal_False;
		if( ! m_lstJob.empty() )
		{
			osl_setCondition( m_cndWait );
		}
	}

	sal_Bool JobQueue::isEmpty()
	{
		MutexGuard guard( m_mutex );
		return m_lstJob.empty();
	}

	sal_Bool JobQueue::isCallstackEmpty()
	{
		MutexGuard guard( m_mutex );
		return m_lstCallstack.empty();
	}

	sal_Bool JobQueue::isBusy()
	{
		return m_nToDo > 0;
	}


}
