import { MACRO_05_HEADER, MACRO_06_HEADER, MACRO_TRAILER, } from './constants';
import HighLevelEncoder from './HighLevelEncoder';
import { MinimalECIInput } from '../../common/MinimalECIInput';
import Integer from '../../util/Integer';
var Mode;
(function (Mode) {
    Mode[Mode["ASCII"] = 0] = "ASCII";
    Mode[Mode["C40"] = 1] = "C40";
    Mode[Mode["TEXT"] = 2] = "TEXT";
    Mode[Mode["X12"] = 3] = "X12";
    Mode[Mode["EDF"] = 4] = "EDF";
    Mode[Mode["B256"] = 5] = "B256";
})(Mode || (Mode = {}));
const C40_SHIFT2_CHARS = [
    '!',
    '"',
    '#',
    '$',
    '%',
    '&',
    "'",
    '(',
    ')',
    '*',
    '+',
    ',',
    '-',
    '.',
    '/',
    ':',
    ';',
    '<',
    '=',
    '>',
    '?',
    '@',
    '[',
    '\\',
    ']',
    '^',
    '_',
];
export class MinimalEncoder {
    static isExtendedASCII(ch, fnc1) {
        return ch !== fnc1 && ch >= 128 && ch <= 255;
    }
    static isInC40Shift1Set(ch) {
        return ch <= 31;
    }
    static isInC40Shift2Set(ch, fnc1) {
        for (const c40Shift2Char of C40_SHIFT2_CHARS) {
            if (c40Shift2Char.charCodeAt(0) === ch) {
                return true;
            }
        }
        return ch === fnc1;
    }
    static isInTextShift1Set(ch) {
        return this.isInC40Shift1Set(ch);
    }
    static isInTextShift2Set(ch, fnc1) {
        return this.isInC40Shift2Set(ch, fnc1);
    }
    /**
     * Performs message encoding of a DataMatrix message
     *
     * @param msg the message
     * @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm
     *   chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority
     *   charset to encode any character in the input that can be encoded by it if the charset is among the
     *   supported charsets.
     * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not a GS1
     *   bar code. If the value is not -1 then a FNC1 is also prepended.
     * @param shape requested shape.
     * @return the encoded message (the char values range from 0 to 255)
     */
    static encodeHighLevel(msg, priorityCharset = null, fnc1 = -1, shape = 0 /* FORCE_NONE */) {
        let macroId = 0;
        if (msg.startsWith(MACRO_05_HEADER) && msg.endsWith(MACRO_TRAILER)) {
            macroId = 5;
            msg = msg.substring(MACRO_05_HEADER.length, msg.length - 2);
        }
        else if (msg.startsWith(MACRO_06_HEADER) && msg.endsWith(MACRO_TRAILER)) {
            macroId = 6;
            msg = msg.substring(MACRO_06_HEADER.length, msg.length - 2);
        }
        return decodeURIComponent(escape(String.fromCharCode(...this.encode(msg, priorityCharset, fnc1, shape, macroId))));
    }
    /**
     * Encodes input minimally and returns an array of the codewords
     *
     * @param input The string to encode
     * @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm
     *   chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority
     *   charset to encode any character in the input that can be encoded by it if the charset is among the
     *   supported charsets.
     * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not a GS1
     *   bar code. If the value is not -1 then a FNC1 is also prepended.
     * @param shape requested shape.
     * @param macroId Prepends the specified macro function in case that a value of 5 or 6 is specified.
     * @return An array of bytes representing the codewords of a minimal encoding.
     */
    static encode(input, priorityCharset, fnc1, shape, macroId) {
        return this.encodeMinimally(new Input(input, priorityCharset, fnc1, shape, macroId)).getBytes();
    }
    static addEdge(edges, edge) {
        const vertexIndex = edge.fromPosition + edge.characterLength;
        if (edges[vertexIndex][edge.getEndMode()] === null ||
            edges[vertexIndex][edge.getEndMode()].cachedTotalSize >
                edge.cachedTotalSize) {
            edges[vertexIndex][edge.getEndMode()] = edge;
        }
    }
    /** @return the number of words in which the string starting at from can be encoded in c40 or text mode.
     *  The number of characters encoded is returned in characterLength.
     *  The number of characters encoded is also minimal in the sense that the algorithm stops as soon
     *  as a character encoding fills a C40 word competely (three C40 values). An exception is at the
     *  end of the string where two C40 values are allowed (according to the spec the third c40 value
     *  is filled  with 0 (Shift 1) in this case).
     */
    static getNumberOfC40Words(input, from, c40, characterLength) {
        let thirdsCount = 0;
        for (let i = from; i < input.length(); i++) {
            if (input.isECI(i)) {
                characterLength[0] = 0;
                return 0;
            }
            const ci = input.charAt(i);
            if ((c40 && HighLevelEncoder.isNativeC40(ci)) ||
                (!c40 && HighLevelEncoder.isNativeText(ci))) {
                thirdsCount++; // native
            }
            else if (!MinimalEncoder.isExtendedASCII(ci, input.getFNC1Character())) {
                thirdsCount += 2; // shift
            }
            else {
                const asciiValue = ci & 0xff;
                if (asciiValue >= 128 &&
                    ((c40 && HighLevelEncoder.isNativeC40(asciiValue - 128)) ||
                        (!c40 && HighLevelEncoder.isNativeText(asciiValue - 128)))) {
                    thirdsCount += 3; // shift, Upper shift
                }
                else {
                    thirdsCount += 4; // shift, Upper shift, shift
                }
            }
            if (thirdsCount % 3 === 0 ||
                ((thirdsCount - 2) % 3 === 0 && i + 1 === input.length())) {
                characterLength[0] = i - from + 1;
                return Math.ceil(thirdsCount / 3.0);
            }
        }
        characterLength[0] = 0;
        return 0;
    }
    static addEdges(input, edges, from, previous) {
        if (input.isECI(from)) {
            this.addEdge(edges, new Edge(input, Mode.ASCII, from, 1, previous));
            return;
        }
        const ch = input.charAt(from);
        if (previous === null || previous.getEndMode() !== Mode.EDF) {
            // not possible to unlatch a full EDF edge to something
            // else
            if (HighLevelEncoder.isDigit(ch) &&
                input.haveNCharacters(from, 2) &&
                HighLevelEncoder.isDigit(input.charAt(from + 1))) {
                // two digits ASCII encoded
                this.addEdge(edges, new Edge(input, Mode.ASCII, from, 2, previous));
            }
            else {
                // one ASCII encoded character or an extended character via Upper Shift
                this.addEdge(edges, new Edge(input, Mode.ASCII, from, 1, previous));
            }
            const modes = [Mode.C40, Mode.TEXT];
            for (const mode of modes) {
                const characterLength = [];
                if (MinimalEncoder.getNumberOfC40Words(input, from, mode === Mode.C40, characterLength) > 0) {
                    this.addEdge(edges, new Edge(input, mode, from, characterLength[0], previous));
                }
            }
            if (input.haveNCharacters(from, 3) &&
                HighLevelEncoder.isNativeX12(input.charAt(from)) &&
                HighLevelEncoder.isNativeX12(input.charAt(from + 1)) &&
                HighLevelEncoder.isNativeX12(input.charAt(from + 2))) {
                this.addEdge(edges, new Edge(input, Mode.X12, from, 3, previous));
            }
            this.addEdge(edges, new Edge(input, Mode.B256, from, 1, previous));
        }
        // We create 4 EDF edges,  with 1, 2 3 or 4 characters length. The fourth normally doesn't have a latch to ASCII
        // unless it is 2 characters away from the end of the input.
        let i;
        for (i = 0; i < 3; i++) {
            const pos = from + i;
            if (input.haveNCharacters(pos, 1) &&
                HighLevelEncoder.isNativeEDIFACT(input.charAt(pos))) {
                this.addEdge(edges, new Edge(input, Mode.EDF, from, i + 1, previous));
            }
            else {
                break;
            }
        }
        if (i === 3 &&
            input.haveNCharacters(from, 4) &&
            HighLevelEncoder.isNativeEDIFACT(input.charAt(from + 3))) {
            this.addEdge(edges, new Edge(input, Mode.EDF, from, 4, previous));
        }
    }
    static encodeMinimally(input) {
        /* The minimal encoding is computed by Dijkstra. The acyclic graph is modeled as follows:
         * A vertex represents a combination of a position in the input and an encoding mode where position 0
         * denotes the position left of the first character, 1 the position left of the second character and so on.
         * Likewise the end vertices are located after the last character at position input.length().
         * For any position there might be up to six vertices, one for each of the encoding types ASCII, C40, TEXT, X12,
         * EDF and B256.
         *
         * As an example consider the input string "ABC123" then at position 0 there is only one vertex with the default
         * ASCII encodation. At position 3 there might be vertices for the types ASCII, C40, X12, EDF and B256.
         *
         * An edge leading to such a vertex encodes one or more of the characters left of the position that the vertex
         * represents. It encodes the characters in the encoding mode of the vertex that it ends on. In other words,
         * all edges leading to a particular vertex encode the same characters (the length of the suffix can vary) using the same
         * encoding mode.
         * As an example consider the input string "ABC123" and the vertex (4,EDF). Possible edges leading to this vertex
         * are:
         *   (0,ASCII)  --EDF(ABC1)--> (4,EDF)
         *   (1,ASCII)  --EDF(BC1)-->  (4,EDF)
         *   (1,B256)   --EDF(BC1)-->  (4,EDF)
         *   (1,EDF)    --EDF(BC1)-->  (4,EDF)
         *   (2,ASCII)  --EDF(C1)-->   (4,EDF)
         *   (2,B256)   --EDF(C1)-->   (4,EDF)
         *   (2,EDF)    --EDF(C1)-->   (4,EDF)
         *   (3,ASCII)  --EDF(1)-->    (4,EDF)
         *   (3,B256)   --EDF(1)-->    (4,EDF)
         *   (3,EDF)    --EDF(1)-->    (4,EDF)
         *   (3,C40)    --EDF(1)-->    (4,EDF)
         *   (3,X12)    --EDF(1)-->    (4,EDF)
         *
         * The edges leading to a vertex are stored in such a way that there is a fast way to enumerate the edges ending
         * on a particular vertex.
         *
         * The algorithm processes the vertices in order of their position thereby performing the following:
         *
         * For every vertex at position i the algorithm enumerates the edges ending on the vertex and removes all but the
         * shortest from that list.
         * Then it processes the vertices for the position i+1. If i+1 == input.length() then the algorithm ends
         * and chooses the the edge with the smallest size from any of the edges leading to vertices at this position.
         * Otherwise the algorithm computes all possible outgoing edges for the vertices at the position i+1
         *
         * Examples:
         * The process is illustrated by showing the graph (edges) after each iteration from left to right over the input:
         * An edge is drawn as follows "(" + fromVertex + ") -- " + encodingMode + "(" + encodedInput + ") (" +
         * accumulatedSize + ") --> (" + toVertex + ")"
         *
         * Example 1 encoding the string "ABCDEFG":
         *
         *
         * Situation after adding edges to the start vertex (0,ASCII)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII)
         * (0,ASCII) B256(A) (3) --> (1,B256)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF)
         * (0,ASCII) C40(ABC) (3) --> (3,C40)
         * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT)
         * (0,ASCII) X12(ABC) (3) --> (3,X12)
         * (0,ASCII) EDF(ABC) (4) --> (3,EDF)
         * (0,ASCII) EDF(ABCD) (4) --> (4,EDF)
         *
         * Situation after adding edges to vertices at position 1
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII)
         * (0,ASCII) B256(A) (3) --> (1,B256)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF)
         * (0,ASCII) C40(ABC) (3) --> (3,C40)
         * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT)
         * (0,ASCII) X12(ABC) (3) --> (3,X12)
         * (0,ASCII) EDF(ABC) (4) --> (3,EDF)
         * (0,ASCII) EDF(ABCD) (4) --> (4,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) B256(B) (4) --> (2,B256)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BC) (5) --> (3,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCD) (5) --> (4,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) ASCII(B) (4) --> (2,ASCII)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256)
         * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BC) (6) --> (3,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) C40(BCD) (5) --> (4,C40)
         * (0,ASCII) B256(A) (3) --> (1,B256) TEXT(BCD) (7) --> (4,TEXT)
         * (0,ASCII) B256(A) (3) --> (1,B256) X12(BCD) (5) --> (4,X12)
         * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCD) (6) --> (4,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCDE) (6) --> (5,EDF)
         *
         * Edge "(1,ASCII) ASCII(B) (2) --> (2,ASCII)" is minimal for the vertex (2,ASCII) so that edge "(1,B256) ASCII(B) (4) --> (2,ASCII)" is removed.
         * Edge "(1,B256) B256(B) (3) --> (2,B256)" is minimal for the vertext (2,B256) so that the edge "(1,ASCII) B256(B) (4) --> (2,B256)" is removed.
         *
         * Situation after adding edges to vertices at position 2
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII)
         * (0,ASCII) B256(A) (3) --> (1,B256)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF)
         * (0,ASCII) C40(ABC) (3) --> (3,C40)
         * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT)
         * (0,ASCII) X12(ABC) (3) --> (3,X12)
         * (0,ASCII) EDF(ABC) (4) --> (3,EDF)
         * (0,ASCII) EDF(ABCD) (4) --> (4,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BC) (5) --> (3,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCD) (5) --> (4,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256)
         * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BC) (6) --> (3,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) C40(BCD) (5) --> (4,C40)
         * (0,ASCII) B256(A) (3) --> (1,B256) TEXT(BCD) (7) --> (4,TEXT)
         * (0,ASCII) B256(A) (3) --> (1,B256) X12(BCD) (5) --> (4,X12)
         * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCD) (6) --> (4,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCDE) (6) --> (5,EDF)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF) ASCII(C) (5) --> (3,ASCII)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF) B256(C) (6) --> (3,B256)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CD) (7) --> (4,EDF)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF) C40(CDE) (6) --> (5,C40)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF) TEXT(CDE) (8) --> (5,TEXT)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF) X12(CDE) (6) --> (5,X12)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CDE) (7) --> (5,EDF)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CDEF) (7) --> (6,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) B256(C) (5) --> (3,B256)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CD) (6) --> (4,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) C40(CDE) (5) --> (5,C40)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) TEXT(CDE) (7) --> (5,TEXT)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) X12(CDE) (5) --> (5,X12)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDE) (6) --> (5,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDEF) (6) --> (6,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) ASCII(C) (4) --> (3,ASCII)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CD) (6) --> (4,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) C40(CDE) (5) --> (5,C40)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) TEXT(CDE) (7) --> (5,TEXT)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) X12(CDE) (5) --> (5,X12)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CDE) (6) --> (5,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CDEF) (6) --> (6,EDF)
         *
         * Edge "(2,ASCII) ASCII(C) (3) --> (3,ASCII)" is minimal for the vertex (3,ASCII) so that edges "(2,EDF) ASCII(C) (5) --> (3,ASCII)"
         * and "(2,B256) ASCII(C) (4) --> (3,ASCII)" can be removed.
         * Edge "(0,ASCII) EDF(ABC) (4) --> (3,EDF)" is minimal for the vertex (3,EDF) so that edges "(1,ASCII) EDF(BC) (5) --> (3,EDF)"
         * and "(1,B256) EDF(BC) (6) --> (3,EDF)" can be removed.
         * Edge "(2,B256) B256(C) (4) --> (3,B256)" is minimal for the vertex (3,B256) so that edges "(2,ASCII) B256(C) (5) --> (3,B256)"
         * and "(2,EDF) B256(C) (6) --> (3,B256)" can be removed.
         *
         * This continues for vertices 3 thru 7
         *
         * Situation after adding edges to vertices at position 7
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII)
         * (0,ASCII) B256(A) (3) --> (1,B256)
         * (0,ASCII) EDF(AB) (4) --> (2,EDF)
         * (0,ASCII) C40(ABC) (3) --> (3,C40)
         * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT)
         * (0,ASCII) X12(ABC) (3) --> (3,X12)
         * (0,ASCII) EDF(ABC) (4) --> (3,EDF)
         * (0,ASCII) EDF(ABCD) (4) --> (4,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256)
         * (0,ASCII) C40(ABC) (3) --> (3,C40) C40(DEF) (5) --> (6,C40)
         * (0,ASCII) X12(ABC) (3) --> (3,X12) X12(DEF) (5) --> (6,X12)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) C40(CDE) (5) --> (5,C40)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) TEXT(CDE) (7) --> (5,TEXT)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) X12(CDE) (5) --> (5,X12)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDEF) (6) --> (6,EDF)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40) C40(EFG) (6) --> (7,C40)    //Solution 1
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12) X12(EFG) (6) --> (7,X12)    //Solution 2
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) TEXT(DEF) (8) --> (6,TEXT)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) EDF(DEFG) (7) --> (7,EDF)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) TEXT(EFG) (9) --> (7,TEXT)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII) ASCII(F) (6) --> (6,ASCII)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256) B256(F) (7) --> (6,B256)
         * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII) ASCII(F) (6) --> (6,ASCII) ASCII(G) (7) --> (7,ASCII)
         * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256) B256(F) (7) --> (6,B256) B256(G) (8) --> (7,B256)
         *
         * Hence a minimal encoding of "ABCDEFG" is either ASCII(A),C40(BCDEFG) or ASCII(A), X12(BCDEFG) with a size of 5 bytes.
         */
        const inputLength = input.length();
        // Array that represents vertices. There is a vertex for every character and mode.
        // The last dimension in the array below encodes the 6 modes ASCII, C40, TEXT, X12, EDF and B256
        const edges = Array(inputLength + 1)
            .fill(null)
            .map(() => Array(6).fill(0));
        this.addEdges(input, edges, 0, null);
        for (let i = 1; i <= inputLength; i++) {
            for (let j = 0; j < 6; j++) {
                if (edges[i][j] !== null && i < inputLength) {
                    this.addEdges(input, edges, i, edges[i][j]);
                }
            }
            // optimize memory by removing edges that have been passed.
            for (let j = 0; j < 6; j++) {
                edges[i - 1][j] = null;
            }
        }
        let minimalJ = -1;
        let minimalSize = Integer.MAX_VALUE;
        for (let j = 0; j < 6; j++) {
            if (edges[inputLength][j] !== null) {
                const edge = edges[inputLength][j];
                const size = j >= 1 && j <= 3 ? edge.cachedTotalSize + 1 : edge.cachedTotalSize; // C40, TEXT and X12 need an
                // extra unlatch at the end
                if (size < minimalSize) {
                    minimalSize = size;
                    minimalJ = j;
                }
            }
        }
        if (minimalJ < 0) {
            throw new Error('Failed to encode "' + input + '"');
        }
        return new Result(edges[inputLength][minimalJ]);
    }
}
class Result {
    constructor(solution) {
        const input = solution.input;
        let size = 0;
        let bytesAL = [];
        const randomizePostfixLength = [];
        const randomizeLengths = [];
        if ((solution.mode === Mode.C40 ||
            solution.mode === Mode.TEXT ||
            solution.mode === Mode.X12) &&
            solution.getEndMode() !== Mode.ASCII) {
            size += this.prepend(Edge.getBytes(254), bytesAL);
        }
        let current = solution;
        while (current !== null) {
            size += this.prepend(current.getDataBytes(), bytesAL);
            if (current.previous === null ||
                current.getPreviousStartMode() !== current.getMode()) {
                if (current.getMode() === Mode.B256) {
                    if (size <= 249) {
                        bytesAL.unshift(size);
                        size++;
                    }
                    else {
                        bytesAL.unshift(size % 250);
                        bytesAL.unshift(size / 250 + 249);
                        size += 2;
                    }
                    randomizePostfixLength.push(bytesAL.length);
                    randomizeLengths.push(size);
                }
                this.prepend(current.getLatchBytes(), bytesAL);
                size = 0;
            }
            current = current.previous;
        }
        if (input.getMacroId() === 5) {
            size += this.prepend(Edge.getBytes(236), bytesAL);
        }
        else if (input.getMacroId() === 6) {
            size += this.prepend(Edge.getBytes(237), bytesAL);
        }
        if (input.getFNC1Character() > 0) {
            size += this.prepend(Edge.getBytes(232), bytesAL);
        }
        for (let i = 0; i < randomizePostfixLength.length; i++) {
            this.applyRandomPattern(bytesAL, bytesAL.length - randomizePostfixLength[i], randomizeLengths[i]);
        }
        // add padding
        const capacity = solution.getMinSymbolSize(bytesAL.length);
        if (bytesAL.length < capacity) {
            bytesAL.push(129);
        }
        while (bytesAL.length < capacity) {
            bytesAL.push(this.randomize253State(bytesAL.length + 1));
        }
        this.bytes = new Uint8Array(bytesAL.length);
        for (let i = 0; i < this.bytes.length; i++) {
            this.bytes[i] = bytesAL[i];
        }
    }
    prepend(bytes, into) {
        for (let i = bytes.length - 1; i >= 0; i--) {
            into.unshift(bytes[i]);
        }
        return bytes.length;
    }
    randomize253State(codewordPosition) {
        const pseudoRandom = ((149 * codewordPosition) % 253) + 1;
        const tempVariable = 129 + pseudoRandom;
        return tempVariable <= 254 ? tempVariable : tempVariable - 254;
    }
    applyRandomPattern(bytesAL, startPosition, length) {
        for (let i = 0; i < length; i++) {
            // See "B.1 253-state algorithm
            const Pad_codeword_position = startPosition + i;
            const Pad_codeword_value = bytesAL[Pad_codeword_position] & 0xff;
            const pseudo_random_number = ((149 * (Pad_codeword_position + 1)) % 255) + 1;
            const temp_variable = Pad_codeword_value + pseudo_random_number;
            bytesAL[Pad_codeword_position] =
                temp_variable <= 255 ? temp_variable : temp_variable - 256;
        }
    }
    getBytes() {
        return this.bytes;
    }
}
class Edge {
    constructor(input, mode, fromPosition, characterLength, previous) {
        this.input = input;
        this.mode = mode;
        this.fromPosition = fromPosition;
        this.characterLength = characterLength;
        this.previous = previous;
        this.allCodewordCapacities = [
            3, 5, 8, 10, 12, 16, 18, 22, 30, 32, 36, 44, 49, 62, 86, 114, 144, 174, 204,
            280, 368, 456, 576, 696, 816, 1050, 1304, 1558,
        ];
        this.squareCodewordCapacities = [
            3, 5, 8, 12, 18, 22, 30, 36, 44, 62, 86, 114, 144, 174, 204, 280, 368, 456,
            576, 696, 816, 1050, 1304, 1558,
        ];
        this.rectangularCodewordCapacities = [5, 10, 16, 33, 32, 49];
        if (!(fromPosition + characterLength <= input.length())) {
            throw new Error('Invalid edge');
        }
        let size = previous !== null ? previous.cachedTotalSize : 0;
        const previousMode = this.getPreviousMode();
        /*
         * Switching modes
         * ASCII -> C40: latch 230
         * ASCII -> TEXT: latch 239
         * ASCII -> X12: latch 238
         * ASCII -> EDF: latch 240
         * ASCII -> B256: latch 231
         * C40 -> ASCII: word(c1,c2,c3), 254
         * TEXT -> ASCII: word(c1,c2,c3), 254
         * X12 -> ASCII: word(c1,c2,c3), 254
         * EDIFACT -> ASCII: Unlatch character,0,0,0 or c1,Unlatch character,0,0 or c1,c2,Unlatch character,0 or
         * c1,c2,c3,Unlatch character
         * B256 -> ASCII: without latch after n bytes
         */
        switch (mode) {
            case Mode.ASCII:
                size++;
                if (input.isECI(fromPosition) ||
                    MinimalEncoder.isExtendedASCII(input.charAt(fromPosition), input.getFNC1Character())) {
                    size++;
                }
                if (previousMode === Mode.C40 ||
                    previousMode === Mode.TEXT ||
                    previousMode === Mode.X12) {
                    size++; // unlatch 254 to ASCII
                }
                break;
            case Mode.B256:
                size++;
                if (previousMode !== Mode.B256) {
                    size++; // byte count
                }
                else if (this.getB256Size() === 250) {
                    size++; // extra byte count
                }
                if (previousMode === Mode.ASCII) {
                    size++; // latch to B256
                }
                else if (previousMode === Mode.C40 ||
                    previousMode === Mode.TEXT ||
                    previousMode === Mode.X12) {
                    size += 2; // unlatch to ASCII, latch to B256
                }
                break;
            case Mode.C40:
            case Mode.TEXT:
            case Mode.X12:
                if (mode === Mode.X12) {
                    size += 2;
                }
                else {
                    let charLen = [];
                    size +=
                        MinimalEncoder.getNumberOfC40Words(input, fromPosition, mode === Mode.C40, charLen) * 2;
                }
                if (previousMode === Mode.ASCII || previousMode === Mode.B256) {
                    size++; // additional byte for latch from ASCII to this mode
                }
                else if (previousMode !== mode &&
                    (previousMode === Mode.C40 ||
                        previousMode === Mode.TEXT ||
                        previousMode === Mode.X12)) {
                    size += 2; // unlatch 254 to ASCII followed by latch to this mode
                }
                break;
            case Mode.EDF:
                size += 3;
                if (previousMode === Mode.ASCII || previousMode === Mode.B256) {
                    size++; // additional byte for latch from ASCII to this mode
                }
                else if (previousMode === Mode.C40 ||
                    previousMode === Mode.TEXT ||
                    previousMode === Mode.X12) {
                    size += 2; // unlatch 254 to ASCII followed by latch to this mode
                }
                break;
        }
        this.cachedTotalSize = size;
    }
    // does not count beyond 250
    getB256Size() {
        let cnt = 0;
        let current = this;
        while (current !== null && current.mode === Mode.B256 && cnt <= 250) {
            cnt++;
            current = current.previous;
        }
        return cnt;
    }
    getPreviousStartMode() {
        return this.previous === null ? Mode.ASCII : this.previous.mode;
    }
    getPreviousMode() {
        return this.previous === null ? Mode.ASCII : this.previous.getEndMode();
    }
    /** Returns Mode.ASCII in case that:
     *  - Mode is EDIFACT and characterLength is less than 4 or the remaining characters can be encoded in at most 2
     *    ASCII bytes.
     *  - Mode is C40, TEXT or X12 and the remaining characters can be encoded in at most 1 ASCII byte.
     *  Returns mode in all other cases.
     * */
    getEndMode() {
        if (this.mode === Mode.EDF) {
            if (this.characterLength < 4) {
                return Mode.ASCII;
            }
            const lastASCII = this.getLastASCII(); // see 5.2.8.2 EDIFACT encodation Rules
            if (lastASCII > 0 &&
                this.getCodewordsRemaining(this.cachedTotalSize + lastASCII) <=
                    2 - lastASCII) {
                return Mode.ASCII;
            }
        }
        if (this.mode === Mode.C40 ||
            this.mode === Mode.TEXT ||
            this.mode === Mode.X12) {
            // see 5.2.5.2 C40 encodation rules and 5.2.7.2 ANSI X12 encodation rules
            if (this.fromPosition + this.characterLength >= this.input.length() &&
                this.getCodewordsRemaining(this.cachedTotalSize) === 0) {
                return Mode.ASCII;
            }
            const lastASCII = this.getLastASCII();
            if (lastASCII === 1 &&
                this.getCodewordsRemaining(this.cachedTotalSize + 1) === 0) {
                return Mode.ASCII;
            }
        }
        return this.mode;
    }
    getMode() {
        return this.mode;
    }
    /** Peeks ahead and returns 1 if the postfix consists of exactly two digits, 2 if the postfix consists of exactly
     *  two consecutive digits and a non extended character or of 4 digits.
     *  Returns 0 in any other case
     **/
    getLastASCII() {
        const length = this.input.length();
        const from = this.fromPosition + this.characterLength;
        if (length - from > 4 || from >= length) {
            return 0;
        }
        if (length - from === 1) {
            if (MinimalEncoder.isExtendedASCII(this.input.charAt(from), this.input.getFNC1Character())) {
                return 0;
            }
            return 1;
        }
        if (length - from === 2) {
            if (MinimalEncoder.isExtendedASCII(this.input.charAt(from), this.input.getFNC1Character()) ||
                MinimalEncoder.isExtendedASCII(this.input.charAt(from + 1), this.input.getFNC1Character())) {
                return 0;
            }
            if (HighLevelEncoder.isDigit(this.input.charAt(from)) &&
                HighLevelEncoder.isDigit(this.input.charAt(from + 1))) {
                return 1;
            }
            return 2;
        }
        if (length - from === 3) {
            if (HighLevelEncoder.isDigit(this.input.charAt(from)) &&
                HighLevelEncoder.isDigit(this.input.charAt(from + 1)) &&
                !MinimalEncoder.isExtendedASCII(this.input.charAt(from + 2), this.input.getFNC1Character())) {
                return 2;
            }
            if (HighLevelEncoder.isDigit(this.input.charAt(from + 1)) &&
                HighLevelEncoder.isDigit(this.input.charAt(from + 2)) &&
                !MinimalEncoder.isExtendedASCII(this.input.charAt(from), this.input.getFNC1Character())) {
                return 2;
            }
            return 0;
        }
        if (HighLevelEncoder.isDigit(this.input.charAt(from)) &&
            HighLevelEncoder.isDigit(this.input.charAt(from + 1)) &&
            HighLevelEncoder.isDigit(this.input.charAt(from + 2)) &&
            HighLevelEncoder.isDigit(this.input.charAt(from + 3))) {
            return 2;
        }
        return 0;
    }
    /** Returns the capacity in codewords of the smallest symbol that has enough capacity to fit the given minimal
     * number of codewords.
     **/
    getMinSymbolSize(minimum) {
        switch (this.input.getShapeHint()) {
            case 1 /* FORCE_SQUARE */:
                for (const capacity of this.squareCodewordCapacities) {
                    if (capacity >= minimum) {
                        return capacity;
                    }
                }
                break;
            case 2 /* FORCE_RECTANGLE */:
                for (const capacity of this.rectangularCodewordCapacities) {
                    if (capacity >= minimum) {
                        return capacity;
                    }
                }
                break;
        }
        for (const capacity of this.allCodewordCapacities) {
            if (capacity >= minimum) {
                return capacity;
            }
        }
        return this.allCodewordCapacities[this.allCodewordCapacities.length - 1];
    }
    /** Returns the remaining capacity in codewords of the smallest symbol that has enough capacity to fit the given
     * minimal number of codewords.
     **/
    getCodewordsRemaining(minimum) {
        return this.getMinSymbolSize(minimum) - minimum;
    }
    static getBytes(c1, c2) {
        const result = new Uint8Array(c2 ? 2 : 1);
        result[0] = c1;
        if (c2) {
            result[1] = c2;
        }
        return result;
    }
    setC40Word(bytes, offset, c1, c2, c3) {
        const val16 = 1600 * (c1 & 0xff) + 40 * (c2 & 0xff) + (c3 & 0xff) + 1;
        bytes[offset] = val16 / 256;
        bytes[offset + 1] = val16 % 256;
    }
    getX12Value(c) {
        return c === 13
            ? 0
            : c === 42
                ? 1
                : c === 62
                    ? 2
                    : c === 32
                        ? 3
                        : c >= 48 && c <= 57
                            ? c - 44
                            : c >= 65 && c <= 90
                                ? c - 51
                                : c;
    }
    getX12Words() {
        if (!(this.characterLength % 3 === 0)) {
            throw new Error('X12 words must be a multiple of 3');
        }
        const result = new Uint8Array((this.characterLength / 3) * 2);
        for (let i = 0; i < result.length; i += 2) {
            this.setC40Word(result, i, this.getX12Value(this.input.charAt(this.fromPosition + (i / 2) * 3)), this.getX12Value(this.input.charAt(this.fromPosition + (i / 2) * 3 + 1)), this.getX12Value(this.input.charAt(this.fromPosition + (i / 2) * 3 + 2)));
        }
        return result;
    }
    getShiftValue(c, c40, fnc1) {
        return (c40 && MinimalEncoder.isInC40Shift1Set(c)) ||
            (!c40 && MinimalEncoder.isInTextShift1Set(c))
            ? 0
            : (c40 && MinimalEncoder.isInC40Shift2Set(c, fnc1)) ||
                (!c40 && MinimalEncoder.isInTextShift2Set(c, fnc1))
                ? 1
                : 2;
    }
    getC40Value(c40, setIndex, c, fnc1) {
        if (c === fnc1) {
            if (!(setIndex === 2)) {
                throw new Error('FNC1 cannot be used in C40 shift 2');
            }
            return 27;
        }
        if (c40) {
            return c <= 31
                ? c
                : c === 32
                    ? 3
                    : c <= 47
                        ? c - 33
                        : c <= 57
                            ? c - 44
                            : c <= 64
                                ? c - 43
                                : c <= 90
                                    ? c - 51
                                    : c <= 95
                                        ? c - 69
                                        : c <= 127
                                            ? c - 96
                                            : c;
        }
        else {
            return c === 0
                ? 0
                : setIndex === 0 && c <= 3
                    ? c - 1 // is this a bug in the spec?
                    : setIndex === 1 && c <= 31
                        ? c
                        : c === 32
                            ? 3
                            : c >= 33 && c <= 47
                                ? c - 33
                                : c >= 48 && c <= 57
                                    ? c - 44
                                    : c >= 58 && c <= 64
                                        ? c - 43
                                        : c >= 65 && c <= 90
                                            ? c - 64
                                            : c >= 91 && c <= 95
                                                ? c - 69
                                                : c === 96
                                                    ? 0
                                                    : c >= 97 && c <= 122
                                                        ? c - 83
                                                        : c >= 123 && c <= 127
                                                            ? c - 96
                                                            : c;
        }
    }
    getC40Words(c40, fnc1) {
        const c40Values = [];
        for (let i = 0; i < this.characterLength; i++) {
            const ci = this.input.charAt(this.fromPosition + i);
            if ((c40 && HighLevelEncoder.isNativeC40(ci)) ||
                (!c40 && HighLevelEncoder.isNativeText(ci))) {
                c40Values.push(this.getC40Value(c40, 0, ci, fnc1));
            }
            else if (!MinimalEncoder.isExtendedASCII(ci, fnc1)) {
                const shiftValue = this.getShiftValue(ci, c40, fnc1);
                c40Values.push(shiftValue); // Shift[123]
                c40Values.push(this.getC40Value(c40, shiftValue, ci, fnc1));
            }
            else {
                const asciiValue = (ci & 0xff) - 128;
                if ((c40 && HighLevelEncoder.isNativeC40(asciiValue)) ||
                    (!c40 && HighLevelEncoder.isNativeText(asciiValue))) {
                    c40Values.push(1); // Shift 2
                    c40Values.push(30); // Upper Shift
                    c40Values.push(this.getC40Value(c40, 0, asciiValue, fnc1));
                }
                else {
                    c40Values.push(1); // Shift 2
                    c40Values.push(30); // Upper Shift
                    const shiftValue = this.getShiftValue(asciiValue, c40, fnc1);
                    c40Values.push(shiftValue); // Shift[123]
                    c40Values.push(this.getC40Value(c40, shiftValue, asciiValue, fnc1));
                }
            }
        }
        if (c40Values.length % 3 !== 0) {
            if (!((c40Values.length - 2) % 3 === 0 &&
                this.fromPosition + this.characterLength === this.input.length())) {
                throw new Error('C40 words must be a multiple of 3');
            }
            c40Values.push(0); // pad with 0 (Shift 1)
        }
        const result = new Uint8Array((c40Values.length / 3) * 2);
        let byteIndex = 0;
        for (let i = 0; i < c40Values.length; i += 3) {
            this.setC40Word(result, byteIndex, c40Values[i] & 0xff, c40Values[i + 1] & 0xff, c40Values[i + 2] & 0xff);
            byteIndex += 2;
        }
        return result;
    }
    getEDFBytes() {
        const numberOfThirds = Math.ceil(this.characterLength / 4.0);
        const result = new Uint8Array(numberOfThirds * 3);
        let pos = this.fromPosition;
        const endPos = Math.min(this.fromPosition + this.characterLength - 1, this.input.length() - 1);
        for (let i = 0; i < numberOfThirds; i += 3) {
            const edfValues = [];
            for (let j = 0; j < 4; j++) {
                if (pos <= endPos) {
                    edfValues[j] = this.input.charAt(pos++) & 0x3f;
                }
                else {
                    edfValues[j] = pos === endPos + 1 ? 0x1f : 0;
                }
            }
            let val24 = edfValues[0] << 18;
            val24 |= edfValues[1] << 12;
            val24 |= edfValues[2] << 6;
            val24 |= edfValues[3];
            result[i] = (val24 >> 16) & 0xff;
            result[i + 1] = (val24 >> 8) & 0xff;
            result[i + 2] = val24 & 0xff;
        }
        return result;
    }
    getLatchBytes() {
        switch (this.getPreviousMode()) {
            case Mode.ASCII:
            case Mode.B256: // after B256 ends (via length) we are back to ASCII
                switch (this.mode) {
                    case Mode.B256:
                        return Edge.getBytes(231);
                    case Mode.C40:
                        return Edge.getBytes(230);
                    case Mode.TEXT:
                        return Edge.getBytes(239);
                    case Mode.X12:
                        return Edge.getBytes(238);
                    case Mode.EDF:
                        return Edge.getBytes(240);
                }
                break;
            case Mode.C40:
            case Mode.TEXT:
            case Mode.X12:
                if (this.mode !== this.getPreviousMode()) {
                    switch (this.mode) {
                        case Mode.ASCII:
                            return Edge.getBytes(254);
                        case Mode.B256:
                            return Edge.getBytes(254, 231);
                        case Mode.C40:
                            return Edge.getBytes(254, 230);
                        case Mode.TEXT:
                            return Edge.getBytes(254, 239);
                        case Mode.X12:
                            return Edge.getBytes(254, 238);
                        case Mode.EDF:
                            return Edge.getBytes(254, 240);
                    }
                }
                break;
            case Mode.EDF:
                // The rightmost EDIFACT edge always contains an unlatch character
                if (this.mode !== Mode.EDF) {
                    throw new Error('Cannot switch from EDF to ' + this.mode);
                }
                break;
        }
        return new Uint8Array(0);
    }
    // Important: The function does not return the length bytes (one or two) in case of B256 encoding
    getDataBytes() {
        switch (this.mode) {
            case Mode.ASCII:
                if (this.input.isECI(this.fromPosition)) {
                    return Edge.getBytes(241, this.input.getECIValue(this.fromPosition) + 1);
                }
                else if (MinimalEncoder.isExtendedASCII(this.input.charAt(this.fromPosition), this.input.getFNC1Character())) {
                    return Edge.getBytes(235, this.input.charAt(this.fromPosition) - 127);
                }
                else if (this.characterLength === 2) {
                    return Edge.getBytes(this.input.charAt(this.fromPosition) * 10 +
                        this.input.charAt(this.fromPosition + 1) +
                        130);
                }
                else if (this.input.isFNC1(this.fromPosition)) {
                    return Edge.getBytes(232);
                }
                else {
                    return Edge.getBytes(this.input.charAt(this.fromPosition) + 1);
                }
            case Mode.B256:
                return Edge.getBytes(this.input.charAt(this.fromPosition));
            case Mode.C40:
                return this.getC40Words(true, this.input.getFNC1Character());
            case Mode.TEXT:
                return this.getC40Words(false, this.input.getFNC1Character());
            case Mode.X12:
                return this.getX12Words();
            case Mode.EDF:
                return this.getEDFBytes();
        }
    }
}
class Input extends MinimalECIInput {
    constructor(stringToEncode, priorityCharset, fnc1, shape, macroId) {
        super(stringToEncode, priorityCharset, fnc1);
        this.shape = shape;
        this.macroId = macroId;
    }
    getMacroId() {
        return this.macroId;
    }
    getShapeHint() {
        return this.shape;
    }
}
