/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/08/16, 20:41
!  AUTHOR(S): KOGA, Junichiro
!  File : ConstraintsPanel.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.plugins.projectmanipulator.phase.preparationpanel.atomconfig;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;

import org.apache.log4j.Logger;

import ciss.phase_viewer.atomcoord.AtomCoords;
import ciss.phase_viewer.common.StringConstants;
import ciss.phase_viewer.mainpanel.InternalFrameChase;
import ciss.phase_viewer.plugins.projectmanipulator.phase.PhaseInputItems;
import ciss.phase_viewer.primitiveguis.ChoicePanelPhase;
import ciss.phase_viewer.primitiveguis.InputPanelPhase;
import ciss.phase_viewer.projectbrowser.ProjectInfo;
import ciss.phase_viewer.projectbrowser.ProjectManipulator;

/**
 * 
 * @author KOGA, Junichiro
 */
public class ConstraintsPanel extends ProjectManipulator {
    private Logger logger = Logger.getLogger(ConstraintsPanel.class.getName());

    public ConstraintsPanel(ProjectInfo projectInfo) {
        super(projectInfo);
    }

    public void init() {
        add(new ConstraintsSubPanel(projectInfo));
    }

    public void initializeProject() {
    }

    class ConstraintsSubPanel extends PhaseInputItems {

        private JButton addButton;
        private JButton deleteButton;
        private JTabbedPane tabbedPane;

        private JComboBox combotype;

        ConstraintsSubPanel(ProjectInfo pinfo) {
            super(pinfo);
        }

        private void generateConstraintsEditorGUI(String constraintType) {
            int id = tabbedPane.getTabCount() + 1;
            ConstraintsEditor editor = ConstraintsEditor.getEditor(
                    constraintType, projectInfo, id);
            if (editor == null)
                return;
            tabbedPane.addTab(editor.getNameOfConstraint(), editor);
            tabbedPane.setToolTipTextAt(tabbedPane.getTabCount() - 1,
                    editor.getDescriptionOfConstraint());
        }

        public void createGUI() {
            // setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
            setLayout(new BorderLayout());
            tabbedPane = new JTabbedPane();
            tabbedPane.setPreferredSize(new Dimension(500, 330));
            tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
            JPanel p = new JPanel();
            p.add(tabbedPane);

            combotype = new JComboBox(ConstraintsEditor.CONSTRAINTS);

            addButton = new JButton("add new constraint");
            deleteButton = new JButton("remove selected constraint");
            JPanel pbtn = new JPanel();
            pbtn.setLayout(new BoxLayout(pbtn, BoxLayout.X_AXIS));
            pbtn.add(combotype);
            pbtn.add(addButton);
            pbtn.add(deleteButton);

            add(p, BorderLayout.CENTER);
            add(pbtn, BorderLayout.SOUTH);

            int i = 0;
            while (true) {
                i++;
                String typ = inputInterface
                        .getInputInterfacePrimitiveEntry(
                                "structure.constrainable" + String.valueOf(i)
                                        + ".type").getValue();
                if (typ.trim().length() != 0)
                    generateConstraintsEditorGUI(typ);
                else
                    break;
            }

            addButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    generateConstraintsEditorGUI(combotype.getSelectedItem()
                            .toString());
                }
            });

            deleteButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    int rem = tabbedPane.getSelectedIndex();
                    ConstraintsEditor editor = ((ConstraintsEditor) tabbedPane
                            .getSelectedComponent());
                    editor.removeTheCurrentConstraint();
                    tabbedPane.remove(editor);
                    for (int i = 0; i < tabbedPane.getTabCount(); i++)
                        ((ConstraintsEditor) tabbedPane.getComponentAt(i))
                                .setID(i + 1);
                }
            });
        }
    }
}

abstract class ConstraintsEditor extends PhaseInputItems {
    public static String BOND_LENGTH = "bond_length";
    public static String BOND_ANGLE = "bond_angle";
    public static String DIHEDRAL_ANGLE = "dihedral_angle";
    public static String BOND_LENGTH_DIFF = "bond_length_diff";
    public static String BOND_LENGTH_SUM = "bond_length_sum";
    public static String BOND_ANGLE_DIFF = "bond_angle_diff";
    public static String DISTANCE_FROM_POS = "distance_from_pos";
    public static String PLANE = "plane";
    public static String CENTER_OF_MASS = "center_of_mass";
    public static String COORDINATION_NUMBER = "coordination_number";

