package ru.yandex.webmaster3.core.util.json.polymorphic;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.annotation.NoClass;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.impl.AsExternalTypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.impl.AsWrapperTypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder;

import java.util.Collection;

/**
 * Для классов, аннотированных TypeInfo, jackson отказывается понять,
 * что при десериализации конкретного потомка можно не ломаться при отсутствии поля type.
 * Тут мы это исправляем
 *
 * @author avhaliullin
 */
public class DefaultValuedTypeResolverBuilder extends StdTypeResolverBuilder {
    @Override
    public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
        if (_idType == JsonTypeInfo.Id.NONE) {
            return null;
        }

        TypeIdResolver idRes = idResolver(config, baseType, subtypes, false, true);

        JavaType defaultImpl;
        if (!baseType.isAbstract()) {
            // затевалось все ради этого кейса
            defaultImpl = baseType;
        } else {
            if (_defaultImpl == null) {
                defaultImpl = null;
            } else {
                if ((_defaultImpl == Void.class)
                        || (_defaultImpl == NoClass.class)) {
                    defaultImpl = config.getTypeFactory().constructType(_defaultImpl);
                } else {
                    defaultImpl = config.getTypeFactory()
                            .constructSpecializedType(baseType, _defaultImpl);
                }
            }

        }

        switch (_includeAs) {
            case WRAPPER_ARRAY:
                return new AsArrayTypeDeserializer(baseType, idRes,
                        _typeProperty, _typeIdVisible, defaultImpl);
            case PROPERTY:
            case EXISTING_PROPERTY:
                return new AsPropertyTypeDeserializer(baseType, idRes,
                        _typeProperty, _typeIdVisible, defaultImpl, _includeAs);
            case WRAPPER_OBJECT:
                return new AsWrapperTypeDeserializer(baseType, idRes,
                        _typeProperty, _typeIdVisible, defaultImpl);
            case EXTERNAL_PROPERTY:
                return new AsExternalTypeDeserializer(baseType, idRes,
                        _typeProperty, _typeIdVisible, defaultImpl);
        }
        throw new IllegalStateException("Do not know how to construct standard type serializer for inclusion type: " + _includeAs);
    }
}
