package org.jfox.framework.management.http;

import java.util.Stack;

/**
 * @author <a href="mailto:yangyong@ufsoft.com.cn">Young Yang</a>
 */

public class ThreadPool {

    /**
     * Stack of idle threads cached for future use.
     */
    private final Stack pool = new Stack();

    /**
     * Maximum number of idle threads cached in this pool.
     */
    private int maxSize = 3;

    private boolean enabled = false;

    /**
     * Create a new pool.
     */
    public ThreadPool() {

    }

    // Public --------------------------------------------------------
    public synchronized void enable() {
        enabled = true;
    }

    public synchronized void disable() {
        enabled = false;
        while(!pool.isEmpty()) {
            Worker w = (Worker) pool.pop();
            w.die();
        } // end of while ()
    }

    /**
     * Set the maximum number of idle threads cached in this pool.
     */
    public void setMaximumSize(int size) {
        maxSize = size;
    }

    /**
     * Do some work.
     * This will either create a new thread to do the work, or
     * use an existing idle cached thread.
     */
    public synchronized void run(Runnable work) {
        if(pool.size() == 0) {
            new Worker(work);
        }
        else {
            Worker w = (Worker) pool.pop();
            w.run(work);
        }
    }

    /**
     * Return an idle worker thread to the pool of cached idle threads.
     * This is called from the worker thread itself.
     */
    private synchronized void returnWorker(Worker w) {
        if(enabled && pool.size() < maxSize) {
            pool.push(w);
        }
        else {
            w.die();
        } // end of else
    }

    class Worker extends Thread {
        /**
         * Flags that this worker may continue to work.
         */
        boolean running = true;

        /**
         * Work to do, of <code>null</code> if no work to do.
         */
        Runnable work;

        /**
         * Create a new Worker to do some work.
         */
        Worker(Runnable work) {
            this.work = work;
            setName("ManagementHttpServer worker thread");
            setDaemon(false);
            start();
        }

        /**
         * Tell this worker to die.
         */
        public synchronized void die() {
            running = false;
            this.notify();
        }

        /**
         * Give this Worker some work to do.
         *
         * @throws IllegalStateException If this worker already
         *                               has work to do.
         */
        public synchronized void run(Runnable work) {
            if(this.work != null)
                throw new IllegalStateException("Worker already has work to do.");
            this.work = work;
            this.notify();
        }

        /**
         * The worker loop.
         */
        public void run() {
            while(running) {
                // If work is available then execute it
                if(work != null) {
                    try {
                        work.run();
                    }
                    catch(Exception e) {
                        e.printStackTrace();
                        //DEBUG Logger.exception(e);
                    }
                    // Clear work
                    work = null;
                }

                // Return to pool of cached idle threads
                returnWorker(this);

                // Wait for more work to become available
                synchronized(this) {
                    while(running && work == null) {
                        try {
                            this.wait();
                        }
                        catch(InterruptedException e) {
                            // Ignore
                        }
                    }
                }
            }
        }
    }
}
