//
// Un'altra soluzione al deadlock
//

class BankAccount {
		
        public BankAccount() {
		this(0.0);
	}
	
	public BankAccount(double aBalance) {
		balance = aBalance;
	}
	
	public synchronized void deposit(double amount) {
		balance += amount;
	}
	public synchronized void withdraw(double amount) {
		balance -= amount;
	}
	public synchronized double getBalance() {
		return balance; 
	}
	
    public void transfer(BankAccount other, double amount) {
	// transfer non e' synchronized
	// a ben vedere il thread non ha bisogno di entrambe le risorse
	// contemporaneamente (not hold-and-wait)

	this.withdraw(amount);
	other.deposit(amount);
    }

	
	private static synchronized int setAccountNumber() {
		return accountCounter++;
	}
	
	public synchronized int getAccountNumber() {
		return accountNumber;
	}

	public String toString() {
		return "[accountNumber = " + accountNumber + "; balance = " + balance + "]";
	}

	private static int accountCounter = 0;
	private final int accountNumber = setAccountNumber();
	private double balance = 0;

}

class Cashier extends Thread {
	
    private BankAccount src, dst;
    private double amount;
    
    public  Cashier(String name, BankAccount aSrc, BankAccount aDst, double anAmount) {
    	super(name);
		src = aSrc;
		dst = aDst;
		amount = anAmount;
    }
	
    public void run() {
			System.out.println(getName() + " begin ");
			src.transfer(dst, amount); 
			System.out.println(getName() + " end ");
    }
    
}


public class DeadlockSolved {
	

    public static void main(String[] args) throws InterruptedException {
	
    	BankAccount pippo = new BankAccount(1000);
    	BankAccount pluto = new BankAccount(1000);

		System.out.println(pippo);
		System.out.println(pluto);
    	
    	Cashier t1 = new Cashier("Cassiere 1", pippo, pluto, 50);
 	 	Cashier t2 = new Cashier("Cassiere 2", pluto, pippo, 75);
    	
    	t1.start();
    	t2.start();
    	
    	t1.join();
    	t2.join();

		System.out.println(pippo);
		System.out.println(pluto);

   	
    }
    
}
