/*
 * @(#) Reporter.java 2003/03/23
 * 
 */

import java.util.Properties;
import java.io.*;


/**
 * Report on GA's progress.  * 
 * @author Sushil J. Louis
 */
public class Reporter implements java.io.Serializable {


    private String ofileNameBase;
    private String ofileFitness;
    private String ofileGeno;

    /**
     * Name of file that App writes descriptions (presumably visualizable)
     * of the phenotype.
     */
    public String ofilePheno;
    /**
     * Constructor extracts the output location from a GA Properties object
     * and creates a set of file names for recording the progress of
     * fitness statistics and evolution of genotype and phenotype over
     * generations.
     *
     * @param props The GA's paramters object.
     *
     */
    public Reporter(Properties props) {
	ofileNameBase = new String (props.getProperty("Outfile", "out"));
	ofileFitness = new String(ofileNameBase + ".fit");
	ofilePheno = new String(ofileNameBase + ".pheno");
	ofileGeno = new String(ofileNameBase + ".geno");
    }

    /**
     * Writes out the max, avg, min, scaled max, and scaled min every
     * generation. Additionally, writes out the generation in which the best 
     * individual
     * evolved so far, the fitness of this best individual, and the index
     * in the population array of this best individual.
     * Lastly, it writes out an objective function value, useful when the 
     * fitness is some function of the objective function value.  All these
     * values are written on one line per generation. Finally, written out 
     * whenever the max fitness in the population improves, are the 
     * the phenotype and genotype. <br> Note that in this version all writing 
     * is to the standard output stream </br>
     *
     * @param pop The population structure.
     * @param app knows how to print a phenotype and this method invokes
     * app's <code> phenoPrint </code> to print the phenotype.
     * @param gen the current generation.
     */
    public void report(Population pop, CigarApp app, int gen){
	String ps = new String(gen + " " 
			       + pop.max + " " 
			       + pop.avg + " " 
			       + pop.min + " " 
			       + pop.bigGen + " "
			       + pop.bigMax + " " 
			       + pop.bigIndex + " " 
			       + pop.bestObjective);

//	appendOutput(ofileNameBase, ps);
        
        //can't do this like this with applets -nc
//	appendReport(ofileFitness, ps);

	appendOutput(ofileFitness, 
		     gen + " " 
		     + pop.max + " " 
		     + pop.avg + " " 
		     + pop.min);
	
	if(pop.bigGen == pop.generation){
//can't do this like this with applets -nc
//	    genoPrint(pop.currentPop[pop.maxi], ofileGeno);
//	    app.phenoPrint(pop, ofilePheno);
	}
	//	dumpPop(pop, ofilePheno);
    }

    private void appendOutput(String location, String msg){
//	System.out.println(location + ":\t " + msg);
        System.out.println( msg);
    }

    /**
     * Prints the allelles in an {@link Individual}'s chromosome
     * to location (standard  output).
     * 
     * @param member The individual whose genotype is to be printed
     * @param location Where to print to (not used in this version).
     */
    public static void genoPrint(Individual member, String location){
	StringBuffer sb = new StringBuffer();
	for(int i = 0; i < member.chromosome.length; i++){
	    sb.append(member.chromosome[i]);
	}
	appendReport(location, sb.toString());
    }

    public static void genoPrint(Individual member, PrintWriter pw){
	StringBuffer sb = new StringBuffer();
	for(int i = 0; i < member.chromosome.length; i++){
	    sb.append(member.chromosome[i]);
	}
	pw.println(sb.toString());
    }

    /**
     * Prints the current population. Useful for debugging.
     * This version ignores the second parameter and prints to standard out.
     *
     * @param pop The current population structure.
     * @param location Where to print to (not used in this version).
     */
    public static void dumpPop(Population pop, String location){
	PrintWriter pw = openWriter(location);
	for(int i = 0; i < pop.popSize * pop.lambda; i++){
	    genoPrint(pop.currentPop[i], pw);
	}
	pw.close();
    }

    private static PrintWriter openWriter(String filename) {
	PrintWriter pw = null;
	try {
	    pw = 
		(new PrintWriter(new BufferedWriter 
				 (new FileWriter(filename))));
	} catch (IOException e){
	    System.err.println("Cannot open " + filename + " for writing");
	    System.exit(1);
	}
	return pw;	    
    }

    private static PrintWriter openAppender(String filename) {
	PrintWriter pw = null;
	try {
	    pw = 
		(new PrintWriter(new BufferedWriter 
				 (new FileWriter(filename, true))));
	} catch (IOException e){
	    System.err.println("Cannot open " + filename + " for writing");
	    System.exit(1);
	}
	return pw;	    
    }

    private static void appendReport(String filename, String msg){
	PrintWriter pw = openAppender(filename);
	pw.println(msg);
	pw.close();	
    }

    private void printReport(String filename, String msg){
	PrintWriter pw = openWriter(filename);
	pw.println(msg);
	pw.close();
    }
}
