/**
* Copyright 2012-2017, 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 constants = require('./constants');
var isNumeric = require('fast-isnumeric');

// This syntax conforms to the existing filter transform syntax, but we don't care
// about open vs. closed intervals for simply drawing contours constraints:
module.exports['[]'] = makeRangeSettings('[]');
module.exports['()'] = makeRangeSettings('()');
module.exports['[)'] = makeRangeSettings('[)');
module.exports['(]'] = makeRangeSettings('(]');

// Inverted intervals simply flip the sign:
module.exports[']['] = makeRangeSettings('][');
module.exports[')('] = makeRangeSettings(')(');
module.exports[')['] = makeRangeSettings(')[');
module.exports[']('] = makeRangeSettings('](');

module.exports['>'] = makeInequalitySettings('>');
module.exports['>='] = makeInequalitySettings('>=');
module.exports['<'] = makeInequalitySettings('<');
module.exports['<='] = makeInequalitySettings('<=');
module.exports['='] = makeInequalitySettings('=');

// This does not in any way shape or form support calendars. It's adapted from
// transforms/filter.js.
function coerceValue(operation, value) {
    var hasArrayValue = Array.isArray(value);

    var coercedValue;

    function coerce(value) {
        return isNumeric(value) ? (+value) : null;
    }

    if(constants.INEQUALITY_OPS.indexOf(operation) !== -1) {
        coercedValue = hasArrayValue ? coerce(value[0]) : coerce(value);
    } else if(constants.INTERVAL_OPS.indexOf(operation) !== -1) {
        coercedValue = hasArrayValue ?
            [coerce(value[0]), coerce(value[1])] :
            [coerce(value), coerce(value)];
    } else if(constants.SET_OPS.indexOf(operation) !== -1) {
        coercedValue = hasArrayValue ? value.map(coerce) : [coerce(value)];
    }

    return coercedValue;
}

// Returns a parabola scaled so that the min/max is either +/- 1 and zero at the two values
// provided. The data is mapped by this function when constructing intervals so that it's
// very easy to construct contours as normal.
function makeRangeSettings(operation) {
    return function(value) {
        value = coerceValue(operation, value);

        // Ensure proper ordering:
        var min = Math.min(value[0], value[1]);
        var max = Math.max(value[0], value[1]);

        return {
            start: min,
            end: max,
            size: max - min
        };
    };
}

function makeInequalitySettings(operation) {
    return function(value) {
        value = coerceValue(operation, value);

        return {
            start: value,
            end: Infinity,
            size: Infinity
        };
    };
}
