package icurves.util

import javafx.application.Application
import javafx.scene.Parent
import javafx.scene.chart.CategoryAxis
import javafx.scene.chart.NumberAxis
import javafx.scene.paint.Color
import java.nio.file.Files
import java.nio.file.Paths

import tornadofx.*
import java.util.*

/**
 * DL duplicate labels
 * DZ disc zones
 * CC concurrency
 * BP brushing points
 * NP triple points
 * NS non-simple
 * OZ omitted zones
 * EZ extra zones
 *
 *
 * @author Almas Baimagambetov (almaslvl@gmail.com)
 */
class Technique(val name: String) {
    val datasets = arrayListOf<Dataset>()
}

class DatasetMapping(val name: String,
                     val snapName: String,
                     val zones: String)

class Dataset(val name: String,
              val failed: Boolean = false,
              val NS: Int = 0,
              val DL: Int = 0,
              val DZ: Int = 0,
              val CC: Int = 0,
              val BP: Int = 0,
              val NP: Int = 0,
              val OZ: Int = 0,
              val EZ: Int = 0,
              var numCircles: Int = 0,
              var zones: String = "") {

    var Q: Int

    var nonCircles: Int = 0
    
    var techniqueName = ""
        set(value) {
            if (value == "iCircles") {
                numCircles = numSets + DL
            } else if (value == "Bubble_Sets") {
                nonCircles = numSets
            } else if (value == "iCurves" || value == "GEDL") {
                nonCircles = numSets - numCircles
            }

            field = value
        }

    val numZones: Int
    val numSets: Int

    init {
        Q = name.removePrefix("D").toInt() % 4

        if (Q == 0)
            Q = 4

        if (zones.isEmpty()) {
            zones = mappings[name]!!.zones
        }

        numZones = zones.split(" +".toRegex()).size
        numSets = zones.split(" +".toRegex()).reduce { acc, s -> acc + s }.toCharArray().distinct().size
    }

    fun badness(): Int {
        return DZ + DL + if (failed) numZones else OZ
    }

    fun allPropSum(): Int {
        return DZ + DL + CC + NP + if (failed) 0 else nonCircles
    }

    override fun toString(): String {
        var s = ""

        if (failed) {
            return "FAILED"
        }

        if (DL > 0)
            s += " DL: $DL "

        if (DZ > 0)
            s += " DZ: $DZ "

        if (CC > 0)
            s += " CC: $CC "

        if (BP > 0)
            s += " BP: $BP "

        if (NP > 0)
            s += " NP: $NP "

        if (OZ > 0)
            s += " OZ: $OZ "

        if (EZ > 0)
            s += " EZ: $EZ "

        return s
    }
}

private val techniques = arrayListOf<Technique>()
private val mappings = hashMapOf<String, DatasetMapping>()

fun main(args: Array<String>) {
    loadMapping()
    loadData()

    //printStats()
    //showGraph()
    //printCSV()
    //printGeneral()
    printTex()
}

private fun loadMapping() {
    val lines = Files.readAllLines(Paths.get("dataset_mapping.txt"))

    for (i in 0 until lines.size step 4) {
        val name = lines[i]

        mappings[name] = DatasetMapping(name, lines[i+1], lines[i+2])
    }

    //mappings.forEach { println(it.name + " " + it.snapName + " " + it.zones) }
}

