/** @module conversions */
const { either, fnOrValue } = require('../logic');
const { curry } = require('../fp');
const { isNumber, isObject } = require('../types');
/** Generic function. Parses a value using a parser function, then
* evaluates the result with an evaluator function. <sup>(curried)</sup>
*
* If the parser throws any exception or the evaluator fails the default value is returned.
* @argument {function} parser parse function to transform the data input
* @argument {function} evaluator evaluates the output of the parser
* @argument {*} defaultValue value/function to be returned/executed if it fails
* @argument {*} data any kind of data that we want to parse
* @example
* jsonOr = parseOr(JSON.parse,isObject);
* jsonOr(0,{}) // -> {}
* jsonOr(0,null) // -> 0
* @see [conversionsTest.js](https://github.com/nerac/keyu/blob/master/test/conversionsTest.js)
* @see [Curring](https://en.wikipedia.org/wiki/Currying)
* @returns {*} parsed value or default one
* @method
*/
const parseOr = curry((parser, evaluator, defaultValue, idata) =>
either(data => {
const res = parser(data);
return typeof evaluator === 'function' && evaluator(res) ? res : fnOrValue(defaultValue, data);
}, defaultValue)(idata)
);
/** Converts passed data into a JSON or returns the default value on failure. <sup>(curried)</sup>
* @argument {Object|Function} defaultValue default value or function to be returned if it fails.
* @argument {*} data any kind of data that we want to parse as JSON
* @example
* jsonOr(-1,"sfdjl") // -> -1
* jsonOr(() => throw Errot("Ups!"),"sfdjl") // -> Error: Ups!
* jsonOr(-1)('{"a":1}') // -> {a:1}
* @see [Curring](https://en.wikipedia.org/wiki/Currying)
* @see [conversionsTest.js](https://github.com/nerac/keyu/blob/master/test/conversionsTest.js)
* @returns {Object|*} Parsed value or the default one.
* @method
*/
const jsonOr = parseOr(JSON.parse, isObject);
/** Converts passed data to float or returns the default value on failure. <sup>(curried)</sup>
* @argument {Object|Function} defaultValue default value or function to be returned if it fails.
* @argument {*} data any kind of data that we want to parse as float
* @example
* floatOr(-1,"x33x") // -> -1
* floatOr(() => throw Errot("Ups!"),"x33x") // -> Error: Ups!
* floatOr(-1)('45.553') // -> 45.553
* @see [Curring](https://en.wikipedia.org/wiki/Currying)
* @see [conversionsTest.js](https://github.com/nerac/keyu/blob/master/test/conversionsTest.js)
* @returns {Float|*} Parsed value or the default one.
* @method
*/
const floatOr = parseOr(parseFloat, isNumber);
/** Converts passed data to int or returns the default value on failure. <sup>(curried)</sup>
* @argument {Object|Function} defaultValue default value or function to be returned if it fails.
* @argument {*} data any kind of data that we want to parse as int
* @example
* intOr(-1,"x33x") // -> -1
* intOr(() => throw Error("Ups!"),"x33x") // -> Error: Ups!
* intOr(-1)('45.553') // -> 45
* @see [Currying](https://en.wikipedia.org/wiki/Currying)
* @see [conversionsTest.js](https://github.com/nerac/keyu/blob/master/test/conversionsTest.js)
* @returns {Int|*} Parsed value or the default one.
* @method
*/
const intOr = parseOr(num => (typeof num === 'number' ? num - (num % 1) : parseInt(`${num}`, 10)), isNumber);
/** Fixes the number of decimals of a float.
* Returns the default value if non numeric value passed.<sup>(curried)</sup>
* @argument {Int} decimals number of decimals to fix.
* @argument {Function|*} defaultValue value to be returned if non number received
* @argument {Float} num float number that we want to fix it's decimals.
* @example
* setPrecisionOr(1,"fail", 3.44) // -> 3.4
* setPrecisionOr(1,"fail", null) // -> "fail"
* setPrecisionOr(0,"fail", 3.44) // -> 3
* @see [Curring](https://en.wikipedia.org/wiki/Currying)
* @see [conversionsTest.js](https://github.com/nerac/keyu/blob/master/test/conversionsTest.js)
* @returns {Float}
* @method
*/
const setPrecisionOr = curry((decimals, defaultValue, num) => (isNumber(num) ? Number(num.toFixed(decimals)) : fnOrValue(defaultValue, num)));
module.exports = { parseOr, jsonOr, floatOr, intOr, setPrecisionOr };