# SourceHighlighter.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:
     *    Marc R. Hoffmann - initial API and implementation
     *
     *******************************************************************************/
    package org.jacoco.report.internal.html.page;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.Reader;
    import java.util.Locale;

    import org.jacoco.core.analysis.ICounter;
    import org.jacoco.core.analysis.ILine;
    import org.jacoco.core.analysis.ISourceNode;
    import org.jacoco.report.internal.html.HTMLElement;
    import org.jacoco.report.internal.html.resources.Styles;

    /**
     * Creates a highlighted output of a source file.
     */
    final class SourceHighlighter {

    	private final Locale locale;

    	private String lang;

    	/**
    	 * Creates a new highlighter with default settings.
    	 *
    	 * @param locale
    	 *            locale for tooltip rendering
    	 */
    	public SourceHighlighter(final Locale locale) {
    		this.locale = locale;
    		lang = "java";
    	}

    	/**
    	 * Specifies the source language. This value might be used for syntax
    	 * highlighting. Default is "java".
    	 *
    	 * @param lang
    	 *            source language identifier
    	 */
    	public void setLanguage(final String lang) {
    		this.lang = lang;
    	}

    	/**
    	 * Highlights the given source file.
    	 *
    	 * @param parent
    	 *            parent HTML element
    	 * @param source
    	 *            highlighting information
    	 * @param contents
    	 *            contents of the source file
    	 * @throws IOException
    	 *             problems while reading the source file or writing the output
    	 */
    	public void render(final HTMLElement parent, final ISourceNode source,
    			final Reader contents) throws IOException {
    		final HTMLElement pre = parent.pre(Styles.SOURCE + " lang-" + lang
    				+ " linenums");
    		final BufferedReader lineBuffer = new BufferedReader(contents);
    		String line;
    		int nr = 0;
    		while ((line = lineBuffer.readLine()) != null) {
    			nr++;
    			renderCodeLine(pre, line, source.getLine(nr), nr);
    		}
    	}

    	private void renderCodeLine(final HTMLElement pre, final String linesrc,
    			final ILine line, final int lineNr) throws IOException {
    		highlight(pre, line, lineNr).text(linesrc);
    		pre.text("\n");
    	}

    	HTMLElement highlight(final HTMLElement pre, final ILine line,
    			final int lineNr) throws IOException {
    		final String style;
    		switch (line.getStatus()) {
    		case ICounter.NOT_COVERED:
    			style = Styles.NOT_COVERED;
    			break;
    		case ICounter.FULLY_COVERED:
    			style = Styles.FULLY_COVERED;
    			break;
    		case ICounter.PARTLY_COVERED:
    			style = Styles.PARTLY_COVERED;
    			break;
    		default:
    			return pre;
    		}

    		final String lineId = "L" + Integer.toString(lineNr);
    		final ICounter branches = line.getBranchCounter();
    		switch (branches.getStatus()) {
    		case ICounter.NOT_COVERED:
    			return span(pre, lineId, style, Styles.BRANCH_NOT_COVERED,
    					"All %2$d branches missed.", branches);
    		case ICounter.FULLY_COVERED:
    			return span(pre, lineId, style, Styles.BRANCH_FULLY_COVERED,
    					"All %2$d branches covered.", branches);
    		case ICounter.PARTLY_COVERED:
    			return span(pre, lineId, style, Styles.BRANCH_PARTLY_COVERED,
    					"%1$d of %2$d branches missed.", branches);
    		default:
    			return pre.span(style, lineId);
    		}
    	}

    	private HTMLElement span(final HTMLElement parent, final String id,
    			final String style1, final String style2, final String title,
    			final ICounter branches) throws IOException {
    		final HTMLElement span = parent.span(style1 + " " + style2, id);
    		final Integer missed = Integer.valueOf(branches.getMissedCount());
    		final Integer total = Integer.valueOf(branches.getTotalCount());
    		span.attr("title", String.format(locale, title, missed, total));
    		return span;
    	}

    }