package de.dhbwstuttgart.syntaxtree.type;

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

public abstract class RefTypeOrTPHOrWildcardOrGeneric extends SyntaxTreeNode implements ISerializableData {
    public RefTypeOrTPHOrWildcardOrGeneric(Token offset) {
        super(offset);
    }

    @Override
    public abstract void accept(ASTVisitor visitor);

    public abstract <A> A acceptTV(TypeVisitor<A> visitor);
    public abstract void accept(ResultSetVisitor visitor);
    
    @Override
    public abstract boolean equals(Object o);

    @Override
    public ISerialNode toSerial(KeyStorage keyStorage) {
        SerialMap serialized = new SerialMap();
        serialized.put("type", this.getClass().getSimpleName());
          // we only insert null for the object and expect the child classes to call this and override the value with themselves
        serialized.put("object", SerialValue.NULL);
        return serialized;
    }

    public static RefTypeOrTPHOrWildcardOrGeneric fromSerial(SerialMap data, UnifyContext context) {
        String type = data.getValue("type").getOf(String.class);
        SerialMap object = data.getMap("object");

        if      (type.equals(ExtendsWildcardType.class.getSimpleName()))    return ExtendsWildcardType.fromSerial(object, context);
        else if (type.equals(GenericRefType.class.getSimpleName()))         return GenericRefType.fromSerial(object, context);
        else if (type.equals(SuperWildcardType.class.getSimpleName()))      return SuperWildcardType.fromSerial(object, context);
        else if (type.equals(RefType.class.getSimpleName()))                return RefType.fromSerial(object, context);
        else if (type.equals(Void.class.getSimpleName()))                   return Void.fromSerial(object, context);
        else if (type.equals(TypePlaceholder.class.getSimpleName()))        return TypePlaceholder.fromSerial(object, context);
        else throw new RuntimeException("Could not unserialize class of unhandled type " + type);
    }
}
