/**
 * Copyright (c) 2005 by Kevin Bierhoff
 */
package edu.cmu.cs.l3.trace;

import java.io.Serializable;
import java.io.IOException;


/**
 * @author Kevin
 *
 */
public class PathGraphEdge implements Serializable {
	
	/** The graph this edge belongs to. */
	private PathGraph graph;
	
	/** Origin vertex. */
	private PathGraphVertex origin;
	
	/** Target vertex. */
	private PathGraphVertex target;
	
	// added to distinguish different kinds of edges better
	/** The back edge this edge replaces. */
	private BackEdge backEdge;
	
	/** Indicates actual CFG edges. */
	private boolean programEdge;
	
	
	/** Edge value as defined by Ball & Larus. */
	private int value;
	
	/** Edge increment as defined by Ball & Larus. */
	private int increment;
	
	/** Indicates the spanning edges of the graph. */
	private boolean spanning = false;

	/**
	 * 
	 */
	public PathGraphEdge(PathGraph graph, PathGraphVertex origin, PathGraphVertex target, boolean programEdge) {
		super();
		this.graph = graph;
		this.origin = origin;
		this.target = target;
		this.backEdge = null;
		this.programEdge = programEdge;
		
		origin.addOutgoing(this);
		target.addIncoming(this);
	}
	
	/**
	 * 
	 */
	public PathGraphEdge(PathGraph graph, PathGraphVertex origin, PathGraphVertex target, BackEdge backEdge) {
		super();
		this.graph = graph;
		this.origin = origin;
		this.target = target;
		this.backEdge = backEdge;
		this.programEdge = false;
		
		origin.addOutgoing(this);
		target.addIncoming(this);
	}
	
	/**
	 * @return Returns the origin.
	 */
	public PathGraphVertex getOrigin() {
		return origin;
	}

	/**
	 * @return Returns the target.
	 */
	public PathGraphVertex getTarget() {
		return target;
	}

	/**
	 * @return Returns the backEdge.
	 */
	public BackEdge getBackEdge() {
		return backEdge;
	}

	/**
	 * @param backEdge The backEdge to set.
	 */
	protected void setBackEdge(BackEdge backEdge) {
		this.backEdge = backEdge;
	}

	/**
	 * Indicates whether this edge is an actual (forward) edge in the CFG.
	 * @return Returns the programEdge.
	 */
	public boolean isProgramEdge() {
		return programEdge;
	}
	
	/**
	 * Indicates whether this (dummy) edge replaces a loop back edge.
	 * @return
	 */
	public boolean isLoopEdge() {
		return backEdge != null;
	}
	
	/**
	 * Indicates whether this edge is the unique cycle edge in the graph.
	 * @return
	 */
	public boolean isCycleEdge() {
		return origin == graph.getExitVertex() && target == graph.getEntryVertex();
	}
	
	/**
	 * Indicates whether this edge "skips" part of the function for incremental profiling.
	 * @return
	 */
	public boolean isSkipEdge() {
		return ! programEdge && ! isCycleEdge() && backEdge == null;
	}

	/**
	 * @return Returns the increment.
	 */
	public int getIncrement() {
		return increment;
	}

	/**
	 * @param increment The increment to set.
	 */
	public void setIncrement(int increment) {
		this.increment = increment;
	}

	/**
	 * @return Returns the value.
	 */
	public int getValue() {
		return value;
	}

	/**
	 * @param numPaths The value to set.
	 */
	public void setValue(long value) {
		this.value = (int) value;
	}

	/**
	 * @return Returns the spanning.
	 */
	public boolean isSpanning() {
		return spanning;
	}

	/**
	 * @param spanning The spanning to set.
	 */
	public void setSpanning(boolean spanning) {
		this.spanning = spanning;
	}
	
	public String toString() {
		String kind = "";
		if(isProgramEdge()) kind = " prog";
		if(isCycleEdge()) kind = " cycl";
		if(isLoopEdge()) kind = " loop";
		if(isSkipEdge()) kind = " skip";
		return "(" + origin + "," + target + ")" + kind;
	}

    /** Serialization code */
    private int origin_ind, target_ind;
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
	out.writeObject(new Boolean(programEdge));
	out.writeObject(new Integer(value));
	out.writeObject(new Integer(increment));
	out.writeObject(new Boolean(spanning));
	out.writeObject(new Integer(graph.getIndex(origin)));
	out.writeObject(new Integer(graph.getIndex(target)));
    }
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
	programEdge = ((Boolean) in.readObject()).booleanValue();
	value = ((Integer) in.readObject()).intValue();
	increment = ((Integer) in.readObject()).intValue();
	spanning = ((Boolean) in.readObject()).booleanValue();
	origin_ind = ((Integer) in.readObject()).intValue();
	target_ind = ((Integer) in.readObject()).intValue();
    }

    /**
     * private functions related to resetting edge after serialization
     */
    protected void setPathGraph(PathGraph pg) {
	graph = pg;
	origin = graph.getVertex(origin_ind);
	target = graph.getVertex(target_ind);
    }

}
