package ru.faulab.guice;

import com.google.inject.*;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.FactoryProvider;
import com.google.inject.internal.Nullable;
import com.google.inject.multibindings.MapBinder;

import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;

public class GuiceAssitedWithMultibindingDontWork
{
    public static interface PersistentDifferToLocaleStringFactory<Type>
    {
        PersistentDiffer<Type, String> create(Locale locale, Type initialValue);
    }

    public static interface DatePersistentDifferToLocaleStringFactory extends PersistentDifferToLocaleStringFactory<Date>
    {
        @Override
        PersistentDiffer<Date, String> create(Locale locale, Date initialValue);

    }

    public static interface IntegerPersistentDifferToLocaleStringFactory extends PersistentDifferToLocaleStringFactory<Integer>
    {
        @Override
        PersistentDiffer<Integer, String> create(Locale locale, Integer initialValue);
    }


    public static class PersistentDifferForDateToLocaleString implements PersistentDiffer<Date, String>
    {
        private final DateFormat dateForamt;
        private final Date initialValue;

        @Inject
        public PersistentDifferForDateToLocaleString(@Nullable @Assisted Date defaultValue, @Assisted Locale locale)
        {
            dateForamt = DateFormat.getDateInstance(DateFormat.FULL, locale);
            initialValue = defaultValue;
        }

        @Override
        public String getDiff(Date date)
        {
            if (initialValue == null || date == null)
            {
                return null;
            }
            Date targetDate = initialValue.before(date) ? date : initialValue;
            return dateForamt.format(targetDate);
        }
    }

    public static class PersistentDifferForIntegerToLocaleString implements PersistentDiffer<Integer, String>
    {
        private final NumberFormat numberFormat;
        private final Integer initialValue;

        @Inject
        public PersistentDifferForIntegerToLocaleString(@Nullable @Assisted Integer defaultValue, @Nullable @Assisted Locale locale)
        {
            numberFormat = NumberFormat.getNumberInstance(locale);
            initialValue = defaultValue;
        }

        @Override
        public String getDiff(Integer integer)
        {
            if (initialValue == null || integer == null)
            {
                return null;
            }
            return numberFormat.format(Math.max(integer, initialValue));
        }
    }

    public static class InStringPersistentDifferFactoryWithAssistedImpl implements InStringPersistentDifferFactory
    {
        private final Map<Class, PersistentDifferToLocaleStringFactory> converterMap;
        private final Locale locale;

        @Inject
        public InStringPersistentDifferFactoryWithAssistedImpl(Map<Class, PersistentDifferToLocaleStringFactory> converterMap)
        {
            this.converterMap = converterMap;
            locale = Locale.ROOT;
        }

        public <Type> PersistentDiffer<Type, String> createPersistentDiffer(Class<Type> type, Type value)
        {
            PersistentDifferToLocaleStringFactory<Type> persistentDiffer = converterMap.get(type);
            if (persistentDiffer == null)
            {
                return null;
            }
            return persistentDiffer.create(locale, value);
        }
    }

    public static void main(String[] args)
    {
        Injector injector = Guice.createInjector(new PrivateModule()
        {
            @Override
            protected void configure()
            {
                MapBinder<Class, PersistentDifferToLocaleStringFactory> fromToStringConverterMultibinder = MapBinder.newMapBinder(binder(), Class.class, PersistentDifferToLocaleStringFactory.class);
                fromToStringConverterMultibinder.addBinding(Date.class).toProvider(FactoryProvider.newFactory(DatePersistentDifferToLocaleStringFactory.class, PersistentDifferForDateToLocaleString.class)).in(Singleton.class);
                fromToStringConverterMultibinder.addBinding(Integer.class).toProvider(FactoryProvider.newFactory(IntegerPersistentDifferToLocaleStringFactory.class, PersistentDifferForIntegerToLocaleString.class)).in(Singleton.class);
                bind(InStringPersistentDifferFactory.class).to(InStringPersistentDifferFactoryWithAssistedImpl.class).in(Singleton.class);
                expose(InStringPersistentDifferFactory.class);
            }
        });
        InStringPersistentDifferFactory persistentDifferFactory = injector.getInstance(InStringPersistentDifferFactory.class);

        PersistentDiffer<Date, String> datePersistentDiffer = persistentDifferFactory.createPersistentDiffer(Date.class, new Date());
        PersistentDiffer<Integer, String> integerPersistentDiffer = persistentDifferFactory.createPersistentDiffer(Integer.class, 10);

        System.out.println(datePersistentDiffer.getDiff(new Date()));
        System.out.println(datePersistentDiffer.getDiff(null));
        System.out.println(integerPersistentDiffer.getDiff(12));
        System.out.println(integerPersistentDiffer.getDiff(8));

    }
}