import javax.swing.*;
import pal.tree.*;
import java.util.*;
import java.io.*;
import java.net.*;
import pal.alignment.*;
import pal.datatype.*;
import pal.distance.*;
import pal.io.*;
import pal.substmodel.*;
import pal.misc.*;
import pal.eval.*;
import vanilla.cui.*;




public class PALTreeOut
	{


	/**
	*Given a String that's a file name, read the file into an array of strings.
	*@param fname a file name to read
	*@return an array of Strings of the lines of the file
	*/
	public static String[] readFileLines(String fname)
		{
		return TreeUtils.readStringFromFile(fname);
		}	

	/**
	*Given an alignment file, read it, build a tree, and print the newick string to stdout
	*@param alignmentFileName a file to read the alignment from and build a tree from and print its newick string to STDOUT to
	*/
	public static void printTreeF84(String alignmentFileName)
		{
		//get the alignment
		PushbackReader in;
		in = FileIO.openIn(alignmentFileName);
		Alignment raw = null;
		try
			{
			raw = new pal.alignment.ReadAlignment(in,true);
			}
		catch(Exception e)
			{
			System.out.println("EXCEPTION caught : ");
			e.printStackTrace();
			System.exit(1);
			}
		FileIO.close(in);


		// Set options
		Options options = new Options();
		options.setMLDIST();
		options.dtyp = raw.getDataType().getTypeID();
		if (options.dtyp == 1)
			{
			options.smodel = AminoAcidModel.getSuitableModelID(raw.getFrequency());
			}
		options.optModel=true;
		raw.setDataType( DataTypeUtils.getInstance(options.dtyp) );			
		SitePattern sitePattern = new SitePattern(raw);
		DistanceMatrix mat = null;			
		//System.out.println();
		//System.out.println("Computing distance matrix");

		SubstitutionModel model = null;
		if (options.useModel)
			{
			// create model
			double[] modelFreq;
			if (options.userFreqs)
				{
				modelFreq = options.freq;
				}
			else
				{
				//raw.estimateFrequencies();
				//modelFreq = raw.frequency;
				
				raw.setFrequency(AlignmentUtils.estimateFrequencies(raw));
				modelFreq = raw.getFrequency();
				}
			RateMatrix rmat = RateMatrixUtils.getInstance(options.dtyp, options.smodel,
			options.params, modelFreq);
			RateDistribution rdist = null;
			if (options.rmodel == 0) rdist = new UniformRate();
			if (options.rmodel == 1) rdist = new GammaRates(options.alphaCats, options.alpha);	
			if (options.rmodel == 2) rdist = new InvariableSites(options.fracInv);	
			model = new SubstitutionModel(rmat, rdist);	
			
			// estimate model parameters
			if (options.optModel && model.getNumParameters() > 0)
				{
				//System.out.println("Optimising model parameters");
				ModelParameters mp = new ModelParameters(sitePattern, model);
				mp.estimate();
				mp = null;
				}
			mat = new AlignmentDistanceMatrix(sitePattern, model);
			}
		else
			{
			mat = new AlignmentDistanceMatrix(sitePattern);
			}

		NeighborJoiningTree tree;
		//System.out.println("Computing NJ tree");
		tree = new NeighborJoiningTree(mat);
		String newickString=tree.toString();
		newickString=newickString.replaceAll("\n","");
		newickString=newickString.trim();
		System.out.println(newickString+"DONE");
		}




	/**
	*Given an array of strings representing fasta lines,
	*make an NJ tree using the p distance and print the 
	*corresponding newick string to STDOUT.
	*@param fastalines a string of fasta lines
	*/
	public static void printTree(String[] fastalines)
		{
		String[][] data=TreeUtils.separateDescriptionsAndAlignmentsFromFastaLines(fastalines);
		String[] desc=data[0];
		String[] aln=data[1];

		//System.out.println("Descriptions are : "+Arrays.toString(desc)+"\n\n");
		//System.out.println("Alignments are : "+Arrays.toString(aln)+"\n\n");

		double[][] dm=TreeUtils.computeDistanceMatrix(aln);
		
		String newickString=TreeUtils.buildNJTreeFromDescriptionsAndDistanceMatrix(dm,desc);
		newickString=newickString.trim();
		newickString=newickString.trim();

		System.out.print(newickString+"DONE");
		}


	/**
	*Given any command-line arguments, the first argument is 
	*expected to be a filename (a FASTA multiple sequence alignment) and
	*the second is expected to be a string indicating a tree-building alogorithm, 
	*build a tree, and print its newick string to STDOUT.
	*args[0] is expected to be a file name.  args[1] is expected
	*to be a tree-building algorithm ("NJ" or somethign else, but right now
	*only "NJ" is implemented)
	*@param args command-line arguments
	*/
	public static void main(String[] args)
		{
		//read an MSA file (fasta format)
		//build an NJ tree!!!!!
		//System.out.println(Arrays.toString(readFileLines(args[0])));
		if(args==null)
			{
			throw new RuntimeException("Error - no arguments passed!!!!");
			}
		if(args.length<1)
			{
			throw new RuntimeException("Error - no arguments passed!!!!");
			}
		else if(args.length>=1)
			{
			if(args.length>=2 && args[1].toUpperCase().compareTo("NJ")==0)
				{
				printTree(readFileLines(args[0]));
				}
			else
				{
				printTreeF84(args[0]);
				}
			}
		}
	}