package utils;

import utils.comparator.DerivativeComparator;
import utils.comparator.PlayerStoreComparator;
import edu.neu.ccs.demeterf.TUCombiner;
import edu.neu.ccs.demeterf.demfgen.lib.Empty;
import edu.neu.ccs.demeterf.demfgen.lib.List;
import edu.neu.ccs.demeterf.demfgen.lib.Some;
import gen.Buy;
import gen.Create;
import gen.Deliver;
import gen.Derivative;
import gen.Finish;
import gen.Pair;
import gen.PlayerID;
import gen.PlayerStore;
import gen.PlayerTransaction;
import gen.Reoffer;
import gen.Store;
import gen.Transaction;
import gen.TransactionType;

/** Class for updating the store after each player transaction
 * @author animesh
 *
 */
public class StoreUpdater extends ListTUCombiner<Pair<PlayerID, PlayerStore>>{//TUCombiner<List<Pair<PlayerID, PlayerStore>>> {
	
	private PlayerID pID;
	private static Store store;

	public StoreUpdater(PlayerID playerID, Store store) {
		super();
		this.store = store;
		this.pID = playerID;
	}

	
	public static Store updateStore(Store existingStore, PlayerTransaction pTrans) {
		TUCombiner.traverse(pTrans, new StoreUpdater(pTrans.player.id, existingStore));
		return store;
	}

	
	List<Pair<PlayerID, PlayerStore>> combine(Transaction trans, Buy b){
		//include the bought der in the bought store of the player
		Pair<PlayerID, PlayerStore> pIdAndStore;
		if(store.stores.contains(new PlayerStoreComparator(pID)))
			pIdAndStore = store.stores.find(new PlayerStoreComparator(pID));
		else
			pIdAndStore = new Pair<PlayerID, PlayerStore>(pID, new PlayerStore(new Empty<Derivative>(), new Empty<Derivative>()));
		Derivative bDer = trans.deriv;
		bDer.optbuyer = new Some<PlayerID>(pID);
		pIdAndStore.b.bought = pIdAndStore.b.bought.push(bDer);
		//remove the bought der from the forSale store of the seller
		Pair<PlayerID, PlayerStore> pIdAndStore2 = store.stores.find(new PlayerStoreComparator((trans.deriv).seller));
		pIdAndStore2.b.forSale = pIdAndStore2.b.forSale.remove(new DerivativeComparator(trans.deriv));
		//make changes to the store
		store.stores = store.stores.replace(new PlayerStoreComparator(pID), pIdAndStore);
		store.stores = store.stores.replace(new PlayerStoreComparator((trans.deriv).seller), pIdAndStore2);
		return List.create(pIdAndStore, pIdAndStore2);
	}
	List<Pair<PlayerID, PlayerStore>> combine(Transaction trans, Finish b){
		// remove the derivative from the boughtStore of the player
		Pair<PlayerID, PlayerStore> pIdAndStore;
			pIdAndStore = store.stores.find(new PlayerStoreComparator(pID));
		pIdAndStore.b.bought = pIdAndStore.b.bought.remove(new DerivativeComparator(trans.deriv));
		store.stores = store.stores.replace(new PlayerStoreComparator(pID), pIdAndStore);
		return List.create(pIdAndStore);		
	}
	List<Pair<PlayerID, PlayerStore>> combine(Transaction trans, Create b){
		Pair<PlayerID, PlayerStore> pIdAndStore;
		if(store.stores.contains(new PlayerStoreComparator(pID)))
			pIdAndStore = store.stores.find(new PlayerStoreComparator(pID));
		else
			pIdAndStore = new Pair<PlayerID, PlayerStore>(pID, new PlayerStore(new Empty<Derivative>(), new Empty<Derivative>()));
		//include the derivative in the forSale store of the player
		
		pIdAndStore.b.forSale = pIdAndStore.b.forSale.push(trans.deriv);
		store.stores = store.stores.remove(new PlayerStoreComparator(pID));
		store.stores = store.stores.push(pIdAndStore);
		return List.create(pIdAndStore);
	}	
	List<Pair<PlayerID, PlayerStore>> combine(Transaction trans, Deliver b){
		//update the derivative in the boughtStore of the buyer
		Pair<PlayerID, PlayerStore> pIdAndStore = store.stores.find(new PlayerStoreComparator(trans.deriv.optbuyer.inner()));
		pIdAndStore.b.bought = pIdAndStore.b.bought.remove(new DerivativeComparator(trans.deriv));
		pIdAndStore.b.bought = pIdAndStore.b.bought.push(trans.deriv);
		store.stores = store.stores.replace(new PlayerStoreComparator(trans.deriv.optbuyer.inner()), pIdAndStore);
		return List.create(pIdAndStore);
	}
	List<Pair<PlayerID, PlayerStore>> combine(Transaction trans, Reoffer b){
		Pair<PlayerID, PlayerStore> pIdAndStore;
		if(store.stores.contains(new PlayerStoreComparator(pID)))
			pIdAndStore = store.stores.find(new PlayerStoreComparator(pID));
		else
			pIdAndStore = new Pair<PlayerID, PlayerStore>(pID, new PlayerStore(new Empty<Derivative>(), new Empty<Derivative>()));

		pIdAndStore.b.forSale = pIdAndStore.b.forSale.push( trans.deriv);
		store.stores = store.stores.replace(new PlayerStoreComparator(pID), pIdAndStore);
		return List.create(pIdAndStore);
	}	
	TransactionType combine(TransactionType t){
		return t;
	}
}