"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeFile = exports.trimRight = exports.trimLeft = exports.trimChars = exports.startsWith = exports.pathIsChildOf = exports.parseCsvFile = exports.parseBool = exports.padRight = exports.padLeft = exports.isValidUrl = exports.insertLocalTimes = exports.humanFileSize = exports.format = exports.fileExists = exports.escapeRegEx = exports.escape$Properties = exports.endsWith = exports.deleteFile = exports.directoryExists = exports.deleteDirRecursive = exports.clone = exports.addExtension = void 0;
const csvParse = require("csv-parse");
const fs = require("fs");
const moment = require("moment");
require("moment-timezone");
const path = require("path");
const thenify = require("thenify");
/** Add the specified extension to a file name, if it doesn't have
 * it already, and return the new file name. */
function addExtension(fileName, extension) {
    extension = trimChars(extension, '.');
    const currentExtension = trimChars(path.extname(fileName), '.');
    if (currentExtension != extension) {
        return fileName + '.' + extension;
    }
    else {
        return fileName;
    }
}
exports.addExtension = addExtension;
function clone(obj) {
    let copy;
    // Handle the 3 simple types, and null or undefined
    if (null == obj || 'object' != typeof obj)
        return obj;
    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }
    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr))
                copy[attr] = clone(obj[attr]);
        }
        return copy;
    }
    throw new Error('Unable to copy object. The object type is not supported.');
}
exports.clone = clone;
function deleteDirRecursive(path) {
    try {
        if (fs.existsSync(path)) {
            fs.readdirSync(path).forEach(function (file, index) {
                var fullPath = path + "/" + file;
                if (fs.lstatSync(fullPath).isDirectory()) {
                    deleteDirRecursive(fullPath);
                }
                else {
                    fs.unlinkSync(fullPath);
                }
            });
            fs.rmdirSync(path);
        }
    }
    catch (err) {
        // Swallowing the exception is fine here
    }
}
exports.deleteDirRecursive = deleteDirRecursive;
function directoryExists(dirPath) {
    try {
        return fs.statSync(dirPath).isDirectory();
    }
    catch (err) {
        return false;
    }
}
exports.directoryExists = directoryExists;
function deleteFile(path) {
    try {
        if (fs.existsSync(path)) {
            fs.unlinkSync(path);
        }
    }
    catch (err) {
        // Swallowing the exception is fine here
    }
}
exports.deleteFile = deleteFile;
function endsWith(testString, searchString, position) {
    var subjectString = testString.toString();
    if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
        position = subjectString.length;
    }
    position -= searchString.length;
    var lastIndex = subjectString.indexOf(searchString, position);
    return lastIndex !== -1 && lastIndex === position;
}
exports.endsWith = endsWith;
/** If the argument is an object value, it recursively renames the
 * properties whose names start with the "$" sign by replacing "$" with
 * "d$", in order to avoid errors when inserting this data in MongoDB-
 * compatible databases */
