"use strict";

const fs = require('fs');
const path = require('path');
const config = require('../build.json');

// Change current directory to script location so that
// the relative paths of the resources can be resolved
process.chdir(path.dirname(process.argv[1]));

function createDirectory(dir) {
    fs.mkdirSync(
        dir,
        { recursive: true },
        (error) => {
            if (error !== null) {
                console.error('Error while creating directory', error);
            }
        }
    );
}

function transformData() {
    // TSV laden und parsen
    var matrix = fs.readFileSync(path.join('../', config.path.data, 'crime.tsv'), 'utf8');
    matrix = matrix.split('\n').map(l => l.split('\t'));

    var rowCount = matrix.length - 1; // trailing new line
    var colCount = matrix[0].length - 1;  // treat dark figures separately

    var result = {entries:[]};
    var nodes = new Map();

    // Die einzelnen Zeilen (je Straftat) in einen Tree einsortieren
    for (var r = 2; r < rowCount; r++) {
        var parentid = matrix[r][1].trim();

        var node = {};
        if (parentid === '') {
            result.tree = node;
        } else {
            var parent = nodes.get(parentid);
            if (!parent) throw Error('"'+parentid+'" not found');
            if (!parent.children) parent.children = [];
            parent.children.push(node);
        }

        nodes.set(matrix[r][0].trim(), node);

        node.id = matrix[r][0].trim();
        node.title = matrix[r][2].trim();
        // node.dark = matrix[r][colcount].trim();
        // node.dark = Math.random() * 0.8 + 0.1;  fake dark figure
    }

    // Jeden Wert den Straftaten, Geschlecht und Alter zuordnen
    for (var c = 3; c < colCount; c++) {

        // Zuordnung zum Alter
        var alter = matrix[0][c];
        switch (alter) {
            case 'alle': alter = ''; break;
            case 'bis unter 6': alter = '0-5'; break;
            case '6 bis unter 14': alter = '6-13'; break;
            case '14 bis unter 18': alter = '14-17'; break;
            case '18 bis unter 21': alter = '18-20'; break;
            case '21 bis unter 60': alter = '21-59'; break;
            case '60 und älter': alter = '60+'; break;
            default: throw Error(alter);
        }

        // Zuordnung zum Geschlecht
        var geschlecht = matrix[1][c];
        switch (geschlecht) {
            case 'insges.': geschlecht = ''; break;
            case 'männlich': geschlecht = 'm'; break;
            case 'weiblich': geschlecht = 'w'; break;
            default: throw Error(geschlecht);
        }

        var entry = {alter:alter, geschlecht:geschlecht, values:{}};
        result.entries.push(entry);

        // Zuordnung zur Straftat
        for (var r = 2; r < rowCount; r++) {
            var crimeId = matrix[r][0].trim();
            var value = parseFloat(matrix[r][c].replace(/,/g, '.')) || 0;
            entry.values[crimeId] = round(value);
        }
    }

    // Validierung, ob die Summen aufgehen
    result.entries.forEach((entry) => {
        var values = entry.values;
        validate(result.tree);
        function validate(node) {
            if (!node.children) return;

            var sum = 0;
            node.children.forEach(child => {
                validate(child);
                sum += values[child.id];
            });
            // if (Math.abs(sum - values[node.id]) > 1e-3) {
            //     var msg = [
            //         'Für Alter "'+entry.alter+'" und Geschlecht "'+entry.geschlecht+'"',
            //         'ist die Differenz von "'+node.id+'" minus der Summe der Kinder gleich',
            //         (sum - values[node.id]).toFixed(3)
            //     ].join(' ');
            //     console.log(msg);
            // }
            values[node.id] = round(sum);
        }
    });

    // Resultat als JSON speichern
    fs.writeFileSync(
        path.join(
            '../',
            config.path.output,
            config.path.data,
            'data.json'),
        JSON.stringify(result, null, '\t'),
        'utf8'
    );

    // Runde alle Zahlen auf 4 Nachkommastellen
    function round(v) {
        return Math.round(v*1e4)/1e4;
    }
}

createDirectory(path.join('../', config.path.output, config.path.data));
transformData();
