/**
 *    Copyright 2011 Peter Murray-Rust et. al.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

// /*======AUTOGENERATED FROM SCHEMA; DO NOT EDIT BELOW THIS LINE ======*/
package org.xmlcml.cml.element;

import nu.xom.Element;
import nu.xom.ParentNode;

import org.xmlcml.cml.base.CMLElement;
import org.xmlcml.euclid.Util;

/** .
*
*
* \n EXPERIMENTAL. join will normally use atomRefs2 to identify 2 R atoms\n (i.e. elementType='R' that should be joined. The atoms to which the R atoms\n are attached are then joined by a new bond and the R groups are then deleted. It is currently \nan error if these atoms already have a connecting bond.
*
* user-modifiable class autogenerated from schema if no class exists
* use as a shell which can be edited
* the autogeneration software will not overwrite an existing class file

*/
public class CMLJoin extends org.xmlcml.cml.element.AbstractJoin {

	/** namespaced element name.*/
	public final static String NS = C_E+TAG;

    /** relationship of molecule in moleculeRefs2.
     *
     */
    public enum MoleculePointer {
        /** child.*/
        CHILD,
        /** next.*/
        NEXT,
        /** parent.*/
        PARENT,
        /** previous.*/
        PREVIOUS;
    }

    /** convenience*/
    public final static String CHILD_S = MoleculePointer.CHILD.toString();
    /** convenience*/
    public final static String PARENT_S = MoleculePointer.PARENT.toString();
    /** convenience*/
    public final static String PREVIOUS_S = MoleculePointer.PREVIOUS.toString();
    /** convenience*/
    public final static String NEXT_S = MoleculePointer.NEXT.toString();

    /** R elementType.
     */
    public final static String R_GROUP = "R";

    /** label to define torsion.
     */
    public final static String TORSION_END = C_A+"torsionEnd";
    /** find labels with torsions.
     */
    public final static String TORSION_END_QUERY =
        CMLLabel.NS+"[@dictRef='"+TORSION_END+"']";

    /** convention attribute indicating that join contains fragments.
     */
    public final static String FRAGMENT_CONTAINER = "fragmentContainer";

    /** must give simple documentation.
    *

    */
    public CMLJoin() {
    }
    /** must give simple documentation.
    *
    * @param old CMLJoin to copy

    */

    public CMLJoin(CMLJoin old) {
        super((org.xmlcml.cml.element.AbstractJoin) old);
    }

    /** copy node .
    *
    * @return Node
    */
    public Element copy() {
        return new CMLJoin(this);
    }
    /** create new instance in context of parent, overridable by subclasses.
    *
    * @param parent parent of element to be constructed (ignored by default)
    * @return CMLJoin
    */
    public CMLElement makeElementInContext(Element parent) {
        return new CMLJoin();
    }

    /**
     * will process repeat attribute.
     *
     * @param parent
     *            element
     */
    public void finishMakingElement(Element parent) {
        super.finishMakingElement(parent);
//        RepeatAttribute.process(this);
    }



    private String getId(CMLMolecule molecule) {
        String ref = molecule.getRef();
        String id = molecule.getId();
        return ref+S_UNDER+id;
    }

//    /** create atomRefs2 from moleculeRefs2 and atomRefs2.
//     *
//     * @param parent
//     * @param previousFragments
//     * @param nextFragments
//     */
//    private void processMoleculeRefs2AndAtomRefs2(
//            CMLFragment previousFragment, CMLFragment nextFragment) {
////      <join id="j1" order="1" moleculeRefs2="PARENT NEXT" atomRefs2="r1 r1">
////      <length>1.4</length>
////      <angle id="l2.1.1" atomRefs3="a2 r1 r1">115</angle>
////  </join>
////  <fragment>
////      <molecule ref="g:po" id="m3" />
////  </fragment>
//        String[] moleculeRefs2 = this.getMoleculeRefs2();
//        if (moleculeRefs2 == null) {
//            throw new RuntimeException("No moleculeRefs2 on join");
//        }
//        if (CMLJoin.PARENT_S.equals(moleculeRefs2[0])) {
//            previousFragment = (CMLFragment) this.getParent();
//            if (previousFragment == null) {
//            	throw new RuntimeException("No parent fragment");
//            }
//        } else if (CMLJoin.PREVIOUS_S.equals(moleculeRefs2[0])) {
//        }
//        CMLMolecule previousMolecule = FragmentTool.getOrCreateTool(previousFragment).getMolecule();
//        if (previousMolecule == null) {
//        	throw new RuntimeException("Cannot find previous molecule to join");
//        }
//        CMLMolecule nextMolecule = null;
//        if (CMLJoin.NEXT_S.equals(moleculeRefs2[1])) {
//            nextMolecule = FragmentTool.getOrCreateTool(nextFragment).getMolecule();
//        }
//        if (nextMolecule == null) {
//        	throw new RuntimeException("Cannot find next molecule to join");
//        }
//        processMoleculeRefs2AndAtomRefs2(previousMolecule, nextMolecule);
//    }