private fun loadData() {
    val iCurves = Technique("iCurves")
    with(iCurves) {
        datasets.add(Dataset("D1", zones = "a b c d", numCircles = 4))
        datasets.add(Dataset("D2", zones = "a ac b c d", numCircles = 4))
        datasets.add(Dataset("D3", zones = "a cd ac b c d", numCircles = 4))
        datasets.add(Dataset("D4", zones = "a bc cd ac b acd ad c d", numCircles = 4))

        datasets.add(Dataset("D5", zones = "ab de b ce cde e", numCircles = 5))
        datasets.add(Dataset("D6", zones = "a cd de b ad c d e", numCircles = 5))
        datasets.add(Dataset("D7", zones = "a cd abd ac bd b ad be c d e", EZ = 2, numCircles = 5))
        datasets.add(Dataset("D8", zones = "a ab cd de b ce be c ae d abe cde e", numCircles = 5))

        datasets.add(Dataset("D9", zones = "a ef b c d e f", numCircles = 6))
        datasets.add(Dataset("D10", zones = "a de ac b c d af e f", numCircles = 6))
        datasets.add(Dataset("D11", zones = "a b df cf c bf d bdf e f", EZ = 1, numCircles = 6))
        datasets.add(Dataset("D12", zones = "de ef df ad cf bf cdf d def cde cef e f acdf cdef bcdf bcdef", EZ = 10, numCircles = 4))

        datasets.add(Dataset("D13", zones = "ab b c bf d e f g", numCircles = 7))
        datasets.add(Dataset("D14", zones = "a ac b eg c cf d bg e f g", numCircles = 7))
        datasets.add(Dataset("D15", zones = "bc de ef fg b bde df aef be c cg d af e ag f g", EZ = 12, numCircles = 5))
        datasets.add(Dataset("D16", zones = "bc fg bef df aef def bg adfg acdf a ef adf afg abc c ae cdf dfg af e f abg g adef abef", failed = true))

        datasets.add(Dataset("D17", zones = "a bc b fh c d e g h", numCircles = 8))
        datasets.add(Dataset("D18", zones = "a gh b eg c d dgh e bh f ah deg g h", EZ = 3, numCircles = 7))
        datasets.add(Dataset("D19", zones = "a fg gh b eg be c dg bf cg d dh bg e ag f g h", EZ = 3, numCircles = 8))
        datasets.add(Dataset("D20", zones = "abcfh a gh ac afh fh c eh cfh cg dh dgh af bfh cgh ch f egh g h acfh bcfh cegh abfh", EZ = 5, numCircles = 7))

        // 36 EZ
        // non-circles 6

        datasets.add(Dataset("D21", numCircles = 4))
        datasets.add(Dataset("D22", numCircles = 4))
        datasets.add(Dataset("D23", EZ = 1, numCircles = 4))
        datasets.add(Dataset("D24", EZ = 2, numCircles = 4))

        datasets.add(Dataset("D25", numCircles = 5))
        datasets.add(Dataset("D26", numCircles = 5))
        datasets.add(Dataset("D27", numCircles = 5))
        datasets.add(Dataset("D28", EZ = 5, numCircles = 4))

        datasets.add(Dataset("D29", numCircles = 6))
        datasets.add(Dataset("D30", EZ = 5, numCircles = 5))
        datasets.add(Dataset("D31", numCircles = 6))
        datasets.add(Dataset("D32", EZ = 2, numCircles = 6))

        datasets.add(Dataset("D33", numCircles = 7))
        datasets.add(Dataset("D34", numCircles = 7))
        datasets.add(Dataset("D35", EZ = 1, numCircles = 7))
        datasets.add(Dataset("D36", failed = true))

        datasets.add(Dataset("D37", numCircles = 8))
        datasets.add(Dataset("D38", numCircles = 8))
        datasets.add(Dataset("D39", EZ = 4, numCircles = 7))
        datasets.add(Dataset("D40", EZ = 7, numCircles = 6))

        // 27 EZ
        // non-circles 5
    }

    val iCircles = Technique("iCircles")
    with(iCircles) {
        datasets.add(Dataset("D1", zones = "a b c d"))
        datasets.add(Dataset("D2", zones = "a ac b c d"))
        datasets.add(Dataset("D3", zones = "a cd ac b c d"))
        datasets.add(Dataset("D4", zones = "a bc cd ac b acd ad c d"))

        datasets.add(Dataset("D5", zones = "ab de b ce cde e"))
        datasets.add(Dataset("D6", zones = "a cd de b ad c d e"))
        datasets.add(Dataset("D7", zones = "a cd abd ac bd b ad be c d e", DL = 2))
        datasets.add(Dataset("D8", zones = "a ab cd de b ce be c ae d abe cde e"))

        datasets.add(Dataset("D9", zones = "a ef b c d e f"))
        datasets.add(Dataset("D10", zones = "a de ac b c d af e f"))
        datasets.add(Dataset("D11", zones = "a b df cf c bf d bdf e f", DL = 1))
        datasets.add(Dataset("D12", zones = "de ef df ad cf bf cdf d def cde cef e f acdf cdef bcdf bcdef", DL = 3))

        datasets.add(Dataset("D13", zones = "ab b c bf d e f g"))
        datasets.add(Dataset("D14", zones = "a ac b eg c cf d bg e f g"))
        datasets.add(Dataset("D15", zones = "bc de ef fg b bde df aef be c cg d af e ag f g", DL = 5))
        datasets.add(Dataset("D16", zones = "bc fg bef df aef def bg adfg acdf a ef adf afg abc c ae cdf dfg af e f abg g adef abef", DL = 4, EZ = 3))

        datasets.add(Dataset("D17", zones = "a bc b fh c d e g h"))
        datasets.add(Dataset("D18", zones = "a gh b eg c d dgh e bh f ah deg g h", DL = 2))
        datasets.add(Dataset("D19", zones = "a fg gh b eg be c dg bf cg d dh bg e ag f g h", DL = 3))
        datasets.add(Dataset("D20", zones = "abcfh a gh ac afh fh c eh cfh cg dh dgh af bfh cgh ch f egh g h acfh bcfh cegh abfh", DL = 5))

        datasets.add(Dataset("D21"))
        datasets.add(Dataset("D22"))
        datasets.add(Dataset("D23", DL = 1))
        datasets.add(Dataset("D24", DL = 1))

        datasets.add(Dataset("D25"))
        datasets.add(Dataset("D26"))
        datasets.add(Dataset("D27"))
        datasets.add(Dataset("D28", DL = 3))

        datasets.add(Dataset("D29"))
        datasets.add(Dataset("D30", DL = 2))
        datasets.add(Dataset("D31"))
        datasets.add(Dataset("D32", DL = 2))

        datasets.add(Dataset("D33"))
        datasets.add(Dataset("D34"))
        datasets.add(Dataset("D35", DL = 1))
        datasets.add(Dataset("D36", DL = 5))

        datasets.add(Dataset("D37"))
        datasets.add(Dataset("D38"))
        datasets.add(Dataset("D39", DL = 2))
        datasets.add(Dataset("D40", DL = 3, EZ = 2))
    }

    val GED = Technique("GEDL")
    with(GED) {
        datasets.add(Dataset("D1", zones = "a b c d", numCircles = 4))
        datasets.add(Dataset("D2", zones = "a ac b c d", numCircles = 4))
        datasets.add(Dataset("D3", zones = "a cd ac b c d", numCircles = 4))
        datasets.add(Dataset("D4", zones = "a bc cd ac b acd ad c d", numCircles = 4))

        datasets.add(Dataset("D5", zones = "ab de b ce cde e", numCircles = 5))
        datasets.add(Dataset("D6", zones = "a cd de b ad c d e", numCircles = 5))
        datasets.add(Dataset("D7", zones = "a cd abd ac bd b ad be c d e", CC = 1, NP = 2))
        datasets.add(Dataset("D8", zones = "a ab cd de b ce be c ae d abe cde e", numCircles = 5))

        datasets.add(Dataset("D9", zones = "a ef b c d e f", numCircles = 6))
        datasets.add(Dataset("D10", zones = "a de ac b c d af e f", numCircles = 6))
        datasets.add(Dataset("D11", zones = "a b df cf c bf d bdf e f", failed = true))
        datasets.add(Dataset("D12", zones = "de ef df ad cf bf cdf d def cde cef e f acdf cdef bcdf bcdef", failed = true))

        datasets.add(Dataset("D13", zones = "ab b c bf d e f g", numCircles = 7))
        datasets.add(Dataset("D14", zones = "a ac b eg c cf d bg e f g", numCircles = 7))
        datasets.add(Dataset("D15", zones = "bc de ef fg b bde df aef be c cg d af e ag f g", failed = true))
        datasets.add(Dataset("D16", zones = "bc fg bef df aef def bg adfg acdf a ef adf afg abc c ae cdf dfg af e f abg g adef abef", failed = true))

        datasets.add(Dataset("D17", zones = "a bc b fh c d e g h", numCircles = 8))
        datasets.add(Dataset("D18", zones = "a gh b eg c d dgh e bh f ah deg g h", failed = true))
        datasets.add(Dataset("D19", zones = "a fg gh b eg be c dg bf cg d dh bg e ag f g h", CC = 2, NP = 6))
        datasets.add(Dataset("D20", zones = "abcfh a gh ac afh fh c eh cfh cg dh dgh af bfh cgh ch f egh g h acfh bcfh cegh abfh", CC = 7, NP = 1))

        // non-circles 21

        datasets.add(Dataset("D21", numCircles = 4))
        datasets.add(Dataset("D22", numCircles = 4))
        datasets.add(Dataset("D23", DZ = 1, numCircles = 4))
        datasets.add(Dataset("D24", NP = 2, CC = 1))

        datasets.add(Dataset("D25", numCircles = 5))
        datasets.add(Dataset("D26", numCircles = 5))
        datasets.add(Dataset("D27", numCircles = 5))
        datasets.add(Dataset("D28", failed = true))

        datasets.add(Dataset("D29", numCircles = 6))
        datasets.add(Dataset("D30", failed = true))
        datasets.add(Dataset("D31", failed = true))
        datasets.add(Dataset("D32", NP = 2))

        datasets.add(Dataset("D33", numCircles = 7))
        datasets.add(Dataset("D34", numCircles = 7))
        datasets.add(Dataset("D35", NP = 3))
        datasets.add(Dataset("D36", failed = true))

        datasets.add(Dataset("D37", numCircles = 8))
        datasets.add(Dataset("D38", failed = true))
        datasets.add(Dataset("D39", CC = 1, DZ = 1, NP = 4))
        datasets.add(Dataset("D40", failed = true))

        // non-circles 25
    }

    val bubbleSets = Technique("Bubble_Sets")
    with(bubbleSets) {
        datasets.add(Dataset("D1", zones = "a b c d"))
        datasets.add(Dataset("D2", zones = "a ac b c d"))
        datasets.add(Dataset("D3", zones = "a cd ac b c d"))
        datasets.add(Dataset("D4", zones = "a bc cd ac b acd ad c d", DZ = 3))

        datasets.add(Dataset("D5", zones = "ab de b ce cde e", EZ = 3, CC = 1))
        datasets.add(Dataset("D6", zones = "a cd de b ad c d e"))
        datasets.add(Dataset("D7", zones = "a cd abd ac bd b ad be c d e", DZ = 2, NP = 1, CC = 1))
        datasets.add(Dataset("D8", zones = "a ab cd de b ce be c ae d abe cde e", DZ = 5, NP = 1, CC = 1))

        datasets.add(Dataset("D9", zones = "a ef b c d e f"))
        datasets.add(Dataset("D10", zones = "a de ac b c d af e f"))
        datasets.add(Dataset("D11", zones = "a b df cf c bf d bdf e f", EZ = 1, DZ = 1))
        datasets.add(Dataset("D12", zones = "de ef df ad cf bf cdf d def cde cef e f acdf cdef bcdf bcdef", NP = 3, CC = 7, EZ = 4, DZ = 11))

        datasets.add(Dataset("D13", zones = "ab b c bf d e f g", EZ = 1, NP = 1))
        datasets.add(Dataset("D14", zones = "a ac b eg c cf d bg e f g"))
        datasets.add(Dataset("D15", zones = "bc de ef fg b bde df aef be c cg d af e ag f g", NP = 2, EZ = 1, CC = 2, DZ = 12))
        datasets.add(Dataset("D16", zones = "bc fg bef df aef def bg adfg acdf a ef adf afg abc c ae cdf dfg af e f abg g adef abef", NP = 7, EZ = 7, CC = 9, DZ = 22))

        datasets.add(Dataset("D17", zones = "a bc b fh c d e g h", EZ = 1))
        datasets.add(Dataset("D18", zones = "a gh b eg c d dgh e bh f ah deg g h", BP = 1, EZ = 5))
        datasets.add(Dataset("D19", zones = "a fg gh b eg be c dg bf cg d dh bg e ag f g h", DZ = 3))
        datasets.add(Dataset("D20", zones = "abcfh a gh ac afh fh c eh cfh cg dh dgh af bfh cgh ch f egh g h acfh bcfh cegh abfh", NP = 3, CC = 9, EZ = 9, DZ = 15))

        datasets.add(Dataset("D21", EZ = 1))
        datasets.add(Dataset("D22", EZ = 4))
        datasets.add(Dataset("D23", EZ = 1, DZ = 1, NP = 1))
        datasets.add(Dataset("D24", BP = 1, NP = 1, DZ = 5))

        datasets.add(Dataset("D25", EZ = 1))
        datasets.add(Dataset("D26", DZ = 1))
        datasets.add(Dataset("D27"))
        datasets.add(Dataset("D28", DZ = 6, NP = 3, BP = 1))

        datasets.add(Dataset("D29", EZ = 1))
        datasets.add(Dataset("D30", CC = 3, DZ = 1, EZ = 12))
        datasets.add(Dataset("D31"))
        datasets.add(Dataset("D32", EZ = 2, DZ = 3))

        datasets.add(Dataset("D33"))
        datasets.add(Dataset("D34", NP = 1, DZ = 3))
        datasets.add(Dataset("D35", DZ = 1))
        datasets.add(Dataset("D36", CC = 3, NP = 2, EZ = 1, DZ = 29))

        datasets.add(Dataset("D37"))
        datasets.add(Dataset("D38", CC = 11, NP = 3, DZ = 1, EZ = 21))
        datasets.add(Dataset("D39", NP = 5, CC = 1, EZ = 5, DZ = 10))
        datasets.add(Dataset("D40", CC = 3, BP = 1, NP = 2, EZ = 6, DZ = 11))
    }

    techniques.add(iCurves)
    techniques.add(iCircles)
    techniques.add(GED)
    techniques.add(bubbleSets)
}