    public static String[] CONSTRAINTS = new String[] { BOND_LENGTH,
            BOND_ANGLE, DIHEDRAL_ANGLE, BOND_LENGTH_DIFF, BOND_LENGTH_SUM,
            BOND_ANGLE_DIFF, DISTANCE_FROM_POS, PLANE, CENTER_OF_MASS,
            COORDINATION_NUMBER };

    protected String constrainable = "structure.constrainable";

    protected int ID;

    protected static Logger logger = Logger.getLogger(ConstraintsEditor.class
            .getName());

    protected String getConstrainableTag() {
        return constrainable + String.valueOf(ID) + ".";
    }

    public ConstraintsEditor(ProjectInfo projectInfo, int ID, String typ) {
        super();
        super.projectInfo = projectInfo;
        super.inputInterface = projectInfo.getInputInterface();
        this.ID = ID;
        this.constraintType = typ;

        createGUI();

    }

    public void setID(int newID) {
        inputInterface.selectRoot();
        inputInterface.selectBlock("structure");
        inputInterface.getBlock("constrainable" + String.valueOf(this.ID))
                .setName("constrainable" + String.valueOf(newID));
        inputInterface.selectRoot();
        this.ID = newID;
        removeAll();
        genGUI();
    }

    private void genGUI() {
        JPanel pall = new JPanel();
        pall.setLayout(new BoxLayout(pall, BoxLayout.X_AXIS));

        InputPanelPhase ippsilent = new InputPanelPhase(
                new String[] { getConstrainableTag() + "type" },
                inputInterface, "", InputPanelPhase.NONE, 1, this);
        if (!inputInterface
                .getInputInterfacePrimitiveEntry(getConstrainableTag() + "type")
                .getValue().equals(constraintType))
            ippsilent.getTextField().setText(constraintType);

        JPanel passc = new JPanel();
        passc.setLayout(new BoxLayout(passc, BoxLayout.Y_AXIS));
        String associatedTag = getConstrainableTag() + "atom";
        for (int i = 0; i < getNumAssociatedAtoms(); i++) {
            String[] atomxx = new String[] { associatedTag
                    + String.valueOf(i + 1) };
            InputPanelPhase ipp = new InputPanelPhase(atomxx, inputInterface,
                    "atom" + String.valueOf(i + 1), InputPanelPhase.NONE, 5,
                    this);
            JPanel pp = new JPanel();
            pp.add(ipp);
            passc.add(pp);
        }
        JPanel ptmp = new JPanel();
        ptmp.add(passc);
        JScrollPane scrpane = new JScrollPane(ptmp);
        scrpane.setPreferredSize(new Dimension(150, 150));
        pall.add(scrpane);

        ChoicePanelPhase cppmob = new ChoicePanelPhase(
                new String[] { getConstrainableTag() + "mobile" },
                inputInterface, "mobile", ON_OFF, ON_OFF_DUPLI, this);
        ChoicePanelPhase cppmon = new ChoicePanelPhase(
                new String[] { getConstrainableTag() + "monitor" },
                inputInterface, "monitor", ON_OFF, ON_OFF_DUPLI, this);
        JPanel psw = new JPanel();
        // psw.setPreferredSize(new Dimension(0,0));
        psw.setLayout(new BoxLayout(psw, BoxLayout.Y_AXIS));
        JPanel ptmp0 = new JPanel();
        ptmp0.add(cppmob);
        JPanel ptmp1 = new JPanel();
        ptmp1.add(cppmon);
        psw.add(ptmp0);
        psw.add(ptmp1);
        JPanel pp = new JPanel();
        pp.add(psw);
        pall.add(pp);

        JButton pmisc = new JButton("other settings");
        pmisc.setEnabled(false);
        psw.add(pmisc);
        if (requiresSubGUI()) {
            pmisc.setEnabled(true);
            pmisc.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    generateSubGUI();
                }
            });
        }

        JPanel preac = new JPanel();

        preac.setLayout(new BoxLayout(preac, BoxLayout.Y_AXIS));

        ChoicePanelPhase ippreac = new ChoicePanelPhase(
                new String[] { getConstrainableTag()
                        + "reaction_coordinate.sw_reaction_coordinate" },
                inputInterface, "reaction coordinate", ON_OFF, ON_OFF_DUPLI,
                this);
        ippreac.setPreferredSize(new Dimension(
                ippreac.getPreferredSize().width + 60, ippreac
                        .getPreferredSize().height));
        JPanel prea = new JPanel();
        prea.add(ippreac);
        preac.add(prea);

        JPanel pval = new JPanel();
        pval.setLayout(new BoxLayout(pval, BoxLayout.Y_AXIS));
        JPanel pinit = new JPanel();
        pinit.setLayout(new BoxLayout(pinit, BoxLayout.X_AXIS));
        JPanel pfinal = new JPanel();
        pfinal.setLayout(new BoxLayout(pfinal, BoxLayout.X_AXIS));
        JPanel pincre = new JPanel();
        pincre.setLayout(new BoxLayout(pincre, BoxLayout.X_AXIS));
        InputPanelPhase ippini = new InputPanelPhase(
                new String[] { getConstrainableTag()
                        + "reaction_coordinate.init_value" }, inputInterface,
                "initial value", getUnit(), 7, this);
        InputPanelPhase ippfinal = new InputPanelPhase(
                new String[] { getConstrainableTag()
                        + "reaction_coordinate.final_value" }, inputInterface,
                "final value", getUnit(), 7, this);
        InputPanelPhase ippincre = new InputPanelPhase(
                new String[] { getConstrainableTag()
                        + "reaction_coordinate.increment" }, inputInterface,
                "increment", getUnit(), 7, this);
        pinit.add(ippini);
        pfinal.add(ippfinal);
        pincre.add(ippincre);
        pval.add(pinit);
        pval.add(pfinal);
        pval.add(pincre);

        preac.add(pval);

        pall.add(preac);

        ippreac.registerDisabableGUI(new int[] { 0, 2 }, ippini);
        ippreac.registerDisabableGUI(new int[] { 0, 2 }, ippfinal);
        ippreac.registerDisabableGUI(new int[] { 0, 2 }, ippincre);

        add(pall);

    }

    public void createGUI() {
        genGUI();
    }

    protected abstract String getNameOfConstraint();

    protected abstract String getDescriptionOfConstraint();

    protected abstract int getNumAssociatedAtoms();

    protected abstract int getNdim();

    protected abstract void generateSubGUI();

    protected abstract boolean requiresSubGUI();

    protected abstract int getUnit();

    protected String constraintType;

    public static ConstraintsEditor getEditor(String editor, ProjectInfo pinfo,
            int ID) {
        ConstraintsEditor edi = null;
        if (editor.equals(BOND_LENGTH))
            edi = new BondLengthEditor(pinfo, ID, editor);
        if (editor.equals(BOND_LENGTH_DIFF))
            edi = new BondLengthDiffEditor(pinfo, ID, editor);
        if (editor.equals(BOND_LENGTH_SUM))
            edi = new BondLengthSumEditor(pinfo, ID, editor);
        if (editor.equals(BOND_ANGLE))
            edi = new BondAngleEditor(pinfo, ID, editor);
        if (editor.equals(BOND_ANGLE_DIFF))
            edi = new BondAngleDiffEditor(pinfo, ID, editor);
        if (editor.equals(DIHEDRAL_ANGLE))
            edi = new DihedralAngleEditor(pinfo, ID, editor);
        if (editor.equals(PLANE))
            edi = new PlaneEditor(pinfo, ID, editor);
        if (editor.equals(DISTANCE_FROM_POS))
            edi = new DistanceFromPosEditor(pinfo, ID, editor);
        if (editor.equals(COORDINATION_NUMBER))
            edi = new CoordinationNumberEditor(pinfo, ID, editor);
        if (editor.equals(CENTER_OF_MASS))
            edi = new CenterOfMassEditor(pinfo, ID, editor);

        if (edi == null)
            logger.error("undefined constraint : " + editor);

        return edi;
    }

    public void removeTheCurrentConstraint() {
        inputInterface.selectRoot();
        inputInterface.selectBlock("structure");
        inputInterface.removeBlock("constrainable" + String.valueOf(ID));
        inputInterface.selectRoot();
    }
}

