/**
   * Copy from the copy method in StructUtil. Did not want to drag that code in. maybe this actually
   * should go to struct.
   *
   * @param from
   * @param to
   * @param excludes
   * @return
   * @throws Exception
   */
  public static <T extends struct> T xcopy(struct from, T to, String... excludes) throws Exception {
    Arrays.sort(excludes);
    for (Field f : from.fields()) {
      if (Arrays.binarySearch(excludes, f.getName()) >= 0) continue;

      Object o = f.get(from);
      if (o == null) continue;

      Field tof = to.getField(f.getName());
      if (tof != null)
        try {
          tof.set(to, Converter.cnv(tof.getGenericType(), o));
        } catch (Exception e) {
          System.out.println(
              "Failed to convert "
                  + f.getName()
                  + " from "
                  + from.getClass()
                  + " to "
                  + to.getClass()
                  + " value "
                  + o
                  + " exception "
                  + e);
        }
    }

    return to;
  }
  /**
   * This function returns a map whose entries hold the coordinates of the sequence as keys and the
   * coordinates of the target sequences as values.</br> If a coordinate in sequence corresponds to
   * a gap in another sequence, then -1 is assigned to that position.</br> For example suppose we
   * have the sequences:</br> seq1: AAT-GCT-TCG</br> seq2: G--C-CTCT-C</br> seq3: A-T--GT-AG-</br>
   * Then, if we wish to find the mapping of seq1's coordinates to seq2's coordinates, this will
   * give us: 0 -> 0, 1 -> -1, 2 -> -1, 3 -> -1, 4 -> 2, 5 -> 3, 6 -> 5, 7 -> -1, 8 -> 6.</br> Also,
   * if we wish to find the mapping of seq1's coordinates to seq2's and seq3's coordinates, this
   * will give us: 0 -> {0, 0}, 1 -> {-1, -1}, 2 -> {-1, 1}, 3 -> {-1, -1}, 4 -> {2, 2}, 5 -> {3,
   * 3}, 6 -> {5, 4}, 7 -> {-1, 5}, 8 -> {6, -1}.
   *
   * @param <T> This could be either the serial number of the sequence (valid range: [0,
   *     sequences.length-1]) or the sequence names
   * @param <E>
   * @param seqID The sequence ID (either serial number or name) which we wish to map</br> Note that
   *     the valid range of serial numbers is [0, sequences.length-1]
   * @param targetSeqIDs The (target) sequences IDs (either serial numbers or names)
   * @return A map whose keys are the sequence coordinates and values the corresponding coordinates
   *     of the target sequences
   * @throws IllegalArgumentException
   * @see GappedAlignmentString
   */
  public <T extends Object> Map mapSeqCoords2SeqsCoords(
      T generic_seqID, Vector<T> generic_targetSeqIDs)
      throws IllegalArgumentException, IndexOutOfBoundsException {
    GappedAlignmentString gas_seq;
    GappedAlignmentString[] gas_targetSeqs;

    String[] speciesNames = species();

    // Check if generic_seqID is mistakenly included in the generic_targetSeqIDs set
    if (generic_targetSeqIDs.contains(generic_seqID)) generic_targetSeqIDs.remove(generic_seqID);

    if (generic_targetSeqIDs.size() + 1 > speciesNames.length)
      throw new IndexOutOfBoundsException("You entered more sequences than are in the file.");

    Map map = new HashMap();
    // Check whether sequence IDs are inputed as serial numbers or as names
    String seqsClassName = generic_seqID.getClass().getSimpleName();

    // if( generic_seqID.getClass() instanceof java.lang.Integer )
    // System.out.println("XAXA");

    if (seqsClassName.equals("Integer")) {
      Integer seqID = (Integer) generic_seqID;
      Integer[] seqIDs = generic_targetSeqIDs.toArray(new Integer[generic_targetSeqIDs.size()]);

      if ((StatUtil.findMax(seqIDs).getFirst() > speciesNames.length - 1)
          || (StatUtil.findMin(seqIDs).getFirst() < 0))
        throw new IndexOutOfBoundsException(
            "The sequence IDs (aka, serial numbers have to lie inside"
                + " the range 0 to speciesNames.length -1");

      gas_seq = getGappedAlignment(speciesNames[seqID]);
      gas_targetSeqs = new GappedAlignmentString[seqIDs.length];
      for (int i = 0; i < seqIDs.length; i++)
        gas_targetSeqs[i] = getGappedAlignment(speciesNames[seqIDs[i]]);
    } else if (seqsClassName.equals("String")) {
      String seqID = (String) generic_seqID;
      String[] seqIDs = generic_targetSeqIDs.toArray(new String[generic_targetSeqIDs.size()]);

      gas_seq = getGappedAlignment(seqID);
      gas_targetSeqs = new GappedAlignmentString[seqIDs.length];
      for (int i = 0; i < seqIDs.length; i++) gas_targetSeqs[i] = getGappedAlignment(seqIDs[i]);
    } else {
      throw new IllegalArgumentException("Sequence IDs should be either of type Integer or String");
    }

    // Pairwise Alignment
    if (gas_targetSeqs.length == 1) {
      map = doMapSeq2Seq(gas_seq, gas_targetSeqs);
    }
    // Multiple Alignment
    else {
      map = doMapSeq2Seqs(gas_seq, gas_targetSeqs);
    }

    return map;
  } // end of mapSeqCoords2SeqsCoords method