/*
 * Bytecode Analysis Framework
 * Copyright (C) 2003,2004 University of Maryland
 * 
 * This library 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 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.umd.cs.findbugs.ba;

import java.io.PrintStream;

import org.apache.bcel.generic.InstructionHandle;

/**
 * CFGPrinter class which prints dataflow values at
 * each basic block and instruction.
 */
public class DataflowCFGPrinter <Fact, AnalysisType extends DataflowAnalysis<Fact>> extends CFGPrinter {
	private Dataflow<Fact, AnalysisType> dataflow;

	/**
	 * Constructor.
	 * 
	 * @param dataflow the Dataflow object whose values should be used to annotate the printed CFG
	 */
	public DataflowCFGPrinter(Dataflow<Fact, AnalysisType> dataflow) {
		super(dataflow.getCFG());
		this.dataflow = dataflow;

		setIsForwards(dataflow.getAnalysis().isForwards());
	}

	/* (non-Javadoc)
	 * @see edu.umd.cs.findbugs.ba.CFGPrinter#edgeAnnotate(edu.umd.cs.findbugs.ba.Edge)
	 */
	@Override
	public String edgeAnnotate(Edge edge) {
		String edgeAnnotation= "";
		try {
			edgeAnnotation = " " + dataflow.getAnalysis().factToString(dataflow.getAnalysis().getFactOnEdge(edge)); 
		} catch (Throwable e) {
			// ignore
		}
		return edgeAnnotation;
	}

	@Override
	public String blockStartAnnotate(BasicBlock bb) {
		boolean flip = isForwards() != dataflow.getAnalysis().isForwards();
		Fact fact = flip ? dataflow.getResultFact(bb) : dataflow.getStartFact(bb);

		return " " + dataflow.getAnalysis().factToString(fact);
	}

	@Override
	public String blockAnnotate(BasicBlock bb) {
		boolean flip = isForwards() != dataflow.getAnalysis().isForwards();
		Fact fact = flip ? dataflow.getStartFact(bb) : dataflow.getResultFact(bb) ;

		return " " + dataflow.getAnalysis().factToString(fact);
	}

	@Override
	public String instructionAnnotate(InstructionHandle handle, BasicBlock bb) {
		try {
			boolean flip = isForwards() != dataflow.getAnalysis().isForwards();

			Location loc =new Location(handle, bb); 

			Fact fact = flip
					? dataflow.getAnalysis().getFactAfterLocation(loc)
					: dataflow.getAnalysis().getFactAtLocation(loc);
			return " " + dataflow.getAnalysis().factToString(fact);
		} catch (DataflowAnalysisException e) {
			throw new IllegalStateException("Caught exception: " + e.toString());
		}
	}

	/**
	 * Print CFG annotated with results from given dataflow analysis.
	 * 
	 * @param <Fact>         Dataflow fact type
	 * @param <AnalysisType> Dataflow analysis type
	 * @param dataflow       dataflow driver
	 * @param out            PrintStream to use
	 */
	public static<Fact, AnalysisType extends BasicAbstractDataflowAnalysis<Fact>>
	void printCFG(Dataflow<Fact, AnalysisType> dataflow, PrintStream out) {
		DataflowCFGPrinter<Fact, AnalysisType> printer =
			new DataflowCFGPrinter<Fact, AnalysisType>(dataflow);
		printer.print(out);
	}

}

// vim:ts=4
