package org.jboss.windup.reporting.ruleexecution;

import java.util.concurrent.atomic.AtomicInteger;

import org.jboss.forge.furnace.util.Assert;
import org.ocpsoft.rewrite.config.Rule;

import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Vertex;

/**
 * Contains information about a {@link Rule} and how it was executed by Windup (whether it was evaluated and executed, whether it failed, and various
 * statistics on what it performed.
 *
 * @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a>
 */
public class RuleExecutionInformation implements RuleExecutionInformationForReading {
    private final Rule rule;
    private boolean evaluationResult;
    private boolean executed;
    private boolean failed;
    private final AtomicInteger vertexIDsAdded = new AtomicInteger();
    private final AtomicInteger edgeIDsAdded = new AtomicInteger();
    private final AtomicInteger vertexIDsRemoved = new AtomicInteger();
    private final AtomicInteger edgeIDsRemoved = new AtomicInteger();

    private Throwable failureCause;

    /**
     * Create an instance for the provided rule.
     */
    public RuleExecutionInformation(Rule rule) {
        Assert.notNull(rule, "Rule object must not be null");
        this.rule = rule;
    }

    /**
     * Gets the {@link Rule}.
     */
    public Rule getRule() {
        return rule;
    }

    /**
     * Gets the result of the evaluation stage of the {@link Rule}. A false value here indicates that the "perform" function of the {@link Rule} would
     * not have executed.
     */
    public boolean getEvaluationResult() {
        return evaluationResult;
    }

    /**
     * Sets the result of the evaluation stage of the {@link Rule}. A false value here indicates that the "perform" function of the {@link Rule} would
     * not have executed.
     */
    void setEvaluationResult(boolean evaluationResult) {
        this.evaluationResult = evaluationResult;
    }

    /**
     * Gets an indication of whether or not this rule was executed by Windup.
     */
    public boolean isExecuted() {
        return executed;
    }

    /**
     * Sets the indication of whether or not this rule was executed by Windup.
     */
    void setExecuted(boolean executed) {
        this.executed = executed;
    }

    /**
     * Contains the failure status of the {@link Rule}.
     */
    public boolean isFailed() {
        return failed;
    }

    /**
     * Contains the failure status of the {@link Rule}.
     */
    void setFailed(boolean failed) {
        this.failed = failed;
    }

    /**
     * Contains the failure cause of the {@link Rule} (if any).
     */
    public Throwable getFailureCause() {
        return failureCause;
    }

    /**
     * Contains the failure cause of the {@link Rule} (if any).
     */
    void setFailureCause(Throwable failureCause) {
        this.failureCause = failureCause;
    }

    /**
     * Contains the IDs of any {@link Edge}s added by this {@link Rule}.
     */
    public int getEdgeIDsAdded() {
        return this.edgeIDsAdded.get();
    }

    /**
     * Contains the IDs of any {@link Vertex}s added by this {@link Rule}.
     */
    public int getVertexIDsAdded() {
        return this.vertexIDsAdded.get();
    }

    /**
     * Contains the IDs of any {@link Vertex} added by this {@link Rule}.
     */
    public void addVertexIDAdded(Object vID) {
        this.vertexIDsAdded.incrementAndGet();
    }

    /**
     * Contains the IDs of any {@link Edge}s added by this {@link Rule}.
     */
    public void addEdgeIDAdded(Object edgeID) {
        this.edgeIDsAdded.incrementAndGet();
    }

    /**
     * Contains the IDs of any {@link Edge}s removed by this {@link Rule}.
     */
    public int getEdgeIDsRemoved() {
        return this.edgeIDsRemoved.get();
    }

    /**
     * Contains the IDs of any {@link Vertex} removed by this {@link Rule}.
     */
    public int getVertexIDsRemoved() {
        return this.vertexIDsRemoved.get();
    }

    /**
     * Contains the IDs of any {@link Vertex} removed by this {@link Rule}.
     */
    public void addVertexIDRemoved(Object vID) {
        this.vertexIDsRemoved.incrementAndGet();
    }

    /**
     * Contains the IDs of any {@link Edge} removed by this {@link Rule}.
     */
    public void addEdgeIDRemoved(Object edgeID) {
        this.edgeIDsRemoved.incrementAndGet();
    }

    @Override
    public String toString() {
        return "RuleExecutionInformation [rule=" + rule + ", evaluationResult=" + evaluationResult + ", executed="
                + executed + ", failed=" + failed + ", failureCause=" + failureCause + "]";
    }
}
