package pl.edu.pw.mini.jk.sg.opt.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.google.common.collect.ImmutableList;
import pl.edu.pw.mini.jk.sg.game.common.DefenderMove;

import pl.edu.pw.mini.jk.sg.game.graph.moves.single.DesiredConfigurationMove;

public final class CodeUtils {
    public static <AM, DM extends DefenderMove> void writeMoveCodes(final File output, final List<ImmutableList<AM>> attackerSequences,
            final List<ImmutableList<DM>> defenderSequences) throws IOException {
        try (FileWriter writer = new FileWriter(output)) {
            writer.write("--DEFENDER--\n");
            IntStream
                    .range(0, defenderSequences.size())
                    .mapToObj(
                            i -> Integer.toString(i)
                                    + ":"
                                    + defenderSequences.get(i).stream()
                                            .map(DM::toString)
                                            .collect(Collectors.joining(" ")) + "\n").forEach(s -> {
                        try {
                            writer.write(s);
                        } catch (IOException ex) {
                            throw new UncheckedIOException(ex);
                        }
                    });
            writer.write("--ATTACKER--\n");
            IntStream
                    .range(0, attackerSequences.size())
                    .mapToObj(
                            i -> Integer.toString(i)
                                    + ":"
                                    + attackerSequences.get(i).stream()
                                            .map(AM::toString)
                                            .collect(Collectors.joining(" ")) + "\n").forEach(s -> {
                        try {
                            writer.write(s);
                        } catch (IOException ex) {
                            throw new UncheckedIOException(ex);
                        }
                    });

        }
    }

    public static Map<Integer, ImmutableList<Integer>> readDefenderMoveCodes(final File input) throws IOException {
        try (final FileReader reader = new FileReader(input);
                final BufferedReader bufferedReader = new BufferedReader(reader);) {
            if (!"--DEFENDER--".equals(bufferedReader.readLine())) {
                throw new IOException("Bad file format");
            }

            final Map<Integer, ImmutableList<Integer>> output = new HashMap<>();

            String line;
            while ((line = bufferedReader.readLine()) != null && !line.equals("--ATTACKER--")) {
                String[] split1 = line.split(":");
                int id = Integer.parseInt(split1[0]);
                output.put(id,
                        ImmutableList.copyOf(Arrays.stream(split1[1].split(" ")).map(Integer::valueOf).iterator()));
            }
            return output;
        }
    }

    public static Map<Integer, Double> encodeProbabilityMap(Map<ImmutableList<Integer>, Double> map,
            Map<Integer, ImmutableList<Integer>> codes) {
        return codes.entrySet().stream().filter(e -> map.containsKey(e.getValue()))
                .collect(Collectors.toMap(e -> e.getKey(), e -> map.get(e.getValue())));
    }

    public static <T> Map<Integer, T> listToMap(List<T> list) {
        return IntStream.range(0, list.size()).boxed().collect(Collectors.toMap(Function.identity(), list::get));
    }
}
