/* **********************************
 *   StoreUpdater.java
 *     StoreUpdater
 * **********************************/
package sdg.admin.utils;

import sdg.local.utils.DerivativesFinder;
import sdg.local.utils.ListTUCombiner;
import sdg.local.utils.comparator.SameDerivative;
import edu.neu.ccs.demeterf.*;
import edu.neu.ccs.demeterf.demfgen.lib.List;
import gen.*;

/** Class for updating the store after each player transaction */
public class StoreUpdater extends ListTUCombiner<Pair<PlayerID, PlayerStore>>{    
    private PlayerID pID;
    Pair<PlayerID, PlayerStore> playerStore;
    private Store store;
    private Player p;
    
    public StoreUpdater(Player player, Store st)
    {
    	store = st;
    	pID = player.id;
    	p = player;
    }
    
    static List<Derivative> empty = List.create();
    Pair<PlayerID, PlayerStore> getPlayerStore(){
        // Lookup the player's stuff...
        if(!store.contains(pID))
            store = store.add(new Pair<PlayerID, PlayerStore>(pID, new PlayerStore(empty,empty)));
        return store.getStorePair(pID);
    }
    
    public static Store updateStore(Store store, PlayerTransaction pTrans)
    {
        StoreUpdater update = new StoreUpdater(pTrans.player, store);
        TUCombiner.traverse(pTrans, update,
                Control.builtins(Derivative.class,Transaction.class));
        return update.store;
    }

    @SuppressWarnings("unchecked")
	List<Pair<PlayerID, PlayerStore>> combine(BuyTrans trans)
	{
    	Derivative d = DerivativesFinder.derByName(store, trans.derivativeName());
        //include the bought der in the bought store of the player
        Pair<PlayerID, PlayerStore> pStore = getPlayerStore();
        pStore.b.bought = pStore.b.bought.push(d.buy(pID));
        
        //remove the bought der from the forSale store of the seller
        Pair<PlayerID, PlayerStore> pStore2 = store.getStorePair(d.seller);
        pStore2.b.forSale = pStore2.b.forSale.remove(new SameDerivative(d));
        
        //make changes to the store
        store = store.replace(pStore);
        store = store.replace(pStore2);
        return List.create(pStore, pStore2);
    }
    
    @SuppressWarnings("unchecked")
	List<Pair<PlayerID, PlayerStore>> combine(FinishTrans trans)
	{
    	Derivative d = DerivativesFinder.derByName(store, trans.derivativeName());
    	d = d.finish(trans.finish);
        // remove the derivative from the boughtStore of the player
        Pair<PlayerID, PlayerStore> pStore = getPlayerStore();
        
        pStore.b.bought = pStore.b.bought.remove(new SameDerivative(d));
        store = store.replace(pStore);
        return List.<Pair<PlayerID, PlayerStore>>create(pStore);        
    }
    
    @SuppressWarnings("unchecked")
	List<Pair<PlayerID, PlayerStore>> combine(CreateTrans trans)
	{
    	Derivative d = new Derivative(trans.derivativeName(), pID, trans.price, trans.type);
        // include the derivative in the forSale store of the player
        Pair<PlayerID, PlayerStore> pStore = getPlayerStore();
        
        pStore.b.forSale = pStore.b.forSale.push(d);
        store = store.replace(pStore);
        return List.<Pair<PlayerID, PlayerStore>>create(pStore);
    }
    
    @SuppressWarnings("unchecked")
	List<Pair<PlayerID, PlayerStore>> combine(DeliverTrans trans)
	{
    	Derivative d = DerivativesFinder.derByName(store, trans.derivativeName());
    	d = d.deliver(trans.rawMat.instance);
        //update the derivative in the boughtStore of the buyer
        Pair<PlayerID, PlayerStore> pStore = store.getStorePair(d.optbuyer.inner());
        pStore.b.bought = pStore.b.bought.replace(new SameDerivative(d), d);
        store = store.replace(pStore);
        return List.<Pair<PlayerID, PlayerStore>>create(pStore);
    }
    
    @SuppressWarnings("unchecked")
	List<Pair<PlayerID, PlayerStore>> combine(ReofferTrans trans)
	{
        Pair<PlayerID, PlayerStore> pStore = getPlayerStore();
        Derivative d = DerivativesFinder.derByName(store, trans.derivativeName());
        //TODO:
        d = new Derivative(sdg.admin.Util.freshName(p), pID, trans.newPrice, d.type);
        pStore.b.forSale = pStore.b.forSale.push(d);
        store = store.replace(pStore);
        return List.<Pair<PlayerID, PlayerStore>>create(pStore);
    }
}