// Path: src/feast/nexus/CharactersBlock.java
// public class CharactersBlock extends NexusBlock {
// 
//     private final Alignment alignment;
// 
//     public CharactersBlock(Alignment alignment) {
//         this.alignment = alignment;
//     }
//     
//     @Override
//     public String getBlockName() {
//         return "characters";
//     }
// 
//     @Override
//     public List<String> getBlockLines() {
//         List<String> lines = new ArrayList<>();
//         
//         lines.add("dimensions nchar=" + alignment.getSiteCount());
//         
//         // Assumes BEAST sequence data types map directly
//         // onto nexus data types.  No doubt a bad idea in general...
//         lines.add("format datatype=" + alignment.getDataType().getTypeDescription());
//         
//         StringBuilder matrix = new StringBuilder("matrix ");
//         for (int i=0; i<alignment.getTaxonCount(); i++) {
//             try {
//                 String taxonName = alignment.getTaxaNames().get(i);
//                 String sequence = alignment.getDataType()
//                         .encodingToString(alignment.getCounts().get(i));
//                 matrix.append("\n\t\t").append(taxonName).append(" ").append(sequence);
//             } catch (Exception ex) {
//                 Logger.getLogger(CharactersBlock.class.getName()).log(Level.SEVERE, null, ex);
//             }
//         }
//         lines.add(matrix.toString());
//         
//         return lines;
//     }
//     
// }
// 
// Path: src/feast/nexus/NexusBuilder.java
// public class NexusBuilder {
//     List<NexusBlock> blocks;
// 
//     /**
//      * Create new NexusBuilder, optionally specifying blocks to include.
//      * 
//      * @param blockArray vararg of NexusBlock objects
//      */
//     public NexusBuilder(NexusBlock ... blockArray) {
//         blocks = new ArrayList<>(Arrays.asList(blockArray));
//     }
//     /**
//      * Append a block to the Nexus file.
//      * 
//      * @param block block to include
//      * @return the NexusBuilder (for method chaining)
//      */
//     public NexusBuilder append(NexusBlock block) {
//         blocks.add(block);
//         
//         return this;
//     }
// 
//     /**
//      * Write the assembled Nexus file to pstream.
//      * 
//      * @param pstream PrintStream to send Nexus to
//      */
//     public void write(PrintStream pstream) {
//         pstream.println("#NEXUS");
//         
//         for (NexusBlock block : blocks)
//             pstream.print("\n" + block);
//     }
// }
// 
// Path: src/feast/nexus/TaxaBlock.java
// public class TaxaBlock extends NexusBlock {
//     
//     private final TaxonSet taxonSet;
// 
//     public TaxaBlock(TaxonSet taxonSet) {
//         this.taxonSet = taxonSet;
//     }
// 
//     @Override
//     public String getBlockName() {
//         return "taxa";
//     }
// 
//     @Override
//     public List<String> getBlockLines() {
//         List<String> lines = new ArrayList<>();
// 
//         int ntax=taxonSet.getTaxonCount();
// 
//         lines.add("dimensions ntax=" + ntax);
// 
//         StringBuilder taxLabels = new StringBuilder("taxlabels");
//         for (int i=0; i<ntax; i++)
//             taxLabels.append(" ").append(taxonSet.getTaxonId(i));
// 
//         lines.add(taxLabels.toString());
//         
//         return lines;
//     }
//     
// }


