import config from './config.json';
import * as d3 from './d3-custom';
import { PDFExport } from './pdfExport';
import createSearchIndex from './search';

// Using postcss, see rollup.config.js for configuration
import '../css/main.css';

function jobLoss() {

    let groups, width, height, selection = -1, oldSelection = selection;
    // selection speichert, welche Berufsgruppe ausgewählt ist
    // Ist selection == -1, dann wird die Überblicksgrafik gezeichnet

    let filteredEntries = [];
    let selectedEntry = undefined;
    let lang = undefined;

    let pdfx = undefined;

    let rowHeight = 30;
    let duration1 = 500, duration2 = 1500, duration3 = 500;

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

    config.path = location.pathname.substr(0, location.pathname.lastIndexOf('/') + 1);

    // set title and labels
    document.title = config.title[lang];
    document.querySelector('#search-label').innerHTML = config.labels.search[lang];

    pdfx = new PDFExport(this, config, lang);

    var svgChart = d3.select('#scroll').append('svg');
    var svgControls = d3.select('.controls')
        .insert('svg', 'div.form-inline')
        .attr('class', 'svg-controls');
    svgControls.attr('width', '58px')
        .attr('height', '35px');

    // Bezeichenr für die Berufsgruppen, links
    var svgLabels = svgChart.append('g')
        .attr('class','groupLabels')
        .attr('opacity',1);

    // Container für die Balken
    var svgContainer = svgChart.append('g');

    // Zurück-geh-Pfeil links oben
    var svgArrow = svgControls.append('path')
        .attr('d', 'M45.7,19.5H22.8v6.8L0,13.1L22.8,0v6.8h22.9V19.5z')
        .attr('fill', 'rgba(255,255,255,1)')
        .attr('opacity', 0)
        .attr('display', 'none')
        .style('cursor', 'pointer')
        .on('click', function () {
            hideAnnotation();
            d3.select('body')
                .transition()
                .duration(duration1)
                .tween('scrollToTop', scrollTopTween(0));
            selectedEntry.d3row.classed('highlight', false);
            selectedEntry = undefined;
            selection = -1;
            redraw();

            d3.select('.export-button')  // fade out pdf export button
                .transition()
                .duration(duration3)
                .style('opacity', 0);

            d3.select('#search').node().value = '';

            setTimeout(function() {  // fade in search form with delay
                d3.select('.search-form').classed('hidden', false);
                d3.select('.search-form')
                    .transition()
                    .duration(duration3)
                    .style('opacity', 1);
                d3.select('.export-button')
                    .classed('hidden', true);
            }, duration1 + duration2);
        });

    var tooltip = d3.select('#scroll')
        .append('div')
        .classed('hidden', true)
        .attr('id', 'tooltip');


    d3.json(config.data.file.path + '/' + config.data.file.name[lang], function(_data) {

        var entries = _data.map(function (entry, index) {
            return {
                label: entry.label,
                group: entry.level0,
                level1: entry.level1,
                value: entry.prob,
                text: entry.label + ': ' + formatPercentage(entry.prob),
                index: index,
                // points: entry.points,
                skills: entry.skills,
                similar: entry.similar
            };
        });

        entries.forEach(function (entry) {
            entry.similar.forEach(function (sim) {
                sim.entry = entries[sim.index];
            });
        });

        entries.sort(function (a,b) {
            return a.value - b.value;
        });

        // Gruppiere alle Einträge nach den großen Berufsgruppen
        groups = {};
        entries.forEach(function (entry) {
            var key = entry.group;
            if (!groups[key]) {
                groups[key] = {
                    name: lang === 'de'? key : key.substr(0,key.length-12),  // strip 'occupations' from english group names (dsst)
                    entries: [],
                    level1: {},
                    sum: 0,
                    container: svgContainer.append('g').attr('opacity',1)
                };
            }

            groups[key].entries.push(entry);
            groups[key].sum += entry.value;
            groups[key].level1[entry.level1] = true;
            entry.group = groups[key];
        });

        // console.log(entries);
        groups = Object.keys(groups).map(function (key) {
            return groups[key];
        });

        groups.forEach(function (group) {
            // Generiere Liste der Berufsuntergruppen
            group.level1 = Object.keys(group.level1);
            group.sum /= group.entries.length;
        });

        // Sortiere Gruppen nach durchschnittlicher Ersetzbarkeit
        groups.sort(function (a,b) {
            return a.sum - b.sum;
        });

        let searchIndex = createSearchIndex(entries, 'index', ['label'], lang);

        d3.select('#search')
            .on('input', function(){

                let searchResults = searchIndex.searchFor(this.value);

                filteredEntries.forEach(function(e) {
                    e.d3row.classed('highlight', false);
                });
                filteredEntries = searchResults;
                redraw();  // redraw to show highlights
            });

        // Einzelne Gruppen vorbereiten
        groups.forEach(function (group, index) {
            group.index = index;

            // Richtung der Tooltips vorbereiten
            group.direction = (index < groups.length-3) ? 's' : 'n';

            // Gruppenbezeichnung am linken Rand
            group.d3label = svgLabels.append('text')
                .attr('text-anchor', 'end')
                .text(group.name)
                .style('cursor', 'default')
                .on('mouseover', function (event) {
                    d3.select(this).classed('group-active', true);
                    showAnnotation(event.target ,group, 'group');
                })
                .on('mouseout', function () {
                    d3.select(this).classed('group-active', false);
                    hideAnnotation();
                });
            group.entries.forEach(function (entry, index) {
                entry.direction = (index < group.entries.length-6) ? 's' : 'n';
            });
        });

        redraw();
    });

    function showAnnotation(target, data, mode) {

        var ttheight = (height - 1) / groups.length;

        var html;
        var wbbox = document.body.getBoundingClientRect();
        var pbbox = target.parentNode.getBoundingClientRect();
        var tbbox = target.getBoundingClientRect();
        var tx = 0;
        var ty = 0;
        var rightAligned = false;
        var lineHeight = 'normal';
        var padding = 'initial';
        var pointerEvents = 'initial';
        var transform = 'initial';
        var twidth = 'initial';
        var textAlign = 'initial';
        var backgroundColour = 'rgba(255,255,255,0.8)';

        switch(mode) {
            case 'group':
                var gArray = Array.prototype.slice.call(target.parentNode.childNodes);

                html = '<ul><li>';
                var list = data.level1.join('</li><li>');
                html += list + '</li></ul>';

                tx = '300px';  // show tooltip right beside group name column
                padding = '0 2rem 0 0';
                lineHeight = (ttheight + 1) + 'px';

                var idx = gArray.indexOf(target);
                var ridx = Math.min(idx, gArray.length - data.level1.length);  // Ensure that complete data.level1 list is visible in every case

                ty = ridx * (ttheight) + 'px';
                break;
            case 'entry-title':  // complex positioning due to invisible overflowing svg elements
                html = data.label;
                // display tooltip on right / left hand side of selection depending on mouse cursor position in relation to bar graph area centre
                if (tbbox.x + pbbox.width < (wbbox.width + 300) / 2) {
                    tx = (pbbox.x + pbbox.width) + 'px';
                } else {  // tx needs to be calculated after html is rendered...see below "tooltip.style('left',...)"
                    rightAligned = true;
                }
                ty = (pbbox.y - 32) + 'px';  // hard coded controls bar height + one pixel or two (cough). see #chart top offset

                twidth = '35rem';
                lineHeight = ttheight + 'px';
                padding = '0 2rem';
                pointerEvents = 'none';
                textAlign = 'center';
                break;
            case 'entry-details':
                html = data.text;
                tx = '50%';

                ty = (pbbox.y + scrollPosition()) + 'px';
                transform = 'translate(-50%, 0)';
                html = [
                    '<h3>' + config.labels.similar[lang] + '</h3>',
                    '<table><tbody>'
                ];
                data.similar.forEach(function (sim, i) {
                    html.push('<tr><td>' + (i + 1) + '. ' + sim.entry.label + '</td><td>' + formatPercentage(sim.entry.value) + '</td></tr>');
                });
                html.push('</tbody></table>');

                // pdf export button
                html = html.join('') +
                    '<div id="export" class="form-inline export-button">' +
                    '<a href="#" id="exportPDF" class="export button" download="pdfilename.pdf">' +
                    '<label id="export-factbox-pdf" class="form-item">pdf Export</label>' +
                    '</a>' +
                    '</div>' +
                    '<div class="context">' +
                        '<p>Prozente geben an, wie wahrscheinlich die Aufgaben eines Berufs digitalisierbar sind</p>'+
                    '</div';

                lineHeight = rowHeight - 1 + 'px';
                padding = '3rem 5rem';
                twidth = '40rem';
                break;
            default:
                console.error('invalid mode');
        }

        tooltip.html(html); // first render the html, then adjust sizing and positioning of tooltip

        tooltip
            .style('left', function() {  // adjust position of tooltip when displayed to the left of selected element
                tx = rightAligned === true ? (tbbox.x - tooltip.node().getBoundingClientRect().width) + 'px' : tx;
                return tx;
            })
            .style('background-color', backgroundColour)
            .style('top', ty)
            .style('min-height', ttheight + 'px')
            .style('line-height', lineHeight)
            .style('transform', transform)
            .style('padding', padding)
            .style('pointer-events', pointerEvents)
            .style('text-align', textAlign)
            .style('width', twidth)
            .classed('hidden', false);
    }

    function hideAnnotation() {
        tooltip.classed('hidden', true);
    }

    function scrollToSelected() {
        let wdim = document.body.getBoundingClientRect();
        let tdim = d3.select('.highlight').node().getBoundingClientRect();
        let yPos = tdim.y + scrollPosition() - wdim.height / 2;

        if (yPos > 0) {
            d3.select('body')
                .transition()
                .duration(duration1)
                .tween('scrollToSelected', scrollTopTween(yPos));

        }
    }

    function formatPercentage(prob) {
        return (prob * 100).toFixed(0) + '%';
    }

    function scrollPosition() { // cross-browser, check on more browsers, OS
        return (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
    }

    function scrollTopTween(st) { // natural scrolling. Test this!!! (IE)
        return function() {
            let i = d3.interpolateNumber(scrollPosition(), st);
            let scrollElement = document.scrollingElement || document.documentElement;
            return function(t) { scrollElement.scrollTop = i(t); };
        };
    }

    d3.select(window).on('resize', redraw);

    function redraw() {
        if (!groups) return;

        // Breite und Höhe des Containers
        width = d3.select('#chart').node().offsetWidth;
        height = d3.select('#chart').node().offsetHeight;

        var animation = (selection !== oldSelection);

        svgChart.attr('width', width);

        // definiere Hintergrund und Vordergrundfarben der Balken
        var strongColors = d3.scaleLinear(d3.interpolateLab)
            .domain([0,0.75,1])
            .range(['#1cb5aa', '#117b90', '#00485e']);
        var lightColors = d3.scaleLinear(d3.interpolateLab)
            .domain([0,0.75,1])
            .range(['#c6f6f3', '#cef2f9', '#c0f0ff']);

        // Wenn selection kleiner als 0, dann zeichne Überblicksdarstellung
        var overview = (selection < 0);

        if (overview) {  // Übersichtsdarstellung
            var leftPadding = 300;
            var groupHeight = (height - 1)/groups.length;
            var groupWidth = width-leftPadding;
            var scaleX = groupWidth/rowHeight;
            var scaleY = (groupHeight-2)/width;

            svgChart.attr('height', height);

            anim(svgLabels, '321').attr('opacity', 1);

            anim(svgArrow, '3')
                .attr('opacity', 0)
                .transition()
                .attr('display', 'none');

            groups.forEach(function (group, index) {
                var wasSelected = (index === oldSelection);

                drawGroup(group);

                var count = group.entries.length;

                group.d3label
                    .attr('x', leftPadding - 5)
                    .attr('y', (index + 0.5)*groupHeight + 5);

                if (wasSelected) {
                    anim(group.container, '32')
                        .attr('transform', 'translate('+leftPadding+', '+(index+1)*groupHeight+') scale('+scaleX/count+','+scaleY+') rotate(-90 0 0)');
                } else {
                    anim(group.container, '320')
                        .attr('transform', 'translate('+leftPadding+', '+(index+1)*groupHeight+') scale('+scaleX/count+','+scaleY+') rotate(-90 0 0)')
                        .attr('display', 'inline');
                }

                anim(group.container, '321')
                    .attr('opacity', 1);

            });
        } else {  // Darstellung der ausgewählten Gruppe

            if (animation) {
                groups.forEach(function (group, index) {
                    var t = anim(group.container, '1');
                    t.attr('opacity', (index === selection) ? 1 : 0);
                    t = anim(t, '0');
                    t.attr('display', (index === selection) ? 'inline' : 'none');

                });
                anim(svgLabels, '1').attr('opacity', 0);

                svgArrow
                    .attr('display', 'inline')
                    .attr('transform', 'translate(5,5)');
                anim(svgArrow, '123').attr('opacity', 1);  // fade in arrow

                // fade out search form
                d3.select('.search-form')
                    .transition()
                    .duration(duration3)
                    .style('opacity', 0);

                // wait for all animations involved in transtition from overview to group view to finish
                // then scroll to selected element
                // fade in pdf export button
                setTimeout(function () {
                    scrollToSelected();
                    d3.select('.export-button').classed('hidden', false);
                    d3.select('.export-button')
                        .transition()
                        .duration(duration3)
                        .style('opacity', 1);
                    d3.select('.search-form').classed('hidden', true);
                }, duration1+duration2);
            } else {  // scroll to selected element without delay (when another entry is clicked in group view)
                scrollToSelected();
            }

            var group = groups[selection];
            height = rowHeight*(group.entries.length);

            if (svgChart.attr('height') < height) {
                anim(svgChart,'0').attr('height', height);
            } else {
                anim(svgChart,'1230').attr('height', height);
            }

            drawGroup(group);

            anim(group.container, '12')
                .attr('transform', 'translate(0,0) scale(1) rotate(0)');

        }

        oldSelection = selection;

        // Zeichne eine Berufsgruppe mit all ihren Balken
        // Dabei wird unterschieden, ob sie im Überblick vereinfacht gezeichnet werden,
        // oder detailliert in der Listen-Darstellung
        function drawGroup(group) {
            var entries = group.entries;

            entries.forEach(function (entry, index) {
                var strongColor = strongColors(entry.value);
                var lightColor = lightColors(entry.value);

                if (!entry.d3row) {

                    entry.d3row = group.container.append('g');

                    if (filteredEntries.indexOf(entry) === -1) {
                        entry.d3row.classed('highlight', false);
                    }

                    entry.d3clippath = svgChart.append('clipPath')
                        .attr('id', 'clip'+entry.index)
                        .append('rect');

                    entry.d3rectB = entry.d3row.append('rect')
                        .attr('fill', lightColor);

                    entry.d3textB = entry.d3row.append('text')
                        .attr('x', 5)
                        .attr('fill', strongColor)
                        .text(entry.text);

                    entry.d3rectF = entry.d3row.append('rect')
                        .attr('x', 0)
                        .attr('y', 0)
                        .attr('fill', strongColor);

                    entry.d3textF = entry.d3row.append('text')
                        .attr('x', 5)
                        .attr('clip-path', 'url(#clip'+entry.index+')')
                        .attr('class', 'clipped')
                        .text(entry.text);

                    entry.d3row
                        .attr('class', 'job')
                        .on('click', function (event) {

                            // 'delete' and hide highlights
                            filteredEntries.forEach(function(e){
                                e.d3row.classed('highlight', false);
                            });

                            selectedEntry.d3row.classed('highlight', false);  // clear previous selection
                            filteredEntries = [];  // reset search results
                            selectedEntry = entry;
                            selectedEntry.d3row.classed('highlight', true);  // set new selection

                            if (selection >= 0) {
                                //update tooltip
                                showAnnotation(event.target, entry, 'entry-details');
                                pdfx.drawPDF(entry);
                            } else {
                                hideAnnotation();
                                setTimeout(function () {
                                    showAnnotation(event.target, entry, 'entry-details');
                                    pdfx.drawPDF(entry);
                                }, duration1+duration2+duration3);
                            }

                            selection = group.index;
                            redraw();
                        })
                        .on('mouseover', function (event) {
                            if (selection < 0) {
                                selectedEntry = entry;
                                selectedEntry.d3row.classed('highlight', true);
                                showAnnotation(event.target, entry, 'entry-title');
                            }
                        })
                        .on('mouseout', function () {
                            if (selection < 0) {
                                hideAnnotation();
                                selectedEntry = undefined;
                                if(filteredEntries.indexOf(entry) === -1) {  // keep search hits higlighted
                                    entry.d3row.classed('highlight', false);
                                }
                            }
                        });
                }

                entry.d3row.attr('transform', 'translate(0,' + (rowHeight*index) + ')');

                if (overview && filteredEntries.length === 0) {  // animate back from group view to overview

                    anim(entry.d3rectB,'32')
                        .attr('x', 0)
                        .attr('y', 0)
                        .attr('width', width)
                        .attr('height', rowHeight);

                    anim(entry.d3textB,'3')
                        .attr('opacity', 0);

                    anim(entry.d3rectF,'32')
                        .attr('width', entry.value*width)
                        .attr('height', rowHeight);

                    anim(entry.d3textF,'3')
                        .attr('opacity', 0);

                } else if (overview && filteredEntries.length > 0){  // highlight filtered elements in overview
                    if(filteredEntries.indexOf(entry) !== -1) {
                        entry.d3row.classed('highlight', true);
                    }
                } else {  // animation to selected group view
                    var barWidth = entry.value*width;
                    entry.d3clippath
                        .attr('width', barWidth)
                        .attr('height', rowHeight);

                    anim(entry.d3rectB,'12')
                        .attr('x', 1)
                        .attr('y', 0)
                        .attr('width', width-2)
                        .attr('height', rowHeight-1);

                    anim(entry.d3rectB,'123')
                        .attr('stroke-opacity', 1);

                    entry.d3textB.attr('y', rowHeight/2 + 4);
                    anim(entry.d3textB,'123').attr('opacity', 1);

                    anim(entry.d3rectF,'12')
                        .attr('width', barWidth)
                        .attr('height', rowHeight-1);

                    entry.d3textF.attr('y', rowHeight/2 + 4);
                    anim(entry.d3textF,'123').attr('opacity', 1);
                }
            });
        }


        function anim(d3node, delaySteps) {
            // anim bekommt einen d3-node, die animiert werden soll
            // delaySteps definiert, welcher der 3 Animation-Schritte (1,2,3)
            // animiert wird.
            // Beispiel: delaySteps = "123": warte Animation für Schritt 1 und 2 ab, und animiere Schritt 3

            if (!animation) return d3node;
            var delay = 0, duration = 0;
            delaySteps.split('').forEach(function (c) {
                delay += duration;
                switch (c) {
                    case '0': duration = 0; break;
                    case '1': duration = duration1; break;
                    case '2': duration = duration2; break;
                    case '3': duration = duration3; break;
                }
            });
            return d3node.transition().delay(delay).duration(duration);
        }
    }
}

jobLoss();
