package ru.yandex.direct.http.smart.converter;

import java.lang.annotation.Annotation;
import java.util.Map;

import javax.annotation.Nonnull;

import com.google.common.collect.ImmutableMap;

import ru.yandex.direct.http.smart.annotations.Json;
import ru.yandex.direct.http.smart.annotations.Proto;
import ru.yandex.direct.http.smart.annotations.ProtoAsJson;
import ru.yandex.direct.http.smart.annotations.Xml;
import ru.yandex.direct.http.smart.http.Body;

import static java.util.Collections.emptyMap;

public class RequestConverterFactory {
    private final Map<Class, RequestBodyConverter> converterMap;

    public RequestConverterFactory() {
        this(emptyMap());
    }

    public RequestConverterFactory(Map<Class<?>, ? extends RequestBodyConverter<?>> converterMap) {
        this.converterMap = ImmutableMap.<Class, RequestBodyConverter>builder()
                .put(JsonRequestConverter.class, new JsonRequestConverter())
                .put(ProtoAsJsonRequestConverter.class, new ProtoAsJsonRequestConverter())
                .put(XmlRequestConverter.class, new XmlRequestConverter())
                .put(ProtoRequestConverter.class, new ProtoRequestConverter())
                .put(StringRequestConverter.class, new StringRequestConverter())
                .putAll(converterMap)
                .build();
    }

    @Nonnull
    public <T> RequestBodyConverter<T> getConverter(Annotation[] parameterAnnotations) {
        Body bodyAnnotation = null;
        for (Annotation parameterAnnotation : parameterAnnotations) {
            if (parameterAnnotation instanceof Json) {
                return getConverter(JsonRequestConverter.class);
            }
            if (parameterAnnotation instanceof ProtoAsJson) {
                return getConverter(ProtoAsJsonRequestConverter.class);
            }
            if (parameterAnnotation instanceof Xml) {
                return getConverter(XmlRequestConverter.class);
            }
            if (parameterAnnotation instanceof Proto) {
                return getConverter(ProtoRequestConverter.class);
            }
            if (parameterAnnotation instanceof Body) {
                bodyAnnotation = ((Body) parameterAnnotation);
            }
        }
        //конвертер, указанный в Body используется с меньшим приоритетом, чем явные аннотации
        if (bodyAnnotation != null) {
            return getConverter(bodyAnnotation.converter());
        }
        return getConverter(StringRequestConverter.class);
    }

    private <T> RequestBodyConverter<T> getConverter(Class<?> converterClass) {
        //noinspection unchecked
        return (RequestBodyConverter<T>) converterMap.get(converterClass);
    }
}
