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 oberer Grenze dar.
 *  z.B. void test(? extends Number var){..}
 *   ... 
 * @author luar 2.12.06
 * 
 */

public class ExtendsWildcardType extends WildcardType implements ISerializableData {
	
	/**
	* Author: Arne LÃ¼dtke<br/>
	* Standard Konstruktor fÃ¼r eine ExtendsWildcard
	*/
	public ExtendsWildcardType (RefTypeOrTPHOrWildcardOrGeneric extendsType, Token offset)
	{
		super(extendsType, offset);
	}

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

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

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

	@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;
		ExtendsWildcardType that = (ExtendsWildcardType) 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 ExtendsWildcardType fromSerial(SerialMap data, UnifyContext context) {
		return new ExtendsWildcardType(
			RefTypeOrTPHOrWildcardOrGeneric.fromSerial(data.getMap("innerType"), context),
			new NullToken()
		);
	}
}
