'use strict';

var d3 = require('@plotly/d3');
var Lib = require('../../lib');
var Drawing = require('../../components/drawing');
var BADNUM = require('../../constants/numerical').BADNUM;
var barPlot = require('../bar/plot');
var clearMinTextSize = require('../bar/uniform_text').clearMinTextSize;

module.exports = function plot(gd, plotinfo, cdModule, traceLayer) {
    var fullLayout = gd._fullLayout;

    clearMinTextSize('funnel', fullLayout);

    plotConnectorRegions(gd, plotinfo, cdModule, traceLayer);
    plotConnectorLines(gd, plotinfo, cdModule, traceLayer);

    barPlot.plot(gd, plotinfo, cdModule, traceLayer, {
        mode: fullLayout.funnelmode,
        norm: fullLayout.funnelmode,
        gap: fullLayout.funnelgap,
        groupgap: fullLayout.funnelgroupgap
    });
};

function plotConnectorRegions(gd, plotinfo, cdModule, traceLayer) {
    var xa = plotinfo.xaxis;
    var ya = plotinfo.yaxis;

    Lib.makeTraceGroups(traceLayer, cdModule, 'trace bars').each(function(cd) {
        var plotGroup = d3.select(this);
        var trace = cd[0].trace;

        var group = Lib.ensureSingle(plotGroup, 'g', 'regions');

        if(!trace.connector || !trace.connector.visible) {
            group.remove();
            return;
        }

        var isHorizontal = (trace.orientation === 'h');

        var connectors = group.selectAll('g.region').data(Lib.identity);

        connectors.enter().append('g')
            .classed('region', true);

        connectors.exit().remove();

        var len = connectors.size();

        connectors.each(function(di, i) {
            // don't draw lines between nulls
            if(i !== len - 1 && !di.cNext) return;

            var xy = getXY(di, xa, ya, isHorizontal);
            var x = xy[0];
            var y = xy[1];

            var shape = '';

            if(
                x[0] !== BADNUM && y[0] !== BADNUM &&
                x[1] !== BADNUM && y[1] !== BADNUM &&
                x[2] !== BADNUM && y[2] !== BADNUM &&
                x[3] !== BADNUM && y[3] !== BADNUM
            ) {
                if(isHorizontal) {
                    shape += 'M' + x[0] + ',' + y[1] + 'L' + x[2] + ',' + y[2] + 'H' + x[3] + 'L' + x[1] + ',' + y[1] + 'Z';
                } else {
                    shape += 'M' + x[1] + ',' + y[1] + 'L' + x[2] + ',' + y[3] + 'V' + y[2] + 'L' + x[1] + ',' + y[0] + 'Z';
                }
            }

            if(shape === '') shape = 'M0,0Z';

            Lib.ensureSingle(d3.select(this), 'path')
                .attr('d', shape)
                .call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
        });
    });
}

function plotConnectorLines(gd, plotinfo, cdModule, traceLayer) {
    var xa = plotinfo.xaxis;
    var ya = plotinfo.yaxis;

    Lib.makeTraceGroups(traceLayer, cdModule, 'trace bars').each(function(cd) {
        var plotGroup = d3.select(this);
        var trace = cd[0].trace;

        var group = Lib.ensureSingle(plotGroup, 'g', 'lines');

        if(!trace.connector || !trace.connector.visible || !trace.connector.line.width) {
            group.remove();
            return;
        }

        var isHorizontal = (trace.orientation === 'h');

        var connectors = group.selectAll('g.line').data(Lib.identity);

        connectors.enter().append('g')
            .classed('line', true);

        connectors.exit().remove();

        var len = connectors.size();

        connectors.each(function(di, i) {
            // don't draw lines between nulls
            if(i !== len - 1 && !di.cNext) return;

            var xy = getXY(di, xa, ya, isHorizontal);
            var x = xy[0];
            var y = xy[1];

            var shape = '';

            if(x[3] !== undefined && y[3] !== undefined) {
                if(isHorizontal) {
                    shape += 'M' + x[0] + ',' + y[1] + 'L' + x[2] + ',' + y[2];
                    shape += 'M' + x[1] + ',' + y[1] + 'L' + x[3] + ',' + y[2];
                } else {
                    shape += 'M' + x[1] + ',' + y[1] + 'L' + x[2] + ',' + y[3];
                    shape += 'M' + x[1] + ',' + y[0] + 'L' + x[2] + ',' + y[2];
                }
            }

            if(shape === '') shape = 'M0,0Z';

            Lib.ensureSingle(d3.select(this), 'path')
                .attr('d', shape)
                .call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
        });
    });
}

function getXY(di, xa, ya, isHorizontal) {
    var s = [];
    var p = [];

    var sAxis = isHorizontal ? xa : ya;
    var pAxis = isHorizontal ? ya : xa;

    s[0] = sAxis.c2p(di.s0, true);
    p[0] = pAxis.c2p(di.p0, true);

    s[1] = sAxis.c2p(di.s1, true);
    p[1] = pAxis.c2p(di.p1, true);

    s[2] = sAxis.c2p(di.nextS0, true);
    p[2] = pAxis.c2p(di.nextP0, true);

    s[3] = sAxis.c2p(di.nextS1, true);
    p[3] = pAxis.c2p(di.nextP1, true);

    return isHorizontal ? [s, p] : [p, s];
}
