import CLASS from './class';
import { ChartInternal } from './core';
import { getBBox, isValue, isWithinBox } from './util';

ChartInternal.prototype.initBar = function () {
    var $$ = this;
    $$.main.select('.' + CLASS.chart).append("g")
        .attr("class", CLASS.chartBars);
};
ChartInternal.prototype.updateTargetsForBar = function (targets) {
    var $$ = this, config = $$.config,
        mainBars, mainBarEnter,
        classChartBar = $$.classChartBar.bind($$),
        classBars = $$.classBars.bind($$),
        classFocus = $$.classFocus.bind($$);
    mainBars = $$.main.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
        .data(targets)
        .attr('class', function (d) { return classChartBar(d) + classFocus(d); });
    mainBarEnter = mainBars.enter().append('g')
        .attr('class', classChartBar)
        .style("pointer-events", "none");
    // Bars for each data
    mainBarEnter.append('g')
        .attr("class", classBars)
        .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });

};
ChartInternal.prototype.updateBar = function (durationForExit) {
    var $$ = this,
        barData = $$.barData.bind($$),
        classBar = $$.classBar.bind($$),
        initialOpacity = $$.initialOpacity.bind($$),
        color = function (d) { return $$.color(d.id); };
    var mainBar = $$.main.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
        .data(barData);
    var mainBarEnter = mainBar.enter().append('path')
        .attr("class", classBar)
        .style("stroke", color)
        .style("fill", color);
    $$.mainBar = mainBarEnter.merge(mainBar)
        .style("opacity", initialOpacity);
    mainBar.exit().transition().duration(durationForExit)
        .style("opacity", 0);
};
ChartInternal.prototype.redrawBar = function (drawBar, withTransition, transition) {
    const $$ = this;

    return [
        (withTransition ? this.mainBar.transition(transition) : this.mainBar)
            .attr('d', drawBar)
            .style("stroke", this.color)
            .style("fill", this.color)
            .style("opacity", (d) => $$.isTargetToShow(d.id) ? 1 : 0)
    ];
};
ChartInternal.prototype.getBarW = function (axis, barTargetsNum) {
    var $$ = this, config = $$.config,
        w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickInterval() * config.bar_width_ratio) / barTargetsNum : 0;
    return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
};
ChartInternal.prototype.getBars = function (i, id) {
    var $$ = this;
    return (id ? $$.main.selectAll('.' + CLASS.bars + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
};
ChartInternal.prototype.expandBars = function (i, id, reset) {
    var $$ = this;
    if (reset) { $$.unexpandBars(); }
    $$.getBars(i, id).classed(CLASS.EXPANDED, true);
};
ChartInternal.prototype.unexpandBars = function (i) {
    var $$ = this;
    $$.getBars(i).classed(CLASS.EXPANDED, false);
};
ChartInternal.prototype.generateDrawBar = function (barIndices, isSub) {
    var $$ = this, config = $$.config,
        getPoints = $$.generateGetBarPoints(barIndices, isSub);
    return function (d, i) {
        // 4 points that make a bar
        var points = getPoints(d, i);

        // switch points if axis is rotated, not applicable for sub chart
        var indexX = config.axis_rotated ? 1 : 0;
        var indexY = config.axis_rotated ? 0 : 1;

        var path = 'M ' + points[0][indexX] + ',' + points[0][indexY] + ' ' +
                'L' + points[1][indexX] + ',' + points[1][indexY] + ' ' +
                'L' + points[2][indexX] + ',' + points[2][indexY] + ' ' +
                'L' + points[3][indexX] + ',' + points[3][indexY] + ' ' +
                'z';

        return path;
    };
};
ChartInternal.prototype.generateGetBarPoints = function (barIndices, isSub) {
    var $$ = this,
        axis = isSub ? $$.subXAxis : $$.xAxis,
        barTargetsNum = barIndices.__max__ + 1,
        barW = $$.getBarW(axis, barTargetsNum),
        barX = $$.getShapeX(barW, barTargetsNum, barIndices, !!isSub),
        barY = $$.getShapeY(!!isSub),
        barOffset = $$.getShapeOffset($$.isBarType, barIndices, !!isSub),
        barSpaceOffset = barW * ($$.config.bar_space / 2),
        yScale = isSub ? $$.getSubYScale : $$.getYScale;
    return function (d, i) {
        var y0 = yScale.call($$, d.id)(0),
            offset = barOffset(d, i) || y0, // offset is for stacked bar chart
            posX = barX(d), posY = barY(d);
        // fix posY not to overflow opposite quadrant
        if ($$.config.axis_rotated) {
            if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
        }

        posY -= (y0 - offset);

        // 4 points that make a bar
        return [
            [posX + barSpaceOffset, offset],
            [posX + barSpaceOffset, posY],
            [posX + barW - barSpaceOffset, posY],
            [posX + barW - barSpaceOffset, offset]
        ];
    };
};

/**
 * Returns whether the data point is within the given bar shape.
 *
 * @param mouse
 * @param barShape
 * @return {boolean}
 */
ChartInternal.prototype.isWithinBar = function (mouse, barShape) {
    return isWithinBox(mouse, getBBox(barShape), 2);
};
