Source: service/AtomicService.js

'use strict';

/**
 * @module Services
 * Plain functionality in service methods.
 * @license MIT
 * @author Kai KRETSCHMANN <kai@kretschmann.consulting>
 */

const log4js = require("log4js");
const logger = log4js.getLogger();
logger.level = process.env.LOGLEVEL || "warn";

const fs = require('fs');
const cdigit = require("cdigit");
const crypto = require('crypto');
const uuid = require('uuid-random');
const dateFormat = require("dateformat");
require("datejs");

function randomIntInc(low, high) {
    return crypto.randomInt(low, high + 1);
}

/**
 * @function
 * Generate random numbers of length numlength.
 * @private
 * @param {int} numlength - number of digits
 */
function randomRangeLength(numlength) {
    const lowNumber = Math.pow(10, numlength - 1);
    const highNumber = Math.pow(10, numlength);

    return crypto.randomInt(lowNumber, highNumber);
}

/**
 * @function
 * Randomly disorder the given array.
 * @private
 * @param {array} array - Shuffle content and give back as call by reference
 */
function shuffle(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(crypto.randomInt(0, i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

/**
 * @function
 * Copy the array x times until length reached, last copy can be partly.
 * @private
 * @param {array} array - source array
 * @param {int} amount - target length wanted
 * @returns {array}
 */
function arrayRepeat(array, amount) {
    const countLoops = Math.floor(amount / array.length);
    const countRest = amount % array.length;
    let newArray = array;

    for (let i = 1; i < countLoops; i++) {
        newArray = newArray.concat(array);
    }
    const remaining = array.slice(0, countRest);
    array = newArray.concat(remaining);
    return array;
}

/**
 * @method
 * Get lorem ipsum text.
 * @public
 *
 * @param {int} amount - Integer positive whole number of words
 * @returns String
 **/
exports.getLoremIpsum = function(amount) {
    return new Promise(function(resolve, reject) {
        if (amount <= 0) {
            logger.error("amount to small");
            reject("amount must be positive");
        }

        let sentence = "";
        fs.readFile('data/lorem_ipsum.txt', 'utf8', function(err, data) {
            if (err) throw err;
            let words = data.split(" ");
            const lengthSource = words.length;
            if (lengthSource >= amount) {
                words = words.slice(0, amount);
                sentence = words.join(" ");
            } else {
                const longWords = arrayRepeat(words, amount);
                sentence = longWords.join(" ");
            }

            resolve(sentence);
        });
    });
}

/**
 * @method
 * Get random process names.
 * @public
 *
 * @param {int} amount - Integer positive whole number of names
 * @returns {array} List - list of strings
 **/
exports.getProcessNames = function(amount) {
    return new Promise(function(resolve, reject) {
        if (amount <= 0) {
            logger.error("amount to small");
            reject("amount must be positive");
        }

        let examples = {};
        let arraySourceNames = fs.readFileSync('data/process_names.txt', 'utf8').toString().split("\n");
        const lengthSource = arraySourceNames.length;
        if (lengthSource >= amount) {
            arraySourceNames = arraySourceNames.slice(0, amount);
        } else {
            arraySourceNames = arrayRepeat(arraySourceNames, amount);
        }

        shuffle(arraySourceNames);
        examples['application/json'] = arraySourceNames;

        if (Object.keys(examples).length > 0) {
            resolve(examples[Object.keys(examples)[0]]);
        } else {
            resolve();
        }
    });
}

/**
 * @method
 * Get random ISBN numbers.
 * @public
 *
 * @param {int} amount - Integer positive whole number of ISBN numbers
 * @returns {array} List - list of ISBN number strings
 **/
exports.getIsbn = function(amount) {
    return new Promise(function(resolve, reject) {
        if (amount <= 0) {
            logger.error("amount to small");
            reject("amount must be positive");
        }
        let examples = {};
        let listIsbn = [];

        for (let i = 0; i < amount; i++) {
            const isbnPrefix = 978 + Math.round(crypto.randomInt(0, 2)); // 978 or 979

            const isbnLengthFull = 10;
            const isbnLengthGroup = crypto.randomInt(1, 6); // Group length from 1 to 5 digits
            const isbnLengthRegistrant = crypto.randomInt(1, isbnLengthFull - isbnLengthGroup - 1);
            const sibnLengthPublication = isbnLengthFull - isbnLengthGroup - isbnLengthRegistrant;

            const isbnGroup = randomRangeLength(isbnLengthGroup); // 10 to 99
            const isbnRegistrant = randomRangeLength(isbnLengthRegistrant); // 10000 to 99999
            const isbnPublication = randomRangeLength(sibnLengthPublication); // 10 to 99
            let isbn = "" + isbnPrefix + isbnGroup + isbnRegistrant + isbnPublication;
            const isbnCheck = cdigit.gtin.compute(isbn);
            isbn = "" + isbnPrefix + "-" + isbnGroup + "-" + isbnRegistrant + "-" + isbnPublication + "-" + isbnCheck;
            listIsbn.push(isbn);
        }

        examples['application/json'] = listIsbn;
        if (Object.keys(examples).length > 0) {
            resolve(examples[Object.keys(examples)[0]]);
        } else {
            resolve();
        }
    });
}

/**
 * @method
 * Get random numbers.
 * @public
 *
 * @param {int} amount - Integer positive whole number
 * @param {int} from - Integer lowest possible value
 * @param {int} to - Integer highest possible value
 * @returns {array} List
 **/
exports.getRandomNumbers = function(amount, from, to) {
    return new Promise(function(resolve, reject) {
        if (amount <= 0) {
            logger.error("amount to small");
            reject("amount must be positive");
        }
        if (from >= to) {
            logger.error("from bigger then to");
            reject("from bigger then to");
        }

        let examples = {};
        let numbers = new Array(amount)
        for (let i = 0; i < numbers.length; i++) {
            numbers[i] = randomIntInc(from, to);
        }
        examples['application/json'] = numbers;
        if (Object.keys(examples).length > 0) {
            resolve(examples[Object.keys(examples)[0]]);
        } else {
            resolve();
        }
    });
}

/**
 * @method
 * Get timestamps.
 * @public
 *
 * @param {int} amount - Integer positive whole number
 * @param {int} from - Integer lowest possible value
 * @param {int} to - Integer highest possible value
 * @returns {array} List
 **/
exports.getTimestamp = function(amount, from, to) {
    return new Promise(function(resolve, reject) {
        logger.debug("param1=" + from + ", param2=" + to + ".");

        let tsFrom;
        let tsTo;

        if ("today" == from) {
            tsFrom = Date.today();
        } else {
            tsFrom = Date.parse(from);
        }

        if ("today" == to) {
            tsTo = Date.today();
        } else {
            tsTo = Date.parse(to);
        }

        logger.debug("TS From " + tsFrom + " to " + tsTo)

        if (isNaN(tsFrom)) {
            reject("Cannot parse FROM value");
        }
        if (isNaN(tsTo)) {
            reject("Cannot parse TO value");
        }

        const secondsFrom = Math.round(tsFrom.getTime() / 1000);
        const secondsTo = Math.round(tsTo.getTime() / 1000);
        logger.debug("SEC From " + secondsFrom + " to " + secondsTo)

        if (secondsFrom >= secondsTo) {
            logger.error("from bigger then to");
            reject("FROM bigger or equal TO");
        }

        let examples = {};
        let numbers = new Array(amount)
        for (let i = 0; i < numbers.length; i++) {
            const tsSeconds = randomIntInc(secondsFrom, secondsTo);
            const t = new Date(tsSeconds * 1000);
            numbers[i] = dateFormat(t, "isoDateTime") + "Z";
        }
        examples['application/json'] = numbers;
        if (Object.keys(examples).length > 0) {
            resolve(examples[Object.keys(examples)[0]]);
        } else {
            resolve();
        }
    });
}

/**
 * @method
 * Get random UUIDs.
 * @public
 *
 * @param {int} amount - Integer positive whole number
 * @returns {array} List
 **/
exports.getUuid = function(amount) {
    return new Promise(function(resolve, reject) {
        if (amount <= 0) {
            logger.error("amount to small");
            reject("amount must be positive");
        }
        let examples = {};
        let numbers = new Array(amount)
        for (let i = 0; i < numbers.length; i++) {
            numbers[i] = uuid();
        }
        examples['application/json'] = numbers;
        if (Object.keys(examples).length > 0) {
            resolve(examples[Object.keys(examples)[0]]);
        } else {
            resolve();
        }
    });
}

/**
 * @method
 * Get random phone numbers.
 * @public
 *
 * @param {int} amount - Integer positive whole number
 * @returns {array} List
 **/
exports.getPhone = function(amount) {
    return new Promise(function(resolve, reject) {
        if (amount <= 0) {
            logger.error("amount to small");
            reject("amount must be positive");
        }
        let examples = {};
        let numbers = new Array(amount)
        for (let i = 0; i < numbers.length; i++) {
            const phoneLengthCountry = crypto.randomInt(1, 4);
            const phoneCountry = randomRangeLength(phoneLengthCountry);
            const phoneLengthCity = crypto.randomInt(2, 5);
            const phoneCity = randomRangeLength(phoneLengthCity);
            const phoneLengthTarget = crypto.randomInt(4, 7);
            const phoneTarget = randomRangeLength(phoneLengthTarget);

            numbers[i] = "+" + phoneCountry + "-" + phoneCity + "-" + phoneTarget;
        }
        examples['application/json'] = numbers;
        if (Object.keys(examples).length > 0) {
            resolve(examples[Object.keys(examples)[0]]);
        } else {
            resolve();
        }
    });
}