import * as d3 from './d3-custom';
import config from './config.json';

// See rollup.config.js for postcss configuration
import '../css/main.css';

function crime() {
    var data = false, root, treemap, cells, width, height, svgLabels = [], selectedNode, svgHighlight, alreadyDrawn;
    // var darkFigure, tlclip, trclip, blclip, brclip;

    var svg = d3.select('#chart').append('svg');
    var svgBackground = svg.append('rect')
        .attr('fill', '#dedddc');

    // introducing margins
    var margin = {
        top: 20,
        right: 20,
        bottom: 20,
        left: 20
    };

    var lang = config.lang;
    var option = window.location.search.substr(1,4);
    if(option === 'lang') {
        lang = window.location.search.substr(6, window.location.search.length - 1);
    }

    document.title = config.title[config.lang];

    var labels = config.labels;
    d3.select('#gender-label').text(labels.gender.all[lang]);
    d3.select('#gender-option').text(labels.gender.all[lang]);
    d3.select('#gender-female').text(labels.gender.female[lang]);
    d3.select('#gender-male').text(labels.gender.male[lang]);
    d3.select('#age-label').text(labels.age[lang]);
    d3.select('#age-option').text(labels.age[lang]);

    var svgWrapper = svg.append('g')
        .attr('transform', 'translate(-' + (margin.left / 2) + ',-' + (margin.top / 2) + ')');

    var svgContainer = svgWrapper.append('g');

    var frame = svg.append('rect')
        .attr('stroke', '#7c7872')
        .attr('stroke-width', margin.top)
        .attr('fill', 'none');

    let arrow = d3.select('#btnback');
    arrow.select('svg').classed('hidden', true);

    d3.json('data/data.json', function (_data) {

        data = _data;

        data.nodes = {};
        var id = 0;
        scanTree(data.tree, function (node) {
            data.nodes[node.id] = node;
            node.nodeid = 'cell'+(id++);
        });

        scanTree(data.tree,            function (node) { node.basecolor = d3.color('#000000'); });
        scanTree(data.nodes['000000'], function (node) { node.basecolor = d3.color('#e36315'); });
        scanTree(data.nodes['100000'], function (node) { node.basecolor = d3.color('#f4881c'); });
        scanTree(data.nodes['200000'], function (node) { node.basecolor = d3.color('#f2d31d'); });
        scanTree(data.nodes['5***00'], function (node) { node.basecolor = d3.color('#f2bf1a'); });
        scanTree(data.nodes['600000'], function (node) { node.basecolor = d3.color('#f7a11d'); });
        scanTree(data.nodes['700000'], function (node) { node.basecolor = d3.color('#d4470f'); });

        redraw();

        function scanTree(node, cb) {
            cb(node);
            if (node.children) node.children.forEach(function (child) { scanTree(child, cb); });
        }
    });

    d3.select(window).on('resize', redraw);
    d3.selectAll('select').on('change', function() { redraw(true); });


    function redraw(doAnimate) {
        // Falls noch keine Daten vorhanden sind, dann gleich die Funktion abbrechen.
        if (!data) return;

        if (!alreadyDrawn) {
            initialDraw();
            arrow.on('click', function () {
                select((selectedNode && selectedNode.parent) ? selectedNode.parent : false);
            });
            alreadyDrawn = true;
        }

        // Welches Alter/Geschlecht ist ausgewählt?
        let alter = d3.select('#alter').node().value;
        let geschlecht = d3.select('#geschlecht').node().value;

        // Suche den Eintrag mit dem ausgewählten Alter/Geschlecht.
        var entry = data.entries.filter(function (entry) {
            if (entry.alter !== alter) return false;
            if (entry.geschlecht !== geschlecht) return false;
            return true;
        });
        if (entry.length !== 1) return console.error(entry);
        entry = entry[0];

        // kopiere alle Werte in den Tree
        Object.keys(entry.values).forEach(function (key) {
            data.nodes[key].value = entry.values[key] || 1e-8;
        });

        width = d3.select('#chart').node().offsetWidth;
        height = d3.select('#chart').node().offsetHeight - 35;

        svg
            .attr('width', width)
            .attr('height', height);
        svgWrapper
            .attr('width', width - margin.left - margin.right)
            .attr('height', height - margin.top - margin.bottom);
        svgBackground
            .attr('width', width)
            .attr('height', height);
        frame
            .attr('width', width)
            .attr('height', height);

        // Aktualisiert alle Texte der Straftaten
        updateCellValues(root);
        function updateCellValues(node) {
            node.value = node.data.value;
            node.data.desc = node.data.value < 1 ? '<1' : round(node.data.value);
            if (node.children) {
                var sum = 0;
                node.children.forEach(function (child) {
                    updateCellValues(child);
                    sum += child.value;
                });
                node.value = sum;
            }
        }

        // Größe der quadratischen Treemap rechts unten
        var size = Math.sqrt(width*height*data.tree.children[1].value/data.tree.value);

        treemap.size([size, size]);
        treemap(root);


        // Label "98,8%"
        svgLabels[0]
            .attr('x', width*0.3)
            .attr('y', height*0.5)
            .text(round(data.tree.children[0].value) + ' von ' + round(100000));

        // Label für "keine Straftat"
        svgLabels[1]
            .attr('x', width*0.3)
            .attr('y', height*0.5+18)
            .text(data.tree.children[0].title);

        // Label "1.2%"
        animate(svgLabels[2])
            .attr('x', width)
            .attr('y', height - size*1.2 - 12)
            .text(round(data.tree.children[1].value) + ' von ' + round(100000));

        // Label für "Opfer einer Straftat"
        animate(svgLabels[3])
            .attr('x', width)
            .attr('y', height - size*1.2)
            .text(data.tree.children[1].title);

        cells.forEach(function (cell) {
            updateCellSize(cell);

            animate(cell.svgGroup).attr('transform', 'translate(' + cell.x + ',' + cell.y + ') scale(' + cell.s + ')');

            animate(cell.svgRect)
                .attr('width', cell.rw)
                .attr('height', cell.rh);

            cell.svgText0.text(cell.data.desc);


            cell.svgText1.html(null);
            cell.svgText1.selectAll('tspan')
                .data(textToLines(cell.data.title, 2*cell.rw/10))
                .enter().append('tspan')
                .attr('x', 4)
                .attr('y', function (d, i) { return (i+1.3)*8+15; })
                .text(function (d) { return d; });
        });

        select(selectedNode);

        function select(node) {
            var duration = (node === undefined) ? 0 : 2000;
            selectedNode = node;

            var cell = node;
            if (!cell) cell = {children:root.children};

            // Je nach ausgewählter Zelle wird berechnet,
            // welche Zellen sichtbar sind und welche nicht.
            cells.forEach(function (cell) {
                cell.wasVisible = cell.isVisible;
                cell.isVisible = false;
            });

            // mache alle Geschwister der Vorfahren sichtbar
            var tCell = cell;
            while (tCell.parent) {
                let p = tCell.parent;
                p.children.forEach(function (child) {
                    child.isVisible = true;
                });
                tCell = p;
            }

            // mache die Unterknoten sichtbar
            if (cell.children && cell.children.length > 0) {
                cell.children.forEach(function (child) { child.isVisible = true; });
            } else {
                cell.isVisible = true;
            }

            // animiere die Zellen je nachdem, ob sie unsichtbar oder sichtbar werden sollen.
            cells.forEach(function (cell) {
                if (cell.wasVisible === cell.isVisible) return;
                if (cell.isVisible) {
                    cell.svgGroup
                        .attr('display', 'inline')
                        .transition().duration(duration*0.3)
                        .style('opacity', 1);
                } else {
                    cell.svgGroup
                        .transition().duration(duration*0.3)
                        .style('opacity', 0)
                        .on('end', function () {
                            cell.svgGroup.attr('display','none');
                        });
                }
            });

            if (node) {
                arrow.select('svg').transition().duration(duration).style('opacity', 1);
            } else {
                arrow.select('svg').transition().duration(duration).style('opacity', 0);
            }

            if (node) {
                // Populate HTML overlay
                // dynamic data
                d3.select('#data-title').text(node.data.title);
                d3.select('#data-desc').text(node.data.desc);
                // "static" data
                var olabels = config.labels.overlay;
                d3.select('#reference-group-title').text(olabels.reference.title[lang]);
                d3.select('#reference-group-size').text(config.labels.of[lang] + ' ' + round(olabels.reference.size));
                d3.select('#chart-title').text(olabels.chart.title[lang]);
                d3.select('#chart-note').text(olabels.chart.note[lang]);
                d3.select('#source').text(olabels.source.prefix[lang] + ' ' + olabels.source.title[lang]);
                d3.select('.overlay').classed('show', true);

                // rote Markierung der ausgewählten Zelle aktualisieren
                svgHighlight
                    .attr('display','inline');

                animate(svgHighlight)
                    .attr('width', node.rw)
                    .attr('height', node.rh)
                    .attr('transform', 'translate('+node.x+','+node.y+')scale('+node.s+')');


                // Diagramm der Infobox zeichnen
                var id = node.data.id;
                var chartData = [];
                var maxValue = 0;
                data.entries.forEach(function (entry) {
                    var row, col;
                    switch (entry.geschlecht) {
                        case 'w': col = 0; break;
                        case 'm': col = 1; break;
                        default: return;
                    }
                    switch (entry.alter) {
                        case '60+': row = 0; break;
                        case '21-59': row = 1; break;
                        case '18-20': row = 2; break;
                        case '14-17': row = 3; break;
                        case '6-13': row = 4; break;
                        case '0-5': row = 5; break;
                        default: return;
                    }
                    if (!chartData[row]) chartData[row] = [];  //
                    var value = entry.values[id];
                    chartData[row][col] = value;
                    if (value > maxValue) maxValue = value;
                });

                var svg2 = d3.select('#chart2 svg');

                var rowHeight = 25;
                var offset = 25;
                //
                // update x axis labels
                svg2.select('#left-axis-label')
                    .text(round(maxValue));

                svg2.select('#right-axis-label')
                    .text(round(maxValue));

                for (let lr = 0; lr < 2; ++lr) {
                    let data = chartData.map(d => d[lr]);
                    svg2.selectAll('.rect-' + lr)
                        .data(data)
                        .join(
                            enter => enter.append('rect')
                                .attr('class', 'rect-' + lr)
                                .attr('x', d => lr ? 90 + offset : 90 + offset - d / maxValue * 90 || 0)  // 
                                .attr('y', (d, i) => i * rowHeight + 15)
                                .attr('width', d => d / maxValue * 90 || 0)
                                .attr('height', rowHeight-0.3)
                                .attr('fill', lr ? '#7c7872' : '#94918c'),
                            update => update
                                .attr('x', d => lr ? 90 + offset : 90 + offset - d / maxValue * 90 || 0)  // 
                                .attr('width', d => d / maxValue * 90 || 0)
                        );
                }
            } else {
                d3.select('.overlay').classed('show', false);
                svgHighlight.attr('display','none');
            }

            var vWidth = node ? width-200 : width;
            var box = node || {x:offset, y:0, w:width, h:height};
            var s = Math.min(vWidth/box.w, height/box.h)*(node ? 0.8 : 1);
            var x = -box.x + (vWidth/s - box.w)/2;
            var y = -box.y + (height/s- box.h)/2;
            var t = d3.zoomIdentity.scale(s).translate(x, y);

            svgContainer.transition()
                .duration(duration)
                .attr('transform', t);
        }

        function animate(node) {
            if (!doAnimate) return node;
            return node.transition().duration(2000);
        }

        function initialDraw() {
            // Falls noch keine Daten vorhanden sind, dann gleich die Funktion abbrechen.
            if (!data) return;

            svgBackground
                .on('click', function () {
                    select(false);
                });

            var entry = data.entries.filter(function (entry) {
                return (entry.alter === '') && (entry.geschlecht === '');
            });
            if (entry.length !== 1) return console.error(entry);
            entry = entry[0];

            Object.keys(entry.values).forEach(function (key) {
                data.nodes[key].value = entry.values[key];
            });

            // Bereite SVG vor
            width = d3.select('#chart').node().offsetWidth;
            height = d3.select('#chart').node().offsetHeight - 35;

            svgContainer.html(null);
            svg
                .attr('width', width)
                .attr('height', height);
            svgWrapper
                .attr('width', width - margin.left - margin.right)
                .attr('height', height - margin.top - margin.bottom);
            svgBackground
                .attr('width', width)
                .attr('height', height);
            frame
                .attr('width', width)
                .attr('height', height);


            var svg2 = d3.select('#chart2').append('svg');
            svg2
                .attr('width', 220)
                .attr('height', 180);

            var rowHeight = 25;
            var offset = 25;
            var axes = {
                x0: offset,
                x1: 90 + offset,
                x2: 180 + offset,
                y0: 15,
                y1: 165,
                y2: 175
            };

            // Zeichne weiße Achsenlinien
            svg2.append('path')
                .attr('d', `M${axes.x0},${axes.y0}H${axes.x2}M${axes.x1},${axes.y0}V${axes.y1}`)
                .attr('stroke', '#fff')
                .attr('fill', 'none');

            // Zeichne graue Achsenlinien unten
            svg2.append('path')
                .attr('d', `M${axes.x0},${axes.y2}V${axes.y1}H${axes.x2}V${axes.y2}`)
                .attr('stroke', '#5b564e')
                .attr('fill', 'none');

            // x-Achsen-Beschriftung links
            svg2.append('text')
                .attr('id', 'left-axis-label')
                .attr('x', 3 + offset)
                .attr('y', axes.y2)
                .attr('fill', '#5b564e')
                .attr('text-anchor', 'start')
                .attr('font-size', '10px');

            // x-Achsen-Beschriftung mitte
            svg2.append('text')
                .attr('x', (axes.x2 + offset) / 2)
                .attr('y', axes.y2)
                .attr('fill', '#5b564e')
                .attr('text-anchor', 'middle')
                .attr('font-size', '10px')
                .text(labels.per[lang] + ' ' + round(labels.overlay.reference.size));

            // x-Achsen-Beschriftung rechts
            svg2.append('text')
                .attr('id', 'right-axis-label')
                .attr('x', 177 + offset)
                .attr('y', axes.y2)
                .attr('fill', '#5b564e')
                .attr('text-anchor', 'end')
                .attr('font-size', '10px');

            // Beschriftung "weiblich"
            svg2.append('text')
                .attr('x', 45 + offset)
                .attr('y', 10)
                .attr('fill', '#5b564e')
                .attr('text-anchor', 'middle')
                .attr('font-size', '10px')
                .attr('font-weight', 'bold')
                .text(labels.gender.female[lang]);

            // Beschriftung "männlich"
            svg2.append('text')
                .attr('x', 135 + offset)
                .attr('y', 10)
                .attr('fill', '#5b564e')
                .attr('text-anchor', 'middle')
                .attr('font-size', '10px')
                .attr('font-weight', 'bold')
                .text(labels.gender.male[lang]);

            // // Beschriftung "Altersklassen"
            ['60+','21-59','18-20','14-17','6-13','0-5'].forEach(function (t,i) {
                svg2.append('text')
                    .attr('x',offset)
                    .attr('y',(i+0.5)*rowHeight+3+15)
                    .attr('fill','#5b564e')
                    .attr('font-size', '10px')
                    .attr('text-anchor', 'end')
                    .text(t);
            });

            // // Gradient definitions
            // var defs = svg.append('defs');
            // // left gradient
            // var gradient = defs.append('linearGradient')
            //     .attr('id', 'leftgradient')
            //     .attr('x1', 0)
            //     .attr('x2', 1)
            //     .attr('y1', 1)
            //     .attr('y2', 1);
            // gradient.append('stop')
            //     .attr('class', 'outside')
            //     .attr('offset', '0%');
            // gradient.append('stop')
            //     .attr('class', 'inside')
            //     .attr('offset', '100%');
            // // top gradient
            // gradient = defs.append('linearGradient')
            //     .attr('id', 'topgradient')
            //     .attr('x1', 0)
            //     .attr('x2', 0)
            //     .attr('y1', 0)
            //     .attr('y2', 1);
            // gradient.append('stop')
            //     .attr('class', 'outside')
            //     .attr('offset', '0%');
            // gradient.append('stop')
            //     .attr('class', 'inside')
            //     .attr('offset', '100%');
            // // right gradient
            // gradient = defs.append('linearGradient')
            //     .attr('id', 'rightgradient')
            //     .attr('x1', 0)
            //     .attr('x2', 1)
            //     .attr('y1', 1)
            //     .attr('y2', 1);
            // gradient.append('stop')
            //     .attr('class', 'inside')
            //     .attr('offset', '0%');
            // gradient.append('stop')
            //     .attr('class', 'outside')
            //     .attr('offset', '100%');
            // // bottom gradient
            // gradient = defs.append('linearGradient')
            //     .attr('id', 'bottomgradient')
            //     .attr('x1', 0)
            //     .attr('x2', 0)
            //     .attr('y1', 0)
            //     .attr('y2', 1);
            // gradient.append('stop')
            //     .attr('class', 'inside')
            //     .attr('offset', '0%');
            // gradient.append('stop')
            //     .attr('class', 'outside')
            //     .attr('offset', '100%');
            // // Radial gradient
            // gradient = defs.append('radialGradient')
            //     .attr('id', 'radialgradient');
            // gradient.append('stop')
            //     .attr('class', 'inside')
            //     .attr('offset', '0%');
            // gradient.append('stop')
            //     .attr('class', 'outside')
            //     .attr('offset', '100%');

            // // clippaths for radial gradients
            // tlclip = defs.append('clipPath')
            //     .attr('id', 'tlclip');
            // tlclip.append('rect');
            // trclip = defs.append('clipPath')
            //     .attr('id', 'trclip');
            // trclip.append('rect');
            // blclip = defs.append('clipPath')
            //     .attr('id', 'blclip');
            // blclip.append('rect');
            // brclip = defs.append('clipPath')
            //     .attr('id', 'brclip');
            // brclip.append('rect');

            root = d3.hierarchy(data.tree.children[1])
                .sort(function(a, b) { return b.value - a.value; });

            updateCellValues(root);

            var size = Math.sqrt(width * height * data.tree.children[1].value / data.tree.value);

            treemap = d3.treemap()
                .tile(d3.treemapResquarify)
                // .tile(d3.treemapSquarify)
                // .tile(d3.treemapBinary)
                .size([size, size])
                .paddingInner(0);

            treemap(root);

            cells = [];
            scanCells(root);

            function scanCells(cell) {
                cells.push(cell);

                if (cell.children) cell.children.forEach(scanCells);
                updateCellSize(cell);
                cell.color = cell.data.basecolor.rgb();
            }

            svgLabels = [
                svgContainer.append('text')
                    .attr('text-anchor', 'start')
                    .attr('fill', '#5b564e')
                    .style('font-family', 'Trebuchet MS, Verdana')
                    .style('font-weight', 'bold')
                    .style('font-size', '48px'),
                svgContainer.append('text')
                    .attr('text-anchor', 'start')
                    .attr('fill', '#5b564e')
                    .style('font-family', 'Trebuchet MS, Verdana')
                    .style('font-size', '12px'),
                svgContainer.append('text')
                    .attr('text-anchor', 'end')
                    .attr('fill', '#9f1c1b')
                    .style('font-family', 'Trebuchet MS, Verdana')
                    .style('font-weight', 'bold')
                    .style('font-size', '24px'),
                svgContainer.append('text')
                    .attr('text-anchor', 'end')
                    .attr('fill', '#9f1c1b')
                    .style('font-family', 'Trebuchet MS, Verdana')
                    .style('font-size', '7px')
            ];

            cells.forEach(function (cell) {
                cell.svgGroup = svgContainer.append('g')
                    .on('click', function () {
                        select(selectedNode ? cell : root);
                    })
                    .attr('class', 'treemap depth'+cell.depth);

                cell.svgRect = cell.svgGroup.append('rect')
                    .attr('id', cell.data.nodeid)
                    .attr('fill', cell.color)
                    .attr('class', 'cell')
                    .attr('vector-effect', 'non-scaling-stroke');

                cell.svgGroup.append('clipPath')
                    .attr('id', 'clip-' + cell.data.nodeid)
                    .append('use')
                    .attr('xlink:href', '#' + cell.data.nodeid);

                cell.svgText0 = cell.svgGroup.append('text')
                    .attr('x', 3)
                    .attr('y', 16)
                    .attr('clip-path', 'url(#clip-' + cell.data.nodeid + ')')
                    .style('font-weight', 'bold')
                    .style('font-size', '16px');

                cell.svgText1 = cell.svgGroup.append('text')
                    .attr('clip-path', 'url(#clip-' + cell.data.nodeid + ')')
                    .style('font-size', '8px');
            });

            svgHighlight = svgContainer.append('rect')
                .attr('display','none')
                .attr('fill','none')
                .attr('stroke','#9f1c1b')
                .attr('stroke-width', 3)
                .attr('vector-effect', 'non-scaling-stroke');

            // // dark figure
            // darkFigure = svgContainer.append('g')
            //     .style('visibility', 'visible');

            // // left horizontal gradient
            // // darkFigure.horizontal = darkFigure.append('rect')
            // darkFigure.left = darkFigure.append('rect')
            //     .attr('class', 'hgradient')
            //     .style('fill', 'url(#leftgradient)')
            //     .attr('class', 'dark-figure');

            // // top vertical gradient
            // darkFigure.top = darkFigure.append('rect')
            //     .attr('class', 'vgradient')
            //     .style('fill', 'url(#topgradient)')
            //     .attr('class', 'dark-figure');

            // // gradients need to be inversed on these rects
            // // // right horizontal gradient
            // darkFigure.right = darkFigure.append('rect')
            //     .attr('class', 'hgradient')
            //     .style('fill', 'url(#rightgradient)')
            //     .attr('class', 'dark-figure');

            // // bottom vertical gradient
            // darkFigure.bottom = darkFigure.append('rect')
            //     .attr('class', 'vgradient')
            //     .style('fill', 'url(#bottomgradient)')
            //     .attr('class', 'dark-figure');

            // // top left radial gradient
            // darkFigure.topleft = darkFigure.append('rect')
            //     .attr('class', 'rgradient')
            //     .style('fill', 'url(#radialgradient)')
            //     .attr('class', 'dark-figure')
            //     .attr('clip-path', 'url(#tlclip)');

            // // bottom right radial gradient
            // darkFigure.bottomright = darkFigure.append('rect')
            //     .attr('class', 'rgradient')
            //     .style('fill', 'url(#radialgradient)')
            //     .attr('class', 'dark-figure')
            //     .attr('clip-path', 'url(#brclip)');

            // // bottom left radial gradient
            // darkFigure.bottomleft = darkFigure.append('rect')
            //     .attr('class', 'rgradient')
            //     .style('fill', 'url(#radialgradient)')
            //     .attr('class', 'dark-figure')
            //     .attr('clip-path', 'url(#blclip)');

            // // top right  radial gradient
            // darkFigure.topright = darkFigure.append('rect')
            //     .attr('class', 'rgradient')
            //     .style('fill', 'url(#radialgradient)')
            //     .attr('class', 'dark-figure')
            //     .attr('clip-path', 'url(#trclip)');
        }
    }

    function round(v) {
        // rundet den Wert v auf ganze zahlen, mit zwei signifikanten Ziffern und Tausender-Trennzeichen
        // Also: aus 3852940.5737 wird "3 800 000"

        // var i = 0;

        // Wiviele Ziffern hat der Wert?
        //var digits = Math.floor(Math.log10(v));
        var digits = Math.floor(Math.log(Math.E) / Math.log(v));  // fix for IE < Edge

        // 10^(digits-1) ist der Genauigkeitsfaktor, auf den gerundet werden muss.
        var factor = Math.pow(10,digits-1);
        v = Math.round(v/factor)*factor;
        // Jetzt ist v auf 2 signifikante Stellen gerundet.

        v = v.toFixed(0);

        // v von hinten in 3-Zeichen-Blöcken durchgehen und mit einem &thinsp; trennen.
        var s = '';
        while (v.length > 3) {
            s = String.fromCharCode(8201) + v.substr(-3) + s;
            v = v.substr(0, v.length-3);
        }
        return v+s;
    }

    function updateCellSize(cell) {
        // Breite und Höhe der Zelle berechnen
        // Achtung: Die Zellen werden diagonal gespiegelt.
        cell.w = (cell.y1 - cell.y0) || 0;
        cell.h = (cell.x1 - cell.x0) || 0;

        // Die Zellen werden nicht klein gezeichnet,
        // sondern in normaler Größe und dann klein skaliert (svg transform)

        // Der Skalierungsfaktor fpr die SVG-Transform
        cell.s = Math.min(cell.w, Math.sqrt(cell.w*cell.h))/100;
        if (cell.s < 1e-9) cell.s = 1;

        // x- und y-Position der Zellen definieren,
        // so dass die Treemap rechts unten und diagonal gespiegelt ist.
        cell.x = (width  - cell.y1);
        cell.y = (height - cell.x1);

        // Mit dieser Größe muss die Zelle gezeichnet werden,
        // so dass sie nach dem Skalieren die Größe von cell.w/cell.h hat.
        cell.rw = cell.w/cell.s;
        cell.rh = cell.h/cell.s;
    }

    function textToLines(text, maxWidth) {
        // Versucht einen Text so in mehrere Zeilen umzubrechen,
        // so dass jede Zeile nicht länger ist als maxWidth

        var lines = text.split('#');
        return lines.map(function (line) {
            line = line.split(' ');
            var i = 0;
            while (i < line.length-1) {
                if (line[i].length+line[i+1].length < maxWidth) {
                    line = [].concat(
                        line.slice(0,i),
                        [line[i]+' '+line[i+1]],
                        line.slice(i+2)
                    );
                    i--;
                }
                i++;
            }
            return line.join('#');
        }).join('#').split('#');
    }
}

crime();