    /** creates atomRefs2 to join previous/parent molecule to next/child.
     *
     * @param previousMolecule
     * @param nextMolecule
     */
    public void processMoleculeRefs2AndAtomRefs2(
        CMLMolecule previousMolecule, CMLMolecule nextMolecule) {
//      <join id="j1" order="1" moleculeRefs2="PARENT NEXT" atomRefs2="r1 r1">
//      <length>1.4</length>
//      <angle id="l2.1.1" atomRefs3="a2 r1 r1">115</angle>
//  </join>
//  <fragment>
//      <molecule ref="g:po" id="m3" />
//  </fragment>
       	if (previousMolecule == null) {
    		throw new RuntimeException("null PREVIOUS, check syntax");
    	}
       	if (nextMolecule == null) {
    		throw new RuntimeException("null NEXT, check syntax");
    	}
        String[] atomRefs2 = this.getAtomRefs2();
        if (atomRefs2 == null) {
        	throw new RuntimeException("No atomrefs2 on Join");
        }
        this.setAtomRefs2(new String[]{
                getId(previousMolecule)+S_UNDER+atomRefs2[0],
                getId(nextMolecule)+S_UNDER+atomRefs2[1]});
        this.setMoleculeRefs2(new String[]{
                getId(previousMolecule),
                getId(nextMolecule)});
    }

    /** get string.
     * 
     * @return string
     */
    public String getString() {
    	String s = S_EMPTY;
    	String id = this.getId();
    	if (id != null) {
    		s += id+S_SPACE;
    	}
    	String[] moleculeRefs2 = this.getMoleculeRefs2();
    	if (moleculeRefs2 != null) {
    		s += Util.concatenate(moleculeRefs2, S_SPACE)+S_SEMICOLON;
    	}
    	String[] atomRefs2 = this.getAtomRefs2();
    	if (atomRefs2 != null) {
    		s += Util.concatenate(atomRefs2, S_SPACE)+S_SEMICOLON;
    	}
    	return s;
    }
    
    
    /**
     * gets the element that is previous or parent to the join, depending
     * on moleculeRefs2
     * 
     * @return
     */
	public Element getParentOrPrevious() {
		
		if (getMoleculeRefs2Attribute().getValue().equals(PARENT_S + " " + CHILD_S)) {
			return (Element) getParent();
		}
		else if (getMoleculeRefs2Attribute().getValue().equals(PREVIOUS_S + " " + NEXT_S)) {
			ParentNode parent = getParent();
			int position = parent.indexOf(this);
			if (position == 0) return null;
			return (Element) parent.getChild(position - 1);
		}
		return null;
	}
	
	
	/**
	 * gets the element that is next or child to the join, depending
	 * on moleculeRefs2
	 * 
	 * @return
	 */
	public CMLElement getChildOrNext() {

		if (getMoleculeRefs2Attribute().getValue().equals(PARENT_S + " " + CHILD_S)) {
			if (getChildCount() > 0) return (CMLElement) getChild(0);
		}
		else if (getMoleculeRefs2Attribute().getValue().equals(PREVIOUS_S + " " + NEXT_S)) {
			ParentNode parent = getParent();
			int position = getParent().indexOf(this);
			if (position == parent.getChildCount() - 1) return null;
			return (CMLElement) parent.getChild(position + 1);
		}
		
		return null;
	}
    
}
