gt: 			outputFile = getParameterAsFile(PARAMETER_FILENAME);
context: /*
   *  RapidMiner
   *
   *  Copyright (C) 2001-2008 by Rapid-I and the contributors
   *
   *  Complete list of developers available at our web site:
   *
   *       http://rapid-i.com
   *
   *  This program is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU Affero General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  This program 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 Affero General Public License for more details.
   *
   *  You should have received a copy of the GNU Affero General Public License
   *  along with this program.  If not, see http://www.gnu.org/licenses/.
   */
  package com.rapidminer.operator.visualization;
  
  import java.io.File;
  import java.io.FileWriter;
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.util.Iterator;
  import java.util.List;
  import java.util.StringTokenizer;
  
  import com.rapidminer.datatable.DataTable;
  import com.rapidminer.datatable.DataTableRow;
  import com.rapidminer.datatable.SimpleDataTable;
  import com.rapidminer.datatable.SimpleDataTableRow;
  import com.rapidminer.operator.IOObject;
  import com.rapidminer.operator.Operator;
  import com.rapidminer.operator.OperatorDescription;
  import com.rapidminer.operator.OperatorException;
  import com.rapidminer.operator.UserError;
  import com.rapidminer.operator.Value;
  import com.rapidminer.parameter.ParameterType;
  import com.rapidminer.parameter.ParameterTypeBoolean;
  import com.rapidminer.parameter.ParameterTypeFile;
  import com.rapidminer.parameter.ParameterTypeList;
  import com.rapidminer.parameter.ParameterTypeValue;
  import com.rapidminer.parameter.UndefinedParameterError;
  
  
  /**
   * This operator records almost arbitrary data. It can written to a file which
   * can be read e.g. by gnuplot. Alternatively, the collected data can be plotted
   * by the GUI. This is even possible during process runtime (i.e. online
   * plotting).<br/>
   * 
   * Parameters in the list <code>log</code> are interpreted as follows: The
   * <var>key</var> gives the name for the column name (e.g. for use in the
   * plotter). The <var>value</var> specifies where to retrieve the value from.
   * This is best explained by an example:
   * <ul>
   * <li>If the value is <code>operator.Evaluator.value.absolute</code>, the
   * ProcessLogOperator looks up the operator with the name
   * <code>Evaluator</code>. If this operator is a
   * {@link com.rapidminer.operator.performance.PerformanceEvaluator}, it has a
   * value named <var>absolute</var> which gives the absolute error of the last
   * evaluation. This value is queried by the ProcessLogOperator</li>
   * <li>If the value is <code>operator.SVMLearner.parameter.C</code>, the
   * ProcessLogOperator looks up the parameter <var>C</var> of the operator
   * named <code>SVMLearner</code>.</li>
   * </ul>
   * Each time the ProcessLogOperator is applied, all the values and parameters
   * specified by the list <var>log</var> are collected and stored in a data row.
   * When the process finishes, the operator writes the collected data rows to
   * a file (if specified). In GUI mode, 2D or 3D plots are automatically
   * generated and displayed in the result viewer. <br/> Please refer to section
   * {@rapidminer.ref sec:parameter_optimization|Advanced Processes/Parameter and performance analysis}
   * for an example application.
   * 
   * @rapidminer.todo Use IOObjects for logging as well (e.g.
   *            {@link com.rapidminer.operator.performance.PerformanceVector})
   * @author Simon Fischer, Ingo Mierswa
   * @version $Id: ProcessLogOperator.java,v 2.27 2006/03/27 13:21:58
   *          ingomierswa Exp $
   */
  public class ProcessLogOperator extends Operator {
  
  	/** The parameter name for &quot;operator.OPERATORNAME.[value|parameter].VALUE_NAME&quot; */
  	public static final String PARAMETER_COLUMN_NAME = "column_name";
  	
  	public static final String PARAMETER_FILENAME = "filename";
  	
  	public static final String PARAMETER_LOG = "log";
  	
  	private static final String PARAMETER_PERSISTENT = "persistent";
  
  	public ProcessLogOperator(OperatorDescription description) {
  		super(description);
  	}
  
  	private double fetchValue(String name, int column) throws UndefinedParameterError {
  		StringTokenizer reader = new StringTokenizer(name, ".");
  		String type = reader.nextToken();
  		if (type.equals("operator")) {
  			String opName = reader.nextToken();
  			Operator operator = getProcess().getOperator(opName);
  			if (operator != null) {
  				type = reader.nextToken();
  				if (type.equals("value")) {
  					String valueName = reader.nextToken();
  					Value value = operator.getValue(valueName);
  					if (value == null) {
  						logWarning("No such value in '" + name + "'");
  						return Double.NaN;
  					}
  					
  					if (value.isNominal()) {
  						String valueString = value.getValue().toString();
  						SimpleDataTable table = (SimpleDataTable)getProcess().getDataTable(getName());
  						return table.mapString(column, valueString);
  					} else {
  						return ((Double)value.getValue()).doubleValue();	
  					}
  				} else if (type.equals("parameter")) {
  					String parameterName = reader.nextToken();
  					ParameterType parameterType = operator.getParameterType(parameterName);
  					if (parameterType == null) {
  						logWarning("No such parameter in '" + name + "'");
  						return Double.NaN;
  					} else {
  						if (parameterType.isNumerical()) { // numerical
  							try {
  								return Double.parseDouble(operator.getParameter(parameterName).toString());
  							} catch (NumberFormatException e) {
  								logWarning("Cannot parse parameter value of '" + name + "'");
  							}
  						} else { // nominal
  							String value = parameterType.toString(operator.getParameter(parameterName));
  							SimpleDataTable table = (SimpleDataTable)getProcess().getDataTable(getName());
  							return table.mapString(column, value);
  						}
  					}
  				} else {
  					logWarning("Unknown token '" + type + "' in '" + name + "'");
  				}
  			} else {
  				logWarning("Unknown operator '" + opName + "' in '" + name + "'");
  			}
  		} else {
  			logWarning("Unknown token '" + type + "' in '" + name + "'");
  		}
  		return Double.NaN;
  	}
  
  	private String[] getValueNames() throws UndefinedParameterError {
  		List parameters = getParameterList(PARAMETER_LOG);
  		String [] valueNames = new String[parameters.size()];
  		Iterator i = parameters.iterator();
  		int j = 0;
  		while (i.hasNext()) {
  			Object[] parameter = (Object[]) i.next();
  			valueNames[j] = (String) parameter[1];
  			j++;
  		}
  		return valueNames;
  	}
  	
  	public void processStarts() throws OperatorException {
  		super.processStarts();
  		List parameters = getParameterList(PARAMETER_LOG);
  		String columnNames[] = new String[parameters.size()];
  		Iterator i = parameters.iterator();
  		int j = 0;
  		while (i.hasNext()) {
  			Object[] parameter = (Object[]) i.next();
  			columnNames[j] = (String) parameter[0];
  			j++;
  		}
  		getProcess().addDataTable(new SimpleDataTable(getName(), columnNames));
  	}
  
  	public Class<?>[] getInputClasses() {
  		return new Class[0];
  	}
  
  	public Class<?>[] getOutputClasses() {
  		return new Class[0];
  	}
  
  	public IOObject[] apply() throws OperatorException {
  		DataTableRow row = fetchAllValues();
  		if (getParameterAsBoolean(PARAMETER_PERSISTENT)) {
  			writeOnline(row);
  		}
  		return new IOObject[] {};
  	}
  
  	private void writeOnline(DataTableRow row) throws UserError {
  		DataTable table = getProcess().getDataTable(getName());
  		File outputFile = null;
  		try {
  