private fun printCSV() {
    println("Data set number,SNAP reference,Technique,Non-simple,Disconnected Zones,Concurrency,Brushing Points,Triple Points,Duplicate Labels,Extra Zones,Omitted Zones,Number of Circles,Failed,Number of sets,Number of zones,Quartile")

    techniques.onEach { t -> t.datasets.forEach { it.techniqueName = t.name } }
            .flatMap { it.datasets }
            .groupBy { it.name }
            .toSortedMap(Comparator.comparingInt({ it.removePrefix("D").toInt() }))
            .forEach { datasetName, datasets ->

                val snap = mappings[datasetName]!!.snapName.substringAfterLast('\\')

                datasets.forEach {
                    print("$datasetName,$snap,${it.techniqueName},${it.NS},${it.DZ},${it.CC},${it.BP},${it.NP},${it.DL},${it.EZ},${it.OZ},${it.numCircles},")
                    print(if (it.failed) "Y," else "N,")
                    print("${it.numSets},${it.numZones},${it.Q}")
                    println()
                }

            }
}

private fun printGeneral() {
    techniques.onEach { t -> t.datasets.forEach { it.techniqueName = t.name } }
        .flatMap { it.datasets }
        .groupBy { it.name }
        .toSortedMap(Comparator.comparingInt({ it.removePrefix("D").toInt() }))
        .forEach { datasetName, datasets ->

            println("$datasetName")

            datasets.forEach {
                println("${it.techniqueName}: $it")
            }

            println()
        }
}

