class AminoAcids {

    public synchronized static AminoAcid[] createAAs() {
        if (aminoAcids != null) {
            return aminoAcids;
        }

        // amino-acids only have benzene aromaticity so we can run a simple
        // alternating pi-bond arom model to keep things in a consistent state
        Aromaticity arom = new Aromaticity(ElectronDonation.cdk(),
                                           Cycles.all(6));

        // Create set of AtomContainers
        aminoAcids = new AminoAcid[20];

        IChemFile list = new ChemFile();
        CMLReader reader = new CMLReader(AminoAcids.class.getClassLoader().getResourceAsStream(
                "org/openscience/cdk/templates/data/list_aminoacids.cml"));
        try {
            list = (IChemFile) reader.read(list);
            List<IAtomContainer> containersList = ChemFileManipulator.getAllAtomContainers(list);
            Iterator<IAtomContainer> iterator = containersList.iterator();
            int counter = 0;
            while (iterator.hasNext()) {
                IAtomContainer ac = (IAtomContainer) iterator.next();
                LOGGER.debug("Adding AA: ", ac);
                // convert into an AminoAcid
                AminoAcid aminoAcid = new AminoAcid();
                Iterator<IAtom> atoms = ac.atoms().iterator();
                Iterator<Object> props = ac.getProperties().keySet().iterator();
                while (props.hasNext()) {
                    Object next = props.next();
                    LOGGER.debug("Prop class: " + next.getClass().getName());
                    LOGGER.debug("Prop: " + next.toString());
                    if (next instanceof DictRef) {
                        DictRef dictRef = (DictRef) next;
                        // logger.debug("DictRef type: " + dictRef.getType());
                        if (dictRef.getType().equals("pdb:residueName")) {
                            aminoAcid.setProperty(RESIDUE_NAME, ac.getProperty(dictRef).toString().toUpperCase());
                            aminoAcid.setMonomerName(ac.getProperty(dictRef).toString());
                        } else if (dictRef.getType().equals("pdb:oneLetterCode")) {
                            aminoAcid.setProperty(RESIDUE_NAME_SHORT, ac.getProperty(dictRef));
                        } else if (dictRef.getType().equals("pdb:id")) {
                            aminoAcid.setProperty(ID, ac.getProperty(dictRef));
                            LOGGER.debug("Set AA ID to: " + ac.getProperty(dictRef));
                        } else {
                            LOGGER.error("Cannot deal with dictRef!");
                        }
                    }
                }
                while (atoms.hasNext()) {
                    IAtom atom = (IAtom) atoms.next();
                    String dictRef = (String) atom.getProperty("org.openscience.cdk.dict");
                    if (dictRef != null && dictRef.equals("pdb:nTerminus")) {
                        aminoAcid.addNTerminus(atom);
                    } else if (dictRef != null && dictRef.equals("pdb:cTerminus")) {
                        aminoAcid.addCTerminus(atom);
                    } else {
                        aminoAcid.addAtom(atom);
                    }
                }
                Iterator<IBond> bonds = ac.bonds().iterator();
                while (bonds.hasNext()) {
                    IBond bond = (IBond) bonds.next();
                    aminoAcid.addBond(bond);
                }
                AminoAcidManipulator.removeAcidicOxygen(aminoAcid);
                aminoAcid.setProperty(NO_ATOMS, "" + aminoAcid.getAtomCount());
                aminoAcid.setProperty(NO_BONDS, "" + aminoAcid.getBondCount());

                AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(aminoAcid);
                arom.apply(aminoAcid);

                if (counter < aminoAcids.length) {
                    aminoAcids[counter] = aminoAcid;
                } else {
                    LOGGER.error("Could not store AminoAcid! Array too short!");
                }
                counter++;
            }
            reader.close();
        } catch (CDKException | IOException exception) {
            LOGGER.error("Failed reading file: ", exception.getMessage());
            LOGGER.debug(exception);
        }

        return aminoAcids;
    }

}