import java.util.Random;
import java.util.Date;

class Account 
{
	private int balance;
	private Date date;
	                        
	public Account(int balance) {
		if (balance < 0) 
      this.balance = 0;
    else 
      this.balance = balance;
		date = new Date();
		System.out.println("Account created with initial balance " + this.balance + ".");
	}
	
	public synchronized void deposit(int id, int k) {
		balance += k;
		date = new Date();
		System.out.println("\nThread " + id + " completed a deposit of " + k + ".\nBalance is " + balance + " at " + date + ".");
		notifyAll();
	}
	
	public synchronized void withdraw(int id, int k) {
		while (balance < k) {
			date = new Date();
			System.out.println("\nThread " + id + " blocked trying withdrawal of " + k + ".\nBalance is " + balance + " at " + date + ".");
			try {
				wait();
			} catch (InterruptedException ie) {}
		}
		balance -= k;
		date = new Date();
		System.out.println("\nThread " + id + " completed withdrawal of " + k + ".\nBalance is " + balance + " at " + date + ".");
	}
}

public class UseAccount1 {
	Account acc;
	
	public UseAccount1() {
		Transaction trans;
		boolean transType;
		int transamt;
		Random r = new Random();
		int initbalance = r.nextInt(2000);
		acc = new Account(initbalance);

		for (int i = 0; i < 20; i++) {
			transType = r.nextBoolean();
			transamt = r.nextInt(2000);
			trans = new Transaction(i, transType, transamt);
			new Thread(trans).start();
			try {
				Thread.sleep(50);
			} catch (InterruptedException ie) {}
		}
		try {
			Thread.sleep(1000);
		} catch (InterruptedException ie) {}
		trans = new Transaction(20, true, 100000);
		new Thread(trans).start();
	}
	
	class Transaction implements Runnable {
		int id;
		boolean transType; 
		boolean pref;
		int transamt;
		public Transaction(int id, boolean transType, int transamt) {
			this.id = id;
			this.transType = transType;
			this.transamt = transamt;
		}
		
		public void run() {
			if (transType) acc.deposit(id, transamt);
			else acc.withdraw(id, transamt);
		}
	}
	
	public static void main(String[] args) {
		new UseAccount1();
	}
}
