package pl.edu.pw.mini.jk.sg.game.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.common.collect.ImmutableList;

public abstract class AbstractGame<DM extends DefenderMove, S extends State<?, ?>>
		implements SecurityGame {
	private int timeStep = 0;
	private int defenderCount;
	private final AccidentHistory accidentHistory;
	private final List<Accident> currentAccidents;
	private ImmutableList<Accident> previousAccidents;
	private final Map<Class<?>, Object> stateInformation;

	public abstract double getDefenderReward(int target, int attacker);

	public abstract double getDefenderPenalty(int target, int attacker);

	public abstract double getAttackerReward(int target, int attacker);

	public abstract double getAttackerPenalty(int target, int attacker);

	protected AbstractGame(int defenderCount, int historyTimeHorizon) {
		super();
		this.defenderCount = defenderCount;
		this.accidentHistory = new SimpleAccidentHistory(historyTimeHorizon);
		currentAccidents = new ArrayList<Accident>();
		previousAccidents = ImmutableList.of();
		stateInformation = new HashMap<Class<?>, Object>();
	}

	
	
	
	protected AbstractGame(final AbstractGame<DM,S> game) {
        super();
        this.timeStep = game.timeStep;
        this.defenderCount = game.defenderCount;
        this.accidentHistory = game.accidentHistory.typedClone();
        this.previousAccidents = game.previousAccidents;
        this.currentAccidents = new ArrayList<Accident>(game.currentAccidents);
        this.stateInformation = new HashMap<>(game.stateInformation);
    }

    /*
	 * (non-Javadoc)
	 * 
	 * @see pl.edu.pw.mini.jk.SecurityGame#getTimeStep()
	 */
	@Override
	public int getTimeStep() {
		return timeStep;
	}

	public int getDefenderCount() {
		return defenderCount;
	}

	protected void registerAccident(Accident accident) {
		accidentHistory.registerAccident(accident);
		currentAccidents.add(accident);
	}

	public AccidentHistory getAccidentHistory() {
		return accidentHistory;
	}

    
    @Override
    public boolean accidentOccured() {
	return !getPreviousAccidents().isEmpty();
    }


	protected void increaseTimeStep() {
		timeStep++;
		previousAccidents = ImmutableList.copyOf(currentAccidents);
		accidentHistory.setCurrentTimestep(timeStep);
	}

	@Override
	public ImmutableList<Accident> getPreviousAccidents() {
        return previousAccidents;
    }
	
	public abstract double getDefenseEfficiency(int target, int defenderCount);
}
