// Space out the shapes a bit
shapeParams.forEach((d) => (d.startX = d.startX * 1.1));

// How to draw the background boxes, which will be styled later
const classifierBgPathTop = "M 420 150 H 0 V 0 H 420 V 150";
const classifierBgPathBottom = "M 420 300 H 0 V 0 H 420 V 300";

const toDropdownValueStringDict = {
    shape_name: "circles, triangles, or rectangles",
    pointiness: "pointy shapes or round shapes",
    size: "small shapes or big shapes",
};

const toShortValueStringDict = {
    shape_name: "circles, triangles, or rectangles",
    pointiness: "pointy or round",
    size: "small or big",
};

const toDropdownValueRoundingStringDict = {
    true: "with our best guess",
    false: 'as "other"',
};

const toPropertyStringDict = {
    pointy: "pointy shapes",
    round: "round shapes",
    small: "small shapes",
    large: "big shapes",
    circle: "circles",
    triangle: "triangles",
    rect: "rectangles",
};

function toOriginalString(inputString) {
    for (const [key, value] of Object.entries(toPropertyStringDict)) {
        if (inputString == value) {
            return key;
        }
    }
}

function toPropertyString(inputProperty, isRounding = true) {
    if (!isRounding && inputProperty.startsWith("rt_")) {
        return "others";
    }
    return toPropertyStringDict[inputProperty.replace("rt_", "")];
}

// Dictionary mapping div name to classifier results and summary sentences
var allResults = {};
var summaries = {};

function toBool(inputString) {
    if (inputString == "true") {
        return true;
    }
    return false;
}
function updateResults() {
    allResults["default-classifier"] = calculateResults();
    allResults["second-classifier"] = calculateResults(
        "shape_name",
        toBool(
            document.getElementById("second-classifier-select-rounding").value
        )
    );

    allResults["final-classifier"] = calculateResults(
        document.getElementById("final-classifier-select-category").value,
        toBool(
            document.getElementById("final-classifier-select-rounding").value
        )
    );

    allResults["conclusion"] = calculateResults(
        document.getElementById("conclusion-select-category").value,
        true
    );

    updateSummaries();
    updateSecondInterfaceImages();
}

// Text summaries are written by hand for simplicity, and keyed simply by
// a string of the form "[category]:[useGuess]" (or simply "none").
// These are hashed in the same way as the results, by div name.
function updateSummaries() {
    summaries["default-classifier"] = getPerformanceSummary("none");
    summaries["second-classifier"] = getPerformanceSummary(
        "shape_name:" +
            document.getElementById("second-classifier-select-rounding").value
    );

    summaries["final-classifier"] = getPerformanceSummary(
        document.getElementById("final-classifier-select-category").value +
            ":" +
            document.getElementById("final-classifier-select-rounding").value
    );

    summaries["conclusion"] = getPerformanceSummary(
        document.getElementById("conclusion-select-category").value + ":" + true
    );
}

// Yes, these background colors are hardcoded in,
// no, this is not good design, this is just how it happened.
function getPerformanceSummary(key) {
    allSummaries = {
        "shape_name:true":
            '<mark style="background-color: rgb(206, 234, 135);" class="well">well</mark> on circles, <mark style="background-color: rgb(244, 123, 74);" class="terribly">terribly</mark> on triangles, and <mark style="background-color: rgb(173, 220, 114);" class="best">best</mark> on rectangles',
        "shape_name:false":
            '<mark style="background-color: rgb(251, 163, 94);" class="poorly">poorly</mark> on circles, <mark style="background-color: rgb(155, 212, 108);" class="best">best</mark> on triangles and rectangles, and <mark style="background-color: rgb(252, 244, 171);" class="fine">fine</mark> on other shapes',
        "pointiness:true":
            '<mark style="background-color: rgb(184, 225, 119);" class="better">better</mark> on pointy shapes and <mark style="background-color: rgb(254, 206, 125);" class="worse">worse</mark> on round shapes',
        "pointiness:false":
            '<mark style="background-color: rgb(140, 205, 104);" class="best">best</mark> on pointy shapes, <mark style="background-color: rgb(243, 248, 171);" class="fine">fine</mark> on round shapes, and <mark style="background-color: rgb(253, 190, 111);" class="poorly">poorly</mark> on other shapes',
        "size:true":
            '<mark style="background-color: rgb(206, 234, 135);" class="better">better</mark> on small shapes, <mark style="background-color: rgb(254, 232, 154);" class="worse">worse</mark> on big shapes',
        "size:false":
            '<mark style="background-color: rgb(254, 215, 135);" class="poorly">poorly</mark> on small shapes, <mark style="background-color: rgb(165, 0, 38); color: #FFCCD8;" class="terribly">terribly</mark> on big shapes, and <mark style="background-color: rgb(110, 192, 99);" class="best">best</mark> on other shapes',
        "none:true":
            '<mark style="background-color: rgb(246, 248, 173);" class="fine">fine</mark> on all shapes',
        "none:false":
            '<mark style="background-color: rgb(246, 248, 173);" class="fine">fine</mark> on all shapes',
        none: '<mark style="background-color: rgb(246, 248, 173);" class="fine">fine</mark> on all shapes',
    };

    return "The Is-Shaded Classifier performs " + allSummaries[key] + ".";
}

