import java.util.concurrent.Semaphore;

public class ProducerConsumerProblem extends MutexProblem {

	public static final int MAX_ITEMS = 10;
	
	Semaphore empty, full, mutex;
	int items;
	
	public ProducerConsumerProblem() {
		//initialize semaphores
		empty = new Semaphore(MAX_ITEMS);
		full = new Semaphore(MAX_ITEMS);
		mutex = new Semaphore(1);
		items = 0;
		//acquite the full permits
		try {
			full.acquire(MAX_ITEMS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	
	@Override
	AbstractProcess createProcess(int type) {
		if(type % 2 == 0)
			return new Producer();
		return new Consumer();
	}

	@Override
	public String toString() {
		return "items = " + items;
	}

	//Producer class
	class Producer extends AbstractProcess {
		public Producer() {
			super(0);
		}

		@Override
		protected boolean entrySection() {
			try {
				empty.acquire();
				
			} catch (InterruptedException e) {
				return false;
			}
			
			try {
				mutex.acquire();
			} catch (InterruptedException e) {
				empty.release();
				return false;
			}
			
			return true;
		}

		@Override
		protected void exitSection() {
			mutex.release();
			full.release();
		}

		@Override
		protected void criticalSection() {
			//write a message to the log window
			//access the singleton CriticalSectionSim
			CriticalSectionSim.getInstance().logMessage(
					"Producer " + getPID() + " produced an item.");
			//produced something
			items++;
		}
	}
	
	
	//Consumer class
	class Consumer extends AbstractProcess {
		public Consumer() {
			super(1);
		}

		@Override
		protected boolean entrySection() {
			try {
				full.acquire();
			} catch (InterruptedException e) {
				return false;
			}
			
			try {
				mutex.acquire();
			} catch (InterruptedException e) {
				full.release();
				return false;
			}
			return true;
		}

		@Override
		protected void exitSection() {
			mutex.release();
			empty.release();
		}

		@Override
		protected void criticalSection() {

			//write a message to the log window
			//access the singleton CriticalSectionSim
			CriticalSectionSim.getInstance().logMessage(
					"Consumer " + getPID() + " consumed an item.");
			//produced something
			items--;
		}
		
		
	}
	
}  //end class ProducerConsumerProblem

