/* Copyright (C) 2007  Ola Spjuth <ospjuth@users.sf.net>
 *
 * Contact: cdk-devel@lists.sourceforge.net
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 * All we ask is that proper credit is given for our work, which includes
 * - but is not limited to - adding the above copyright notice to the beginning
 * of your source code files, and to any copyright notice that you may distribute
 * with programs based on this work.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.openscience.cdk.libio.cml;

import java.util.Iterator;

import nu.xom.Attribute;

import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.libio.md.ChargeGroup;
import org.openscience.cdk.libio.md.MDMolecule;
import org.openscience.cdk.libio.md.Residue;
import org.xmlcml.cml.element.CMLAtom;
import org.xmlcml.cml.element.CMLAtomArray;
import org.xmlcml.cml.element.CMLMolecule;
import org.xmlcml.cml.element.CMLScalar;

/**
 * Customize persistence of MDMolecule by adding support for residues and charge groups.
 *
 * @author ola
 * @cdk.module libiomd
 * @cdk.githash
 *
 * @cdk.set       libio-cml-customizers
 */
public class MDMoleculeCustomizer implements ICMLCustomizer {

    /**
     * No customization for bonds.
     */
    @Override
    public void customize(IBond bond, Object nodeToAdd) throws Exception {
        // nothing to do
    }

    /**
     * Customize Atom.
     */
    @Override
    public void customize(IAtom atom, Object nodeToAdd) throws Exception {
        // nothing to do
    }

    /**
     * Customize Molecule.
     */
    @Override
    public void customize(IAtomContainer molecule, Object nodeToAdd) throws Exception {
        if (!(nodeToAdd instanceof CMLMolecule)) throw new CDKException("NodeToAdd must be of type nu.xom.Element!");

        //The nodeToAdd
        CMLMolecule molToCustomize = (CMLMolecule) nodeToAdd;

        if ((molecule instanceof MDMolecule)) {
            MDMolecule mdmol = (MDMolecule) molecule;
            molToCustomize.setConvention("md:mdMolecule");
            molToCustomize.addNamespaceDeclaration("md", "http://www.bioclipse.net/mdmolecule/");

            //Residues
            if (mdmol.getResidues().size() > 0) {
                Iterator it = mdmol.getResidues().iterator();
                while (it.hasNext()) {
                    Residue residue = (Residue) it.next();
                    int number = residue.getNumber();

                    CMLMolecule resMol = new CMLMolecule();
                    resMol.setDictRef("md:residue");
                    resMol.setTitle(residue.getName());

                    //Append resNo
                    CMLScalar residueNumber = new CMLScalar(number);
                    residueNumber.addAttribute(new Attribute("dictRef", "md:resNumber"));
                    resMol.addScalar(residueNumber);

                    // prefix for residue atom id
                    String rprefix = "r" + number;
                    //Append atoms
                    CMLAtomArray ar = new CMLAtomArray();
                    for (int i = 0; i < residue.getAtomCount(); i++) {
                        CMLAtom cmlAtom = new CMLAtom();
                        //            			System.out.println("atom ID: "+ residue.getAtom(i).getID());
                        //            			cmlAtom.addAttribute(new Attribute("ref", residue.getAtom(i).getID()));
                        // the next thing is better, but throws an exception
                        //
                        // setRef to keep consistent usage
                        // setId to satisfy Jumbo 54. need for all atoms to have id
                        cmlAtom.setRef(residue.getAtom(i).getID());
                        cmlAtom.setId(rprefix + "_" + residue.getAtom(i).getID());
                        ar.addAtom(cmlAtom);
                    }
                    resMol.addAtomArray(ar);

                    molToCustomize.appendChild(resMol);
                }
            }

            //Chargegroups
            if (mdmol.getChargeGroups().size() > 0) {
                Iterator it = mdmol.getChargeGroups().iterator();
                while (it.hasNext()) {
                    ChargeGroup chargeGroup = (ChargeGroup) it.next();
                    int number = chargeGroup.getNumber();

                    //FIXME: persist the ChargeGroup
                    CMLMolecule cgMol = new CMLMolecule();
                    cgMol.setDictRef("md:chargeGroup");
                    // etc: add name, refs to atoms etc

                    //Append chgrpNo
                    CMLScalar cgNo = new CMLScalar(number);
                    cgNo.addAttribute(new Attribute("dictRef", "md:cgNumber"));
                    cgMol.appendChild(cgNo);

                    // prefix for residue atom id
                    String cprefix = "cg" + number;

                    //Append atoms from chargeGroup as it is an AC
                    CMLAtomArray ar = new CMLAtomArray();
                    for (int i = 0; i < chargeGroup.getAtomCount(); i++) {
                        CMLAtom cmlAtom = new CMLAtom();
                        // setRef to keep consistent usage
                        // setId to satisfy Jumbo 5.4 need for all atoms to have id
                        cmlAtom.setRef(chargeGroup.getAtom(i).getID());
                        cmlAtom.setId(cprefix + "_" + chargeGroup.getAtom(i).getID());

                        //Append switching atom?
                        if (chargeGroup.getAtom(i).equals(chargeGroup.getSwitchingAtom())) {
                            CMLScalar scalar = new CMLScalar();
                            scalar.setDictRef("md:switchingAtom");
                            cmlAtom.addScalar(scalar);
                        }
                        ar.addAtom(cmlAtom);
                    }
                    cgMol.addAtomArray(ar);

                    molToCustomize.appendChild(cgMol);
                }
            }
        }
    }

}
