import java.util.*;
import java.io.*;

class NegAmountException extends Exception
{
    int amount;
    NegAmountException (int amount) { super("amount = "+amount); }
}

class NegCashException extends Exception
{
    int amount;
    NegCashException (int amount) { super("missing cash = "+amount); }
}

public class FinancialHistory implements Serializable
{
    private int cashOnHand;
    private Hashtable incomes;
    private Hashtable expenditures;

    FinancialHistory (int amount) throws NegAmountException
    {
	//PRE: amount >= 0

	if (amount < 0) throw new NegAmountException(amount);
	cashOnHand = amount;
	incomes = new Hashtable();
	expenditures = new Hashtable();

	//POST: cashOnHand() = amount
	//		ReceivedFrom(s) = 0 per ogni s
	//		SpentFor(r) = 0 per ogni r
    }

    void receiveFrom (int amount, String s) throws NegAmountException
    {
	//PRE: amount >=0

	if (amount < 0) throw new NegAmountException(amount);
	cashOnHand += amount;
	Object oldTot = incomes.get(s);
	if (oldTot == null)
	    incomes.put(s,new Integer(amount));
	else
	{
            int newTot = amount + ((Integer)oldTot).intValue();
	    incomes.put(s,new Integer(newTot));
	};	

	//POST: cashOnHand() = OLD cashOnHand() + amount
	//ReceivedFrom(s) = OLD ReceivedFrom(s) + amount
	//ReceivedFrom(s') = OLD ReceivedFrom(s') per r != r'
	//SpentFor(r) = OLD SpentFor(r) per ogni r
    }

    void spendFor (int amount, String r) 
	throws NegAmountException, NegCashException
    {
	//PRE: 	amount >=0
	//	cashOnHand() - amount >= 0		

	if (amount < 0) throw new NegAmountException(amount);
	if (cashOnHand() - amount < 0) 
	    throw new NegCashException(amount-cashOnHand());
	cashOnHand -= amount;
	Object oldTot = expenditures.get(r);
	if (oldTot == null)
	    expenditures.put(r,new Integer(amount));
	else
        {
	    int newTot = amount + ((Integer)oldTot).intValue();
	    expenditures.put(r,new Integer(newTot));
	};	

	//POST: cashOnHand() = OLD cashOnHand() + amount
	//SpentFor(r) = OLD SpentFor(r) + amount
	//SpentFor(r') = OLD SpentFor(r') per r != r'
	//ReceivedFrom(s) = OLD ReceivedFrom(s) per ogni s
    }

    int cashOnHand ()
    {
	return cashOnHand;
	//POST: NOCHANGE
    }

    int ReceivedFrom (String s)
    {
	Object old = incomes.get(s);
	if (old == null) return 0;
	else return ((Integer)old).intValue();
		
	//POST: NOCHANGE
	// RESULT >= 0
    }

    int SpentFor (String r)
    {
	Object old = expenditures.get(r);
	if (old == null) return 0;
	else return ((Integer)old).intValue ();

        //POST: NOCHANGE
	// RESULT >= 0
    }

    String printIncomes()
    {
        StringBuffer sb = new StringBuffer();
	sb.append("ENTRATE DA:\n");
	Enumeration sources = incomes.keys();
	while (sources.hasMoreElements ())
        {
	    String s = (String)sources.nextElement();
	    sb.append(s + " = " + ReceivedFrom(s) + "\n"); 
	}
        return new String(sb);
    }

    String printExpenditures() 
    {
        StringBuffer sb = new StringBuffer();
	sb.append("USCITE PER:\n");
	Enumeration reasons = expenditures.keys();
	while (reasons.hasMoreElements ())
        {
	    String s = (String)reasons.nextElement();
            sb.append(s + " = " + SpentFor(s) + "\n"); 
	}
        return new String(sb);
    }

    //INV:cashOnHand()= amount iniziale  
    //					+ SUM{ReceivedFrom(s) | per ogni s} 
    //					- SUM{SpentFor(r) | per ogni r }
}