class BondLengthEditor extends ConstraintsEditor {
    public BondLengthEditor(ProjectInfo pinfo, int ID, String typ) {
        super(pinfo, ID, typ);
    }

    protected boolean requiresSubGUI() {
        return false;
    }

    protected String getNameOfConstraint() {
        return "bond length";
    }

    protected String getDescriptionOfConstraint() {
        return "constrain the bond-length defined by two atoms.";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 2;
    }

    protected void generateSubGUI() {
    }

    protected int getUnit() {
        return InputPanelPhase.LENGTH;
    }

}

class BondLengthDiffEditor extends ConstraintsEditor {
    public BondLengthDiffEditor(ProjectInfo pinfo, int ID, String typ) {
        super(pinfo, ID, typ);
    }

    protected boolean requiresSubGUI() {
        return false;
    }

    protected String getNameOfConstraint() {
        return "bond length diff";
    }

    protected String getDescriptionOfConstraint() {
        return "constrain the difference of the bond-length.";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 4;
    }

    protected void generateSubGUI() {
    }

    protected int getUnit() {
        return InputPanelPhase.LENGTH;
    }
}

class BondLengthSumEditor extends ConstraintsEditor {
    public BondLengthSumEditor(ProjectInfo pinfo, int ID, String typ) {
        super(pinfo, ID, typ);
    }