function escape$Properties(obj) {
    if (obj && typeof obj === 'object') {
        Object.keys(obj).forEach((propName) => {
            if (obj[propName] && typeof obj[propName] === 'object') {
                obj[propName] = escape$Properties(obj[propName]);
            }
            if (propName.startsWith('$')) {
                obj['d' + propName] = obj[propName];
                delete obj[propName];
            }
        });
    }
    return obj;
}
exports.escape$Properties = escape$Properties;
/** Escape a string so we can safely use it in a regular expression. */
function escapeRegEx(text) {
    return text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
exports.escapeRegEx = escapeRegEx;
function fileExists(filePath) {
    try {
        if (!filePath) {
            return false;
        }
        return fs.statSync(filePath).isFile();
    }
    catch (err) {
        return false;
    }
}
exports.fileExists = fileExists;
/** Utility function for string formatting.
 * Example: format("{0}, {1}!", "Hello", "world") // "Hello, world!"
 */
function format(text, ...any) {
    var args = arguments;
    var arg;
    var argIndex;
    return text.replace(/\{(\d+)\}/g, function (match, index) {
        argIndex = Number(index) + 1;
        arg = args[argIndex];
        switch (typeof arg) {
            case 'number':
            case 'string': return args[argIndex];
            case 'object': return JSON.stringify(args[argIndex]);
            case 'undefined': return match;
            default: return args[argIndex];
        }
    });
}
exports.format = format;
/** Convert a file size from bytes to a human-readable value. */
function humanFileSize(size) {
    var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
    return Number((size / Math.pow(1024, i)).toFixed(2)) + ['B', 'K', 'M', 'G', 'T'][i];
}
exports.humanFileSize = humanFileSize;
;
// Looks into an object for properties that represent time values and inserts
// additional properties that represent the corresponding local time
function insertLocalTimes(obj, timezone, propertyNames) {
    if (!propertyNames) {
        Object.keys(obj).forEach(function (key) {
            if ((startsWith(key, 'time') || endsWith(key, 'Time')) && typeof obj[key] === 'number' && obj[key] > 21600000) {
                insertLocalTime(obj, timezone, key);
            }
        });
    }
    else {
        propertyNames.forEach(function (propertyName) {
            insertLocalTime(obj, timezone, propertyName);
        });
    }
    function insertLocalTime(obj, timezone, propertyName) {
        obj[propertyName + 'Local'] = moment.tz(obj[propertyName], timezone).valueOf();
    }
}
exports.insertLocalTimes = insertLocalTimes;
function isValidUrl(str) {
    var urlRegexp = new RegExp("^" +
        // protocol identifier
        "(?:(?:https?|ftp)://)" +
        // user:pass authentication
        "(?:\\S+(?::\\S*)?@)?" +
        "(?:" +
        // IP address exclusion
        // private & local networks
        "(?!(?:10|127)(?:\\.\\d{1,3}){3})" +
        "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" +
        "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
        // IP address dotted notation octets
        // excludes loopback network 0.0.0.0
        // excludes reserved space >= 224.0.0.0
        // excludes network & broadcast addresses
        // (first & last IP address of each class)
        "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
        "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
        "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
        "|" +
        // host name
        "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" +
        // domain name
        "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" +
        // TLD identifier
        "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
        // TLD may end with dot
        "\\.?" +
        ")" +
        // port number
        "(?::\\d{2,5})?" +
        // resource path
        "(?:[/?#]\\S*)?" +
        "$", "i");
    return urlRegexp.test(str);
}
exports.isValidUrl = isValidUrl;
/** Pad left a number (or string) with zeroes, or any other character,
 * up to the specified width */
function padLeft(value, width, character = ' ') {
    character = character || ' ';
    value = value.toString();
    return value.length >= width ?
        value :
        new Array(width - value.length + 1).join(character) + value;
}
exports.padLeft = padLeft;
/** Pad right a number (or string) with zeroes, or any other character,
 * up to the specified width */
function padRight(value, width, character = ' ') {
    character = character || ' ';
    value = value.toString();
    return value.length >= width ?
        value :
        value + new Array(width - value.length + 1).join(character);
}
exports.padRight = padRight;
function parseBool(value) {
    value = value.toString().trim().toUpperCase();
    var result;
    switch (value) {
        case 'TRUE':
            result = true;
            break;
        case 'FALSE':
            result = false;
            break;
        case '1':
            result = true;
            break;
        case '0':
            result = false;
            break;
        case 'YES':
            result = true;
            break;
        case 'NO':
            result = false;
            break;
        default: throw new Error('Failed to convert value "' + value + '" to a boolean.');
    }
    return result;
}
exports.parseBool = parseBool;
function parseCsvFile(csvFile, options) {
    return __awaiter(this, void 0, void 0, function* () {
        options = options || {};
        options.columns = options.columns || true;
        options.encoding = options.encoding || 'utf8';
        const csvData = yield thenify(fs.readFile)(csvFile, options.encoding);
        const csvParseOptions = {
            columns: options.columns
        };
        const csvRecords = yield new Promise(function (resolve, reject) {
            return __awaiter(this, void 0, void 0, function* () {
                try {
                    const parser = csvParse(csvParseOptions, function (err, records) {
                        if (err) {
                            return reject(err);
                        }
                        else {
                            resolve(records);
                        }
                    });
                    parser.write(csvData);
                    parser.end();
                }
                catch (err) {
                    reject(err);
                }
            });
        });
        return csvRecords;
    });
}
exports.parseCsvFile = parseCsvFile;
/** Determine if a path (file of directory) is a child of another. */
function pathIsChildOf(parent, child) {
    const relative = path.relative(parent, child);
    return !!relative && !relative.startsWith('..') && !path.isAbsolute(relative);
}
exports.pathIsChildOf = pathIsChildOf;
function startsWith(testString, searchString, position) {
    position = position || 0;
    return testString.substr(position, searchString.length) === searchString;
}
exports.startsWith = startsWith;
/** Trim specified characters from the beginning and end of a string */
function trimChars(text, chars = ' \t\r\n\f') {
    if (!text) {
        return '';
    }
    const escapedChars = escapeRegEx(chars);
    const regex = new RegExp(format('^[{0}]+|[{0}]+$', escapedChars), 'g');
    return text.replace(regex, '');
}
exports.trimChars = trimChars;
/** Trim specified characters from the beginning of a string */
function trimLeft(text, chars = ' \t\r\n\f') {
    const escapedChars = escapeRegEx(chars);
    const regex = new RegExp(format('^[{0}]+', escapedChars), 'g');
    return text.replace(regex, '');
}
exports.trimLeft = trimLeft;
/** Trim specified characters from the end of a string */
function trimRight(text, chars = ' \t\r\n\f') {
    const escapedChars = escapeRegEx(chars);
    const regex = new RegExp(format('[{0}]+$', escapedChars), 'g');
    return text.replace(regex, '');
}
exports.trimRight = trimRight;
function writeFile(filePath, fileName, data) {
    if (typeof data !== 'string') {
        data = JSON.stringify(data, null, '\t');
    }
    fs.writeFileSync(path.join(filePath, fileName), data);
}
exports.writeFile = writeFile;
//# sourceMappingURL=helpers.js.map