'use strict';

var Lib = require('../../lib');
var Axes = require('../../plots/cartesian/axes');
var handleArrayContainerDefaults = require('../../plots/array_container_defaults');

var attributes = require('./attributes');
var helpers = require('./helpers');


module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
    handleArrayContainerDefaults(layoutIn, layoutOut, {
        name: 'shapes',
        handleItemDefaults: handleShapeDefaults
    });
};

function dfltLabelYanchor(isLine, labelTextPosition) {
    // If shape is a line, default y-anchor is 'bottom' (so that text is above line by default)
    // Otherwise, default y-anchor is equal to y-component of `textposition`
    // (so that text is positioned inside shape bounding box by default)
    return isLine ? 'bottom' :
        labelTextPosition.indexOf('top') !== -1 ? 'top' :
        labelTextPosition.indexOf('bottom') !== -1 ? 'bottom' : 'middle';
}

function handleShapeDefaults(shapeIn, shapeOut, fullLayout) {
    function coerce(attr, dflt) {
        return Lib.coerce(shapeIn, shapeOut, attributes, attr, dflt);
    }

    shapeOut._isShape = true;

    var visible = coerce('visible');
    if(!visible) return;

    var showlegend = coerce('showlegend');
    if(showlegend) {
        coerce('legend');
        coerce('legendwidth');
        coerce('legendgroup');
        coerce('legendgrouptitle.text');
        Lib.coerceFont(coerce, 'legendgrouptitle.font');
        coerce('legendrank');
    }

    var path = coerce('path');
    var dfltType = path ? 'path' : 'rect';
    var shapeType = coerce('type', dfltType);
    var noPath = shapeType !== 'path';
    if(noPath) delete shapeOut.path;

    coerce('editable');
    coerce('layer');
    coerce('opacity');
    coerce('fillcolor');
    coerce('fillrule');
    var lineWidth = coerce('line.width');
    if(lineWidth) {
        coerce('line.color');
        coerce('line.dash');
    }

    var xSizeMode = coerce('xsizemode');
    var ySizeMode = coerce('ysizemode');

    // positioning
    var axLetters = ['x', 'y'];
    for(var i = 0; i < 2; i++) {
        var axLetter = axLetters[i];
        var attrAnchor = axLetter + 'anchor';
        var sizeMode = axLetter === 'x' ? xSizeMode : ySizeMode;
        var gdMock = {_fullLayout: fullLayout};
        var ax;
        var pos2r;
        var r2pos;

        // xref, yref
        var axRef = Axes.coerceRef(shapeIn, shapeOut, gdMock, axLetter, undefined,
            'paper');
        var axRefType = Axes.getRefType(axRef);

        if(axRefType === 'range') {
            ax = Axes.getFromId(gdMock, axRef);
            ax._shapeIndices.push(shapeOut._index);
            r2pos = helpers.rangeToShapePosition(ax);
            pos2r = helpers.shapePositionToRange(ax);
            if(ax.type === 'category' || ax.type === 'multicategory') {
                coerce(axLetter + '0shift');
                coerce(axLetter + '1shift');
            }
        } else {
            pos2r = r2pos = Lib.identity;
        }

        // Coerce x0, x1, y0, y1
        if(noPath) {
            var dflt0 = 0.25;
            var dflt1 = 0.75;

            // hack until V3.0 when log has regular range behavior - make it look like other
            // ranges to send to coerce, then put it back after
            // this is all to give reasonable default position behavior on log axes, which is
            // a pretty unimportant edge case so we could just ignore this.
            var attr0 = axLetter + '0';
            var attr1 = axLetter + '1';
            var in0 = shapeIn[attr0];
            var in1 = shapeIn[attr1];
            shapeIn[attr0] = pos2r(shapeIn[attr0], true);
            shapeIn[attr1] = pos2r(shapeIn[attr1], true);

            if(sizeMode === 'pixel') {
                coerce(attr0, 0);
                coerce(attr1, 10);
            } else {
                Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attr0, dflt0);
                Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attr1, dflt1);
            }

            // hack part 2
            shapeOut[attr0] = r2pos(shapeOut[attr0]);
            shapeOut[attr1] = r2pos(shapeOut[attr1]);
            shapeIn[attr0] = in0;
            shapeIn[attr1] = in1;
        }

        // Coerce xanchor and yanchor
        if(sizeMode === 'pixel') {
            // Hack for log axis described above
            var inAnchor = shapeIn[attrAnchor];
            shapeIn[attrAnchor] = pos2r(shapeIn[attrAnchor], true);

            Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attrAnchor, 0.25);

            // Hack part 2
            shapeOut[attrAnchor] = r2pos(shapeOut[attrAnchor]);
            shapeIn[attrAnchor] = inAnchor;
        }
    }

    if(noPath) {
        Lib.noneOrAll(shapeIn, shapeOut, ['x0', 'x1', 'y0', 'y1']);
    }

    // Label options
    var isLine = shapeType === 'line';
    var labelTextTemplate, labelText;
    if(noPath) { labelTextTemplate = coerce('label.texttemplate'); }
    if(!labelTextTemplate) { labelText = coerce('label.text'); }
    if(labelText || labelTextTemplate) {
        coerce('label.textangle');
        var labelTextPosition = coerce('label.textposition', isLine ? 'middle' : 'middle center');
        coerce('label.xanchor');
        coerce('label.yanchor', dfltLabelYanchor(isLine, labelTextPosition));
        coerce('label.padding');
        Lib.coerceFont(coerce, 'label.font', fullLayout.font);
    }
}
