package code.stuff;

import code.space.Computation;
import code.stuff.Logger;
import code.term.*;
import code.symbols.DataSymbol;
import code.table.MapTable;

import java.io.IOException;
import java.io.BufferedWriter;

/**
 * This class contains a collection of Tracing Variables,
 * a collection of variables that denote the profiling related statistics
 * and methods to access the statistics.
 * See <A HREF="../../../README/Design-Notes/FLVMState.html">FLVM State</A>
 * for more details about how to use this class. 
 *
 * @author Sergio Antoy
 * @since June 17, 2003
 */
public class Tracer {

    // Singleton
    private Tracer() {}

    
    public static boolean pakcs = true;

    /**
     * Traces creation and state change of a computation.
     */
    public static boolean computation = false;

    public static boolean space = false;

    public static boolean reduction = false;

    public static boolean instruction = false;

    public static boolean batch = false;

    public static boolean script = false;

    public static boolean test = false;

    public static boolean rule = false;

    public static boolean time = false;

    public static boolean output = false;

    //loader's traces
    /**
     * Loading state, when open, user can follow each step of loading process.
     */

    public static boolean symbols = false;

    //Command Line Parser
    public static boolean clp = false;

    // Type creation, storage and access
    public static boolean typecache = false;

    // ------------------------------------------------------------------
    // Statistics

    /**
     * Description of the Field
     */
    public static long zeroTime;
    /**
     * Description of the Field
     */
    public static int steps;

    public static int instructions;
    /**
     * Description of the Field
     */
    public static int terms;
    
    //------------------------------------------------------------------
    
    public static void traceRewrite(Computation computation,
				    Term redex,
				    Term reduct) {
	/*  Uncomment to print the context of the redex */
        Computation top = computation.getTop();
        Term topLevel = top.getResult();
	Logger.logln("");
	Logger.logln(computation.getIdString() + " REW " + topLevel);
	/*	*/
	Logger.logln(computation.getIdString() + " REW " +
		     redex + " -> " + reduct);
    }

    //------------------------------------------------------------------

    /**
     * Initialize all statistics related variables.
     */
    public static void startComputation() {
        zeroTime = System.currentTimeMillis();
        steps = 0;
        instructions = 0;
        terms = 0;
    }

    /**
     * Return a string depicting the current statistics
     *
     * @return String a string depicting the current statistics
     */
    public static String statistics() {
        long elapsed = System.currentTimeMillis() - zeroTime;
        return "   Elapsed time:" + elapsed + "ms. "
                + "  steps:" + steps
                + "  instructions:" + instructions
                + "  terms:" + terms;
    }

    /**
     * Display the current statistics 
     * (which includes time, #steps, #instructions and #terms).
     * @param out Output should be sent here.
     * @throws IOException
     */
    public static void conditionallyPrintTime(BufferedWriter out) throws IOException {
        if (Tracer.time) {
            out.write(Tracer.statistics());
            out.newLine();
        }
    }


    // ------------------------------------------------------------------
    // The following code provide a crude print representation
    // of terms, which should work also when terms are malformed.
    // Use it only for debugging the nastiest bugs.

    public static int printDepth = 8;
    public static void printTerm(Term term) { paux(term, 0); }
    private static void paux(Term term, int depth) {
	if (depth <= printDepth) {
	    for (int i = 0; i < depth; i++) System.out.print("  ");
	    String identity = Integer.toHexString(term.hashCode());
	    if (term.getRepresentation() instanceof TermImplUser) {
		DataSymbol symbol
		    = (DataSymbol) MapTable.getSymbol(term.getRoot());
		System.out.println(symbol.symbolName+"  "+
				   symbol.arity+"  "+
				   identity);
		for (int i = 0; i < symbol.arity; i++)
		    paux(term.getArgument((byte) i), depth+1);
	    } else {
		System.out.println("builtin  "+identity);
	    }
	}
    }

}

