/*
 * Copyright 2017 IntroPro Ventures, Inc. and/or its affiliates.
 *
 * 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 com.introproventures.graphql.jpa.query.boot.autoconfigure;

import java.util.function.Supplier;

import javax.persistence.EntityManagerFactory;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.introproventures.graphql.jpa.query.autoconfigure.GraphQLSchemaConfigurer;
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutionInputFactory;
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutor;
import com.introproventures.graphql.jpa.query.schema.GraphQLExecutorContextFactory;
import com.introproventures.graphql.jpa.query.schema.GraphQLSchemaBuilder;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutor;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaExecutorContextFactory;
import com.introproventures.graphql.jpa.query.schema.impl.GraphQLJpaSchemaBuilder;

import graphql.GraphQL;
import graphql.GraphQLContext;
import graphql.execution.instrumentation.Instrumentation;
import graphql.schema.GraphQLSchema;
import graphql.schema.visibility.GraphqlFieldVisibility;

@Configuration
@ConditionalOnClass(GraphQL.class)
@ConditionalOnProperty(name="spring.graphql.jpa.query.enabled", havingValue="true", matchIfMissing=true)
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
public class GraphQLJpaQueryAutoConfiguration {

    @Configuration
    public static class DefaultGraphQLJpaQueryConfiguration {

        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnSingleCandidate(EntityManagerFactory.class)
        public GraphQLSchemaBuilder graphQLSchemaBuilder(final EntityManagerFactory entityManagerFactory) {
            return new GraphQLJpaSchemaBuilder(entityManagerFactory.createEntityManager());
        }
        
        @Bean
        @ConditionalOnMissingBean
        public GraphQLSchemaConfigurer graphQLJpaQuerySchemaConfigurer(GraphQLSchemaBuilder graphQLSchemaBuilder) {
            
            return (registry) -> {
                registry.register(graphQLSchemaBuilder.build());
            };
        }
        
        @Bean 
        @ConditionalOnMissingBean
        public GraphQLExecutorContextFactory graphQLExecutorContextFactory(ObjectProvider<GraphQLExecutionInputFactory> graphQLExecutionInputFactory,
                                                                           ObjectProvider<Supplier<GraphqlFieldVisibility>> graphqlFieldVisibility,
                                                                           ObjectProvider<Supplier<Instrumentation>> instrumentation,
                                                                           ObjectProvider<Supplier<GraphQLContext>> graphqlContext) {
            GraphQLJpaExecutorContextFactory bean = new GraphQLJpaExecutorContextFactory();
            
            graphQLExecutionInputFactory.ifAvailable(bean::withExecutionInputFactory);
            graphqlFieldVisibility.ifAvailable(bean::withGraphqlFieldVisibility);
            instrumentation.ifAvailable(bean::withInstrumentation);
            graphqlContext.ifAvailable(bean::withGraphqlContext);
            
            return bean;
        }

        @Bean
        @ConditionalOnMissingBean
        public GraphQLExecutor graphQLExecutor(GraphQLSchema graphQLSchema,
                                               GraphQLExecutorContextFactory graphQLExecutorContextFactory) {
            return new GraphQLJpaExecutor(graphQLSchema,
                                          graphQLExecutorContextFactory);
        }
        
    }
}

@@ -2069,25 +2069,24 @@
 emaBuilder;%0A
-%0A
 import graph
@@ -2773,32 +2773,35 @@
 aBuilder graphQL
+Jpa
 SchemaBuilder(fi
@@ -2947,33 +2947,25 @@
 ;%0A        %7D%0A
-        
 %0A
+
         @Bea
@@ -3116,29 +3116,17 @@
 lder) %7B%0A
-            
 %0A
+
         
@@ -3238,32 +3238,24 @@
 ;%0A        %7D%0A
-        
 %0A        @Be
@@ -3256,17 +3256,16 @@
    @Bean
- 
 %0A       
@@ -3335,32 +3335,35 @@
 tFactory graphQL
+Jpa
 ExecutorContextF
@@ -3952,29 +3952,17 @@
 tory();%0A
-            
 %0A
+
         
@@ -4260,21 +4260,9 @@
 t);%0A
-            
 %0A
+
     
@@ -4371,32 +4371,35 @@
 Executor graphQL
+Jpa
 Executor(GraphQL
@@ -4412,32 +4412,35 @@
  graphQLSchema,%0A
+   
                 
@@ -4674,24 +4674,16 @@
       %7D%0A
-        
 %0A    %7D%0A%7D

Resolve exception when using graphql-jpa with leangen (#255)