    protected boolean requiresSubGUI() {
        return false;
    }

    protected String getNameOfConstraint() {
        return "bond length sum";
    }

    protected String getDescriptionOfConstraint() {
        return "constrain the sum of the bond-length.";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 4;
    }

    protected void generateSubGUI() {
    }

    protected int getUnit() {
        return InputPanelPhase.LENGTH;
    }
}

class DistanceFromPosEditor extends ConstraintsEditor {
    public DistanceFromPosEditor(ProjectInfo pinfo, int ID, String typ) {
        super(pinfo, ID, typ);
    }

    protected boolean requiresSubGUI() {
        return true;
    }

    protected String getNameOfConstraint() {
        return "distance from pos";
    }

    protected String getDescriptionOfConstraint() {
        return "constrain the distance between the specified atom and position in space.";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 1;
    }

    protected void generateSubGUI() {
        new poseditor();
    }

    class poseditor extends InternalFrameChase {
        public poseditor() {
            super("set norm", true, true, true, true, new Dimension(350, 150));

            getContentPane().setLayout(
                    new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

            getContentPane().add(new posedi(projectInfo));

            JButton btndismiss = new JButton("dismiss");
            btndismiss.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    dispose();
                }
            });
            JPanel pbtn = new JPanel();
            pbtn.add(btndismiss);
            getContentPane().add(pbtn);
        }

        class posedi extends PhaseInputItems {
            posedi(ProjectInfo pinfo) {
                super(pinfo);
            }

            public void createGUI() {
                setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
                String[] posx = new String[] { getConstrainableTag()
                        + "distance_from_pos.posx" };
                String[] posy = new String[] { getConstrainableTag()
                        + "distance_from_pos.posy" };
                String[] posz = new String[] { getConstrainableTag()
                        + "distance_from_pos.posz" };

                InputPanelPhase ippposx = new InputPanelPhase(posx,
                        inputInterface, "posx", InputPanelPhase.NONE, 7, this);
                JPanel px = new JPanel();
                px.add(ippposx);
                add(px);

                InputPanelPhase ippposy = new InputPanelPhase(posy,
                        inputInterface, "posy", InputPanelPhase.NONE, 7, this);
                JPanel py = new JPanel();
                py.add(ippposy);
                add(py);

                InputPanelPhase ippposz = new InputPanelPhase(posz,
                        inputInterface, "posz", InputPanelPhase.NONE, 7, this);
                JPanel pz = new JPanel();
                pz.add(ippposz);
                add(pz);
            }

        }
    }

    protected int getUnit() {
        return InputPanelPhase.LENGTH;
    }
}

class BondAngleEditor extends ConstraintsEditor {

