/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/


'use strict';

var Axes = require('../cartesian/axes');

var convertHTMLToUnicode = require('../../lib/html2unicode');
var str2RGBArray = require('../../lib/str2rgbarray');

function Axes2DOptions(scene) {
    this.scene = scene;
    this.gl = scene.gl;
    this.pixelRatio = scene.pixelRatio;

    this.screenBox = [0, 0, 1, 1];
    this.viewBox = [0, 0, 1, 1];
    this.dataBox = [-1, -1, 1, 1];

    this.borderLineEnable = [false, false, false, false];
    this.borderLineWidth = [1, 1, 1, 1];
    this.borderLineColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.ticks = [[], []];
    this.tickEnable = [true, true, false, false];
    this.tickPad = [15, 15, 15, 15];
    this.tickAngle = [0, 0, 0, 0];
    this.tickColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];
    this.tickMarkLength = [0, 0, 0, 0];
    this.tickMarkWidth = [0, 0, 0, 0];
    this.tickMarkColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.labels = ['x', 'y'];
    this.labelEnable = [true, true, false, false];
    this.labelAngle = [0, Math.PI / 2, 0, 3.0 * Math.PI / 2];
    this.labelPad = [15, 15, 15, 15];
    this.labelSize = [12, 12];
    this.labelFont = ['sans-serif', 'sans-serif'];
    this.labelColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.title = '';
    this.titleEnable = true;
    this.titleCenter = [0, 0, 0, 0];
    this.titleAngle = 0;
    this.titleColor = [0, 0, 0, 1];
    this.titleFont = 'sans-serif';
    this.titleSize = 18;

    this.gridLineEnable = [true, true];
    this.gridLineColor = [
        [0, 0, 0, 0.5],
        [0, 0, 0, 0.5]
    ];
    this.gridLineWidth = [1, 1];

    this.zeroLineEnable = [true, true];
    this.zeroLineWidth = [1, 1];
    this.zeroLineColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.borderColor = false;
    this.backgroundColor = [0, 0, 0, 0];

    this.static = this.scene.staticPlot;
}

var proto = Axes2DOptions.prototype;

var AXES = ['xaxis', 'yaxis'];

