package nl.hsac.fitnesse.junit.reportmerge;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * Helper to use Google Chart.
 */
public class ChartWriter {
    protected final PrintWriter pw;

    public ChartWriter(PrintWriter pw) {
        this.pw = pw;
    }

    public void writeLoadScriptTag() {
        pw.write("<script type='text/javascript' src='https://www.gstatic.com/charts/loader.js'></script>");
    }

    public <T> void writeChartGenerators(List<T> htmls,
                                         BiConsumer<ChartWriter, List<T>> bodyFunction,
                                         String extraJs) {
        pw.write("<script type='text/javascript'>" +
                "if(window.google){google.charts.load('current',{'packages':['corechart']});" +
                "google.charts.setOnLoadCallback(drawChart);" +
                "function drawChart() {");
        bodyFunction.accept(this, htmls);
        pw.write("};");
        pw.write(extraJs);
        pw.write("}</script>");
    }

    public <T> void writePieChartGenerator(String title,
                                           String chartId,
                                           List<T> values,
                                           Function<T, String> keyFunction,
                                           Collector<T, ?, Long> groupValueCollector) {
        List<Map.Entry<String, Long>> sums = sortBy(
                values.stream()
                        .collect(Collectors.groupingBy(
                                keyFunction,
                                groupValueCollector))
                        .entrySet(),
                r -> r.getKey());
        writePieChartGenerator(title, chartId,
                "",
                r -> r.getKey(), r -> r.getValue(), sums);
    }

    public <T> void writePieChartGenerator(String title,
                                           String chartElementId,
                                           String extraOptions,
                                           Function<T, String> keyFunction,
                                           Function<T, Object> valueFunction,
                                           Iterable<T> groups) {
        String dataArray = createDataArray("'Group',''", keyFunction, valueFunction, groups);

        pw.write("new google.visualization.PieChart(document.getElementById('");
        pw.write(chartElementId);
        pw.write("')).draw(google.visualization.arrayToDataTable(");
        pw.write(dataArray);
        pw.write("),{title:'");
        pw.write(title);
        pw.write("',sliceVisibilityThreshold:0,is3D:true,pieSliceTextStyle:{color:'black'}");
        pw.write(extraOptions);
        pw.write("});");
    }

    public <T> void writeBarChartGenerator(String title,
                                           String chartElementId,
                                           String extraOptions,
                                           String headers,
                                           Function<T, String> keyFunction,
                                           Function<T, Object> valueFunction,
                                           Iterable<T> groups) {
        String dataArray = createDataArray(headers, keyFunction, valueFunction, groups);

        pw.write("new google.visualization.ColumnChart(document.getElementById('");
        pw.write(chartElementId);
        pw.write("')).draw(google.visualization.arrayToDataTable(");
        pw.write(dataArray);
        pw.write("),{title:'");
        pw.write(title);
        pw.write("',bar: {groupWidth: '80%'},legend:{position: 'none'}");
        pw.write(extraOptions);
        pw.write("});");
    }

    protected <T> String createDataArray(String firstElement, Function<T, String> keyFunction, Function<T, Object> valueFunction, Iterable<T> groups) {
        StringBuilder data = new StringBuilder("[[");
        data.append(firstElement);
        data.append("],");
        groups.forEach(r -> {
            data.append("['");
            data.append(keyFunction.apply(r));
            data.append("',");
            data.append(valueFunction.apply(r));
            data.append("],");
        });
        data.append("]");
        return data.toString();
    }

    protected static <T> List<T> sortBy(Collection<T> values, Function<T, ? extends Comparable> function) {
        return values.stream().sorted((o1, o2) -> function.apply(o1).compareTo(function.apply(o2)))
                .collect(Collectors.toList());
    }
}

@@ -2499,32 +2499,281 @@
       pw.write(%22
+var %22);%0A        pw.write(chartElementId);%0A        pw.write(%22Data = google.visualization.arrayToDataTable(%22);%0A        pw.write(dataArray);%0A        pw.write(%22);%22);%0A%0A        pw.write(%22var %22);%0A        pw.write(chartElementId);%0A        pw.write(%22Chart = 
 new google.visua
@@ -2878,53 +2878,111 @@
 %22'))
-.draw(google.visualization.arrayToDataTable(%22
+;%22);%0A        pw.write(chartElementId);%0A        pw.write(%22Chart.draw(%22);%0A        pw.write(chartElementId
 );%0A 
@@ -2993,33 +2993,30 @@
    pw.write(
-dataArray
+%22Data%22
 );%0A        p
@@ -3016,33 +3016,32 @@
       pw.write(%22
-)
 ,%7Btitle:'%22);%0A   
@@ -3793,16 +3793,265 @@
 .write(%22
+var %22);%0A        pw.write(chartElementId);%0A        pw.write(%22Data = google.visualization.arrayToDataTable(%22);%0A        pw.write(dataArray);%0A        pw.write(%22);%22);%0A%0A        pw.write(%22var %22);%0A        pw.write(chartElementId);%0A        pw.write(%22Chart = 
 new goog
@@ -4167,53 +4167,111 @@
 %22'))
-.draw(google.visualization.arrayToDataTable(%22
+;%22);%0A        pw.write(chartElementId);%0A        pw.write(%22Chart.draw(%22);%0A        pw.write(chartElementId
 );%0A 
@@ -4282,33 +4282,30 @@
    pw.write(
-dataArray
+%22Data%22
 );%0A        p
@@ -4313,17 +4313,16 @@
 .write(%22
-)
 ,%7Btitle:

Introduce variables to hold charts and their data