import beast.core.Description;
import beast.core.Input;
import beast.evolution.alignment.Alignment;
import beast.evolution.alignment.Sequence;
import beast.evolution.alignment.TaxonSet;
import beast.evolution.datatype.DataType;
import beast.evolution.sitemodel.SiteModel;
import beast.evolution.substitutionmodel.JukesCantor;
import beast.evolution.substitutionmodel.SubstitutionModel;
import beast.evolution.tree.Node;
import beast.evolution.tree.Tree;
import beast.util.BEASTClassLoader;
import beast.util.PackageManager;
import beast.util.Randomizer;
import feast.nexus.CharactersBlock;
import feast.nexus.NexusBuilder;
import feast.nexus.TaxaBlock;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
    private Tree tree;
    private SiteModel siteModel;
    private int seqLength;
    private DataType dataType;

    private String ancestralSeqStr;

    public SimulatedAlignment() {
        sequenceInput.setRule(Input.Validate.OPTIONAL);
    }

    @Override
    public void initAndValidate() {

        tree = treeInput.get();
        siteModel = siteModelInput.get();
        seqLength = sequenceLengthInput.get();

        sequences.clear();

        grabDataType();

        simulate();

        super.initAndValidate();

        // Write simulated alignment to disk if required
        if (outputFileNameInput.get() != null) {
            try (PrintStream pstream = new PrintStream(outputFileNameInput.get())) {
                NexusBuilder nb = new NexusBuilder();
// Path: src/feast/nexus/CharactersBlock.java
// public class CharactersBlock extends NexusBlock {
// 
//     private final Alignment alignment;
// 
//     public CharactersBlock(Alignment alignment) {
//         this.alignment = alignment;
//     }
//     
//     @Override
//     public String getBlockName() {
//         return "characters";
//     }
// 
//     @Override
//     public List<String> getBlockLines() {
//         List<String> lines = new ArrayList<>();
//         
//         lines.add("dimensions nchar=" + alignment.getSiteCount());
//         
//         // Assumes BEAST sequence data types map directly
//         // onto nexus data types.  No doubt a bad idea in general...
//         lines.add("format datatype=" + alignment.getDataType().getTypeDescription());
//         
//         StringBuilder matrix = new StringBuilder("matrix ");
//         for (int i=0; i<alignment.getTaxonCount(); i++) {
//             try {
//                 String taxonName = alignment.getTaxaNames().get(i);
//                 String sequence = alignment.getDataType()
//                         .encodingToString(alignment.getCounts().get(i));
//                 matrix.append("\n\t\t").append(taxonName).append(" ").append(sequence);
//             } catch (Exception ex) {
//                 Logger.getLogger(CharactersBlock.class.getName()).log(Level.SEVERE, null, ex);
//             }
//         }
//         lines.add(matrix.toString());
//         
//         return lines;
//     }
//     
// }
// 
// Path: src/feast/nexus/NexusBuilder.java
// public class NexusBuilder {
//     List<NexusBlock> blocks;
// 
//     /**
//      * Create new NexusBuilder, optionally specifying blocks to include.
//      * 
//      * @param blockArray vararg of NexusBlock objects
//      */
//     public NexusBuilder(NexusBlock ... blockArray) {
//         blocks = new ArrayList<>(Arrays.asList(blockArray));
//     }
//     /**
//      * Append a block to the Nexus file.
//      * 
//      * @param block block to include
//      * @return the NexusBuilder (for method chaining)
//      */
//     public NexusBuilder append(NexusBlock block) {
//         blocks.add(block);
//         
//         return this;
//     }
// 
//     /**
//      * Write the assembled Nexus file to pstream.
//      * 
//      * @param pstream PrintStream to send Nexus to
//      */
//     public void write(PrintStream pstream) {
//         pstream.println("#NEXUS");
//         
//         for (NexusBlock block : blocks)
//             pstream.print("\n" + block);
//     }
// }
// 
// Path: src/feast/nexus/TaxaBlock.java
// public class TaxaBlock extends NexusBlock {
//     
//     private final TaxonSet taxonSet;
// 
//     public TaxaBlock(TaxonSet taxonSet) {
//         this.taxonSet = taxonSet;
//     }
// 
//     @Override
//     public String getBlockName() {
//         return "taxa";
//     }
// 
//     @Override
//     public List<String> getBlockLines() {
//         List<String> lines = new ArrayList<>();
// 
//         int ntax=taxonSet.getTaxonCount();
// 
//         lines.add("dimensions ntax=" + ntax);
// 
//         StringBuilder taxLabels = new StringBuilder("taxlabels");
//         for (int i=0; i<ntax; i++)
//             taxLabels.append(" ").append(taxonSet.getTaxonId(i));
// 
//         lines.add(taxLabels.toString());
//         
//         return lines;
//     }
//     
// }


// Path: src/feast/simulation/SimulatedAlignment.java
import beast.core.Description;
import beast.core.Input;
import beast.evolution.alignment.Alignment;
import beast.evolution.alignment.Sequence;
import beast.evolution.alignment.TaxonSet;
import beast.evolution.datatype.DataType;
import beast.evolution.sitemodel.SiteModel;
import beast.evolution.substitutionmodel.JukesCantor;
import beast.evolution.substitutionmodel.SubstitutionModel;
import beast.evolution.tree.Node;
import beast.evolution.tree.Tree;
import beast.util.BEASTClassLoader;
import beast.util.PackageManager;
import beast.util.Randomizer;
import feast.nexus.CharactersBlock;
import feast.nexus.NexusBuilder;
import feast.nexus.TaxaBlock;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

    private Tree tree;
    private SiteModel siteModel;
    private int seqLength;
    private DataType dataType;

    private String ancestralSeqStr;

    public SimulatedAlignment() {
        sequenceInput.setRule(Input.Validate.OPTIONAL);
    }

    @Override
    public void initAndValidate() {

        tree = treeInput.get();
        siteModel = siteModelInput.get();
        seqLength = sequenceLengthInput.get();

        sequences.clear();

        grabDataType();

        simulate();

        super.initAndValidate();

        // Write simulated alignment to disk if required
        if (outputFileNameInput.get() != null) {
            try (PrintStream pstream = new PrintStream(outputFileNameInput.get())) {
                NexusBuilder nb = new NexusBuilder();
                nb.append(new TaxaBlock(new TaxonSet(this)));