package aku.domino.extended.example.misc;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import lotus.domino.NotesThread;

/**
 * based on
 * http://java.dzone.com/news/java-concurrency-thread-pools
 * http://tutorials.jenkov.com/java-concurrency/blocking-queues.html 
 * 
 *  @author aku
 *
 */
public class NotesExecutorService {
 private BlockingQueue queue = null;
 private List<notestask> threads = new ArrayList<notestask>();
 private boolean isStopped = false;

 public NotesExecutorService(int threadsNumber) {
  queue = new BlockingQueue(threadsNumber);
  startThreads(threadsNumber);
 }

 private void startThreads(int threadsNumber) {
  for (int i = 0; i < threadsNumber; i++) {
   threads.add(new NotesTask(queue));
  }
  
  for (NotesTask thread : threads) thread.start();
 }

 public synchronized void execute(Runnable task) throws Exception {
  if (this.isStopped) throw new IllegalStateException("ThreadPool is stopped");
  this.queue.enqueue(task);
 }

 public synchronized void shutdown() throws InterruptedException {
  this.isStopped = true;
  for (NotesTask thread : threads) {
   thread.stopThread();
   thread.join();
  }
 }

 public class NotesTask extends NotesThread {
  private BlockingQueue taskQueue = null;
  private boolean isStopped = false;

  public NotesTask(BlockingQueue queue) {
   taskQueue = queue;
  }

  @Override
  public void runNotes() {
   while (!isStopped()) {
    try {
     Runnable runnable = (Runnable) taskQueue.dequeue();
     runnable.run();
    } catch (InterruptedException ie){
     //do nothing, this is just stopping 
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }

  public synchronized void stopThread() {
   isStopped = true;
   this.interrupt(); // break pool thread out of dequeue() call.
  }

  public synchronized boolean isStopped() {
   return isStopped;
  }
 }

 private class BlockingQueue {

  @SuppressWarnings("rawtypes")
  private List queue = new LinkedList();
  private int limit = 10;

  public BlockingQueue(int limit) {
   this.limit = limit;
  }

  @SuppressWarnings("unchecked")
  public synchronized void enqueue(Object item)throws InterruptedException {
   while (this.queue.size() == this.limit) wait();
   if (this.queue.size() == 0) notifyAll();
   this.queue.add(item);
  }

  public synchronized Object dequeue() throws InterruptedException {
   while (this.queue.size() == 0) wait();
   if (this.queue.size() == this.limit) notifyAll();
   return this.queue.remove(0);
  }

 }

}