package at.ac.tuwien.kr.alpha.common.terms;

import at.ac.tuwien.kr.alpha.common.Interner;
import at.ac.tuwien.kr.alpha.grounder.Substitution;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Copyright (c) 2016, the Alpha Team.
 */
public class ConstantTerm<T extends Comparable<T>> implements Term {
	private static final Interner<ConstantTerm> INTERNER = new Interner<>();

	public T getObject() {
		return object;
	}

	private final T object;

	private ConstantTerm(T object) {
		this.object = object;
	}

	public static <T extends Comparable<T>> ConstantTerm getInstance(T object) {
		return INTERNER.intern(new ConstantTerm<>(object));
	}

	@Override
	public boolean isGround() {
		return true;
	}

	@Override
	public List<VariableTerm> getOccurringVariables() {
		return Collections.emptyList();
	}

	@Override
	public Term substitute(Substitution substitution) {
		return this;
	}

	@Override
	public String toString() {
		return object.toString();
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}

		if (o == null || getClass() != o.getClass()) {
			return false;
		}

		ConstantTerm that = (ConstantTerm) o;

		return object.equals(that.object);
	}

	@Override
	public int hashCode() {
		return object.hashCode();
	}

	private static final Map<Class<?>, Integer> PRIORITY = new HashMap<>();

	static {
		PRIORITY.put(Integer.class, 0);
		PRIORITY.put(String.class, 1);
	}

	@Override
	public int compareTo(Term o) {
		if (o instanceof ConstantTerm) {
			ConstantTerm otherConstantTerm = (ConstantTerm) o;

			if (otherConstantTerm.object.getClass() == this.object.getClass()) {
				return this.object.compareTo((T) otherConstantTerm.object);
			}

			int myPrio = PRIORITY.getOrDefault(this.object.getClass(), Integer.MAX_VALUE);
			int otherPrio = PRIORITY.getOrDefault(otherConstantTerm.object.getClass(), Integer.MAX_VALUE);

			if (myPrio == otherPrio) {
				throw new RuntimeException("WUT");
			}

			return myPrio - otherPrio;
		}
		if (o instanceof FunctionTerm) {
			return -1;
		}
		if (o instanceof VariableTerm) {
			return -1;
		}
		throw new UnsupportedOperationException("Comparison of terms is not fully implemented.");
	}
}

@@ -1479,32 +1479,64 @@
 %0A%09%7D%0A%0A%09@Override%0A
+%09@SuppressWarnings(%22unchecked%22)%0A
 %09public int comp
@@ -1574,45 +1574,234 @@
 eof 
-ConstantTerm) %7B%0A%09%09%09ConstantTerm other
+FunctionTerm) %7B%0A%09%09%09return -1;%0A%09%09%7D%0A%09%09if (o instanceof VariableTerm) %7B%0A%09%09%09return -1;%0A%09%09%7D%0A%0A%09%09if (!(o instanceof ConstantTerm)) %7B%0A%09%09%09throw new UnsupportedOperationException(%22Comparison of terms is not fully implemented.%22);%0A%09%09%7D%0A%0A%09%09
 Cons
@@ -1809,16 +1809,22 @@
 antTerm 
+other 
 = (Const
@@ -1842,30 +1842,578 @@
 %0A%0A%09%09
-%09if (otherConstantTerm
+// We will perform an unchecked cast.%0A%09%09// Because of type erasure, we cannot know the exact type%0A%09%09// of other.object.%0A%09%09// However, may assume that other.object actually is of%0A%09%09// type T.%0A%09%09// We know that this.object if of type T and implements%0A%09%09// Comparable%3CT%3E. We ensure that the class of other.object%0A%09%09// equals the class of this.object, which in turn is T.%0A%09%09// That assumption should be quite safe. It can only be%0A%09%09// wrong if we have some bug that generates strange%0A%09%09// ConstantTerms at runtime, bypassing the check for T%0A%09%09// at compile-time.%0A%09%09if (other
 .obj
@@ -2459,17 +2459,16 @@
 )) %7B%0A%09%09%09
-%09
 return t
@@ -2493,36 +2493,24 @@
 To((T) other
-ConstantTerm
 .object);%0A%09%09
@@ -2509,21 +2509,19 @@
 ect);%0A%09%09
-%09
 %7D%0A%0A
-%09
 %09%09int my
@@ -2595,17 +2595,16 @@
 LUE);%0A%09%09
-%09
 int othe
@@ -2638,28 +2638,16 @@
 lt(other
-ConstantTerm
 .object.
@@ -2681,17 +2681,16 @@
 UE);%0A%0A%09%09
-%09
 if (myPr
@@ -2708,17 +2708,16 @@
 Prio) %7B%0A
-%09
 %09%09%09throw
@@ -2748,21 +2748,19 @@
 UT%22);%0A%09%09
-%09
 %7D%0A%0A
-%09
 %09%09return
@@ -2784,210 +2784,8 @@
 io;%0A
-%09%09%7D%0A%09%09if (o instanceof FunctionTerm) %7B%0A%09%09%09return -1;%0A%09%09%7D%0A%09%09if (o instanceof VariableTerm) %7B%0A%09%09%09return -1;%0A%09%09%7D%0A%09%09throw new UnsupportedOperationException(%22Comparison of terms is not fully implemented.%22);%0A
 %09%7D%0A%7D

Clarify unchecked cast