void distinguishAndPropagateGroup(int groupIndex, Chain chain, String group3, int seqcode, int firstAtomIndex,
			int maxAtomIndex) {
		/*
		 * called by finalizeGroupBuild()
		 * 
		 * first: build array of special atom names, for example "CA" for the alpha carbon is assigned #2 see
		 * JmolConstants.specialAtomNames[] the special atoms all have IDs based on Atom.lookupSpecialAtomID(atomName)
		 * these will be the same for each conformation
		 * 
		 * second: creates the monomers themselves based on this information thus building the byte offsets[] array for
		 * each monomer, indicating which position relative to the first atom in the group is which atom. Each
		 * monomer.offsets[i] then points to the specific atom of that type these will NOT be the same for each
		 * conformation
		 * 
		 */
		Group group = null;
		int lastAtomIndex = maxAtomIndex - 1;

		if (group3 != null) {
			int distinguishingBits = 0;

			// clear previous specialAtomIndexes
			for (int i = JmolConstants.ATOMID_MAX; --i >= 0;)
				specialAtomIndexes[i] = Integer.MIN_VALUE;

			if (specialAtomIDs != null) {
				// go last to first so that FIRST confirmation is default
				for (int i = maxAtomIndex; --i >= firstAtomIndex;) {
					int specialAtomID = specialAtomIDs[i];
					if (specialAtomID > 0) {
						if (specialAtomID < JmolConstants.ATOMID_DISTINGUISHING_ATOM_MAX) {
							int bit = 1 << specialAtomID;
							/*
							 * save for future option -- turns out the 1jsa bug was in relation to an author using the
							 * same group number for two different groups
							 * 
							 * System.out.println( i + " " + atoms[i].getIdentity() + " " + specialAtomID); if
							 * ((distinguishingBits & bit) != 0) {
							 * 
							 * //bh 9/21/2006: // "if the group has two of the same, that cannot be right." // Thus, for
							 * example, two C's doth not make a protein "carbonyl C" distinguishingBits = 0; break; }
							 */
							distinguishingBits |= bit;
						}
						specialAtomIndexes[specialAtomID] = i;
					}
				}
			}

			if (lastAtomIndex < firstAtomIndex)
				throw new NullPointerException();

			if ((distinguishingBits & JmolConstants.ATOMID_PROTEIN_MASK) == JmolConstants.ATOMID_PROTEIN_MASK) {
				group = AminoMonomer.validateAndAllocate(chain, group3, seqcode, firstAtomIndex, lastAtomIndex,
						specialAtomIndexes, atoms);
				countGroup(atoms[firstAtomIndex].modelIndex, "p>", group3);
			}
			else if (distinguishingBits == JmolConstants.ATOMID_ALPHA_ONLY_MASK) {
				group = AlphaMonomer.validateAndAllocate(chain, group3, seqcode, firstAtomIndex, lastAtomIndex,
						specialAtomIndexes, atoms);
				countGroup(atoms[firstAtomIndex].modelIndex, "p>", group3);
			}
			else if (((distinguishingBits & JmolConstants.ATOMID_NUCLEIC_MASK) == JmolConstants.ATOMID_NUCLEIC_MASK)) {
				group = NucleicMonomer.validateAndAllocate(chain, group3, seqcode, firstAtomIndex, lastAtomIndex,
						specialAtomIndexes, atoms);
				countGroup(atoms[firstAtomIndex].modelIndex, "n>", group3);
			}
			else if (distinguishingBits == JmolConstants.ATOMID_PHOSPHORUS_ONLY_MASK) {
				group = PhosphorusMonomer.validateAndAllocate(chain, group3, seqcode, firstAtomIndex, lastAtomIndex,
						specialAtomIndexes, atoms);
				countGroup(atoms[firstAtomIndex].modelIndex, "n>", group3);
			}
			else if (JmolConstants.checkCarbohydrate(group3)) {
				group = CarbohydrateMonomer.validateAndAllocate(chain, group3, seqcode, firstAtomIndex, lastAtomIndex,
						specialAtomIndexes, atoms);
				countGroup(atoms[firstAtomIndex].modelIndex, "c>", group3);
			}

		}
		if (group == null) {
			group = new Group(chain, group3, seqcode, firstAtomIndex, lastAtomIndex);
			if (group3 != null)
				countGroup(atoms[firstAtomIndex].modelIndex, "o>", group3);
		}

		chain.addGroup(group);
		groups[groupIndex] = group;

		for (int i = maxAtomIndex; --i >= firstAtomIndex;)
			atoms[i].setGroup(group);

	}