/*
 *
 * @(#)InputParameters.java 1.0 September 2009
 *
 * Copyright (c) 2009 Peter Troshin
 *
 *                    BioJava development code
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  If you do not have a copy,
 * see:
 *
 *      http://www.gnu.org/copyleft/lesser.html
 *
 * Copyright for this code is held jointly by the individual
 * authors.  These should be listed in @author doc comments.
 *
 * For more information on the BioJava project and its aims,
 * or to join the biojava-l mailing list, visit the home page
 * at:
 *
 *      http://www.biojava.org/
 *
 */
package org.biojava.nbio.ronn;

import org.biojava.nbio.ronn.ORonn.ResultLayout;

import java.io.*;


/**
 * Holder for input parameters of the {@link ORonn} class
 *
 * @author Peter Troshin
 * @version 1.0
 * @since 3.0.2

 */
final class InputParameters {
	static final String inputKey = "-i=";
	static final String outputKey = "-o=";
	static final String statKey = "-s=";
	static final String disorderKey = "-d=";
	static final String formatKey = "-f=";
	static final String threadKey = "-n=";

	private File input;
	private File output;
	private File statistics;
	private ResultLayout format;
	private float disorder;
	private int threadNum;
	private volatile PrintWriter outWriter;
	private volatile PrintWriter statWriter;

	InputParameters() {
	threadNum = Runtime.getRuntime().availableProcessors();
	disorder = RonnConstraint.DEFAULT_DISORDER;
	}

	File setFilePrm(String filename, final String key) throws IOException {
	File file = null;
	if (filename == null) {
		throw new IllegalArgumentException("File name is not provided! ");
	}
	filename = filename.trim();
	if (filename.toLowerCase().startsWith(key)) {
		file = new File(filename.substring(key.length()));
		if (!file.exists()) {
		file.createNewFile();
		}
		if (key.equals(InputParameters.inputKey)) {
		input = file;
		}
		if (key.equals(InputParameters.outputKey)) {
		output = file;
		}
		if (key.equals(InputParameters.statKey)) {
		statistics = file;
		}
	}
	return file;
	}

	PrintWriter getOutputWriter() throws FileNotFoundException {
	if (outWriter == null) {
		synchronized (this) {
		if (outWriter == null) {
			if (output != null) {
			outWriter = new PrintWriter(output);
			} else {
			outWriter = new PrintWriter(System.out);
			}
		}
		}
	}
	return outWriter;
	}

	ResultLayout parseFormat(String format) {
	// default layout
	if (format == null) {
		return ResultLayout.VERTICAL;
	}
	format = format.trim().substring(InputParameters.formatKey.length());
	if (format.toUpperCase().equals("V")) {
		return ResultLayout.VERTICAL;
	}
	if (format.toUpperCase().equals("H")) {
		return ResultLayout.HORIZONTAL;
	}
	throw new IllegalArgumentException("Unrecognised format: '" + format
		+ "' Output format for results must be either H or V.");
	}

	/**
	 *
	 * @param key
	 * @return
	 * @throws NumberFormatException
	 */
	int parseThreadNum(String key) {
	key = key.trim().substring(InputParameters.threadKey.length());
	final int nthreads = Integer.parseInt(key);
	return nthreads;
	}

	@Override
	public String toString() {
	final String def = " [default]";
	final String newLine = System.getProperty("line.separator");
	String value = "input=" + input + newLine;

	if (output != null) {
		value += "output=" + output + newLine;
	} else {
		value += "output= standard out" + newLine;
	}
	if (statistics != null) {
		value += "statistics=" + statistics + newLine;
	} else {
		value += "statistics= not kept" + newLine;
	}
	value += "disorder=" + getDisorder();
	if (disorder == RonnConstraint.DEFAULT_DISORDER) {
		value += def;
	}
	value += newLine;
	value += "thread number=" + getThreadNum() + newLine;
	value += "format=" + getFormat();
	if (format == null) {
		value += def;
	}
	// value += newLine ;
	return value;
	}

	ResultLayout getFormat() {
	return format == null ? ResultLayout.VERTICAL : format;
	}

	float getDisorder() {
	return disorder;
	}

	void setDisorder(final String prm) {
	final float disorder = Float.parseFloat(prm
		.substring(InputParameters.disorderKey.length()));
	// do not set disorder values if it is invalid
	// default disorder set in the constructor
	if ((disorder > 0) || (disorder <= 1)) {
		this.disorder = disorder;
	}
	}

	void setFormat(final String prm) {
	format = parseFormat(prm);
	}

	void setThreadNum(final String prm) {
	// default number of threads are set in the constructor and
	// equals to the number of cores
	final int procNum = threadNum;
	final int tnum = parseThreadNum(prm);
	if (tnum != 0) {
		if ((tnum < 1) || (tnum > procNum * 2)) {
		throw new IllegalArgumentException(
			"Number of threads must be between 1 "
				+ "and 2 x number of cores available on the executing machine");
		}
		threadNum = tnum;
	}
	}

	private void initStatWriter() throws IOException {
	if (statistics != null) {
		statWriter = new PrintWriter(new FileWriter(statistics), true);
	} else {
		statWriter = new PrintWriter(new NullOutputStream());
	}
	}

	public PrintWriter getStatWriter() throws IOException {
	if (statWriter == null) {
		synchronized (this) {
		if (statWriter == null) {
			initStatWriter();
		}
		}
	}
	return statWriter;
	}

	File getInput() {
	return input;
	}

	int getThreadNum() {
	return threadNum;
	}

}
