class InChINumbersTools {

    static long[] parseUSmilesNumbers(String aux, IAtomContainer container) {

        int index;
        long[] numbers = new long[container.getAtomCount()];
        int[] first = null;
        int label = 1;

        if ((index = aux.indexOf("/R:")) >= 0) { // reconnected metal numbers
            int endIndex = aux.indexOf('/', index + 8);
            if (endIndex<0)
                endIndex = aux.length();
            String[] baseNumbers = aux.substring(index + 8, endIndex).split(";");
            first = new int[baseNumbers.length];
            Arrays.fill(first, -1);
            for (int i = 0; i < baseNumbers.length; i++) {
                String[] numbering = baseNumbers[i].split(",");
                first[i] = Integer.parseInt(numbering[0]) - 1;
                for (String number : numbering) {
                    numbers[Integer.parseInt(number) - 1] = label++;
                }
            }
        } else if ((index = aux.indexOf("/N:")) >= 0) { // standard numbers

            // read the standard numbers first (need to reference back for some structures)
            String[] baseNumbers = aux.substring(index + 3, aux.indexOf('/', index + 3)).split(";");
            first = new int[baseNumbers.length];
            Arrays.fill(first, -1);

            if ((index = aux.indexOf("/F:")) >= 0) {
                String[] fixedHNumbers = aux.substring(index + 3, aux.indexOf('/', index + 3)).split(";");
                for (int i = 0; i < fixedHNumbers.length; i++) {
                    String component = fixedHNumbers[i];

                    // m, 2m, 3m ... need to lookup number in the base numbering
                    if (component.charAt(component.length() - 1) == 'm') {
                        int n = component.length() > 1 ? Integer
                                .parseInt(component.substring(0, component.length() - 1)) : 1;
                        for (int j = 0; j < n; j++) {
                            String[] numbering = baseNumbers[i + j].split(",");
                            first[i + j] = Integer.parseInt(numbering[0]) - 1;
                            for (String number : numbering)
                                numbers[Integer.parseInt(number) - 1] = label++;
                        }
                    } else {
                        String[] numbering = component.split(",");
                        for (String number : numbering)
                            numbers[Integer.parseInt(number)-1] = label++;
                    }
                }
            } else {
                for (int i = 0; i < baseNumbers.length; i++) {
                    String[] numbering = baseNumbers[i].split(",");
                    first[i] = Integer.parseInt(numbering[0]) - 1;
                    for (String number : numbering)
                        numbers[Integer.parseInt(number) - 1] = label++;
                }
            }
        } else {
            throw new IllegalArgumentException("AuxInfo did not contain extractable base numbers (/N: or /R:).");
        }

        // Rule E: swap any oxygen anion for a double bonded oxygen (InChI sees
        // them as equivalent)
        for (int v : first) {
            if (v >= 0) {
                IAtom atom = container.getAtom(v);
                if (atom.getFormalCharge() == null) continue;
                if (atom.getAtomicNumber() == 8 && atom.getFormalCharge() == -1) {
                    List<IAtom> neighbors = container.getConnectedAtomsList(atom);
                    if (neighbors.size() == 1) {
                        IAtom correctedStart = findPiBondedOxygen(container, neighbors.get(0));
                        if (correctedStart != null) exch(numbers, v, container.indexOf(correctedStart));
                    }
                }
            }
        }

        // assign unlabelled atoms
        for (int i = 0; i < numbers.length; i++)
            if (numbers[i] == 0) numbers[i] = label++;

        return numbers;
    }

}