import edu.neu.ccs.demeter.dj.ClassGraph;
import edu.neu.ccs.demeter.dj.Traversal;
import java.util.List;
import java.util.Iterator;

public class Main {
	
	public static ClassGraph cg;
	public static Traversal traversal;
	public static PaperBoy paperboy;

	public static void main(String[] args) {
		BuildClassGraph();
		traversal = new Traversal("from Customer to TotalMoney", Main.cg);
		Customer customer = new Customer(2, 4 , 5);
		paperboy = new PaperBoy(customer);
		int billingAmount = 3;
		paperboy.setPayment(billingAmount);
		System.out.println("bill = " + billingAmount);

		System.out.println("Money available before = " + 
		customer.moneyAvailable(billingAmount));

		paperboy.getPay();

		System.out.println("Money available afterwards = " + 
		customer.moneyAvailable(billingAmount));
	}
	
	private static void BuildClassGraph(){
		cg = new ClassGraph(true, false);
	}
}

class Apartment {

	private Kitchen kitchen;
	private Bedroom bedroom;
	private Bathroom bathroom;

	Apartment(float inkitchen, float undermattress){
		kitchen = new Kitchen(inkitchen);
		bedroom = new Bedroom(undermattress);
		bathroom = new Bathroom();
	}
}

class Bathroom {

	public Bathroom() {
	}

}

class Bedroom {

	private Mattress mattress;

	public Bedroom(float undermattress) {
		mattress = new Mattress(undermattress);
	}

}

class Customer {

	private Wallet wallet;
	private Apartment apartment;
	
	public Customer(float inwallet, float inkitchen, float undermattress) {
		wallet = new Wallet(inwallet);
		apartment = new Apartment(inkitchen, undermattress);
	}

	public float moneyAvailable(float bill) {
		List al = Main.traversal.gather(this);

		Iterator al_it = al.iterator();
		float sum = 0;
		while(al_it.hasNext()){
			sum += ((TotalMoney)al_it.next()).getTotalMoney();
		}
		System.out.println(
		  "Total money found : " + sum);
	        return sum;
        }

	public float getPayment(float bill) {
		List al = Main.traversal.gather(this);

		Iterator al_it = al.iterator();
		float sum = 0;
		while(al_it.hasNext()){
			sum += ((TotalMoney)al_it.next()).getTotalMoney();
		}

		if(sum>=bill){
			al_it = al.iterator();
			sum = bill;
			while(sum>0){
				TotalMoney tmp = (TotalMoney)al_it.next();

				if(sum>tmp.getTotalMoney()){
				    System.out.println("money taken " + tmp.getTotalMoney());
				    sum -= tmp.getTotalMoney();
				    tmp.subtractMoney(tmp.getTotalMoney());
				}
				else{
				    System.out.println("money taken " + sum);
					tmp.subtractMoney(sum);
					sum = 0;
				}
			}
			
			return bill;
		}
		else return 0;
	}
}

class Kitchen {

	private KitchenCabinet kitchenCabinet;

	public Kitchen(float inkitchen) {
		kitchenCabinet = new KitchenCabinet(inkitchen);
	}

}

class KitchenCabinet extends PlaceWithMoney{
	
	KitchenCabinet(float money){
		totalMoney = new TotalMoney(money);
	}

	public String toString(){
		return "In Kitchen Cabinet";
	}
}

class Mattress extends PlaceWithMoney{
	
	Mattress(float money){
		totalMoney = new TotalMoney(money);
	}

	public String toString(){
		return "Under Mattress";
	}
}

class PaperBoy {
        private Customer customer;
	private float payment;

        PaperBoy(Customer c){customer = c;};
	public void setPayment(float bill){
		payment = bill;
	}

	public void getPay(){
		float paidAmount = customer.getPayment(payment);
// the following would violate the Law of Demeter
// customer.wallet.totalMoney;
// customer.apartment.bedroom.mattress.totalMoney;
// customer.apartment.kitchen.kitchenCabinet.totalMoney;
		if(paidAmount == payment) {
			System.out.println("Thank you!");
		}
		else{
			System.out.println("I will come back later!");
		}
	}

}

class PlaceWithMoney {

	protected TotalMoney totalMoney;

	public void subtractMoney(float bill){
		totalMoney.subtractMoney(bill);
	}

}

class TotalMoney {
	private float totalMoney;

	TotalMoney(float total){
		totalMoney = total;
	}

	public float getTotalMoney(){
		return totalMoney;
	}

	public void subtractMoney(float bill){
		totalMoney -= bill;
	}
}

class Wallet extends PlaceWithMoney{

	Wallet(float money){
		totalMoney = new TotalMoney(money);
	}
	
	public String toString(){
		return "In Wallet";
	}
}




