/**
   * Construct new <code>Genotype</code> object from population in specified run XML data.
   *
   * @param runXml XML data from which to construct initial population
   * @return new <code>Genotype</code>
   * @throws Exception
   */
  private Genotype genotypeFromRunXml(InputStream runXml, Configuration config) throws Exception {
    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    Document doc = builder.parse(runXml, baseDir.getAbsolutePath());
    Node runNode = doc.getFirstChild();
    if (XmlPersistableRun.RUN_TAG.equals(runNode.getNodeName()) == false)
      throw new IllegalArgumentException("node name not " + XmlPersistableRun.RUN_TAG);

    // loop through list to find last generation
    Node generationNode = null;
    for (int i = 0; i < runNode.getChildNodes().getLength(); ++i) {
      Node nextNode = runNode.getChildNodes().item(i);
      if (Generation.GENERATION_TAG.equals(nextNode.getNodeName())) generationNode = nextNode;
    }

    return genotypeFromXml(generationNode, config, this);
  }
  /**
   * Create a <code>Genotype</code> from XML.
   *
   * @param generationNode XML
   * @param config
   * @param db persistence repository from which to read chromosomes
   * @return new genotype
   * @throws Exception
   */
  private static Genotype genotypeFromXml(Node generationNode, Configuration config, Persistence db)
      throws Exception {
    if (Generation.GENERATION_TAG.equals(generationNode.getNodeName()) == false)
      throw new IllegalArgumentException("node name not " + Generation.GENERATION_TAG);

    // loop through list to find chromosomes
    ArrayList chroms = new ArrayList();
    for (int generationChildIdx = 0;
        generationChildIdx < generationNode.getChildNodes().getLength();
        ++generationChildIdx) {
      Node specieNode = generationNode.getChildNodes().item(generationChildIdx);
      if (Specie.SPECIE_TAG.equals(specieNode.getNodeName())) {
        // for each specie ...
        NamedNodeMap specieAttrs = specieNode.getAttributes();
        if (specieAttrs == null) throw new IllegalArgumentException("missing specie attributes");

        // ... and loop through chromosomes
        for (int specieChildIdx = 0;
            specieChildIdx < specieNode.getChildNodes().getLength();
            ++specieChildIdx) {
          Node chromNode = specieNode.getChildNodes().item(specieChildIdx);
          if (Specie.CHROMOSOME_TAG.equals(chromNode.getNodeName())) {
            NamedNodeMap chromAttrs = chromNode.getAttributes();
            if (chromAttrs == null)
              throw new IllegalArgumentException("missing chromosome attributes");
            Node chromIdNode = chromAttrs.getNamedItem(Specie.ID_TAG);
            if (chromIdNode == null) throw new IllegalArgumentException("missing chromosome id");

            // get id and load chromosome from persistence (skip if representative since its
            // already been added
            Long chromId = Long.valueOf(chromIdNode.getNodeValue());
            Chromosome c = db.loadChromosome(chromId.toString(), config);
            if (c != null) chroms.add(c);
            else logger.warn("chromosome in run not found: " + chromId);
          }
        }
      }
    }

    // don't return empty genotype
    if (chroms.size() <= 0) return null;

    // sort in order of id so that they will be added in proper order (age)
    Collections.sort(chroms);
    return new Genotype(config, chroms);
  }