package de.dhbwstuttgart.syntaxtree.type;


import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.server.packet.dataContainers.ISerializableData;
import de.dhbwstuttgart.server.packet.dataContainers.KeyStorage;
import de.dhbwstuttgart.server.packet.dataContainers.serialized.SerialMap;
import de.dhbwstuttgart.syntaxtree.ASTVisitor;
import de.dhbwstuttgart.typeinference.result.ResultSetVisitor;
import de.dhbwstuttgart.typeinference.unify.UnifyContext;
import org.antlr.v4.runtime.Token;

import java.util.Objects;

/**
 *  Stellt eine Wildcard mit unterer Grenze dar.
 *  z.B. void test(? super Integer var){..}
 *   ... 
 * @author luar 2.12.06
 * 
 */

public class SuperWildcardType extends WildcardType implements ISerializableData {

	/**
	* Author: Arne LÃ¼dtke<br/>
	* Standard Konstruktor fÃ¼r eine SuperWildcard
	*/
	public SuperWildcardType( RefTypeOrTPHOrWildcardOrGeneric innerType, Token offset)
	{
		super(innerType, offset);
	}
	
	/**
	* Author: Arne LÃ¼dtke<br/>
	* Gibt den Typen in der Wildcard zurÃ¼ck.
	* Beispiel: ? super Integer.
	* Integer wird zurÃ¼ckgegeben.
	*/
	public RefTypeOrTPHOrWildcardOrGeneric getInnerType()
	{
		return this.innerType;
	}

	@Override
	public String toString() {
		return "? super "+innerType.toString();
	}

	@Override
	public boolean isExtends() {
		return false;
	}

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

	@Override
	public void accept(ASTVisitor visitor) {
		visitor.visit(this);
	}

	@Override
	public <A> A acceptTV(TypeVisitor<A> visitor) {
		return visitor.visit(this);
	}

	@Override
	public void accept(ResultSetVisitor visitor) {
		visitor.visit(this);
	}

	@Override
	public int hashCode() {
		return Objects.hashCode(this.innerType);
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		SuperWildcardType that = (SuperWildcardType) o;
		return that.innerType.equals(this.innerType);
	}

	@Override
	public SerialMap toSerial(KeyStorage keyStorage) {
		SerialMap serialized = new SerialMap();
		serialized.put("innerType", this.innerType.toSerial(keyStorage));

		// create the wrapper and put this as the object
		var serializedWrapper = super.toSerial(keyStorage).assertType(SerialMap.class);
		serializedWrapper.put("object", serialized);
		return serializedWrapper;
	}

	public static SuperWildcardType fromSerial(SerialMap data, UnifyContext context) {
		return new SuperWildcardType(
			RefTypeOrTPHOrWildcardOrGeneric.fromSerial(data.getMap("innerType"), context),
			new NullToken()
		);
	}
}
