package de.dhbwstuttgart.target.tree.type;

import de.dhbwstuttgart.syntaxtree.type.RefType;

public sealed interface TargetType
        permits TargetExtendsWildcard, TargetGenericType, TargetSpecializedType, TargetSuperWildcard, TargetPrimitiveType {

    // Builtin types
    TargetRefType Boolean  = new TargetRefType("java.lang.Boolean");
    TargetRefType Char     = new TargetRefType("java.lang.Character");
    TargetRefType Byte     = new TargetRefType("java.lang.Byte");
    TargetRefType Short    = new TargetRefType("java.lang.Short");
    TargetRefType Integer  = new TargetRefType("java.lang.Integer");
    TargetRefType Long     = new TargetRefType("java.lang.Long");
    TargetRefType Float    = new TargetRefType("java.lang.Float");
    TargetRefType Double   = new TargetRefType("java.lang.Double");
    TargetRefType String   = new TargetRefType("java.lang.String");
    TargetRefType Object   = new TargetRefType("java.lang.Object");

    // Builtin types
    TargetPrimitiveType boolean_  = new TargetPrimitiveType("Z");
    TargetPrimitiveType char_     = new TargetPrimitiveType("C");
    TargetPrimitiveType byte_     = new TargetPrimitiveType("B");
    TargetPrimitiveType short_    = new TargetPrimitiveType("S");
    TargetPrimitiveType int_      = new TargetPrimitiveType("I");
    TargetPrimitiveType long_     = new TargetPrimitiveType("J");
    TargetPrimitiveType float_    = new TargetPrimitiveType("F");
    TargetPrimitiveType double_   = new TargetPrimitiveType("D");

    static TargetType toPrimitive(TargetType type) {
        if (type.equals(Boolean))   return boolean_;
        if (type.equals(Char))      return char_;
        if (type.equals(Byte))      return byte_;
        if (type.equals(Short))     return short_;
        if (type.equals(Integer))   return int_;
        if (type.equals(Long))      return long_;
        if (type.equals(Float))     return float_;
        if (type.equals(Double))    return double_;
        return type;
    }

    static TargetType toPrimitive(RefType type) {
        return switch(type.getName().toString()) {
            case "java.lang.Boolean" -> boolean_;
            case "java.lang.Character" -> char_;
            case "java.lang.Byte" -> byte_;
            case "java.lang.Short" -> short_;
            case "java.lang.Integer" -> int_;
            case "java.lang.Long" -> long_;
            case "java.lang.Float" -> float_;
            case "java.lang.Double" -> double_;
            default -> null;
        };
    }

    static TargetType toWrapper(TargetType f) {
        if (f.equals(boolean_))    return Boolean;
        if (f.equals(char_))       return Char;
        if (f.equals(byte_))       return Byte;
        if (f.equals(short_))      return Short;
        if (f.equals(int_))        return Integer;
        if (f.equals(long_))       return Long;
        if (f.equals(float_))      return Float;
        if (f.equals(double_))     return Double;

        return f;
    }

    String toSignature();
    String toDescriptor();
    String getInternalName();
    String name();
}
