package de.uni_hildesheim.sse.trans;

import java.io.File;
import java.io.StringWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.Assert;

import de.uni_hildesheim.sse.model.varModel.IvmlKeyWords;
import de.uni_hildesheim.sse.trans.convert.OptimizationParameter;
import de.uni_hildesheim.sse.trans.in.InputType;
import de.uni_hildesheim.sse.trans.out.DimacsWriter;
import de.uni_hildesheim.sse.trans.out.OutputType;

/**
 * Helping methods for testing translation into dimacs.
 * @author El-Sharkawy
 *
 */
public class DimacsTestUtils {
    
    /**
     * Unused constructor.
     */
    private DimacsTestUtils() {
        // Not needed as this is only a utility class with static methods.
    }

    /**
     * Loads the given input file and transforms it into a DIMACS model using the given <tt>optimizations</tt>.
     * @param input The input file to load (must exist).
     * @param optimizations Specification which optimizations shall be applied to the transformed model. Will only be
     *     applied to transformations into CNF.
     * @param removePreamble <tt>true</tt> the preamble (comment, version, and a help information) will be removed
     *     from the beginning of this string). 
     * @return The translated DIMACS model.
     */
    public static String loadModel(File input, OptimizationParameter optimizations, boolean removePreamble) {
        String comment = "A comment";
        String version = "0.1";
        StringWriter sWriter = new StringWriter();
        
        // Test precondition
        Assert.assertTrue(input.exists());
        
        // Translation
        ModelTranslator.translate(input, sWriter, InputType.RSF, OutputType.DIMCAS, comment, version, optimizations);
        String result = sWriter.toString();
        
        // Test correct translation of comment, version, and help
        Assert.assertNotNull(result);
        Assert.assertTrue("Error in preamble.",
            result.startsWith(
                "c " + comment + IvmlKeyWords.LINEFEED
                + "c Version " + version + IvmlKeyWords.LINEFEED
                + DimacsWriter.HELP));
        
        if (removePreamble) {
            result = removePreamble(result);
        }

        /*
         * Test found bugs:
         */
        // Test correct translation of negative values (-- must not occur)
        int beginningOfConstraints = result.indexOf("p cnf");
        int minusMinus = result.indexOf("--", beginningOfConstraints);
        if (-1 != minusMinus) {
            Assert.fail("Error: \"--\" found in a constraint at " + minusMinus + ", but must not occur.");
        }
        
        return result;
    }
    
    /**
     * Removes the preamble of a already translated dimacs model.
     * @param dimacsModel The model where the preamble shall be deleted
     * @return Only the relevant information of the translated dimacs model.
     */
    private static String removePreamble(String dimacsModel) {
        int beginning = dimacsModel.indexOf(DimacsWriter.HELP);
        return dimacsModel.substring(beginning + DimacsWriter.HELP.length());
    }
    
    /**
     * Returns the DIMACs number of the given variable which is used inside the constraints.
     * @param dimacsModel The complete dimacs model
     * @param variable The variable for which the number shall be retrieved.
     * @return The number of the variable used inside the constraints.
     */
    public static int getNumberOfVariable(String dimacsModel, String variable) {
        Pattern dimacsVarDefintion = Pattern.compile("(?m)^c (\\d+) " + variable + "$");
        Matcher m = dimacsVarDefintion.matcher(dimacsModel);
        String result = null;
        if (m.find()) {
            result = m.group(1);
        }
        
        Assert.assertNotNull("Error: Variable not found.", result);
        
        
        return Integer.valueOf(result);
    }
    
    /**
     * Checks whether a given constraint is included in <tt>dimacsModel</tt>.
     * @param dimacsModel The complete dimacs model
     * @param literals positive and negative variable numbers (must not be 0).
     * @return <tt>true</tt> if the constraint is included in <tt>dimacsModel</tt>.
     */
    public static boolean containsConstraint(String dimacsModel, int... literals) {
        StringBuffer constraintDef = new StringBuffer("(?m)^(");
        constraintDef.append(literals[0]);
        constraintDef.append(" ");
        for (int i = 1; i < literals.length; i++) {
            constraintDef.append("|");
            constraintDef.append(literals[i]);
            constraintDef.append(" ");
        }
        constraintDef.append("){");
        constraintDef.append(literals.length);
        constraintDef.append("}0$");
        
        Pattern constraintDefinition = Pattern.compile(constraintDef.toString());
        Matcher m = constraintDefinition.matcher(dimacsModel);
        return m.find();
    }
}