class GraphApp : App(GraphView::class)

var index = 0

//iCurves, drawn: 8.0 numSets: 4 badness: 0.0
//iCurves, drawn: 8.0 numSets: 5 badness: 0.125
//iCurves, drawn: 8.0 numSets: 6 badness: 0.375
//iCurves, drawn: 6.0 numSets: 7 badness: 0.3333333333333333
//iCurves, drawn: 8.0 numSets: 8 badness: 0.625
//iCircles, drawn: 8.0 numSets: 4 badness: 0.25
//iCircles, drawn: 8.0 numSets: 5 badness: 0.625
//iCircles, drawn: 8.0 numSets: 6 badness: 1.0
//iCircles, drawn: 8.0 numSets: 7 badness: 1.875
//iCircles, drawn: 8.0 numSets: 8 badness: 1.875
//GEDL, drawn: 8.0 numSets: 4 badness: 1.0
//GEDL, drawn: 7.0 numSets: 5 badness: 1.1428571428571428
//GEDL, drawn: 4.0 numSets: 6 badness: 2.0
//GEDL, drawn: 5.0 numSets: 7 badness: 2.0
//GEDL, drawn: 5.0 numSets: 8 badness: 9.2
//Bubble_Sets, drawn: 8.0 numSets: 4 badness: 5.375
//Bubble_Sets, drawn: 8.0 numSets: 5 badness: 7.75
//Bubble_Sets, drawn: 8.0 numSets: 6 badness: 9.625
//Bubble_Sets, drawn: 8.0 numSets: 7 badness: 18.75
//Bubble_Sets, drawn: 8.0 numSets: 8 badness: 17.625

