package fr.inria.diversify.transformation;
import com.fasterxml.uuid.Generators;
import fr.inria.diversify.diversification.InputProgram;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import spoon.reflect.cu.SourcePosition;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.*;
/**
* User: Simon
* Date: 12/02/14
* Time: 10:44
*/
public abstract class Transformation {
//A global ID for the transformations. For our purposes is enough a simple global increment.
private static int globalID = 0;
//public default String getTransformationString() throws Exception {return "";}
public abstract String getTransformationString() throws Exception;
private static int id = 0;
//status of the transformation when transformation raises an exception
public static int EXCEPTION = -4;
//status of the transformation when the transformation has not been tested
public static int NOT_TESTED = -3;
public UUID getIndex() {
if ( index == null ) index = Generators.timeBasedGenerator().generate();
return index;
}
//status of the transformation when the transformation fails to compile
public static int COMPILED_FAIL = -2;
public void setIndex(UUID index) {
this.index = index;
}
//status of the transformation when the transformation's test fails
public static int TEST_FAIL = -1;
//sosie status for a transformation
public static int SOSIE = 0;
//sosie status for a transformation and transformation code executed
public static int EXE = 1;
/**
* An index to identify the transformation in the storage
*/
private UUID index = null;
/**
* The series number is an ID for a given serie containing this transformation.
*
* Remember that a series is a set of multi-sosies, each one being child of another in the set.
*/
private int series;
//Current status of the transformation
protected Integer status = NOT_TESTED;
//List of test failures as result of transforming the source code using the current transformation
protected List<String> failures = new ArrayList<>();
protected static Map<String,Integer> failuresDico = new HashMap<>();
//Name of the current transformation. More like a subtype
protected String name;
// type of the current transformation.
protected String type;
//Parent of the current transformation.
protected Transformation parent;
//input programs over which transformations are going to be perform
private InputProgram inputProgram;
public abstract void apply(String srcDir) throws Exception;
public abstract void applyWithParent(String srcDir) throws Exception;
public abstract void restore(String srcDir) throws Exception;
public JSONObject toJSONObject() throws JSONException {
JSONObject object = new JSONObject();
object.put("type", type);
object.put("name", name);
object.put("failures", failuresToJSON());
object.put("status", status);
if ( index == null ) {
globalID++;
index = Generators.timeBasedGenerator().generate();
}
object.put("tindex", index);
object.put("series", getSeries());
if(parent != null)
object.put("parent",parent.toJSONObject());
return object;
}
protected JSONArray failuresToJSON() {
JSONArray array = new JSONArray();
if(failures == null) {
return array;
}
for(String failure : failures) {
if(failure != null) {
if (!failuresDico.containsKey(failure)) {
failuresDico.put(failure, id);
id++;
}
array.put(failuresDico.get(failure));
}
}
return array;
}
public int hashCode() {
return name.hashCode() * type.hashCode() + status.hashCode() + failures.hashCode();
}
public void setParent(Transformation parent) {
this.parent = parent;
}
public Transformation getParent() {
return parent;
}
/**
* indicate if the other transformation shares the same parent
* @param otherParent transformation to which we want to check
* @return
*/
protected boolean equalParent(Transformation otherParent) {
if(parent != null)
return parent.equals(otherParent);
if(otherParent != null)
return otherParent.equals(parent);
return true;
}
/**
* The series number is an ID for a given serie containing this transformation.
*
* Remember that a series is a set of multi-sosies, each one being child of another in the set.
*/
public int getSeries() {
return series;
}
public void setSeries(int series) {
this.series = series;
}
public void setInputProgram(InputProgram inputProgram) {
this.inputProgram = inputProgram;
}
/**
* Global input configuration
*/
public InputProgram getInputProgram() {
return inputProgram;
}
public void setStatus(Integer result) {
status = result;
}
/**
* Current status of the transformation
*/
public int getStatus() {
return status;
}
/**
* indicate if this transformation is a Sosie
* @return
*/
public boolean isSosie() { return status == SOSIE; }
public void setFailures(List<String> f) {
failures = f;
}
public List<String> getFailures() {
return failures;
}
public String getType() {
return type;
}
public String getName() {
return name;
}
public static void setFailuresDico(Map<String, Integer> failuresDico) {
Transformation.failuresDico = failuresDico;
}
public abstract SourcePosition getPosition();
}