/**
 * Tidy operations.
 *
 * @author n1474335 [n1474335@gmail.com]
 * @copyright Crown Copyright 2016
 * @license Apache-2.0
 *
 * @namespace
 */
const Tidy = {

    /**
     * @constant
     * @default
     */
    REMOVE_SPACES: true,
    /**
     * @constant
     * @default
     */
    REMOVE_CARIAGE_RETURNS: true,
    /**
     * @constant
     * @default
     */
    REMOVE_LINE_FEEDS: true,
    /**
     * @constant
     * @default
     */
    REMOVE_TABS: true,
    /**
     * @constant
     * @default
     */
    REMOVE_FORM_FEEDS: true,
    /**
     * @constant
     * @default
     */
    REMOVE_FULL_STOPS: false,

    /**
     * Remove whitespace operation.
     *
     * @param {string} input
     * @param {Object[]} args
     * @returns {string}
     */
    runRemoveWhitespace: function (input, args) {
        let removeSpaces = args[0],
            removeCariageReturns = args[1],
            removeLineFeeds = args[2],
            removeTabs = args[3],
            removeFormFeeds = args[4],
            removeFullStops = args[5],
            data = input;

        if (removeSpaces) data = data.replace(/ /g, "");
        if (removeCariageReturns) data = data.replace(/\r/g, "");
        if (removeLineFeeds) data = data.replace(/\n/g, "");
        if (removeTabs) data = data.replace(/\t/g, "");
        if (removeFormFeeds) data = data.replace(/\f/g, "");
        if (removeFullStops) data = data.replace(/\./g, "");
        return data;
    },


    /**
     * Remove null bytes operation.
     *
     * @param {byteArray} input
     * @param {Object[]} args
     * @returns {byteArray}
     */
    runRemoveNulls: function (input, args) {
        const output = [];
        for (let i = 0; i < input.length; i++) {
            if (input[i] !== 0) output.push(input[i]);
        }
        return output;
    },


    /**
     * @constant
     * @default
     */
    APPLY_TO_EACH_LINE: false,
    /**
     * @constant
     * @default
     */
    DROP_START: 0,
    /**
     * @constant
     * @default
     */
    DROP_LENGTH: 5,

    /**
     * Drop bytes operation.
     *
     * @param {ArrayBuffer} input
     * @param {Object[]} args
     * @returns {ArrayBuffer}
     */
    runDropBytes: function(input, args) {
        const start = args[0],
            length = args[1],
            applyToEachLine = args[2];

        if (start < 0 || length < 0)
            throw "Error: Invalid value";

        if (!applyToEachLine) {
            const left = input.slice(0, start),
                right = input.slice(start + length, input.byteLength);
            let result = new Uint8Array(left.byteLength + right.byteLength);
            result.set(new Uint8Array(left), 0);
            result.set(new Uint8Array(right), left.byteLength);
            return result.buffer;
        }

        // Split input into lines
        const data = new Uint8Array(input);
        let lines = [],
            line = [],
            i;

        for (i = 0; i < data.length; i++) {
            if (data[i] === 0x0a) {
                lines.push(line);
                line = [];
            } else {
                line.push(data[i]);
            }
        }
        lines.push(line);

        let output = [];
        for (i = 0; i < lines.length; i++) {
            output = output.concat(lines[i].slice(0, start).concat(lines[i].slice(start+length, lines[i].length)));
            output.push(0x0a);
        }
        return new Uint8Array(output.slice(0, output.length-1)).buffer;
    },


    /**
     * @constant
     * @default
     */
    TAKE_START: 0,
    /**
     * @constant
     * @default
     */
    TAKE_LENGTH: 5,

    /**
     * Take bytes operation.
     *
     * @param {ArrayBuffer} input
     * @param {Object[]} args
     * @returns {ArrayBuffer}
     */
    runTakeBytes: function(input, args) {
        const start = args[0],
            length = args[1],
            applyToEachLine = args[2];

        if (start < 0 || length < 0)
            throw "Error: Invalid value";

        if (!applyToEachLine)
            return input.slice(start, start+length);

        // Split input into lines
        const data = new Uint8Array(input);
        let lines = [],
            line = [],
            i;

        for (i = 0; i < data.length; i++) {
            if (data[i] === 0x0a) {
                lines.push(line);
                line = [];
            } else {
                line.push(data[i]);
            }
        }
        lines.push(line);

        let output = [];
        for (i = 0; i < lines.length; i++) {
            output = output.concat(lines[i].slice(start, start+length));
            output.push(0x0a);
        }
        return new Uint8Array(output.slice(0, output.length-1)).buffer;
    },


    /**
     * @constant
     * @default
     */
    PAD_POSITION: ["Start", "End"],
    /**
     * @constant
     * @default
     */
    PAD_LENGTH: 5,
    /**
     * @constant
     * @default
     */
    PAD_CHAR: " ",

    /**
     * Pad lines operation.
     *
     * @param {string} input
     * @param {Object[]} args
     * @returns {string}
     */
    runPad: function(input, args) {
        let position = args[0],
            len = args[1],
            chr = args[2],
            lines = input.split("\n"),
            output = "",
            i = 0;

        if (position === "Start") {
            for (i = 0; i < lines.length; i++) {
                output += lines[i].padStart(lines[i].length+len, chr) + "\n";
            }
        } else if (position === "End") {
            for (i = 0; i < lines.length; i++) {
                output += lines[i].padEnd(lines[i].length+len, chr) + "\n";
            }
        }

        return output.slice(0, output.length-1);
    },

};

export default Tidy;