// On the second-classifier dropdown, update the "task interface" image.
function updateSecondInterfaceImages() {
    d3.select(".second-interface").html(function () {
        if (
            !document.getElementById("second-classifier-select-rounding").value
        ) {
            return;
        }
        var imgPath =
            "img/interface_shape_name_" +
            document.getElementById("second-classifier-select-rounding").value;
        return (
            '<img src="' +
            imgPath +
            '.png" alt="" class="interface-image" srcset="' +
            imgPath +
            '.svg"></img>'
        );
    });
}

// Calculate results given input parameters
function calculateResults(property = "none", useGuess = false) {
    switch (property) {
        case "none":
            var nAccurate = shapeParams.filter(
                (shape) => shape.correctness == "correct"
            ).length;
            var totalShapes = shapeParams.length;

            var results = [
                {
                    object: "shape",
                    n: totalShapes,
                    "n correct": nAccurate,
                    accuracy: (nAccurate / totalShapes).toFixed(3),
                    rawCategoryName: "none",
                },
            ];

            return results;
        case "pointiness":
            categories = ["pointy", "round"];
            break;
        case "size":
            categories = ["small", "large"];
            break;
        case "shape_name":
            categories = ["circle", "triangle", "rect"];
            break;
    }

    var results = [];
    if (useGuess == true) {
        // Rounding shapes to categories

        for (const category of categories) {
            // Get shapes that are either in this category (e.g. rectangle) or "rounds to" this category (e.g. rt_rectangle)
            var theseShapes = shapeParams.filter(
                (shape) =>
                    shape[property] == category ||
                    shape[property] == "rt_" + category
            );
            var nAccurate = theseShapes.filter(
                (shape) => shape.correctness == "correct"
            ).length;
            var totalShapes = theseShapes.length;

            results.push({
                object: toPropertyString(category),
                n: totalShapes,
                "n correct": nAccurate,
                accuracy: (nAccurate / totalShapes).toFixed(3),
                rawCategoryName: category,
            });
        }
    } else {
        // Not rounding, treat everything else as "other"

        // First go through existing categories
        for (const category of categories) {
            var theseShapes = shapeParams.filter(
                (shape) => shape[property] == category
            );
            var nAccurate = theseShapes.filter(
                (shape) => shape.correctness == "correct"
            ).length;
            var totalShapes = theseShapes.length;
            results.push({
                object: toPropertyString(category),
                n: totalShapes,
                "n correct": nAccurate,
                accuracy: (nAccurate / totalShapes).toFixed(3),
                rawCategoryName: category,
            });
        }

        // Now get "other" shapes
        var theseShapes = shapeParams.filter(
            (shape) => !categories.includes(shape[property])
        );
        var nAccurate = theseShapes.filter(
            (shape) => shape.correctness == "correct"
        ).length;
        var totalShapes = theseShapes.length;
        results.push({
            object: "other shapes",
            n: totalShapes,
            "n correct": nAccurate,
            accuracy: (nAccurate / totalShapes).toFixed(3),
            rawCategoryName: "other",
        });
    }

    return results;
}