package strucTypes5;

import de.dhbwstuttgart.parser.JavaTXParser;
import de.dhbwstuttgart.strucTypes3.SubTypeConstraint;
import de.dhbwstuttgart.strucTypes5.algo.TI;
import de.dhbwstuttgart.strucTypes5.assumptions.AssumptionMap;
import de.dhbwstuttgart.strucTypes5.constraints.*;
import de.dhbwstuttgart.strucTypes5.solve.Ruler;
import de.dhbwstuttgart.strucTypes5.solve.Rules;
import de.dhbwstuttgart.strucTypes5.typeVars.*;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import org.junit.Test;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

/**
 * Dieser Test prï¿½ft nur, ob .java-Dateien fehlerfrei geparst werden. Der
 * dabei erstellte Syntaxbaum wird nicht kontrolliert.
 * 
 * @author janulrich
 *
 */
public class SolveTest {
	private static final String rootDirectory = System.getProperty("user.dir") + "/test/strucTypes5/";

	@Test
	public void run() {


		List<String> filenames = new ArrayList<String>();
		filenames.add("SolveTest.jav");

		JavaTXParser parser = new JavaTXParser();
		try {
			for (String filename : filenames) {

				System.out.println("Teste: " + filename);

				SourceFile sf = parser.parse(new File(rootDirectory + filename));

				SourceFile sfdebug = sf;

				ClassOrInterface mainClass = sf.getClasses().get(0);
				ClassOrInterface aClass = sf.getClasses().get(1);


				AssumptionMap assumptionMap = new AssumptionMap();

				TI ti = new TI(assumptionMap, aClass);

				TI ti1 = new TI(ti.assresult, mainClass);

				// Take The Generatet Constraints from ti:
				// Try To Solve

				System.out.println("\n \n \n \n  Starte einfach Unifikation ");
				System.out.println("Gegegeben Constraints: " + ti1.resultConstraints);

				// Generate Interfaces Give
				TypeVarRefType myInteger = (TypeVarRefType) getTypeVar(ti1.resultConstraints , "TVar_MyInteger");
				TypeVarAbstract v2 = getTypeVar(ti1.resultConstraints , "TVar_2");
				TypeVarAbstract v5 = getTypeVar(ti1.resultConstraints , "TVar_5");
				System.out.println(myInteger.toString());
				System.out.println(v2.toString());
				System.out.println(v5.toString());

				// Generiere Interface 1
				List<TypeVarAbstract> generics = new ArrayList<>();
				generics.add(TypeVarFactory.makeTypeVar(myInteger.getRefType()));
				generics.add(TypeVarFactory.makeTypeVar(myInteger.getRefType()));
				InterfaceForConstraint if1 = new InterfaceForConstraint(v2, generics);
				ConstraintInterface constraintInterface = new ConstraintInterface(TypeVarFactory.makeTypeVar(myInteger.getRefType()) , TypeVarFactory.makeTypeVar(if1) );
				List<ConstraintInterface> interfaces = new ArrayList<>();
				interfaces.add(constraintInterface);


				// Generiere Interface 2
				List<TypeVarAbstract> generics2 = new ArrayList<>();
				generics2.add(TypeVarFactory.makeTypeVar(myInteger.getRefType()));
				generics2.add(TypeVarFactory.makeTypeVar(myInteger.getRefType()));
				InterfaceForConstraint if2 = new InterfaceForConstraint(v5, generics);
				ConstraintInterface constraintInterface2 = new ConstraintInterface(TypeVarFactory.makeTypeVar(myInteger.getRefType()) , TypeVarFactory.makeTypeVar(if2) );
				interfaces.add(constraintInterface2);

				System.out.println(interfaces);


				System.out.println("Manuell Test");

				/*
				Rules rules = new Rules();
				rules.setConstraintInterfaces(interfaces);



				System.out.println(ti1.resultConstraints);

				rules.adapt2(ti1.resultConstraints);
				System.out.println(ti1.resultConstraints);

				rules.swap(ti1.resultConstraints);
				System.out.println(ti1.resultConstraints);

				rules.swap(ti1.resultConstraints);
				System.out.println(ti1.resultConstraints);

				rules.subst(ti1.resultConstraints);
				System.out.println(ti1.resultConstraints);

				rules.subst(ti1.resultConstraints);
				System.out.println(ti1.resultConstraints);


				System.out.println(rules.substitutions);

				*/


				List<ConstraintSubstitution> substitutions = new ArrayList<>();
				Ruler ruler = new Ruler(interfaces,substitutions,ti1.resultConstraints);

				System.out.println("start ...");


				while (ti1.resultConstraints.size() > 0) {
					ruler.rule();
				}




			}




		} catch (Exception exc) {
			exc.printStackTrace();
			fail();
		}
		assertTrue("Tests durchlaufen", filenames.size() > 0);
	}

	private TypeVarAbstract getTypeVar(List<ConstraintAbstract> constraints , String name) {
		for (ConstraintAbstract cs : constraints) {
			if (cs instanceof ConstraintSubType) {
				ConstraintSubType css = (ConstraintSubType) cs;
				if (css.getSubtype().toString().equals(name)) {
					return css.getSubtype();
				}
				else if (css.getSuperType().toString().equals(name)) {
					return css.getSuperType();
				}
				else if (css.getSuperType() instanceof TypeVarInterface) {
					TypeVarInterface tcv = (TypeVarInterface) css.getSuperType();
					if (tcv.getInterfaceForConstraint().getStrucType().toString().equals(name)) {
						return tcv.getInterfaceForConstraint().getStrucType();
					}
				}
			}
		}
		return null;
	}
}
