package com.github.meteoorkip.utils;

import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import com.github.meteoorkip.prolog.TuProlog;
import org.graphstream.graph.Element;

import javax.swing.*;
import java.awt.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.github.meteoorkip.prolog.TuProlog.*;
import static com.github.meteoorkip.utils.TermUtils.elementTerm;
import static org.junit.Assert.assertEquals;

public final class TestUtils {

    public static boolean mapContains(Map<String, Term> map, String key, Term value) {
        return map.containsKey(key) && map.get(key).equals(value);
    }

    public static boolean mapContains(Map<String, Term> haystack, Map<String, Term> needle) {
        return haystack.entrySet().containsAll(needle.entrySet());
    }

    public static boolean answerContains(Collection<Map<String, Term>> answers, String... kvPairs) throws Exception {
        Map<String, Term> needle = new HashMap<>();
        if (kvPairs.length % 2 != 0)
            throw new Exception("kvPairs must be even");
        for (int i = 0; i < kvPairs.length; i += 2) {
            String k = kvPairs[i];
            String v = kvPairs[i + 1];
            needle.put(k, term(v));
        }
        for (Map<String, Term> answer : answers) {
            if (mapContains(answer, needle))
                return true;
        }
        return false;
    }

    public static void testPredicateValue(TuProlog prolog, Element element, String predicate, String expectedID, String expectedValue) {
        Collection<Map<String, Term>> answers = prolog.solve(and(elementTerm(element), struct(predicate, term(expectedID), var("Value"))));
        assert answers.size() == 1;
        try {
            assert answerContains(answers, "Value", expectedValue);
        } catch (Exception | AssertionError e) {
            e.printStackTrace();
            throw new AssertionError();
        }
    }

    public static void testAttributesCorrect(TuProlog prolog, Element element) {
        element.getAttributeKeySet().forEach(
                attributeKey -> {

                    List<Map<String, Term>> answers = prolog.solve(and(elementTerm(element), struct("attribute", struct(element.getId()), struct("\"" + attributeKey + "\""), var("Value"))));
                    String expectedValue = StringUtils.ObjectToString(element.getAttribute(attributeKey));
                    if (StringUtils.isDouble(StringUtils.removeQuotation(expectedValue)) || expectedValue.contains("[")) {
                        return;
                    }
                    try {
                        assert answerContains(answers, "Value", expectedValue) || ((Struct) answers.get(0).get("Value")).getName().equals(expectedValue);
                    } catch (Exception e) {
                        e.printStackTrace();
                        assert false;
                    } catch (AssertionError e) {
                        throw new AssertionError(answers + " does not contain " + expectedValue);
                    }
                }
        );
    }


    public static void testSimpleFact(TuProlog prolog, Element element, String predicate, String expectedID, boolean shouldExist) {
        assertEquals(shouldExist, !prolog.solve(and(elementTerm(element), struct(predicate, term(expectedID)))).isEmpty());
    }


    public static void showImage(Image image) {
        JFrame f = new JFrame();
        JLabel label = new JLabel();
        label.setIcon(new ImageIcon(image));
        f.add(label);
        f.setVisible(true);
        f.pack();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

@@ -1714,32 +1714,50 @@
 ar(%22Value%22))));%0A
+        try %7B%0A    
         assert a
@@ -1776,30 +1776,16 @@
 ) == 1;%0A
-        try %7B%0A
         
@@ -1875,25 +1875,8 @@
 ion 
-%7C AssertionError 
 e) %7B
@@ -1945,24 +1945,255 @@
 ionError();%0A
+        %7D catch (AssertionError e) %7B%0A            e.printStackTrace();%0A            throw new AssertionError((and(elementTerm(element), struct(predicate, term(expectedID), var(%22Value%22))).toString()) + %22 did not yield any results.%22);%0A
         %7D%0A  

Improve method for easier debug