/*
 * Copyright (C) 2013 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.airlift.drift.transport.netty;

import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import io.airlift.drift.transport.DriftClientConfig;
import io.airlift.drift.transport.MethodInvokerFactory;

import java.lang.annotation.Annotation;

import static io.airlift.configuration.ConfigBinder.configBinder;

public class DriftNettyClientModule
        implements Module
{
    @Override
    public void configure(Binder binder)
    {
        configBinder(binder).bindConfig(DriftNettyConnectionFactoryConfig.class);
        configBinder(binder).bindConfigurationBindingListener((binding, configBinder) -> {
            if (binding.getConfigClass().equals(DriftClientConfig.class)) {
                configBinder.bindConfig(DriftNettyClientConfig.class, binding.getKey().getAnnotation(), binding.getPrefix().orElse(null));
            }
        });
    }

    @Provides
    @Singleton
    private static MethodInvokerFactory<Annotation> getMethodInvokerFactory(DriftNettyConnectionFactoryConfig factoryConfig, Injector injector)
    {
        return new DriftNettyMethodInvokerFactory<>(factoryConfig, annotation -> injector.getInstance(Key.get(DriftNettyClientConfig.class, annotation)));
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o) {
            return true;
        }
        return o != null && getClass() == o.getClass();
    }

    @Override
    public int hashCode()
    {
        return getClass().hashCode();
    }
}

@@ -794,22 +794,20 @@
 .inject.
-Provid
+Scop
 es;%0Aimpo
@@ -827,25 +827,27 @@
 .inject.
-Singleton
+TypeLiteral
 ;%0Aimport
@@ -965,37 +965,195 @@
 java
-.lang.annotation.Annotation;%0A
+x.annotation.PreDestroy;%0Aimport javax.inject.Inject;%0Aimport javax.inject.Provider;%0A%0Aimport java.lang.annotation.Annotation;%0A%0Aimport static com.google.common.base.Preconditions.checkState;
 %0Aimp
@@ -1759,43 +1759,464 @@
 %7D);%0A
+%0A
     
-%7D%0A%0A    @Provides%0A    @Singleton
+    binder.bind(new TypeLiteral%3CMethodInvokerFactory%3CAnnotation%3E%3E() %7B%7D)%0A                .toProvider(MethodInvokerFactoryProvider.class)%0A                .in(Scopes.SINGLETON);%0A    %7D%0A%0A    @Override%0A    public boolean equals(Object o)%0A    %7B%0A        if (this == o) %7B%0A            return true;%0A        %7D%0A        return o != null && getClass() == o.getClass();%0A    %7D%0A%0A    @Override%0A    public int hashCode()%0A    %7B%0A        return getClass().hashCode();%0A    %7D%0A
 %0A   
@@ -2231,16 +2231,22 @@
  static 
+class 
 MethodIn
@@ -2261,94 +2261,241 @@
 tory
-%3CAnnotation%3E getMethodInvokerFactory(DriftNettyConnectionFactoryConfig factoryConfig, 
+Provider%0A            implements Provider%3CMethodInvokerFactory%3CAnnotation%3E%3E%0A    %7B%0A        private Injector injector;%0A        private DriftNettyMethodInvokerFactory%3CAnnotation%3E factory;%0A%0A        @Inject%0A        public void setInjector(
 Inje
@@ -2509,16 +2509,20 @@
 jector)%0A
+    
     %7B%0A  
@@ -2531,66 +2531,362 @@
     
-return new DriftNettyMethodInvokerFactory%3C%3E(factoryConfig,
+    this.injector = injector;%0A        %7D%0A%0A        @Override%0A        public MethodInvokerFactory%3CAnnotation%3E get()%0A        %7B%0A            checkState(factory == null, %22factory already created%22);%0A%0A            factory = new DriftNettyMethodInvokerFactory%3C%3E(%0A                    injector.getInstance(DriftNettyConnectionFactoryConfig.class),%0A                   
  ann
@@ -2974,95 +2974,8 @@
 ));%0A
-    %7D%0A%0A    @Override%0A    public boolean equals(Object o)%0A    %7B%0A        if (this == o) %7B
 %0A   
@@ -2982,36 +2982,39 @@
          return 
-true
+factory
 ;%0A        %7D%0A    
@@ -3005,32 +3005,33 @@
 ;%0A        %7D%0A
+%0A
         
 return o != 
@@ -3022,107 +3022,58 @@
     
-return o != null && getClass() == o.getClass();%0A    %7D%0A%0A    @Override%0A    public int hashCode
+@PreDestroy%0A        public void destroy
 ()%0A    
+  
+  
 %7B%0A  
@@ -3082,37 +3082,38 @@
     
-return getClass().hashCode();
+    factory.close();%0A        %7D
 %0A   

Fix lifecycle handling in DriftNettyClientModule