"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.chemicalFormulaHash = void 0;
const uuid_1 = require("./uuid");
const elements = [
    { element: 'Carbon', symbol: 'C' },
    { element: 'Hydrogen', symbol: 'H' },
    { element: 'Nitrogen', symbol: 'N' },
    { element: 'Oxygen', symbol: 'O' },
];
const sortChemicalFormula = (formula) => {
    const finalCompounds = { 'C': 0, 'H': 0, 'N': 0, 'O': 0 };
    for (const symbol of formula) {
        finalCompounds[symbol.symbol] += symbol.atoms;
    }
    let finalFormula = '';
    for (const key of Object.keys(finalCompounds)) {
        if (finalCompounds[key] > 0) {
            const atoms = (finalCompounds[key] % 9) + 1;
            finalFormula += key + (atoms > 1 ? atoms.toString(10) : '');
        }
    }
    return finalFormula;
};
const alphabetSize = elements.length;
const generateFormula = (uuidBuffer, startIndex, endIndex, round) => {
    const alphabet = [
        elements[uuidBuffer[0 + (round << 2)] % alphabetSize].symbol,
        elements[uuidBuffer[1 + (round << 2)] % alphabetSize].symbol,
        elements[uuidBuffer[2 + (round << 2)] % alphabetSize].symbol,
        elements[uuidBuffer[3 + (round << 2)] % alphabetSize].symbol
    ];
    const formula = [];
    for (let i = startIndex; i < endIndex; ++i) {
        const nibbles = [uuidBuffer[i] >> 4, uuidBuffer[i] & 0xf];
        for (const nibble of nibbles) {
            const index = ((nibble >> 2) + (i % 3)) % 3;
            formula.push({ symbol: alphabet[index], atoms: (nibble & 3) + 1 });
        }
    }
    return sortChemicalFormula(formula);
};
/*
This function produces a formated UUID that is made up of the following values separated by dashes:
1. A caller specified prefix
2. A pseudo chemical formula derived from the first half of a UUID
3. A pseudo chemical formula derived from the last half of a UUID
4. A radix 32 (similar to base32hex defined by RFC-2938) encoded version of the UUID

The chemical formulas are composed of at most 4 elements:
* C: Carbon
* H: Hydrogen
* N: Nitrogen
* O: Oxygen
Each element can be followed by an optional subscript that will be a positive integer between 2 and 9.

The chemical formulas are supposed to be a slightly easier values to memorize than the UUID, but they
lack sufficient uniqueness to be a unique ID on their own. Each chemical formula has 10^4 (10k) potential
variants. And the combination has 10k^2 (100m) potential combinations.
In a simple test, it takes on average ~1500 attempts to hit a collision. For comparison:
* Finding a collision in the first 10 characters of a UUID string would take: ~1.3m iterations
* Finding a collision in two words selected from a set of 256 words takes: ~350 iterations
* Finding a collision in a single formula: ~44 iterations

The length of the chemical formulas are variable (from 1 character to 8 characters each). This makes the
length of the final ID variable as well. The following values exclude the length of the prefix, as this
is choosen by the caller:
* Max Length: 3 (the dashes) + 8 (formula 1) + 8 (formula 2) + 26 (radix 32 encoded UUID) = 45
* Min Length: 3 (the dashes) + 1 (formula 1) + 1 (formula 2) + 26 (radix 32 encoded UUID) = 31
* Average Length in tests: 41.6
*/
const chemicalFormulaHash = (prefix) => {
    const uniqueId = (0, uuid_1.uuid)();
    const uuidHexString = uniqueId.replace(/-/g, '');
    const uuidBuffer = Buffer.from(uuidHexString, 'hex');
    const numberOfElements = 16;
    let hash = prefix;
    hash += '-' + generateFormula(uuidBuffer, 0, numberOfElements / 2, 0);
    hash += '-' + generateFormula(uuidBuffer, numberOfElements / 2, numberOfElements, 1);
    const hashEnd = BigInt('0x' + uuidHexString).toString(32);
    return hash + '-' + hashEnd;
};
exports.chemicalFormulaHash = chemicalFormulaHash;
//# sourceMappingURL=chemicalFormulaHash.js.map