class Monitor
{
	private int readers; //specifies number of consumers reading
	private boolean writing; //specifies if something is writing
	private Condition OK_to_Read, OK_to_Write;
	
	public Monitor()
	{
		readers = 0;
		writing = false;
		OK_to_Read = new Condition();
		OK_to_Write = new Condition();
	}
	
	public synchronized void Start_Read()
	{
		
		 System.out.println("entered start read");
		if(writing || OK_to_Write.is_non_empty())
		{
			try{
				
	  System.out.println("Reader is waiting");
		OK_to_Read.wait_();
			}catch(InterruptedException e){}
		}
		
		readers +=1;
		OK_to_Read.release_all();
		
	}
	
	public synchronized void End_Read()
	{
		
			System.out.println("entered end read");
			readers -=1;
			if(readers==0)
			{
				OK_to_Write.release_one();
			}
	
	}

	public synchronized void Start_Write()
	{
		System.out.println("entered start write");
		if(readers!=0 || writing)
		{
			try{
				System.out.println("Writer is waiting");
				OK_to_Write.wait_();
					}catch(InterruptedException e){}
		}
		
		writing = true;
		
	}
	
	public synchronized void End_Write()
	{

		System.out.println("entered end write");
		writing = false;
		if(OK_to_Read.is_non_empty())
		{
			OK_to_Read.release_all();
		}
		else
		{
			OK_to_Write.release_one();
		}
	
	}
	
}

 class Condition
 {
    private int number;//specifies the number of readers/writers waiting

    /** Create a new condition variable*/
    public Condition()
    { 
    	number = 0; 
    }

     /** See if their is anyone waiting.
     */
    public synchronized boolean is_non_empty()  
    { 
    	if(number == 0)
    	{
    		return false; 
    	}
    	else
    	{
    		return true;
    	}
    }

     /** Release all waiting threads and number waiting is zero
      */
     public synchronized void release_all()
     { 
     	number = 0;
     	notifyAll(); 
     }

     /** Release one waiting thread and decrement number waiting
      */
     public synchronized void release_one()
     { 
     	number -=1;
     	notify(); 
     }

    /** Wait (potentially forever) for the condition to become true.
      */
     public synchronized void wait_() throws InterruptedException
     {  
     		
     		number++;
     		wait();
     	
     }
     
 }




class Consumer extends Thread
{

	private Monitor M;
	private String value;
	public Consumer(String name,Monitor c)
	{
		super(name);
		M=c;
	}
	
	public void run()
	{
		while(true)	//loops
		{
			   
				M.Start_Read();
				System.out.println("Consumer "+getName()+" is retreiving data...");
				M.End_Read();
		}
		
	}
}

class Producer extends Thread
{

	private Monitor M;
	private int value;
	public Producer(String name, Monitor d)
	{
		super(name);
		M = d;
	
	}
	
	public void run()
	{
		while(true)	//loops
		{
				M.Start_Write();
				System.out.println("Producer "+getName()+" is writing data...");
				M.End_Write();
			
		}
		
	}
}

class mainClass
{
	public static void main(String [] args)
	{
	
		Monitor M = new Monitor();
		
		Consumer consumer1 = new Consumer("1",M);
	
		Producer producer1 = new Producer("1",M);
	
		
		producer1.start();
	
		consumer1.start();
		
	}


}