//iCurves, drawn: 10.0 Q: 1 badness: 0.0
//iCurves, drawn: 10.0 Q: 2 badness: 0.2
//iCurves, drawn: 10.0 Q: 3 badness: 0.3
//iCurves, drawn: 8.0 Q: 4 badness: 0.75
//iCircles, drawn: 10.0 Q: 1 badness: 0.0
//iCircles, drawn: 10.0 Q: 2 badness: 0.4
//iCircles, drawn: 10.0 Q: 3 badness: 1.5
//iCircles, drawn: 10.0 Q: 4 badness: 2.6
//GEDL, drawn: 10.0 Q: 1 badness: 0.0
//GEDL, drawn: 7.0 Q: 2 badness: 0.0
//GEDL, drawn: 7.0 Q: 3 badness: 7.0
//GEDL, drawn: 5.0 Q: 4 badness: 6.2
//Bubble_Sets, drawn: 10.0 Q: 1 badness: 6.2
//Bubble_Sets, drawn: 10.0 Q: 2 badness: 8.4
//Bubble_Sets, drawn: 10.0 Q: 3 badness: 10.3
//Bubble_Sets, drawn: 10.0 Q: 4 badness: 22.4

class GraphView : View() {
    override val root: Parent = stackpane {
        val chart = linechart("Diagrams 2018 data", CategoryAxis(), NumberAxis()) {


            techniques.onEach { t -> t.datasets.forEach { it.techniqueName = t.name } }
                    .flatMap { it.datasets }
                    .groupBy { it.techniqueName }
                    .forEach { techniqueName, datasets ->

                        series(techniqueName + " ALL") {
                            datasets.groupBy { it.Q }
                                    .forEach { numSets, datasetsPerNumSets ->

                                        val drawnNumber = datasetsPerNumSets.filter { !it.failed }.size.toDouble()

                                        val badness = datasetsPerNumSets.sumBy { it.EZ } / drawnNumber

                                        println("$techniqueName, drawn: $drawnNumber numSets: $numSets badness: $badness")

                                        data(numSets.toString(), badness)
                                    }

                        }



//                        series(techniqueName) {
//                            datasets.groupBy { it.numSets }
//                                    .forEach { numSets, datasetsPerNumSets ->
//
//                                        val drawnNumber = datasetsPerNumSets.size.toDouble()
//
//                                        val badness = datasetsPerNumSets.sumBy { it.badness() } / drawnNumber
//
//                                        println("$techniqueName, sets: $numSets badness: $badness")
//
//                                        data(numSets.toString(), badness)
//                                    }
//
//                        }

//                        series(techniqueName) {
//                            datasets.groupBy { it.Q }
//                                    .forEach { quartile, datasetsPerNumSets ->
//
//                                        val drawnNumber = datasetsPerNumSets.size.toDouble()
//
//                                        println(drawnNumber)
//
//                                        val badness = datasetsPerNumSets.sumBy { it.badness() } / drawnNumber
//
//                                        println("$techniqueName, Q: $quartile badness: $badness")
//
//                                        data(quartile.toString(), badness)
//                                    }
//
//                        }

//                        series(techniqueName) {
//                            datasets.groupBy { it.numSets }
//                                    .forEach { numSets, datasetsPerNumSets ->
//
//                                        val drawnNumber = datasetsPerNumSets.filter { !it.failed }.size.toDouble()
//
//                                        data(numSets.toString(), datasetsPerNumSets.sumBy { it.nonCircles } / drawnNumber)
//                                    }
//
//                        }


//                        if (techniqueName == "iCircles") {
//                            val s1 = series(techniqueName + " DL") {
//                                datasets.groupBy { it.numSets }
//                                        .forEach { numSets, datasetsPerNumSets ->
//                                            data(numSets.toString(), datasetsPerNumSets.sumBy { it.DL })
//                                        }
//                            }
//                        }

//                        if (techniqueName != "GEDL") {
//                            val s1 = series(techniqueName + " EZ") {
//                                datasets.groupBy { it.numSets }
//                                        .forEach { numSets, datasetsPerNumSets ->
//                                            data(numSets.toString(), datasetsPerNumSets.sumBy { it.EZ })
//                                        }
//                            }
//
//                        } else {
//                            val s1 = series(techniqueName + " TP") {
//                                datasets.groupBy { it.numSets }
//                                        .forEach { numSets, datasetsPerNumSets ->
//                                            data(numSets.toString(), datasetsPerNumSets.sumBy { it.NP })
//                                        }
//                            }
//                        }
                    }


//            series("Product X") {
//                data("MAR", 10245)
//                data("APR", 23963)
//                data("MAY", 15038)
//            }
//            series("Product Y") {
//                data("MAR", 28443)
//                data("APR", 22845)
//                data("MAY", 19045)
//            }
        }
    }
}

