/*
 * Cobertura - http://cobertura.sourceforge.net/
 *
 * Copyright (C) 2011 Piotr Tabor
 *
 * Note: This file is dual licensed under the GPL and the Apache
 * Source License (so that it can be used from both the main
 * Cobertura classes and the ant tasks).
 *
 * Cobertura is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * Cobertura 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cobertura; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

package net.sourceforge.cobertura.instrument.pass3;

import net.sourceforge.cobertura.instrument.tp.ClassMap;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;

/**
 * Universal API for all methods that are responsible for generating any JASM code that have
 * to be injected into real classes.
 * <p/>
 * The general idea is that injected code is responsible for incrementing counters. The realization of counters
 * is implementation dependent.
 *
 * @author piotr.tabor@gmail.com
 */
public interface CodeProvider {
	/**
	 * Name of a field that have to be injected into instrumented class that is responsible for storing counters
	 */
	public static final String COBERTURA_COUNTERS_FIELD_NAME = "__cobertura_counters";

	/**
	 * Name of a method that will to be injected into instrumented class that is responsible for storing
	 * class-map (information on mapping of counter identifiers into lines, jumps and switch-touches).
	 */
	public static final String COBERTURA_CLASSMAP_METHOD_NAME = "__cobertura_classmap";

	/**
	 * Name of method that will initialize internal counters variable.
	 */
	public static final String COBERTURA_INIT_METHOD_NAME = "__cobertura_init";

	/**
	 * Name of a method that have to be injected into instrumented class that is responsible for reading
	 * value of given counter.
	 * <p/>
	 * Signature of this method is: int[] __cobertura_counter(int counterId);
	 */
	public static final String COBERTURA_GET_AND_RESET_COUNTERS_METHOD_NAME = "__cobertura_get_and_reset_counters";

	/**
	 * Generates fields injected into  instrumented class  by cobertura.
	 *
	 * @param cv - ClassVisitor that is listener of code-generation events
	 */
	public abstract void generateCountersField(ClassVisitor cv);

	/**
	 * Injects code that increments counter given by parameter.
	 *
	 * @param nextMethodVisitor - {@link MethodVisitor} that is listener of code-generation events
	 * @param counterId         -  counterId of counter that have to be incremented
	 * @param className         - internal name (asm) of class being instrumented
	 */
	public abstract void generateCodeThatIncrementsCoberturaCounter(
			MethodVisitor nextMethodVisitor, Integer counterId, String className);

	/**
	 * Injects code that increments counter given by internal variable.
	 * The id of the variable is identified by lastJumpIdVariableIndex. The variable is in most cases set (by {@link #generateCodeThatSetsJumpCounterIdVariable(MethodVisitor, int, int)}
	 * to some counterId and in the target label, the counter identified by the variable is incremented.
	 * long
	 *
	 * @param nextMethodVisitor       - {@link MethodVisitor} that is listener of code-generation events
	 * @param lastJumpIdVariableIndex - id of the variable used to store counterId that have to be incremented
	 * @param className               - internal name (asm) of class being instrumented
	 */
	public abstract void generateCodeThatIncrementsCoberturaCounterFromInternalVariable(
			MethodVisitor nextMethodVisitor, int lastJumpIdVariableIndex,
			String className);

	/**
	 * Injects code that sets internal variable (identified by lastJumpIdVariableIndex) to given value.
	 *
	 * @param nextMethodVisitor       - {@link MethodVisitor} that is listener of code-generation events
	 * @param new_value               - value to set the variable to
	 * @param lastJumpIdVariableIndex - index of variable that have to be set
	 */
	public abstract void generateCodeThatSetsJumpCounterIdVariable(
			MethodVisitor nextMethodVisitor, int new_value,
			int lastJumpIdVariableIndex);

	/**
	 * Injects code that sets internal variable (identified by lastJumpIdVariableIndex) to zero.
	 *
	 * @param nextMethodVisitor       - {@link MethodVisitor} that is listener of code-generation events
	 * @param lastJumpIdVariableIndex - index of variable that have to be set
	 */
	public abstract void generateCodeThatZeroJumpCounterIdVariable(
			MethodVisitor nextMethodVisitor, int lastJumpIdVariableIndex);

	/**
	 * Injects code that behaves the same as such a code snippet:
	 * <pre>
	 * if (value('lastJumpIdVariableIndex')==neededJumpCounterIdVariableValue){
	 * 	 cobertura_counters.increment(counterIdToIncrement);
	 * }
	 * </pre>
	 * <p/>
	 * This snippet is used in switch case of switch statement. We have a label and we want to ensure that
	 * we are executing the label in effect of switch statement-jump, and not other JUMP or fall-throught.
	 */
	public abstract void generateCodeThatIncrementsCoberturaCounterIfVariableEqualsAndCleanVariable(
			MethodVisitor nextMethodVisitor,
			Integer neededJumpCounterIdVariableValue,
			Integer counterIdToIncrement, int lastJumpIdVariableIndex,
			String className);

	/**
	 * The version of cobertura prior to 1.10 used *.ser file to store information of lines, jumps, switches and other
	 * constructions used in the class. It was difficult to user to transfer the files after instrumentation into
	 * 'production' directory. To avoid that we are now creating the class-map as a special injected method that is responsible
	 * for keeping such a informations.
	 *
	 * @param cv       - listener used to inject the code
	 * @param classMap - structure that is keeping all collected information about the class. The information from the structure will be stored as
	 *                 method body.
	 */
	public void generateCoberturaClassMapMethod(ClassVisitor cv,
			ClassMap classMap);

	/**
	 * Generate method {@value #COBERTURA_GET_AND_RESET_COUNTERS_METHOD_NAME} that is accessor to couters.
	 * Signature of this method is: static int __cobertura_counter(int counterId);
	 *
	 * @param cv - listener used to inject the code
	 */
	public abstract void generateCoberturaGetAndResetCountersMethod(
			ClassVisitor cv, String className);

	public void generateCoberturaInitMethod(ClassVisitor cv, String className,
			int countersCnt);

	public abstract void generateCallCoberturaInitMethod(MethodVisitor mv,
			String className);
}