proto.merge = function(options) {

    // titles are rendered in SVG
    this.titleEnable = false;
    this.backgroundColor = str2RGBArray(options.plot_bgcolor);

    var axisName, ax, axTitle, axMirror;
    var hasAxisInDfltPos, hasAxisInAltrPos, hasSharedAxis, mirrorLines, mirrorTicks;
    var i, j;

    for(i = 0; i < 2; ++i) {
        axisName = AXES[i];
        var axisLetter = axisName.charAt(0);

        // get options relevant to this subplot,
        // '_name' is e.g. xaxis, xaxis2, yaxis, yaxis4 ...
        ax = options[this.scene[axisName]._name];

        axTitle = ax.title === this.scene.fullLayout._dfltTitle[axisLetter] ? '' : ax.title;

        for(j = 0; j <= 2; j += 2) {
            this.labelEnable[i + j] = false;
            this.labels[i + j] = convertHTMLToUnicode(axTitle);
            this.labelColor[i + j] = str2RGBArray(ax.titlefont.color);
            this.labelFont[i + j] = ax.titlefont.family;
            this.labelSize[i + j] = ax.titlefont.size;
            this.labelPad[i + j] = this.getLabelPad(axisName, ax);

            this.tickEnable[i + j] = false;
            this.tickColor[i + j] = str2RGBArray((ax.tickfont || {}).color);
            this.tickAngle[i + j] = (ax.tickangle === 'auto') ?
                0 :
                Math.PI * -ax.tickangle / 180;
            this.tickPad[i + j] = this.getTickPad(ax);

            this.tickMarkLength[i + j] = 0;
            this.tickMarkWidth[i + j] = ax.tickwidth || 0;
            this.tickMarkColor[i + j] = str2RGBArray(ax.tickcolor);

            this.borderLineEnable[i + j] = false;
            this.borderLineColor[i + j] = str2RGBArray(ax.linecolor);
            this.borderLineWidth[i + j] = ax.linewidth || 0;
        }

        hasSharedAxis = this.hasSharedAxis(ax);
        hasAxisInDfltPos = this.hasAxisInDfltPos(axisName, ax) && !hasSharedAxis;
        hasAxisInAltrPos = this.hasAxisInAltrPos(axisName, ax) && !hasSharedAxis;

        axMirror = ax.mirror || false;
        mirrorLines = hasSharedAxis ?
            (String(axMirror).indexOf('all') !== -1) :  // 'all' or 'allticks'
            !!axMirror;                                 // all but false
        mirrorTicks = hasSharedAxis ?
            (axMirror === 'allticks') :
            (String(axMirror).indexOf('ticks') !== -1); // 'ticks' or 'allticks'

        // Axis titles and tick labels can only appear of one side of the scene
        //  and are never show on subplots that share existing axes.

        if(hasAxisInDfltPos) this.labelEnable[i] = true;
        else if(hasAxisInAltrPos) this.labelEnable[i + 2] = true;

        if(hasAxisInDfltPos) this.tickEnable[i] = ax.showticklabels;
        else if(hasAxisInAltrPos) this.tickEnable[i + 2] = ax.showticklabels;

        // Grid lines and ticks can appear on both sides of the scene
        //  and can appear on subplot that share existing axes via `ax.mirror`.

        if(hasAxisInDfltPos || mirrorLines) this.borderLineEnable[i] = ax.showline;
        if(hasAxisInAltrPos || mirrorLines) this.borderLineEnable[i + 2] = ax.showline;

        if(hasAxisInDfltPos || mirrorTicks) this.tickMarkLength[i] = this.getTickMarkLength(ax);
        if(hasAxisInAltrPos || mirrorTicks) this.tickMarkLength[i + 2] = this.getTickMarkLength(ax);

        this.gridLineEnable[i] = ax.showgrid;
        this.gridLineColor[i] = str2RGBArray(ax.gridcolor);
        this.gridLineWidth[i] = ax.gridwidth;

        this.zeroLineEnable[i] = ax.zeroline;
        this.zeroLineColor[i] = str2RGBArray(ax.zerolinecolor);
        this.zeroLineWidth[i] = ax.zerolinewidth;
    }
};

// is an axis shared with an already-drawn subplot ?
proto.hasSharedAxis = function(ax) {
    var scene = this.scene;
    var subplotIds = scene.fullLayout._subplots.gl2d;
    var list = Axes.findSubplotsWithAxis(subplotIds, ax);

    // if index === 0, then the subplot is already drawn as subplots
    // are drawn in order.
    return (list.indexOf(scene.id) !== 0);
};

// has an axis in default position (i.e. bottom/left) ?
proto.hasAxisInDfltPos = function(axisName, ax) {
    var axSide = ax.side;

    if(axisName === 'xaxis') return (axSide === 'bottom');
    else if(axisName === 'yaxis') return (axSide === 'left');
};

// has an axis in alternate position (i.e. top/right) ?
proto.hasAxisInAltrPos = function(axisName, ax) {
    var axSide = ax.side;

    if(axisName === 'xaxis') return (axSide === 'top');
    else if(axisName === 'yaxis') return (axSide === 'right');
};

proto.getLabelPad = function(axisName, ax) {
    var offsetBase = 1.5,
        fontSize = ax.titlefont.size,
        showticklabels = ax.showticklabels;

    if(axisName === 'xaxis') {
        return (ax.side === 'top') ?
            -10 + fontSize * (offsetBase + (showticklabels ? 1 : 0)) :
            -10 + fontSize * (offsetBase + (showticklabels ? 0.5 : 0));
    }
    else if(axisName === 'yaxis') {
        return (ax.side === 'right') ?
            10 + fontSize * (offsetBase + (showticklabels ? 1 : 0.5)) :
            10 + fontSize * (offsetBase + (showticklabels ? 0.5 : 0));
    }
};

proto.getTickPad = function(ax) {
    return (ax.ticks === 'outside') ? 10 + ax.ticklen : 15;
};

proto.getTickMarkLength = function(ax) {
    if(!ax.ticks) return 0;

    var ticklen = ax.ticklen;

    return (ax.ticks === 'inside') ? -ticklen : ticklen;
};


function createAxes2D(scene) {
    return new Axes2DOptions(scene);
}

module.exports = createAxes2D;