    public BondAngleEditor(ProjectInfo projectInfo, int ID, String typ) {
        super(projectInfo, ID, typ);
    }

    protected int getUnit() {
        return InputPanelPhase.ANGLE;
    }

    protected String getDescriptionOfConstraint() {
        return "constrain the bond-angle among three atoms";
    }

    protected String getNameOfConstraint() {
        return "bond angle";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 3;
    }

    protected void generateSubGUI() {
    }

    protected boolean requiresSubGUI() {
        return false;
    }

}

class BondAngleDiffEditor extends ConstraintsEditor {

    public BondAngleDiffEditor(ProjectInfo projectInfo, int ID, String typ) {
        super(projectInfo, ID, typ);
    }

    protected int getUnit() {
        return InputPanelPhase.ANGLE;
    }

    protected String getDescriptionOfConstraint() {
        return "constrain the difference of two bond-angle.";
    }

    protected String getNameOfConstraint() {
        return "bond angle diff";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 6;
    }

    protected void generateSubGUI() {
    }

    protected boolean requiresSubGUI() {
        return false;
    }

}

class DihedralAngleEditor extends ConstraintsEditor {

    public DihedralAngleEditor(ProjectInfo projectInfo, int ID, String typ) {
        super(projectInfo, ID, typ);
    }

    protected int getUnit() {
        return InputPanelPhase.ANGLE;
    }

    protected String getDescriptionOfConstraint() {
        return "constrain the dihedral-angle defined from four atoms";
    }

    protected String getNameOfConstraint() {
        return "dihedral angle";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 4;
    }

    protected void generateSubGUI() {
    }

    protected boolean requiresSubGUI() {
        return false;
    }

}

class PlaneEditor extends ConstraintsEditor {
    public PlaneEditor(ProjectInfo pinfo, int ID, String typ) {
        super(pinfo, ID, typ);
    }

    protected void generateSubGUI() {
        new peditor();
    }

    class peditor extends InternalFrameChase {
        public peditor() {
            super("set norm", true, true, true, true, new Dimension(350, 150));

            getContentPane().setLayout(
                    new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

            getContentPane().add(new pedi(projectInfo));

            JButton btndismiss = new JButton("dismiss");
            btndismiss.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    dispose();
                }
            });
            JPanel pbtn = new JPanel();
            pbtn.add(btndismiss);
            getContentPane().add(pbtn);
        }

        class pedi extends PhaseInputItems {
            pedi(ProjectInfo pinfo) {
                super(pinfo);
            }

            public void createGUI() {
                setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
                String[] nx = new String[] { getConstrainableTag()
                        + "plane.normx" };
                String[] ny = new String[] { getConstrainableTag()
                        + "plane.normy" };
                String[] nz = new String[] { getConstrainableTag()
                        + "plane.normz" };

                InputPanelPhase ippnx = new InputPanelPhase(nx, inputInterface,
                        "normx", InputPanelPhase.NONE, 7, this);
                JPanel px = new JPanel();
                px.add(ippnx);
                add(px);

                InputPanelPhase ippny = new InputPanelPhase(ny, inputInterface,
                        "normy", InputPanelPhase.NONE, 7, this);
                JPanel py = new JPanel();
                py.add(ippny);
                add(py);

                InputPanelPhase ippnz = new InputPanelPhase(nz, inputInterface,
                        "normz", InputPanelPhase.NONE, 7, this);
                JPanel pz = new JPanel();
                pz.add(ippnz);
                add(pz);
            }

        }
    }

    protected String getDescriptionOfConstraint() {
        return "constrain an atom within the specified plane";
    }

    protected String getNameOfConstraint() {
        return "plane";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 1;
    }

    protected int getUnit() {
        return InputPanelPhase.LENGTH;
    }

    protected boolean requiresSubGUI() {
        return true;
    }

}

class CoordinationNumberEditor extends ConstraintsEditor {
    public CoordinationNumberEditor(ProjectInfo pinfo, int ID, String typ) {
        super(pinfo, ID, typ);
    }

    protected void generateSubGUI() {
        new ceditor();
    }

