package player;

import player.playeragent.*;
import utils.*;
import edu.neu.ccs.demeterf.demfgen.lib.List;
import classes.*;

/**
 * @author animesh
 * Class for processing the turn for a player
 */
public class PlayerProcessor {
    private final Player player;
    private final Store store;
    private final Config config;

    /** Constructor
     * @param player
     */
    public PlayerProcessor(Player player) {
        this.player = player;
        store = DocumentHandler.getStore();
        config = DocumentHandler.getConfig();
    }

    /** Takes turn */
    public void takeTurn() {
        PlayerTransaction playerTrans = new PlayerTransaction(player, List.<Transaction>create());
        if(!isSaleStoresEmpty(store)){			
            buyOrReofferDerivative(this.player, playerTrans);
        }
        createDerivative(this.player, playerTrans);
        deliverRawMaterial(this.player, playerTrans);
        finishProduct(this.player, playerTrans);
        DocumentHandler.commitPlayerTransaction(playerTrans);
    }

    /** Indicates if the sale stores are empty
     * @param store
     * @return boolean
     */
    private boolean isSaleStoresEmpty(Store store) {
        return EmptySaleStoresIndicator.isSalesStoresEmpty(store);
    }

    /** Finishes the derivatives that need finishing
     * @param player
     * @param playerTrans
     */
    private void finishProduct(Player player, PlayerTransaction playerTrans) {		
        List<Derivative> dersThatNeedFinishing = DerivativesFinder.findDersThatNeedFinishing(store.stores, player);
        List<Derivative> finishedDers = FinishAgent.finishDerivatives(dersThatNeedFinishing);
        for(Derivative der: finishedDers){
            System.out.println("Player "+player.id.id+" is finishing derivative bought from Player "+der.seller.id);
            Transaction trans = new Transaction(new Finish(), der);
            playerTrans.transactions = playerTrans.transactions.push(trans);
        }
    }

    /** Delivers raw material for the derivatives that need raw material
     * @param player
     * @param playerTrans
     */
    private void deliverRawMaterial(Player player, PlayerTransaction playerTrans) {		
        List<Derivative> dersThatNeedRM = DerivativesFinder.findDersThatNeedRM(store.stores, player);
        List<Derivative> dersWithRM = DeliverAgent.deliverRawMaterial(dersThatNeedRM);
        for(Derivative der: dersWithRM){
            System.out.println("Player "+player.id.id+" is delivering raw material to Player "+der.optbuyer.inner().id);
            Transaction trans = new Transaction(new Deliver(), der);
            playerTrans.transactions = playerTrans.transactions.push(trans);
        }
    }

    /** Creates a derivative
     * @param player
     * @param playerTrans
     */
    private void createDerivative(Player player, PlayerTransaction playerTrans) {
        System.out.println("Player "+player.id.id+" is creating derivative.");
        List<Type> existingDerTypes = DerivativesFinder.findExistingDerTypes(store.stores);
        Derivative der = CreateAgent.createDerivative(existingDerTypes, player);		
        Transaction trans = new Transaction(new Create(), der);
        playerTrans.transactions  = playerTrans.transactions.push(trans);
    }

    /** Buys a derivative from the sale stores or reoffers all of them
     * @param player
     * @param playerTrans
     */
    private void buyOrReofferDerivative(Player player, PlayerTransaction playerTrans) {		
        List<Derivative> dersForSale = DerivativesFinder.findDerivativesForSale(store.stores);
        boolean isBuyGood =  BuyAgent.isBuyGood();
        if(!isBuyGood){
            System.out.println("Player "+player.id.id+" is reoffering all derivatives.");			
            List<Derivative> reducedDers = ReofferAgent.reofferAll(dersForSale, player, config.mindec);
            for(Derivative der: reducedDers){
                Transaction trans = new Transaction(new Reoffer(), der);
                playerTrans.transactions = playerTrans.transactions.push(trans);
            }
        }
        else{			
            Derivative der = BuyAgent.buyAgent(dersForSale);
            System.out.println("Player "+player.id.id+" is buying derivative from Player "+der.seller.id);
            Transaction trans = new Transaction(new Buy(), der);
            playerTrans.transactions = playerTrans.transactions.push(trans);
        }		
    }
}