val colors = arrayListOf<Color>()

private fun rgb(): String {
    val color = colors[index++]

    return String.format("%d, %d, %d",
            (color.getRed() * 255).toInt(),
            (color.getGreen() * 255).toInt(),
            (color.getBlue() * 255).toInt())
}

private fun showGraph() {
    // these values are adapted from "How should we use colour in ED" Andrew Blake, et al
    for (i in 0..29) {
        colors.add(Color.hsb(((i + 1) * 32).toDouble(),
                if (i == 1 || i == 2) 0.26 else 0.55,
                if (i == 1 || i == 2) 0.88 else 0.92))
    }

    Collections.swap(colors, 1, 9)
    Collections.swap(colors, 3, 7)

    Application.launch(GraphApp::class.java)
}

private fun printTex() {
    val tex = arrayListOf<String>()

    techniques.onEach { t -> t.datasets.forEach { it.techniqueName = t.name } }
            .flatMap { it.datasets }
            .groupBy { it.name }
            .toSortedMap(Comparator.comparingInt({ it.removePrefix("D").toInt() }))
            .forEach { datasetName, datasets ->

                val data = datasets[0]
                val snap = mappings[data.name]!!.snapName.substringAfterLast('\\')

                tex.add("\\newpage")
                tex.add("\\textbf{SNAP ID: ${snap}}")
                tex.add("")
                tex.add("\\textbf{Number of Sets: ${data.numSets}}")
                tex.add("")
                tex.add("\\textbf{Number of Zones: ${data.numZones}}")
                tex.add("")
                tex.add("\\textbf{Quartile: ${data.Q}}")
                tex.add("")

                tex.add("\\begin{center}\n" +
                        "\\begin{minipage}[t]{0.49\\linewidth}\n" +
                        "\\captionof*{figure}{\\textbf{iCurves}}\n" +
                        "\\includegraphics[width=0.8\\textwidth,height=0.36\\textheight,keepaspectratio=true]{iCurves/${data.name}}\n" +
                        "\\end{minipage}\n" +
                        "\\hfill\n" +
                        "\\begin{minipage}[t]{0.49\\linewidth}\n" +
                        "\\captionof*{figure}{\\textbf{iCircles}}\n" +
                        "\\includegraphics[width=0.8\\textwidth,height=0.36\\textheight,keepaspectratio=true]{iCircles/${data.name}}\n" +
                        "\\end{minipage}\n" +
                        "\\end{center}\n" +
                        "\\vspace{0.5cm}\n" +
                        "\\begin{center}\n" +
                        "\\begin{minipage}[t]{0.49\\linewidth}\n" +
                        "\\captionof*{figure}{\\textbf{GED-L}}\n" +
                        "\\includegraphics[width=0.8\\textwidth,height=0.36\\textheight,keepaspectratio=true]{GEDL/${data.name}}\n" +
                        "\\end{minipage}\n" +
                        "\\hfill\n" +
                        "\\begin{minipage}[t]{0.49\\linewidth}\n" +
                        "\\captionof*{figure}{\\textbf{Bubble Sets}}\n" +
                        "\\includegraphics[width=0.8\\textwidth,height=0.36\\textheight,keepaspectratio=true]{Bubble_Sets/${data.name}}\n" +
                        "\\end{minipage}\n" +
                        "\\end{center}")

                tex.add("")

                val iCurves = datasets.find { it.techniqueName == "iCurves" }!!
                val iCircles = datasets.find { it.techniqueName == "iCircles" }!!
                val GEDL = datasets.find { it.techniqueName == "GEDL" }!!
                val BS = datasets.find { it.techniqueName == "Bubble_Sets" }!!

                val iNonCircles = if (iCurves.failed) 0 else iCurves.nonCircles
                val gedlNonCircles = if (GEDL.failed) 0 else GEDL.nonCircles

                tex.add("\\begin{center}\n" +
                        "\\begin{tabular}{ | l | l | l | l | l | }\n" +
                        "\\hline\n" +
                        " & iCurves & iCircles & GED-L & Bubble Sets \\\\ \\hline\n" +
                        "Duplicated Labels & 0 & ${iCircles.DL} & 0 & 0 \\tabularnewline \\hline\n" +
                        "Disconnected Zones & 0 & 0 & ${GEDL.DZ} & ${BS.DZ} \\tabularnewline \\hline \\hline\n" +
                        "Extra Zones & ${iCurves.EZ} & ${iCircles.EZ} & ${GEDL.EZ} & ${BS.EZ} \\tabularnewline \\hline \\hline\n" +
                        "Concurrency & 0 & 0 & ${GEDL.CC} & ${BS.CC} \\tabularnewline \\hline\n" +
                        "Triple Points & 0 & 0 & ${GEDL.NP} & ${BS.NP} \\tabularnewline \\hline\n" +
                        "Non-circles & ${iNonCircles} & 0 & ${gedlNonCircles} & ${BS.nonCircles} \\tabularnewline \\hline \n" +
                        "\\end{tabular}\n" +
                        "\\end{center}")

                tex.add("")
            }

    Files.write(Paths.get("tex.txt"), tex)
}

private fun printStats() {
    techniques.onEach { t -> t.datasets.forEach { it.techniqueName = t.name } }
            .flatMap { it.datasets }
            .groupBy { it.techniqueName }
            .forEach { techniqueName, datasets ->
                val total = datasets.filter { !it.failed }.sumBy { it.EZ }

                val avg = total.toDouble() / datasets.filter { !it.failed }.size

                println("$techniqueName total: $total")
                println("average: $avg")
                println("occured in " + datasets.filter { it.EZ > 0 && !it.failed }.size)
            }
}