    class ceditor extends InternalFrameChase {
        public ceditor() {
            super("set norm", true, true, true, true, new Dimension(350, 150));

            getContentPane().setLayout(
                    new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

            getContentPane().add(new cedi(projectInfo));

            JButton btndismiss = new JButton("dismiss");
            btndismiss.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    dispose();
                }
            });
            JPanel pbtn = new JPanel();
            pbtn.add(btndismiss);
            getContentPane().add(pbtn);
        }

        class cedi extends PhaseInputItems {
            cedi(ProjectInfo pinfo) {
                super(pinfo);
            }

            public void createGUI() {
                setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
                String[] kappa = new String[] { getConstrainableTag()
                        + "coordination_number.kappa" };
                String[] rc = new String[] { getConstrainableTag()
                        + "coordination_number.rcut" };

                InputPanelPhase ippkappa = new InputPanelPhase(kappa,
                        inputInterface, "kappa", InputPanelPhase.NONE, 7, this);
                JPanel pkappa = new JPanel();
                pkappa.add(ippkappa);
                add(pkappa);

                InputPanelPhase ipprc = new InputPanelPhase(rc, inputInterface,
                        "rcut", InputPanelPhase.LENGTH, 7, this);
                JPanel prc = new JPanel();
                prc.add(ipprc);
                add(prc);
            }

        }
    }

    protected String getDescriptionOfConstraint() {
        return "constrain the coordination number of the specified atom";
    }

    protected String getNameOfConstraint() {
        return "coordination number";
    }

    protected int getNdim() {
        return 1;
    }

    protected int getNumAssociatedAtoms() {
        return 1;
    }

    protected int getUnit() {
        return InputPanelPhase.NONE;
    }

    protected boolean requiresSubGUI() {
        return true;
    }

}

class CenterOfMassEditor extends ConstraintsEditor {
    public CenterOfMassEditor(ProjectInfo pinfo, int ID, String typ) {
        super(pinfo, ID, typ);
    }

    protected void generateSubGUI() {
        new comeditor();
    }

    class comeditor extends InternalFrameChase {
        public comeditor() {
            super("set norm", true, true, true, true, new Dimension(350, 150));

            getContentPane().setLayout(
                    new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));

            getContentPane().add(new comedi(projectInfo));

            JButton btndismiss = new JButton("dismiss");
            btndismiss.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    dispose();
                }
            });
            JPanel pbtn = new JPanel();
            pbtn.add(btndismiss);
            getContentPane().add(pbtn);
        }

        class comedi extends PhaseInputItems {
            comedi(ProjectInfo pinfo) {
                super(pinfo);
            }

            public void createGUI() {
                setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
                String[] directionx = new String[] { getConstrainableTag()
                        + "center_of_mass.directionx" };
                String[] directiony = new String[] { getConstrainableTag()
                        + "center_of_mass.directiony" };
                String[] directionz = new String[] { getConstrainableTag()
                        + "center_of_mass.directionz" };

                InputPanelPhase ippdirectionx = new InputPanelPhase(directionx,
                        inputInterface, "directionx", InputPanelPhase.NONE, 7,
                        this);
                JPanel px = new JPanel();
                px.add(ippdirectionx);
                add(px);

                InputPanelPhase ippdirectiony = new InputPanelPhase(directiony,
                        inputInterface, "directiony", InputPanelPhase.NONE, 7,
                        this);
                JPanel py = new JPanel();
                py.add(ippdirectiony);
                add(py);

                InputPanelPhase ippdirectionz = new InputPanelPhase(directionz,
                        inputInterface, "directionz", InputPanelPhase.NONE, 7,
                        this);
                JPanel pz = new JPanel();
                pz.add(ippdirectionz);
                add(pz);
            }

        }

    }

    protected String getDescriptionOfConstraint() {
        return "constrain the center of mass of the specified group of atoms.";
    }

    protected String getNameOfConstraint() {
        return "center of mass";
    }

    protected int getNdim() {
        return 3;
    }

    protected int getNumAssociatedAtoms() {
        AtomCoords coords = new AtomCoords();
        coords.inputInterface2AtomCoords(inputInterface,
                StringConstants.phase_atom_tag);
        return coords.getNumAt();
    }

    protected int getUnit() {
        return InputPanelPhase.LENGTH;
    }

    protected boolean requiresSubGUI() {
        return true;
    }

}
