package com.actelion.research.chem.contrib;


import com.actelion.research.chem.*;

public class DiastereotopicAtomID {

	private static int xAtomicNumber = Molecule.getAtomicNoFromLabel("X");

	public static String[] getAtomIds(StereoMolecule molecule) {
		addMissingChirality(molecule);
		
		int numberAtoms=molecule.getAllAtoms();
		String[] ids=new String[numberAtoms];
		StereoMolecule tempMolecule;
		for (int iAtom=0; iAtom<numberAtoms; iAtom++) {
			tempMolecule=molecule.getCompactCopy();
			changeAtom(tempMolecule, iAtom);
			makeRacemic(tempMolecule);
			// We need to ensure the helper array in order to get correctly the result of racemisation
			ids[iAtom]=(new Canonizer(tempMolecule, Canonizer.ENCODE_ATOM_CUSTOM_LABELS)).getIDCode();
		}
		return ids;
	}

	/**
	 * The problem is that sometimes we need to add chiral bond that was not planned because it is the same group
	 * This is the case for example for the valine where the 2 C of the methyl groups are diastereotopic
	 * @param molecule
	 */
	public static void addMissingChirality(StereoMolecule molecule, int esrType) {
		for (int iAtom=0; iAtom<molecule.getAllAtoms(); iAtom++) {
			StereoMolecule tempMolecule=molecule.getCompactCopy();
			changeAtomForStereo(tempMolecule, iAtom);
			// After copy, helpers must be recalculated
			tempMolecule.ensureHelperArrays(Molecule.cHelperParities);
			// We need to have >0 and not >1 because there could be unspecified chirality in racemate
			for (int i=0; i<tempMolecule.getAtoms(); i++) {
				// changed from from handling below; TLS 9.Nov.2015
				if (tempMolecule.isAtomStereoCenter(i) && tempMolecule.getStereoBond(i)==-1) {
					int stereoBond = tempMolecule.getAtomPreferredStereoBond(i);
					if (stereoBond != -1) {
						molecule.setBondType(stereoBond, Molecule.cBondTypeUp);
						if (molecule.getBondAtom(1, stereoBond) == i) {
							int connAtom = molecule.getBondAtom(0, stereoBond);
							molecule.setBondAtom(0, stereoBond, i);
							molecule.setBondAtom(1, stereoBond, connAtom);
						}
					// To me it seems that we have to add all stereo centers into AND group 0.	TLS 9.Nov.2015
					molecule.setAtomESR(i, esrType, 0);
					}
				}
			}
		}
	}

	public static void addMissingChirality(StereoMolecule molecule) {
		addMissingChirality(molecule, Molecule.cESRTypeAnd);
	}

	private static void changeAtomForStereo(StereoMolecule molecule, int iAtom) {
		// need to force the change to an excotic atom to check if it is really chiral
		molecule.setAtomicNo(iAtom, xAtomicNumber);
	}

	private static void changeAtom(StereoMolecule molecule, int iAtom) {
		molecule.setAtomCustomLabel(iAtom, molecule.getAtomLabel(iAtom)+"*");
		if (molecule.getAtomicNo(iAtom)==1) {
			molecule.setAtomicNo(iAtom, xAtomicNumber);
		} else {
			// we can not use X because we would have problems with valencies if it is
			// expanded hydrogens or not
			// we can not only use a custom label because it does not cound for the canonisation
			molecule.setAtomMass( iAtom,molecule.getAtomMass(iAtom)+5);
		}
	}


	private static void makeRacemic(StereoMolecule molecule) {
		// if we don't calculate this we have 2 epimers
		molecule.ensureHelperArrays(Molecule.cHelperParities);
		// we need to make one group "AND" for chiral (to force to racemic, this means diastereotopic and not enantiotopic)
		for (int i=0; i<molecule.getAllAtoms(); i++) {
			if (molecule.getAtomParity(i)!=Molecule.cAtomParityNone) {
				molecule.setAtomESR(i, Molecule.cESRTypeAnd, 0);	// changed to group 0; TLS 9.Nov.2015
			}
		}
	}

	public static String test(StereoMolecule molecule) {		// changed to use StringBuilder; TLS 9.Nov.2015
		String[] ids=getAtomIds(molecule);
		StringBuilder sb = new StringBuilder();
		for (int i=0; i<ids.length; i++)
			sb.append(Integer.toString(i)).append(" - ").append(ids[i]).append("\n");
		return sb.toString();
	}
	
	/**
	 * In order to debug we could number the group of diastereotopic atoms
	 * 
	 * @param molecule
	 */
	public static void markDiastereotopicAtoms(StereoMolecule molecule) {		// changed from markDiastereo(); TLS 9.Nov.2015
		String[] ids = getAtomIds(molecule);
		SortedStringList analyzed = new SortedStringList();
		int group=0;
		for (String id:ids) {
			System.out.println(id+" - "+group);
			if (!analyzed.contains(id)) {
				analyzed.addString(id);
				for (int iAtom=0; iAtom<ids.length; iAtom++) {
					if (id.equals(ids[iAtom])) {
						molecule.setAtomCustomLabel(iAtom, Integer.toString(group));
					}
				}
				group++;
			}
		}
	}
}
