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


import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.collections4.Factory;

import com.google.common.base.Stopwatch;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;

import pl.edu.pw.mini.jk.sg.game.common.DefenderMove;
import pl.edu.pw.mini.jk.sg.game.configuration.StaticGameConfigurationReader;
import pl.edu.pw.mini.jk.sg.game.graph.advanceable.AdvanceableGraphGameConfiguration;
import pl.edu.pw.mini.jk.sg.game.graph.advanceable.AdvanceableStateGraphGame;
import pl.edu.pw.mini.jk.sg.game.DefenderAttackerGame;
import pl.edu.pw.mini.jk.sg.game.graph.moves.many.advanceable.ManyMovesAdvanceableStateGame;
import pl.edu.pw.mini.jk.sg.game.graph.moves.many.advanceable.SingleUnitDestination;
import pl.edu.pw.mini.jk.sg.game.graph.moves.single.DesiredConfigurationMove;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author jan
 */
public class ProfilerTest {
    
    @SuppressWarnings("unused")
	private static final int[][] game1defenderMoveSequences = { { 0, 6, 6, 6, 6 }, { 6, 6, 6, 5, 6 }, { 6, 6, 6, 6, 4 },
            { 6, 6, 6, 6, 6 } };

    @SuppressWarnings("unused")
	private static final int[][] game1attackerMoveSequences = { { 5, 5, 5, 5, 5 }, { 5, 5, 5, 5, 6 } };

    private static final int[][] game3defenderMoveSequences ={
        {0, 0, 3, 0, 0},
        {3, 0, 0, 0, 0},
        {0, 0, 0, 0, 0},
        {3, 4, 5, 2, 2}
    };
    
    private static final int[][] game3attackerMoveSequences ={
        {7, 7, 6, 5, 2},
        {7, 6, 6, 5, 2},
        {8, 7, 6, 5, 2},
        {7, 6, 5, 5, 2},
        {7, 6, 5, 2, 2},
        {7, 6, 5, 2, 5}
    };
    
    private static final int stepLimit = 5;
    private static final int gamesPerTest = 500000;
    
    public static void main(String[] args) throws IOException {
        @SuppressWarnings("unused")
	    final AdvanceableGraphGameConfiguration game1 = StaticGameConfigurationReader.readFromStream(Thread.currentThread().getContextClassLoader().getResourceAsStream("game1.json"));
        
        final AdvanceableGraphGameConfiguration game3 = StaticGameConfigurationReader
                .readFromStream(Thread.currentThread().getContextClassLoader().getResourceAsStream("game3.json"));
        
        
         final Cache<Object, ImmutableList<DesiredConfigurationMove>> cache1 = CacheBuilder.newBuilder().build();
	 final Factory<AdvanceableStateGraphGame> smGameFactory = () -> new AdvanceableStateGraphGame(game3, cache1, false);

        final Cache<Integer, ImmutableList<SingleUnitDestination>> cache2 = CacheBuilder.newBuilder().build();
        final Factory<ManyMovesAdvanceableStateGame> mmGameFactory = () -> new ManyMovesAdvanceableStateGame(game3,
													     Optional.of(cache2), false);

        final List<List<DesiredConfigurationMove>> defenderDcm = Arrays.stream(game3defenderMoveSequences)
                .map(ProfilerTest::arrayToDcmList).collect(Collectors.toList());

        final List<List<DesiredConfigurationMove>> attackerDcm = Arrays.stream(game3attackerMoveSequences)
                .map(ProfilerTest::arrayToDcmList).collect(Collectors.toList());

        final List<List<SingleUnitDestination>> defenderSud = Arrays.stream(game3defenderMoveSequences)
                .map(ProfilerTest::arrayToSudList).collect(Collectors.toList());

        final List<List<SingleUnitDestination>> attackerSud = Arrays.stream(game3attackerMoveSequences)
                .map(ProfilerTest::arrayToSudList).collect(Collectors.toList());
        
        Stopwatch sw1 = Stopwatch.createStarted();
        for (int i = 0; i < gamesPerTest; i++) {
            playeSingleGame(smGameFactory.create(), defenderDcm.get(i % defenderDcm.size()),
                    attackerDcm.get(i % attackerDcm.size()), stepLimit);
        }
        sw1.stop();

        Stopwatch sw2 = Stopwatch.createStarted();
        for (int i = 0; i < gamesPerTest; i++) {
            playeSingleGame(mmGameFactory.create(), defenderSud.get(i % defenderSud.size()),
                    attackerSud.get(i % attackerSud.size()), stepLimit);
        }
        sw2.stop();

        final long t1 = sw1.elapsed(TimeUnit.MILLISECONDS);
        final long t2 = sw2.elapsed(TimeUnit.MILLISECONDS);
        
  
        System.err.format("%d %d\n", t1, t2);
    }
    
     public static ImmutableList<DesiredConfigurationMove> arrayToDcmList(int[] destinations) {
        return ImmutableList.copyOf(
                Arrays.stream(destinations).mapToObj(i -> new DesiredConfigurationMove(new int[] { i })).iterator());
    }

    public static ImmutableList<SingleUnitDestination> arrayToSudList(int[] destinations) {
        return ImmutableList.copyOf(Arrays.stream(destinations).mapToObj(SingleUnitDestination::new).iterator());
    }

    public static <AM, DM extends DefenderMove, G extends DefenderAttackerGame<AM, DM, ?, ?, ?>> void playeSingleGame(
            G game, List<DM> dm, List<AM> am, int rounds) {

        for (int i = 0; i < rounds; i++) {
            game.getCurrentState();
            game.playDefenderMove(dm.get(i));
            game.playAttackerMove(am.get(i));
            game.finishRound();
        }
    }
    
    
}
