--- /dev/null
+package ext.edu.ucsf.rbvi.strucviz2;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import ext.edu.ucsf.rbvi.strucviz2.StructureManager.ModelType;
+
+/**
+ * This class provides the implementation for the ChimeraModel, ChimeraChain, and ChimeraResidue
+ * objects
+ *
+ * @author scooter
+ *
+ */
+public class ChimeraModel implements ChimeraStructuralObject {
+
+ private String name; // The name of this model
+ private ModelType type; // The type of the model
+ private int modelNumber; // The model number
+ private int subModelNumber; // The sub-model number
+
+ private Color modelColor = null; // The color of this model (from Chimera)
+ private Object userData = null; // User data associated with this model
+ private boolean selected = false; // The selected state of this model
+
+ private TreeMap<String, ChimeraChain> chainMap; // The list of chains
+ // private TreeMap<String, ChimeraResidue> residueMap; // The list of residues
+ private HashSet<ChimeraResidue> funcResidues; // List of functional residues
+
+ /**
+ * Constructor to create a model
+ *
+ * @param name
+ * the name of this model
+ * @param color
+ * the model Color
+ * @param modelNumber
+ * the model number
+ * @param subModelNumber
+ * the sub-model number
+ */
+ public ChimeraModel(String name, ModelType type, int modelNumber, int subModelNumber) {
+ this.name = name;
+ this.type = type;
+ this.modelNumber = modelNumber;
+ this.subModelNumber = subModelNumber;
+
+ this.chainMap = new TreeMap<String, ChimeraChain>();
+ this.funcResidues = new HashSet<ChimeraResidue>();
+ }
+
+ /**
+ * Constructor to create a model from the Chimera input line
+ *
+ * @param inputLine
+ * Chimera input line from which to construct this model
+ */
+ // TODO: [Optional] How to distinguish between PDB and MODBASE?
+ // invoked when listing models: listm type molecule; lists level molecule
+ // line = model id #0 type Molecule name 1ert
+ public ChimeraModel(String inputLine) {
+ this.name = ChimUtils.parseModelName(inputLine);
+ // TODO: [Optional] Write a separate method to get model type
+ if (name.startsWith("smiles")) {
+ this.type = ModelType.SMILES;
+ } else {
+ this.type = ModelType.PDB_MODEL;
+ }
+ this.modelNumber = ChimUtils.parseModelNumber(inputLine)[0];
+ this.subModelNumber = ChimUtils.parseModelNumber(inputLine)[1];
+
+ this.chainMap = new TreeMap<String, ChimeraChain>();
+ this.funcResidues = new HashSet<ChimeraResidue>();
+ }
+
+ /**
+ * Add a residue to this model
+ *
+ * @param residue
+ * to add to the model
+ */
+ public void addResidue(ChimeraResidue residue) {
+ residue.setChimeraModel(this);
+ // residueMap.put(residue.getIndex(), residue);
+ String chainId = residue.getChainId();
+ if (chainId != null) {
+ addResidue(chainId, residue);
+ } else {
+ addResidue("_", residue);
+ }
+ // Put it in our map so that we can return it in order
+ // residueMap.put(residue.getIndex(), residue);
+ }
+
+ /**
+ * Add a residue to a chain in this model. If the chain associated with chainId doesn't exist,
+ * it will be created.
+ *
+ * @param chainId
+ * to add the residue to
+ * @param residue
+ * to add to the chain
+ */
+ public void addResidue(String chainId, ChimeraResidue residue) {
+ ChimeraChain chain = null;
+ if (!chainMap.containsKey(chainId)) {
+ chain = new ChimeraChain(this.modelNumber, this.subModelNumber, chainId);
+ chain.setChimeraModel(this);
+ chainMap.put(chainId, chain);
+ } else {
+ chain = chainMap.get(chainId);
+ }
+ chain.addResidue(residue);
+ }
+
+ /**
+ * Get the ChimeraModel (required for ChimeraStructuralObject interface)
+ *
+ * @return ChimeraModel
+ */
+ public ChimeraModel getChimeraModel() {
+ return this;
+ }
+
+ /**
+ * Get the model color of this model
+ *
+ * @return model color of this model
+ */
+ public Color getModelColor() {
+ return this.modelColor;
+ }
+
+ /**
+ * Set the color of this model
+ *
+ * @param color
+ * Color of this model
+ */
+ public void setModelColor(Color color) {
+ this.modelColor = color;
+ }
+
+ /**
+ * Return the name of this model
+ *
+ * @return model name
+ */
+ public String getModelName() {
+ return name;
+ }
+
+ /**
+ * Set the name of this model
+ *
+ * @param name
+ * model name
+ */
+ public void setModelName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Get the model number of this model
+ *
+ * @return integer model number
+ */
+ public int getModelNumber() {
+ return modelNumber;
+ }
+
+ /**
+ * Set the model number of this model
+ *
+ * @param modelNumber
+ * integer model number
+ */
+ public void setModelNumber(int modelNumber) {
+ this.modelNumber = modelNumber;
+ }
+
+ /**
+ * Get the sub-model number of this model
+ *
+ * @return integer sub-model number
+ */
+ public int getSubModelNumber() {
+ return subModelNumber;
+ }
+
+ /**
+ * Set the sub-model number of this model
+ *
+ * @param subModelNumber
+ * integer model number
+ */
+ public void setSubModelNumber(int subModelNumber) {
+ this.subModelNumber = subModelNumber;
+ }
+
+ public ModelType getModelType() {
+ return type;
+ }
+
+ public void setModelType(ModelType type) {
+ this.type = type;
+ }
+
+ public HashSet<ChimeraResidue> getFuncResidues() {
+ return funcResidues;
+ }
+
+ public void setFuncResidues(List<String> residues) {
+ for (String residue : residues) {
+ for (ChimeraChain chain : getChains()) {
+ if (residue.indexOf("-") > 0) {
+ funcResidues.addAll(chain.getResidueRange(residue));
+ } else {
+ funcResidues.add(chain.getResidue(residue));
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the user data for this model
+ *
+ * @return user data
+ */
+ public Object getUserData() {
+ return userData;
+ }
+
+ /**
+ * Set the user data for this model
+ *
+ * @param data
+ * user data to associate with this model
+ */
+ public void setUserData(Object data) {
+ this.userData = data;
+ }
+
+ /**
+ * Return the selected state of this model
+ *
+ * @return the selected state
+ */
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ * Set the selected state of this model
+ *
+ * @param selected
+ * a boolean to set the selected state to
+ */
+ public void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+
+ /**
+ * Return the chains in this model as a List
+ *
+ * @return the chains in this model as a list
+ */
+ public List<ChimeraStructuralObject> getChildren() {
+ return new ArrayList<ChimeraStructuralObject>(chainMap.values());
+ }
+
+ /**
+ * Return the chains in this model as a colleciton
+ *
+ * @return the chains in this model
+ */
+ public Collection<ChimeraChain> getChains() {
+ return chainMap.values();
+ }
+
+ /**
+ * Get the number of chains in this model
+ *
+ * @return integer chain count
+ */
+ public int getChainCount() {
+ return chainMap.size();
+ }
+
+ /**
+ * Get the list of chain names associated with this model
+ *
+ * @return return the list of chain names for this model
+ */
+ public Collection<String> getChainNames() {
+ return chainMap.keySet();
+ }
+
+ /**
+ * Get the residues associated with this model
+ *
+ * @return the list of residues in this model
+ */
+ public Collection<ChimeraResidue> getResidues() {
+ Collection<ChimeraResidue> residues = new ArrayList<ChimeraResidue>();
+ for (ChimeraChain chain : getChains()) {
+ residues.addAll(chain.getResidues());
+ }
+ return residues;
+ }
+
+ /**
+ * Get the number of residues in this model
+ *
+ * @return integer residues count
+ */
+ public int getResidueCount() {
+ int count = 0;
+ for (ChimeraChain chain : getChains()) {
+ count += chain.getResidueCount();
+ }
+ return count;
+ }
+
+ /**
+ * Get a specific chain from the model
+ *
+ * @param chain
+ * the ID of the chain to return
+ * @return ChimeraChain associated with the chain
+ */
+ public ChimeraChain getChain(String chain) {
+ if (chainMap.containsKey(chain)) {
+ return chainMap.get(chain);
+ }
+ return null;
+ }
+
+ /**
+ * Return a specific residue based on its index
+ *
+ * @param index
+ * of the residue to return
+ * @return the residue associated with that index
+ */
+ public ChimeraResidue getResidue(String chainId, String index) {
+ if (chainMap.containsKey(chainId)) {
+ return chainMap.get(chainId).getResidue(index);
+ }
+ return null;
+ }
+
+ /**
+ * Checks if this model has selected children.
+ */
+ public boolean hasSelectedChildren() {
+ if (selected) {
+ return true;
+ } else {
+ for (ChimeraChain chain : getChains()) {
+ if (chain.hasSelectedChildren()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the list of selected residues
+ *
+ * @return all selected residues
+ */
+ public List<ChimeraResidue> getSelectedResidues() {
+ List<ChimeraResidue> residueList = new ArrayList<ChimeraResidue>();
+ for (ChimeraChain chain : getChains()) {
+ if (selected) {
+ residueList.addAll(chain.getSelectedResidues());
+ } else {
+ residueList.addAll(getResidues());
+ }
+ }
+ return residueList;
+ }
+
+
+ /**
+ * Return the Chimera specification for this model.
+ */
+ public String toSpec() {
+ if (subModelNumber == 0)
+ return ("#" + modelNumber);
+ return ("#" + modelNumber + "." + subModelNumber);
+ }
+
+ /**
+ * Return a string representation for the model. Shorten if longer than 100 characters.
+ */
+ public String toString() {
+ String modelName = "";
+ // TODO: [Optional] Change cutoff for shortening model names in the structure naviagator dialog
+ if (getChainCount() > 0) {
+ modelName = "Model " + toSpec() + " " + name + " (" + getChainCount() + " chains, "
+ + getResidueCount() + " residues)";
+ } else if (getResidueCount() > 0) {
+ modelName = "Model " + toSpec() + " " + name + " (" + getResidueCount() + " residues)";
+ } else {
+ modelName = "Model " + toSpec() + " " + name + "";
+ }
+
+ Set<String> networkNames = new HashSet<String>();
+ Set<String> nodeNames = new HashSet<String>();
+ Set<String> edgeNames = new HashSet<String>();
+
+ String cytoName = " [";
+ if (networkNames.size() > 0) {
+ if (networkNames.size() == 1) {
+ cytoName += "Network {";
+ } else if (networkNames.size() > 1) {
+ cytoName += "Networks {";
+ }
+ for (String cName : networkNames) {
+ cytoName += cName + ",";
+ }
+ cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, ";
+ }
+ if (nodeNames.size() > 0) {
+ if (nodeNames.size() == 1) {
+ cytoName += "Node {";
+ } else if (nodeNames.size() > 1) {
+ cytoName += "Nodes {";
+ }
+ for (String cName : nodeNames) {
+ cytoName += cName + ",";
+ }
+ cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, ";
+ }
+ if (edgeNames.size() > 0) {
+ if (edgeNames.size() == 1) {
+ cytoName += "Edge {";
+ } else if (edgeNames.size() > 1) {
+ cytoName += "Edges {";
+ }
+ for (String cName : edgeNames) {
+ cytoName += cName + ",";
+ }
+ cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, ";
+ }
+ if (cytoName.endsWith(", ")) {
+ cytoName = cytoName.substring(0, cytoName.length() - 2);
+ }
+ cytoName += "]";
+ String nodeName = modelName + cytoName;
+ if (nodeName.length() > 100) {
+ nodeName = nodeName.substring(0, 100) + "...";
+ }
+ return nodeName;
+ }
+}