/*
 * 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 _DECAF_UTIL_CONCURRENT_THREADPOOLEXECUTOR_H_
#define _DECAF_UTIL_CONCURRENT_THREADPOOLEXECUTOR_H_

#include <decaf/lang/Runnable.h>
#include <decaf/lang/Throwable.h>
#include <decaf/util/concurrent/ThreadFactory.h>
#include <decaf/util/concurrent/BlockingQueue.h>
#include <decaf/util/concurrent/TimeUnit.h>
#include <decaf/util/concurrent/AbstractExecutorService.h>
#include <decaf/util/concurrent/RejectedExecutionHandler.h>
#include <decaf/util/concurrent/RejectedExecutionException.h>
#include <decaf/util/LinkedList.h>
#include <decaf/util/ArrayList.h>
#include <decaf/util/Config.h>

#include <vector>

namespace decaf{
namespace util{
namespace concurrent{

    using decaf::lang::Pointer;

    class ExecutorKernel;

    /**
     * Defines a Thread Pool object that implements the functionality
     * of pooling threads to perform user tasks.  The Thread Poll has
     * max size that it will grow to.  The thread pool allocates threads
     * in blocks.  When there are no waiting worker threads and a task
     * is queued then a new batch is allocated.  The user can specify
     * the size of the blocks, otherwise a default value is used.
     * <P>
     * When the user queues a task they must also queue a listener to
     * be notified when the task has completed, this provides the user
     * with a mechanism to know when a task object can be freed.
     * <P>
     * To have the Thread Pool perform a task, the user enqueue's an
     * object that implements the <code>Runnable</code> interface and
     * one of the worker threads will executing it in its thread context.
     */
    class DECAF_API ThreadPoolExecutor : public AbstractExecutorService {
    private:

        ThreadPoolExecutor( const ThreadPoolExecutor& );
        ThreadPoolExecutor& operator= ( const ThreadPoolExecutor& );

    private:

        friend class ExecutorKernel;
        ExecutorKernel* kernel;

    public:

        /**
         * Creates a new instance of a ThreadPoolExecutor.
         *
         * The executor instance is configured with the passed in parameters and a
         * default thread Factory is used along with a default rejected execution
         * handler.
         *
         * @param corePoolSize
         *      The number of threads to pool regardless of their idle state.
         * @param maxPoolSize
         *      The maximum number of threads that will ever exist at one time in the pool.
         * @param keepAliveTime
         *      The maximum time to keep a thread in the pool for if the number of current
         *      threads exceeds to core pool size.
         * @param unit
         *      The units that the keepAliveTime is specified in.
         * @param workQueue
         *      A BlockingQueue implementation that will be used to hold Runnable tasks
         *      that are awaiting execution within this executor.  The Executor takes
         *      ownership of the BlockingQueue instance passed once this method returns.
         *
         * @throws IllegalArguementException if the corePoolSize or keepAliveTime are negative
         *         or the or if maximumPoolSize is less than or equal to zero, or if corePoolSize
         *         is greater than maximumPoolSize.
         * @throws NullPointerException if the workQueue pointer is NULL.
         */
        ThreadPoolExecutor(int corePoolSize, int maxPoolSize,
                           long long keepAliveTime, const TimeUnit& unit,
                           BlockingQueue<decaf::lang::Runnable*>* workQueue);

        /**
         * Creates a new instance of a ThreadPoolExecutor.
         *
         * The executor instance is configured with the passed in parameters and a
         * default thread Factory is used along with a default rejected execution
         * handler.
         *
         * @param corePoolSize
         *      The number of threads to pool regardless of their idle state.
         * @param maxPoolSize
         *      The maximum number of threads that will ever exist at one time in the pool.
         * @param keepAliveTime
         *      The maximum time to keep a thread in the pool for if the number of current
         *      threads exceeds to core pool size.
         * @param unit
         *      The units that the keepAliveTime is specified in.
         * @param workQueue
         *      A BlockingQueue implementation that will be used to hold Runnable tasks
         *      that are awaiting execution within this executor.  The Executor takes
         *      ownership of the BlockingQueue instance passed once this method returns.
         * @param handler
         *      A RejectedExecutionHandler implementation that will be used to handle any
         *      rejected tasks when they are submitted to this executor.  The Executor takes
         *      ownership of the RejectedExecutionHandler instance passed once this method returns.
         *
         * @throws IllegalArguementException if the corePoolSize or keepAliveTime are negative
         *         or the or if maximumPoolSize is less than or equal to zero, or if corePoolSize
         *         is greater than maximumPoolSize.
         * @throws NullPointerException if the workQueue pointer is NULL.
         */
        ThreadPoolExecutor(int corePoolSize, int maxPoolSize,
                           long long keepAliveTime, const TimeUnit& unit,
                           BlockingQueue<decaf::lang::Runnable*>* workQueue,
                           RejectedExecutionHandler* handler);

        /**
         * Creates a new instance of a ThreadPoolExecutor.
         *
         * The executor instance is configured with the passed in parameters and a
         * default thread Factory is used along with a default rejected execution
         * handler.
         *
         * @param corePoolSize
         *      The number of threads to pool regardless of their idle state.
         * @param maxPoolSize
         *      The maximum number of threads that will ever exist at one time in the pool.
         * @param keepAliveTime
         *      The maximum time to keep a thread in the pool for if the number of current
         *      threads exceeds to core pool size.
         * @param unit
         *      The units that the keepAliveTime is specified in.
         * @param workQueue
         *      A BlockingQueue implementation that will be used to hold Runnable tasks
         *      that are awaiting execution within this executor.  The Executor takes
         *      ownership of the BlockingQueue instance passed once this method returns.
         * @param threadFactory
         *      A ThreadFactory implementation that will be used to create worker threads
         *      that are used by this executor to run the submitted tasks.  The Executor takes
         *      ownership of the ThreadFactory instance passed once this method returns.
         *
         * @throws IllegalArguementException if the corePoolSize or keepAliveTime are negative
         *         or the or if maximumPoolSize is less than or equal to zero, or if corePoolSize
         *         is greater than maximumPoolSize.
         * @throws NullPointerException if the workQueue pointer is NULL.
         */
        ThreadPoolExecutor(int corePoolSize, int maxPoolSize,
                           long long keepAliveTime, const TimeUnit& unit,
                           BlockingQueue<decaf::lang::Runnable*>* workQueue,
                           ThreadFactory* threadFactory);

        /**
         * Creates a new instance of a ThreadPoolExecutor.
         *
         * The executor instance is configured with the passed in parameters and a
         * default thread Factory is used along with a default rejected execution
         * handler.
         *
         * @param corePoolSize
         *      The number of threads to pool regardless of their idle state.
         * @param maxPoolSize
         *      The maximum number of threads that will ever exist at one time in the pool.
         * @param keepAliveTime
         *      The maximum time to keep a thread in the pool for if the number of current
         *      threads exceeds to core pool size.
         * @param unit
         *      The units that the keepAliveTime is specified in.
         * @param workQueue
         *      A BlockingQueue implementation that will be used to hold Runnable tasks
         *      that are awaiting execution within this executor.  The Executor takes
         *      ownership of the BlockingQueue instance passed once this method returns.
         * @param threadFactory
         *      A ThreadFactory implementation that will be used to create worker threads
         *      that are used by this executor to run the submitted tasks.  The Executor takes
         *      ownership of the ThreadFactory instance passed once this method returns.
         * @param handler
         *      A RejectedExecutionHandler implementation that will be used to handle any
         *      rejected tasks when they are submitted to this executor.  The Executor takes
         *      ownership of the BlockingQueue instance passed once this method returns.
         *
         * @throws IllegalArguementException if the corePoolSize or keepAliveTime are negative
         *         or the or if maximumPoolSize is less than or equal to zero, or if corePoolSize
         *         is greater than maximumPoolSize.
         * @throws NullPointerException if the workQueue pointer is NULL.
         */
        ThreadPoolExecutor(int corePoolSize, int maxPoolSize,
                           long long keepAliveTime, const TimeUnit& unit,
                           BlockingQueue<decaf::lang::Runnable*>* workQueue,
                           ThreadFactory* threadFactory,
                           RejectedExecutionHandler* handler);

        virtual ~ThreadPoolExecutor();

        virtual void execute(decaf::lang::Runnable* task);

        virtual void execute(decaf::lang::Runnable* task, bool takeOwnership);

        virtual void shutdown();

        virtual ArrayList<decaf::lang::Runnable*> shutdownNow();

        virtual bool awaitTermination(long long timeout, const decaf::util::concurrent::TimeUnit& unit);

        virtual bool isShutdown() const;

        virtual bool isTerminated() const;

        /**
         * Returns the number of threads that currently exists for this Executor.
         *
         * @return the configured number of Threads in the Pool.
         */
        virtual int getPoolSize() const;

        /**
         * Returns the configured number of core threads for this Executor.
         *
         * @return the configured number of core Threads.
         */
        virtual int getCorePoolSize() const;

        /**
         * Set the number of threads that this executor treats as its core threads, this value
         * will override the value set in the constructor.  If the value given is less than the
         * current value then the core threads will shrink to the new value over time.  If the
         * value is larger than the current value then new threads may be started to process
         * currently pending tasks, otherwise they will be started as needed when new tasks
         * arrive.
         *
         * @param poolSize
         *      The new core pool size for this executor.
         *
         * @throws IllegalArgumentException if the pool size value is less than zero.
         */
        virtual void setCorePoolSize(int poolSize);

        /**
         * Returns the configured maximum number of threads for this Executor.
         *
         * @return the configured maximum number of Threads.
         */
        virtual int getMaximumPoolSize() const;

        /**
         * Sets the maximum number of workers this Executor is allowed to have at any given
         * time above the core pool size.  This new value overrides any set in the constructor
         * and if smaller than the current value worker threads will terminate as they complete
         * their current tasks and become idle.
         *
         * @param maxSize
         *      The new maximum allowed worker pool size.
         *
         * @throws IllegalArgumentException if maxSize is negative or less than core pool size.
         */
        virtual void setMaximumPoolSize(int maxSize);

        /**
         * Returns the current number of pending tasks in the work queue.  This is
         * an approximation as the number of pending tasks can quickly changes as
         * tasks complete and new tasks are started.
         *
         * @return number of outstanding tasks, approximate.
         */
        virtual long long getTaskCount() const;

        /**
         * Returns an approximation of the number of threads that are currently running
         * tasks for this executor.  This value can change rapidly.
         *
         * @return the number of currently active threads.
         */
        virtual int getActiveCount() const;

        /**
         * Returns the approximate number of Tasks that have been completed by this
         * Executor, this value never decreases.
         *
         * @return the number of completed tasks since creation of the Executor.
         */
        virtual long long getCompletedTaskCount() const;

        /**
         * Returns the most Threads that have ever been active at one time within this
         * Executors Thread pool.
         *
         * @return the largest number of threads ever to coexist in this executor.
         */
        virtual int getLargestPoolSize() const;

        /**
         * Provides access to the Task Queue used by this Executor.  This method is meant mainly
         * for debugging and monitoring, care should be taken when using this method.  The executor
         * continues to execute tasks from the Queue.
         *
         * @return a pointer to the blocking queue that this executor stores future tasks in.
         */
        virtual BlockingQueue<decaf::lang::Runnable*>* getQueue();

        /**
         * Returns true if the executor has begin the process of terminating but has not yet
         * completed the process of shutting down all worker threads.  If the Executor does
         * not transition from this state to terminated after some time its generally an
         * indication that one of the submitted tasks will not complete and the executor is
         * locked in a terminating state.
         *
         * @return true if all tasks have completed after a request to shut down was made.
         */
        virtual bool isTerminating() const;

        /**
         * When true this setting allows the threads in the core pool to terminate if they
         * sit idle longer than the set keep alive time.  Core threads that terminate are
         * replaced as needed by new ones on demand.  This settings requires that the set
         * keep alive time be greater than zero and will throw an IllegalArguementException
         * if that is not the case.
         *
         * @param value
         *      Boolean value indicating if core threads are allowed to time out when idle.
         *
         * @throws IllegalArgumentException if the keep alive time is set to zero.
         */
        virtual void allowCoreThreadTimeout(bool value);

        /**
         * Returns whether this executor has been configured to allow core threads to
         * terminate if they sit idle longer than the configured keep alive time. Threads
         * that are not core threads continue to time out using the set keep alive value
         * regardless of whether this option is enabled.
         *
         * @return true if core threads can timeout when idle.
         */
        virtual bool allowsCoreThreadTimeout() const;

        /**
         * Returns the currently set value for the maximum amount of time a worker Thread
         * that is not part of the core threads is allowed to sit idle before it terminates.
         *
         * @param unit
         *      The unit of time to return the results in.
         *
         * @return the configure keep alive time in the requested time units.
         */
        virtual long long getKeepAliveTime(const TimeUnit& unit) const;

        /**
         * Configures the amount of time a non core Thread will remain alive after it has
         * completed its assigned task.  This value can also be applied to core threads if
         * the allowCoreThreadsTimeout option is enabled.
         *
         * @param timeout
         *      The amount of time an idle worker will live before terminating.
         * @param unit
         *      The units that the timeout is given in.
         *
         * @throws IllegalArgumentException if allowCoreThreadsTimeout is enabled and the
         *         the timeout value given is zero, or the timeout given is negative.
         */
        virtual void setKeepAliveTime(long long timeout, const TimeUnit& unit);

        /**
         * Sets the ThreadFactory instance used to create new Threads for this Executor.
         *
         * This class takes ownership of the given ThreadFactory and will destroy it
         * upon termination or when a new ThreadFactory is set using this method.
         *
         * @param factory
         *      A ThreadFactory instance used by this Executor to create new Threads.
         *
         * @throws NullPointerException if the given factory pointer is NULL.
         */
        virtual void setThreadFactory(ThreadFactory* factory);

        /**
         * Gets the currently configured ThreadFactory.  It is considered a programming
         * error to delete the pointer returned by this method.
         *
         * @return the currently configured ThreadFactory instance used by this object.
         */
        virtual ThreadFactory* getThreadFactory() const;

        /**
         * Gets the currently configured RejectedExecutionHandler for this Executor.
         *
         * @return a pointer to the current RejectedExecutionHandler.
         */
        virtual RejectedExecutionHandler* getRejectedExecutionHandler() const;

        /**
         * Sets the new RejectedExecutionHandler that this executor should use to process any
         * rejected Runnable tasks.  This executor takes ownership of the supplied pointer and
         * will desotroy it upon termination, any previous handler is destroyed by this call.
         *
         * @param handler
         *      The new RejectedExecutionHandler instance to use.
         *
         * @throws NullPointerException if the handler is NULL.
         */
        virtual void setRejectedExecutionHandler(RejectedExecutionHandler* handler);

        /**
         * By default a Core thread is only created once the first task is queued, this method
         * forces the creation of core thread that waits in an idle mode for new work to be
         * enqueued.  If the limit on core threads has already been reached then this method
         * returns false.
         *
         * @return true if a new core thread was added, false otherwise.
         */
        virtual bool prestartCoreThread();

        /**
         * This method will create and start new core threads running in an idle state waiting for
         * new tasks up to the set core thread limit.  When the limit is reached this method returns
         * zero to indicate no more core threads can be created.
         *
         * @return the number of core threads created, or zero if the limit has already been met.
         */
        virtual int prestartAllCoreThreads();

        /**
         * Attempts to remove the Runnable from the work queue, if successful then the caller
         * now owns the Runnable and is responsible for deleting it.
         *
         * @param task
         *      The task that is to be removed from the work queue.
         *
         * @return true if the task was removed from the Queue.
         */
        bool remove(decaf::lang::Runnable* task);

        /**
         * Attempts to remove any Future derived tasks from the pending work queue if they have
         * been canceled.  This method can be used to more quickly remove and reclaim space as
         * canceled tasks are not run but must await a worker thread to be removed normally.
         * Since there are multiple threads in operation its possible for this method to not
         * remove all canceled tasks from the work queue.
         */
        virtual void purge();

    protected:

        /**
         * Method called before a task is executed by the given thread.  The default implementation
         * of this method does nothing, however a subclass can override this method to add some
         * new functionality.
         *
         * It is recommended that a subclass call this method on its base class to ensure that
         * all base classes have a chance to process this event.
         *
         * @param thread
         *      The thread that will be executing the given task.
         * @param task
         *      The task that will be executed by the given thread.
         */
        virtual void beforeExecute(decaf::lang::Thread* thread, decaf::lang::Runnable* task);

        /**
         * Called upon completion of execution of a given task.  This method is called
         * from the Thread that executed the given Runnable.  If the Throwable pointer is
         * not NULL then its value is the Exception that caused the task to terminate.
         *
         * The base class implementation does nothing, a derived class should call this
         * method on its base class to ensure that all subclasses have a chance to process
         * the afterExecute event.
         *
         * @param task
         *      The Runnable instance that was executed by the calling Thread.
         * @param error
         *      The exception that was thrown from the given Runnable.
         */
        virtual void afterExecute(decaf::lang::Runnable* task, decaf::lang::Throwable* error);

        /**
         * Method invoked when the Executor has terminated, by default this method does
         * nothing.  When overridden the subclass should call superclass::terminated to
         * ensure that all subclasses have their terminated method invoked.
         */
        virtual void terminated();

    protected:

        /**
         * Used by some Decaf ThreadPoolExecutor extensions to correctly handle the shutdown case.
         */
        virtual void onShutdown();

    public:  // RejectedExecutionHandler implementations.

        /**
         * Handler policy for tasks that are rejected upon a call to ThreadPoolExecutor::execute
         * this class always throws a RejectedExecutionException.
         *
         * @since 1.0
         */
        class AbortPolicy : public RejectedExecutionHandler {
        public:

            AbortPolicy() : RejectedExecutionHandler() {
            }

            virtual ~AbortPolicy() {
            }

            virtual void rejectedExecution(decaf::lang::Runnable* task, ThreadPoolExecutor* executer DECAF_UNUSED) {
                delete task;
                throw RejectedExecutionException(__FILE__, __LINE__, "Unable to execute task.");
            }

        };

        /**
         * Handler policy for tasks that are rejected upon a call to ThreadPoolExecutor::execute
         * this class will attempt to run the task in the Thread that called the execute method
         * unless the executor is shutdown in which case the task is not run and is destroyed.
         *
         * @since 1.0
         */
        class CallerRunsPolicy : public RejectedExecutionHandler {
        public:

            CallerRunsPolicy() : RejectedExecutionHandler() {
            }

            virtual ~CallerRunsPolicy() {
            }

            virtual void rejectedExecution(decaf::lang::Runnable* task, ThreadPoolExecutor* executer DECAF_UNUSED) {

                if (executer->isShutdown()) {
                    delete task;
                    return;
                }

                try {
                    task->run();
                    delete task;
                } catch (decaf::lang::Exception& ex) {
                    delete task;
                    throw ex;
                }
            }
        };

        /**
         * Handler policy for tasks that are rejected upon a call to ThreadPoolExecutor::execute
         * this class always destroys the rejected task and returns quietly.
         *
         * @since 1.0
         */
        class DiscardPolicy : public RejectedExecutionHandler {
        public:

            DiscardPolicy() : RejectedExecutionHandler() {
            }

            virtual ~DiscardPolicy() {
            }

            virtual void rejectedExecution(decaf::lang::Runnable* task, ThreadPoolExecutor* executer DECAF_UNUSED) {
                delete task;
            }

        };

        /**
         * Handler policy for tasks that are rejected upon a call to ThreadPoolExecutor::execute
         * this class always destroys the oldest unexecuted task in the Queue and then attempts
         * to execute the rejected task using the passed in executor.
         *
         * @since 1.0
         */
        class DiscardOldestPolicy : public RejectedExecutionHandler {
        public:

            DiscardOldestPolicy() : RejectedExecutionHandler() {
            }

            virtual ~DiscardOldestPolicy() {
            }

            virtual void rejectedExecution(decaf::lang::Runnable* task, ThreadPoolExecutor* executer) {

                if (executer->isShutdown()) {
                    delete task;
                    return;
                }

                try {
                    decaf::lang::Runnable* oldest = NULL;
                    executer->getQueue()->poll(oldest);
                    delete oldest;

                    executer->execute(task);
                } catch (decaf::lang::Exception& ex) {
                    delete task;
                    throw ex;
                }
            }

        };

    };

}}}

#endif /*_DECAF_UTIL_CONCURRENT_THREADPOOLEXECUTOR_H_*/
