package pl.edu.pw.mini.sg.graphviz;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Optional;
import java.util.stream.IntStream;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import au.com.bytecode.opencsv.CSVReader;
import pl.edu.pw.mini.jk.sg.game.configuration.StaticGameConfiguration;
import pl.edu.pw.mini.jk.sg.game.configuration.StaticGameConfigurationReader;

public class App {
    static final ImmutableMap<String, String> spawnParams = ImmutableMap.of("fixedsize", "true", "width", "1.2",
            "height", "0.9");

    public static void main(String[] args) throws IOException {
        final StaticGameConfiguration sgc = StaticGameConfigurationReader.readAagcFromFile(new File(args[0]))
                .getStaticGameConfiguration();
	final Optional<ImmutableList<PositionInfo>> positionInfo;
	if(args.length>2) {
	    positionInfo = Optional.of(readPositionInfo(new File(args[2])));
	} else {
	    positionInfo = Optional.empty();
	}

        final ImmutableList<Vertex> vertices = ImmutableList.copyOf(IntStream
								    .range(0, sgc.getGraphDescription().vertexCount()).mapToObj(i -> createFromGraph(sgc, i, positionInfo)).iterator());
        final ImmutableList<Edge> edges = ImmutableList.copyOf(sgc.getGraphDescription().getEdges().stream()
                .map(e -> new Edge(vertices.get(e.from()), vertices.get(e.to()))).iterator());

        try (FileWriter fw = new FileWriter(args[1]);) {
            fw.write(new Graph(vertices, edges).getCode());
        }
    }

    public static Vertex createFromGraph(StaticGameConfiguration g, int vertex, Optional<ImmutableList<PositionInfo>> positionInfo) {
	final ImmutableMap.Builder<String, String> paramsBuilder = ImmutableMap.builder();
	if(g.getSpawns().contains(vertex)) {
	    paramsBuilder.putAll(spawnParams);
	}
	paramsBuilder.putAll(positionInfo.flatMap(l -> l.stream().filter(pi -> pi.id() == vertex).findAny().map(pi -> ImmutableMap.<String, String>of("pos", "\""+pi.x()*110+","+pi.y()*(-85)+"\""))).orElse(ImmutableMap.<String, String>of()));
        return new Vertex(Integer.toString(vertex), buildLabel(g, vertex),
                g.getSpawns().contains(vertex) ? Shape.TRIANGLE
                        : (g.getTargets().contains(vertex) ? Shape.DIAMOND : Shape.CIRCLE),
                g.getSpawns().contains(vertex) ? "red" : (g.getTargets().contains(vertex) ? "green" : "black"),
                g.getSpawns().contains(vertex) ? Optional.of("\"#FFBBBB\"")
                        : (g.getTargets().contains(vertex) ? Optional.of("\"#BBFFBB\"") : Optional.empty()),

			  paramsBuilder.build());
    }

    private static String buildLabel(final StaticGameConfiguration g, final int vertex) {
        StringBuilder builder = new StringBuilder();

        builder.append(vertex).append(": A(").append("-").append(g.getVertexAttackerPenalties()[vertex][0]);
        if (g.getTargets().contains(vertex)) {
            builder.append(",").append(g.getAttackerRewards()[g.getTargets().indexOf(vertex)][0]);
        }
        builder.append(")\\nD(").append(g.getVertexDefenderRewards()[vertex][0]);
        if (g.getTargets().contains(vertex)) {
            builder.append(",-").append(g.getDefenderPenalties()[g.getTargets().indexOf(vertex)][0]);
        }
        builder.append(")");

        return builder.toString();
    }

    public static ImmutableList<PositionInfo> readPositionInfo(File file) {
	try(final FileReader reader = new FileReader(file); 
	    final CSVReader csvReader = new CSVReader(reader);) {
	    final ImmutableList.Builder<PositionInfo> listBuilder = ImmutableList.builder();
	    String[] line;
	    csvReader.readNext(); // Skip header
	    while((line = csvReader.readNext()) != null) {
		final PositionInfo pi = new PositionInfo(
							 Integer.valueOf(line[0]),
							 Integer.valueOf(line[1]),
							 Integer.valueOf(line[2]),
							 Integer.valueOf(line[3]),
							 line[4]
							 );
		listBuilder.add(pi);
	    }
	    return listBuilder.build();
	} catch (IOException ex) {
	    throw new UncheckedIOException(ex);
	}
    }
}
