// Path: src/main/java/heapdl/io/HeapDatabaseConsumer.java
// public interface HeapDatabaseConsumer {
//     /**
//      * Record a tuple in a table.
//      *
//      * @param table   the table
//      * @param arg     the value of the first column
//      * @param args    the values of the rest of the columns
//      */
//     void add(PredicateFile table, String arg, String... args);
// 
//     /**
//      * Finish writing to the database.
//      *
//      * @throws IOException if the operation failed
//      */
//     void finishWriting() throws IOException;
// }
// 
// Path: src/main/java/heapdl/io/PredicateFile.java
// public enum PredicateFile {
//     DYNAMIC_NORMAL_HEAP_OBJECT("DynamicNormalHeapObject"),
//     DYNAMIC_STRING_HEAP_OBJECT("DynamicStringHeapObject"),
//     DYNAMIC_STATIC_FIELD_POINTS_TO("DynamicStaticFieldPointsTo"),
//     DYNAMIC_INSTANCE_FIELD_POINTS_TO("DynamicInstanceFieldPointsTo"),
//     DYNAMIC_ARRAY_INDEX_POINTS_TO("DynamicArrayIndexPointsTo"),
//     DYNAMIC_VAR_POINTS_TO("DynamicVarPointsTo"),
//     DYNAMIC_REACHABLE_METHOD("DynamicReachableMethod"),
//     DYNAMIC_CALL_GRAPH_EDGE("DynamicCallGraphEdge"),
//     DYNAMIC_NORMAL_HEAP_ALLOCATION("DynamicNormalHeapAllocation"),
//     DYNAMIC_CONTEXT("DynamicContext"),
//     STRING_CONST("StringConstant"),
//     STRING_RAW("StringRaw");
// 
//     private final String name;
// 
//     PredicateFile(String name) {
//         this.name = name;
//     }
// 
//     @Override
//     public String toString() {
//         return  name;
//     }
// 
//     public Writer getWriter(File directory, String suffix) throws IOException {
//         File factsFile = new File(directory, name + suffix);
//         FileUtils.touch(factsFile);
//         return new FileWriter(factsFile, true);
//     }
// }


import heapdl.io.HeapDatabaseConsumer;
import heapdl.io.PredicateFile;
package heapdl.core;


/**
 * Created by neville on 15/03/2017.
 */
public class DoubleContext<T extends ComposableContext> implements Context {

    private final T ctx1;
    private final T ctx2;
    private final String representation;

    public DoubleContext(T ctx1, T ctx2) {
        this.ctx1 = ctx1;
        this.ctx2 = ctx2;
        this.representation = ctx1.getRepresentation() + "..." + ctx2.getRepresentation();
    }

    @Override
    public final void write_fact(HeapDatabaseConsumer db) {
        String[] args = DEFAULT_CTX_ARGS.clone();

        for (int i = 0, j = ctx1.getStartIndex();
             i < ctx1.getComponents().length;
             i++, j++)
            args[j] = ctx1.getComponents()[i];


        for (int i = 0, j = ctx2.getStartIndex() + ctx2.getComponents().length;
             i < ctx2.getComponents().length;
             i++, j++)
// Path: src/main/java/heapdl/io/HeapDatabaseConsumer.java
// public interface HeapDatabaseConsumer {
//     /**
//      * Record a tuple in a table.
//      *
//      * @param table   the table
//      * @param arg     the value of the first column
//      * @param args    the values of the rest of the columns
//      */
//     void add(PredicateFile table, String arg, String... args);
// 
//     /**
//      * Finish writing to the database.
//      *
//      * @throws IOException if the operation failed
//      */
//     void finishWriting() throws IOException;
// }
// 
// Path: src/main/java/heapdl/io/PredicateFile.java
// public enum PredicateFile {
//     DYNAMIC_NORMAL_HEAP_OBJECT("DynamicNormalHeapObject"),
//     DYNAMIC_STRING_HEAP_OBJECT("DynamicStringHeapObject"),
//     DYNAMIC_STATIC_FIELD_POINTS_TO("DynamicStaticFieldPointsTo"),
//     DYNAMIC_INSTANCE_FIELD_POINTS_TO("DynamicInstanceFieldPointsTo"),
//     DYNAMIC_ARRAY_INDEX_POINTS_TO("DynamicArrayIndexPointsTo"),
//     DYNAMIC_VAR_POINTS_TO("DynamicVarPointsTo"),
//     DYNAMIC_REACHABLE_METHOD("DynamicReachableMethod"),
//     DYNAMIC_CALL_GRAPH_EDGE("DynamicCallGraphEdge"),
//     DYNAMIC_NORMAL_HEAP_ALLOCATION("DynamicNormalHeapAllocation"),
//     DYNAMIC_CONTEXT("DynamicContext"),
//     STRING_CONST("StringConstant"),
//     STRING_RAW("StringRaw");
// 
//     private final String name;
// 
//     PredicateFile(String name) {
//         this.name = name;
//     }
// 
//     @Override
//     public String toString() {
//         return  name;
//     }
// 
//     public Writer getWriter(File directory, String suffix) throws IOException {
//         File factsFile = new File(directory, name + suffix);
//         FileUtils.touch(factsFile);
//         return new FileWriter(factsFile, true);
//     }
// }


// Path: src/main/java/heapdl/core/DoubleContext.java
import heapdl.io.HeapDatabaseConsumer;
import heapdl.io.PredicateFile;

package heapdl.core;


/**
 * Created by neville on 15/03/2017.
 */
public class DoubleContext<T extends ComposableContext> implements Context {

    private final T ctx1;
    private final T ctx2;
    private final String representation;

    public DoubleContext(T ctx1, T ctx2) {
        this.ctx1 = ctx1;
        this.ctx2 = ctx2;
        this.representation = ctx1.getRepresentation() + "..." + ctx2.getRepresentation();
    }

    @Override
    public final void write_fact(HeapDatabaseConsumer db) {
        String[] args = DEFAULT_CTX_ARGS.clone();

        for (int i = 0, j = ctx1.getStartIndex();
             i < ctx1.getComponents().length;
             i++, j++)
            args[j] = ctx1.getComponents()[i];


        for (int i = 0, j = ctx2.getStartIndex() + ctx2.getComponents().length;
             i < ctx2.getComponents().length;
             i++, j++)
            args[j] = ctx2.getComponents()[i];