/**
 *
 * Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
 *
 * 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.speedment.generator.standard.internal.util;

import com.speedment.common.codegen.constant.DefaultType;
import com.speedment.common.codegen.constant.SimpleParameterizedType;
import com.speedment.common.codegen.model.File;
import com.speedment.common.codegen.model.Import;
import com.speedment.common.codegen.model.Method;
import com.speedment.generator.translator.TranslatorSupport;
import com.speedment.runtime.config.Column;
import com.speedment.runtime.config.Table;
import com.speedment.runtime.config.trait.HasEnabled;
import com.speedment.runtime.core.exception.SpeedmentException;

import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static com.speedment.common.codegen.constant.DefaultAnnotationUsage.OVERRIDE;
import static com.speedment.common.codegen.util.Formatting.*;
import static java.util.stream.Collectors.joining;

/**
 *
 * @author  Emil Forslund
 * @since   3.0.0
 */
public final class GenerateMethodBodyUtil {

    public static Method generateFields(TranslatorSupport<Table> support, File file, String methodName, Supplier<Stream<? extends Column>> columnsSupplier) {
        return Method.of(methodName, 
                DefaultType.stream(
                    SimpleParameterizedType.create(
                        com.speedment.runtime.field.Field.class,
                        support.entityType()
                    )
                )
            )
            .public_().add(OVERRIDE)
            .add(generateFieldsBody(support, file, columnsSupplier));
    }

    public static String[] generateFieldsBody(TranslatorSupport<Table> support, File file, Supplier<Stream<? extends Column>> columnsSupplier) {
        file.add(Import.of(Stream.class));
        final List<String> rows = new LinkedList<>();

        rows.add("return Stream.of(");
        rows.add(indent(columnsSupplier.get()
            .filter(HasEnabled::isEnabled)
            .map(Column::getJavaName)
            .map(support.namer()::javaStaticFieldName)
            .map(field -> support.typeName() + "." + field)
            .collect(joining("," + nl()))
        ));
        rows.add(");");

        return rows.toArray(new String[rows.size()]);
    }
    
    @FunctionalInterface
    public interface ReadFromResultSet {
        String readFromResultSet(File file, Column c, AtomicInteger position);
    }

    public static String[] generateApplyResultSetBody(
            ReadFromResultSet readFromResultSet,
            TranslatorSupport<Table> support,
            File file,
            Supplier<Stream<? extends Column>> columnsSupplier) {

        file.add(Import.of(SQLException.class));
        
        final List<String> rows = new LinkedList<>();
        rows.add("final " + support.entityName() + " entity = createEntity();");

        final Stream.Builder<String> streamBuilder = Stream.builder();

        final AtomicInteger position = new AtomicInteger(1);
        columnsSupplier.get()
            .filter(HasEnabled::isEnabled)
            .forEachOrdered(c -> 
                streamBuilder.add("entity.set" +
                    support.namer().javaTypeName(c.getJavaName()) + "(\t " +
                    readFromResultSet.readFromResultSet(file, c, position) +
                    " \t);")
            );

        rows.add(
            "try " + block(streamBuilder.build()) +
            " catch (final " + SQLException.class.getSimpleName() + " sqle) " + block(
            "throw new " + SpeedmentException.class.getSimpleName() + "(sqle);"
        ));
        rows.add("return entity;");

        return rows.toArray(new String[rows.size()]);
    }
    
    private GenerateMethodBodyUtil() {
        throw new UnsupportedOperationException();
    }
}

@@ -1764,16 +1764,29 @@
 eFields(
+%0A            
 Translat
@@ -1810,27 +1810,51 @@
 support,
- File file,
+%0A            File file,%0A           
  String 
@@ -1864,16 +1864,28 @@
 hodName,
+%0A           
  Supplie
@@ -1923,32 +1923,33 @@
 umnsSupplier) %7B%0A
+%0A
         return M
@@ -2382,16 +2382,29 @@
 ldsBody(
+%0A            
 Translat
@@ -2428,27 +2428,51 @@
 support,
- File file,
+%0A            File file,%0A           
  Supplie
@@ -2514,24 +2514,25 @@
 Supplier) %7B%0A
+%0A
         file
@@ -2554,32 +2554,217 @@
 Stream.class));%0A
+%0A        // If there are no matching columns:%0A        if (columnsSupplier.get().noneMatch($ -%3E true)) %7B%0A            return new String%5B%5D %7B%22return Stream.empty();%22%7D;%0A        %7D else %7B%0A    
         final Li
@@ -2802,32 +2802,36 @@
 t%3C%3E();%0A%0A        
+    
 rows.add(%22return
@@ -2845,16 +2845,20 @@
 .of(%22);%0A
+    
         
@@ -2899,32 +2899,36 @@
 t()%0A            
+    
 .filter(HasEnabl
@@ -2934,32 +2934,36 @@
 led::isEnabled)%0A
+    
             .map
@@ -2992,24 +2992,28 @@
             
+    
 .map(support
@@ -3039,24 +3039,28 @@
 cFieldName)%0A
+    
             
@@ -3119,16 +3119,20 @@
         
+ 
+   
 .collect
@@ -3153,32 +3153,36 @@
  nl()))%0A        
+    
 ));%0A        rows
@@ -3169,32 +3169,36 @@
     ));%0A        
+ 
+   
 rows.add(%22);%22);%0A
@@ -3194,24 +3194,28 @@
 add(%22);%22);%0A%0A
+    
         retu
@@ -3248,32 +3248,42 @@
 %5Brows.size()%5D);%0A
+        %7D%0A
     %7D%0A    %0A    @

Return empty result set if no columns