# DelimitedWriter.java

    /*******************************************************************************
     * Copyright (c) 2009, 2013 Mountainminds GmbH & Co. KG and Contributors
     * All rights reserved. This program and the accompanying materials
     * are made available under the terms of the Eclipse Public License v1.0
     * which accompanies this distribution, and is available at
     * http://www.eclipse.org/legal/epl-v10.html
     *
     * Contributors:
     *    Brock Janiczak - initial API and implementation
     *
     *******************************************************************************/
    package org.jacoco.report.csv;

    import java.io.IOException;
    import java.io.Writer;

    /**
     * Helper class for writing out CSV or tab delimited files.
     * <p>
     * <strong>Example Usage:</strong>
     *
     * <pre>
     * delimitedWriter.writeFields(&quot;header1&quot;, &quot;header2&quot;, ...);
     * for each line to be written {
     *   delimitedWriter.writeField(value1);
     *   delimitedWriter.writeField(value2);
     *   delimitedWriter.nextLine();
     * }
     * delimitedWriter.close();
     * </pre>
     *
     * </p>
     */
    class DelimitedWriter {
    	private static final String QUOTE = "\"";
    	private static final String ESCAPED_QUOTE = "\"\"";

    	private static final char DEFAULT_DELIMITER = ',';
    	private static final String NEW_LINE = System.getProperty("line.separator");
    	private final char delimiter;
    	private final Writer delegate;
    	private int fieldPosition = 0;

    	/**
    	 * Creates a new Delimited writer using the default delimiter
    	 *
    	 * @param delegate
    	 *            Writer to delegate all writes to
    	 */
    	public DelimitedWriter(final Writer delegate) {
    		this(delegate, DEFAULT_DELIMITER);
    	}

    	/**
    	 * Creates a new Delimited writer using the default delimiter
    	 *
    	 * @param delegate
    	 *            Writer to delegate all writes to
    	 * @param delimiter
    	 *            delimiter to use (usually a comma, tab or space)
    	 */
    	public DelimitedWriter(final Writer delegate, final char delimiter) {
    		this.delegate = delegate;
    		this.delimiter = delimiter;
    	}

    	/**
    	 * Write multiple fields at once. Values will be auto escaped and quoted as
    	 * needed. Each value will be separated using the current delimiter
    	 *
    	 * @param fields
    	 *            Values to write
    	 * @throws IOException
    	 *             Error writing to the underlying writer object
    	 */
    	public void write(final String... fields) throws IOException {
    		for (final String field : fields) {
    			write(field);
    		}
    	}

    	/**
    	 * Write a single value. Values will be auto escaped and quoted as needed.
    	 * If this is not the first field of the current line the value will be
    	 * prepended with the current delimiter
    	 *
    	 * @param field
    	 *            Value to write
    	 * @throws IOException
    	 *             Error writing to the underlying writer object
    	 */
    	public void write(final String field) throws IOException {
    		if (fieldPosition != 0) {
    			delegate.write(delimiter);
    		}
    		delegate.write(escape(field));
    		fieldPosition++;
    	}

    	/**
    	 * Write a single integer value.
    	 *
    	 * @param value
    	 *            Value to write
    	 * @throws IOException
    	 *             Error writing to the underlying writer object
    	 */
    	public void write(final int value) throws IOException {
    		write(Integer.toString(value));
    	}

    	/**
    	 * Write muliple integer values
    	 *
    	 * @param values
    	 *            values to write
    	 * @throws IOException
    	 *             Error writing to the underlying writer object
    	 */
    	public void write(final int... values) throws IOException {
    		for (final int value : values) {
    			write(Integer.toString(value));
    		}
    	}

    	/**
    	 * Output a new line and advance the writer to the next line. The line
    	 * delimiter is the default for the platform.
    	 *
    	 * @throws IOException
    	 *             Error writing to the underlying writer object
    	 */
    	public void nextLine() throws IOException {
    		delegate.write(NEW_LINE);
    		fieldPosition = 0;
    	}

    	/**
    	 * Close the underlying writer object. Once closed all write operations will
    	 * fail
    	 *
    	 * @throws IOException
    	 *             Error closing the underlying writer object
    	 */
    	public void close() throws IOException {
    		delegate.close();
    	}

    	/**
    	 * Escapes any occurrences of the quote character in value by replacing it
    	 * with a double quote. Also Quotes the value if a quote or delimiter value
    	 * is found.
    	 *
    	 * @param value
    	 *            String that needs escaping
    	 * @return New string with all values escaped
    	 */
    	private String escape(final String value) {
    		String escapedValue = value;

    		// Escape and quote if the source value contains the delimiter
    		// or the quote character
    		if (value.indexOf(QUOTE) != -1 || value.indexOf(delimiter) != -1) {
    			escapedValue = value.replace(QUOTE, ESCAPED_QUOTE);
    			escapedValue = QUOTE + escapedValue + QUOTE;
    		}

    		return escapedValue;
    	}
    }