/*
* Copyright 2007-2013
* Licensed under GNU Lesser General Public License
*
* This file is part of EpochX
*
* EpochX is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EpochX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with EpochX. If not, see <http://www.gnu.org/licenses/>.
*
* The latest version is available from: http://www.epochx.org
*/
package org.epochx.event.stat;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.epochx.event.Event;
import org.epochx.event.EventManager;
import org.epochx.event.Listener;
/**
* Utility class to output information of stat objects. The basic idea is simple: create a
* new <code>StatPrinter</code> object, register the stats and inform which event will
* trigger the output of the information.
*
* <p>
* An example that outputs the generation number and the best generation fitness is:
* <pre>
* StatPrinter printer = new StatPrinter();
* printer.add(GenerationNumber.class);
* printer.add(GenerationBestFitness.class);
* printer.printOnEvent(EndGeneration.class);
* </pre>
* </p>
* <p>
* The above example will generate the following output:
* <pre>
* 1 12.0
* 2 12.0
* 3 11.0
* 4 10.0
* 5 9.0
* </pre>
* </p>
*/
public class StatPrinter {
/**
* The default separator string.
*/
public static final String SEPARATOR = "\t";
/**
* The list of <code>AbstractStat</code> to be printed.
*/
private ArrayList<AbstractStat<?>> fields = new ArrayList<AbstractStat<?>>();
/**
* The mapping of listerners registered by this <code>StatPrinter</code>.
*/
private Map<Class<?>, Listener<?>> listeners = new HashMap<Class<?>, Listener<?>>();
/**
* The current separator.
*/
private String separator;
/**
* The output stream.
*/
private PrintStream out;
/**
* Constructs a <code>StatPrinter</code>.
*/
public StatPrinter() {
this(System.out, SEPARATOR);
}
/**
* Constructs a <code>StatPrinter</code>.
*
* @param out the output stream.
*/
public StatPrinter(PrintStream out) {
this(out, SEPARATOR);
}
/**
* Constructs a <code>StatPrinter</code>.
*
* @param separator the delimiter string.
*/
public StatPrinter(String separator) {
this(System.out, separator);
}
/**
* Constructs a <code>StatPrinter</code>.
*
* @param out the output stream.
* @param separator the separator string.
*/
public StatPrinter(PrintStream out, String separator) {
this.out = out;
this.separator = separator;
}
/**
* Adds a new stat field to the printer.
*
* @param type the stat class to be added.
*/
public <E extends Event> void add(Class<? extends AbstractStat<E>> type) {
AbstractStat.register(type);
fields.add(AbstractStat.get(type));
}
/**
* Removes all fields from the printer.
*/
public void clear() {
fields.clear();
}
/**
* Prints the fields to the printer's output stream.
*/
public void print() {
if (!fields.isEmpty()) {
StringBuffer buffer = new StringBuffer();
for (AbstractStat<?> stat: fields) {
buffer.append(separator);
buffer.append(stat);
}
buffer.delete(0, separator.length());
out.println(buffer.toString());
}
}
/**
* Sets the event that triggers the output of the printer's fields.
*
* @param type the event class.
*/
public <E extends Event> void printOnEvent(Class<E> type) {
// only creates a new listener if we do not have one already
if (!listeners.containsKey(type)) {
Listener<E> listener = new Listener<E>() {
@Override
public void onEvent(E event) {
StatPrinter.this.print();
}
};
EventManager.getInstance().add(type, listener);
listeners.put(type, listener);
}
}
}