/* **********************************
 *   AccountUpdater.java
 *     AccountUpdater
 * **********************************/
package admin.utils;

import edu.neu.ccs.demeterf.*;
import edu.neu.ccs.demeterf.demfgen.lib.List;
import gen.*;
import utils.ListTUCombiner;

/** Class for updating the accounts */
public class AccountUpdater{

    /** Returns a list of new accounts that are updated after a round */
    public static Accounts updateAccounts(Accounts old, PlayerTransaction trans){
        List<Pair<PlayerID, Double>> change = changes(trans.transactions, trans.player);
        return change.fold(new List.Fold<Pair<PlayerID,Double>, Accounts>(){
            public Accounts fold(Pair<PlayerID,Double> ch, Accounts accs){ return accs.update(ch); }
        }, old);
    }
    /** Simple helper method... */
    static List<Pair<PlayerID, Double>> changes(List<Transaction> trans, Player p){
        return TUCombiner.traverse(trans, new AccountChanges(p),
                Control.builtins(TransactionType.class,Derivative.class));
    }
    /** Create a Pair for the Store/Accounts */
    static Pair<PlayerID,Double> pair(PlayerID pid, Double d){ return new Pair<PlayerID,Double>(pid,d); }

    /** Calculate the Account changes for each Transaction */
    static class AccountChanges extends ListTUCombiner<Pair<PlayerID, Double>>{
        Player player;
        AccountChanges(Player p){ player = p; }
        TransactionType combine(TransactionType t){ return t; }
        List<Pair<PlayerID, Double>> combine(Transaction t, TransactionType tt){ return combine(); }
        
        @SuppressWarnings("unchecked")
		List<Pair<PlayerID, Double>> combine(Transaction trans, Buy b) {
            //deduct from account of buyer, add to the account of seller
            return List.create(
                    pair(player.id, -trans.deriv.price.val),
                    pair(trans.deriv.seller, trans.deriv.price.val));
        }

        @SuppressWarnings("unchecked")
		List<Pair<PlayerID, Double>> combine(Transaction trans, Finish f){
            //add to the account of buyer, deduct from the account of seller
            return List.create(
                    pair(player.id, trans.deriv.optfinished.inner().quality.val),
                    pair(trans.deriv.seller, -trans.deriv.optfinished.inner().quality.val));        
        }
    }
}