/**
 * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. 
 * This file is licensed under the terms of the Modified BSD License.
 */
package org.abs_models.backend.java.absunit;

import java.util.List;

import org.abs_models.backend.java.lib.runtime.ABSException;
import org.abs_models.backend.java.lib.types.ABSValue;
import org.abs_models.backend.java.observing.TaskStackFrameView;

/**
 * An instance of this class is created when a test method is invoked. The
 * created instance is used to track the progress and status of the test.
 * Eentually, it can be queried if the test passed or failed. There are
 * different failure reasons like FAILED (assertion violated), deadlocked or an
 * (internal) error.
 * 
 * The status instance also tracks the currently executed line of code which can
 * be used to identify the point of failure.
 * 
 * 
 * @author Richard Bubel
 * 
 */
public class TestStatus {

    /* enumeration of possible test statuses */
    enum Status {
        /** test method running or at least task created */
        ACTIVE,
        /* test passed */
        OK,
        /* test assertion failed */
        FAILED,
        /* test deadlocked */
        DEADLOCKED,
        /* test error */
        ERROR
    }

    /* the status of the test */
    private Status status;

    /* the id of the task executing the tracked test */
    private final int taskID;

    /* the name of the test method and its class */
    private final String testMethod;
    private final String className;

    /** The value of the parameters of the test method at invocation time */
    private final List<ABSValue> args;

    /*
     * the last executed line of code and the name of the file containing the
     * test method
     */
    private int line = -1;
    private String fileName = "";

    /* not iff a test assertion failed or an internal error occurred */
    private ABSException exception;

    /*
     * depth of stack frame of the test's task when the test method has been
     * invoked
     */
    private final int framesDepth;

    public TestStatus(int id, String method, String className, List<ABSValue> args,
            List<? extends TaskStackFrameView> frames, Status status) {
        taskID = id;
        testMethod = method;
        this.className = className;
        this.args = args;
        this.framesDepth = frames == null ? 0 : frames.size();
        this.status = status;
    }

    /* the tasks' stack frame depth when starting the thread */
    public int depth() {
        return framesDepth;
    }

    /* formatted text which can be displayed */
    public String displayString() {
        String result = "<html><body>";
        result += "<strong>Class:</strong> " + className + "<br>";
        result += "<strong>Method:</strong> " + testMethod + "<br>";
        result += "<strong>Arguments:</strong> " + args + "<br>";
        result += "<strong>Status:</strong> " + status + "<br>";
        if (getException() != null) {
            if (exception.isAssertion()) {
                result += "<strong>Reason:</strong> Assertion failed.";
                if (line > 0) {
                    result += " at line " + line + " in file " + fileName + "\n";
                }
            } else if (!exception.isDeadlock()) {
                result += "<strong>Reason:</strong> Internal Error,\n";
            }
        }
        return result + "</body></html>";
    }

    /**
     * ABS exception instance of Java backend used to indicate a failure
     * situation
     */
    public ABSException getException() {
        return exception;
    }

    /* the name of the testmethod */
    public String getMethodName() {
        return testMethod;
    }

    /* returns the test status */
    public Status getStatus() {
        return status;
    }

    /* returns the id of the task running the test method */
    public int getTaskID() {
        return taskID;
    }

    /*
     * set the ABSException used by the Java backend to represent a failure
     * situation
     */
    public void setException(ABSException exception) {
        this.exception = exception;
    }

    /* sets the test status */
    public void setStatus(Status status) {
        this.status = status;
    }

    /* toString */
    public String toString() {
        String result = "";
        result += testMethod;
        if (getException() != null && getException().isAssertion()) {
            result += " at: " + getException().getMessage().substring(0, getException().getMessage().lastIndexOf(':'));
        }
        return result;
    }

    /**
     * called to update the current execution position of the test method the
     * information is used to identify the source code position of the failed
     * assertion
     */
    public void updatePos(String fileName, int line) {
        this.fileName = fileName;
        this.line = line;
    }
}
