class SimulationState { // Holds state of program
  SimulationSetup sim; // Holds file information
  SphereList spheres;
  int foldStep = -1; // The current bond

  SimulationState() {
    this.spheres = new SphereList();
    this.sim = new SimulationSetup();
  }
  
  SimulationState(SimulationState other) {
    this.sim = other.sim.cloneFunction();
    this.spheres = other.getSpheres().cloneFunction();
    this.foldStep = other.foldStep;
  }

  SimulationState(SimulationSetup _sim, SphereList _spheres, int _foldStep) {
    this.sim = _sim.cloneFunction();
    this.spheres = _spheres.cloneFunction();
    this.foldStep = _foldStep;
  }

  SimulationState cloneFunction() {
    SimulationState result = new SimulationState(sim, spheres, foldStep);
    return result;
  }

  SphereList getSpheres() { 
    return spheres;
  }

  String[] writeSaveFile() {
    if (debugPrints) { println("Starting writeSaveFile..."); }
    SimulationSetup s = sim;
    
    ArrayList<String> saveLines = new ArrayList<String>();
    
    String line = "sequences=";
    for (int i = 0; i < s.sequences.length; ++i) {
      line += s.sequences[i];
      if ((i+1) < s.sequences.length) {
        line += "; ";
      }
    }
    saveLines.add(line);
    
    line = "starts=";
    for (int i = 0; i < s.starts.length; ++i) {
      line += s.starts[i];
      if ((i+1) < s.starts.length) {
        line += ",";
      }
    }
    saveLines.add(line);
    
    line = "positions="; // Writes a semicolon separated string of coordinates
    for (int i = 0; i < spheres.size(); ++i) {
      line += (int)(spheres.get(i).x) + "," + (int)(spheres.get(i).y) + "," + (int)(spheres.get(i).z);
      if ((i+1) < spheres.size()) {
        line += "; ";
      }
    }
    saveLines.add(line);
    
    saveLines.add("radius=" + ff.radius);
    saveLines.add("backbone_distance=" + ff.backboneDist);
    saveLines.add("basepair_distance=" + ff.bpDist);
    //saveLines.add("padding=" + ds.padding);
    saveLines.add("color_scheme=" + ds.colorMode);
    
    saveLines.add("outline=" + ds.outlineMode);
    saveLines.add("movement=" + simulationMode);
    saveLines.add("simulation_type=" + simulateAllMode);
    saveLines.add("labels=" + ds.labelMode);
    saveLines.add("rigid_helices=" + rigidHelices);
    saveLines.add("rigid_hairpins=" + rigidHairpins);
    saveLines.add("rigid_loops=" + rigidLoops);
    
    line = "relaxed_ids=";
    for (Iterator<Integer> it = spheres.relaxedIds.keySet().iterator(); it.hasNext(); ) {
      line += it.next() + " ";
    }
    saveLines.add(line.trim());

    line = "display_order=";
    for (int i = 0; i < spheres.displayOrder.size(); ++i) {
      line += spheres.displayOrder.get(i);
      if ( i+1 < spheres.displayOrder.size() ) {
        line += ",";
      }
    }
    saveLines.add(line);
    
    line = "pair_table=";
    for (short i = 0; i < s.pairTable.length; ++i) {
      line += s.pairTable[i];
      if ( i+1 < s.pairTable.length ) {
        line += ",";
      }
    }
    saveLines.add(line);
    
    line = "non_canonicals=";
    for (Map.Entry<String, String> nc : s.nonCanonicals.entrySet()) {
      line += nc.getKey() + " " + nc.getValue() + ", ";
    }
    line = line.substring(0, line.length() - 2);
    saveLines.add(line);
    
    line = "base_colors=";
    for (int i = 0, l = spheres.size(); i < l; i++) {
      line += spheres.get(i).colorNum;
      if ( i+1 < l ) {
        line += ",";
      }
    }
    saveLines.add(line);
    
    if (debugPrints) { println("Finished writeSaveFile!"); }
    return saveLines.toArray(new String[saveLines.size()]);
  }

 /*
 Base number: index n
 Base (A, C, G, T, U, X)
 Index n-1
 Index n+1
 Number of the base to which n is paired. No pairing is indicated by 0 (zero).
 Natural numbering. RNAstructure ignores the actual value given in natural numbering, so it is easiest to repeat n here.

*HOW TO FORMAT A CT OR BPSEQ FILE*
 Lines preceded by \"#\" and empty lines are ignored.
 If you have multiple strands in a ct file, the first line before the data should be a header line,
 or the file should be formatted such that the line for each residue that begins a new strand has 0 as its 3rd column.
*/

  /** Output of secondary structure in mfold "CT" (i.e. connectivity) file format */
  String[] writeCtFile() {
    if (debugPrints) { println("Starting writeCtFile..."); }
    SimulationSetup s = sim;    
    ArrayList<String> saveLines = new ArrayList<String>();    
    String concatSeq = "";
    for (int i = 0; i < s.sequences.length; ++i) {
      concatSeq += s.sequences[i];
    }
 //   saveLines.add(line);
    String DELI = " ";
    String headerLine = "" + concatSeq.length() + "  " + s.starts.length;
    for (int i = 0; i < s.starts.length; ++i) {
      headerLine += (s.starts[i] + 1);
      if ((i+1) < s.starts.length) {
        headerLine += " ";
      }
    }
    saveLines.add(headerLine);

    for (short i = 0; i < s.pairTable.length; ++i) {
      int firstId = i;
      if ((i > 0) && (s.seqIds[i] != s.seqIds[i-1])) {
       firstId = 0; // must be beggining of new strand
      }
      int bp = s.pairTable[i] + 1; // pairTable[i] is -1 if unpaired, so bp == 0 if unpaired
      String line = "" + (i+1) + DELI + concatSeq.charAt(i) + DELI + firstId + DELI + (i+2) + DELI + bp + DELI + (i+1);
      saveLines.add(line);
    }
    if (debugPrints) { println("Finished writeCtFile!"); }
    return saveLines.toArray(new String[saveLines.size()]);
  }
}