/**
 *
 * 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.
 */
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.speedment.runtime.core.internal.stream;

import com.speedment.runtime.core.db.SqlFunction;
import com.speedment.runtime.core.exception.SpeedmentException;
import com.speedment.runtime.core.stream.parallel.ParallelStrategy;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Optional;
import java.util.Spliterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static com.speedment.runtime.core.util.StaticClassUtil.instanceNotAllowed;
import static java.util.Objects.requireNonNull;

/**
 *
 * @author Emil Forslund
 */
public final class StreamUtil {
    
    public static <T> Stream<T> streamOfOptional(@SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<T> element) {
        return Stream.of(element.orElse(null)).filter(e -> e != null);
    }

    public static <T> Stream<T> streamOfNullable(T element) {
        // Needless to say, element is nullable...
        if (element == null) {
            return Stream.empty();
        } else {
            return Stream.of(element);
        }
    }

    public static <T> Stream<T> asStream(Iterator<T> iterator) {
        requireNonNull(iterator);
        return asStream(iterator, false);
    }

    public static <T> Stream<T> asStream(Iterator<T> iterator, boolean parallel) {
        requireNonNull(iterator);
        final Iterable<T> iterable = () -> iterator;
        return StreamSupport.stream(iterable.spliterator(), parallel);
    }

    public static <T> Stream<T> asStream(ResultSet resultSet, SqlFunction<ResultSet, T> mapper) {
//        requireNonNull(resultSet);
//        requireNonNull(mapper);
//        final Iterator<T> iterator = new ResultSetIterator<>(resultSet, mapper);
//        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.IMMUTABLE + Spliterator.NONNULL), false);
         return asStream(resultSet, mapper, ParallelStrategy.computeIntensityDefault());
    }
    
    public static <T> Stream<T> asStream(ResultSet resultSet, SqlFunction<ResultSet, T> mapper, ParallelStrategy parallelStrategy) {
        requireNonNull(resultSet);
        requireNonNull(mapper);
        final Iterator<T> iterator = new ResultSetIterator<>(resultSet, mapper);
        return StreamSupport.stream(parallelStrategy.spliteratorUnknownSize(iterator, Spliterator.IMMUTABLE + Spliterator.NONNULL), false);
    }

    public static <T> Stream<T> from(@SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional<T> optional) {
        requireNonNull(optional);
        return optional.isPresent() ? Stream.of(optional.get()) : Stream.empty();
    }

    private static class ResultSetIterator<T> implements Iterator<T> {

        private final ResultSet resultSet;
        private final SqlFunction<ResultSet, T> mapper;

        public ResultSetIterator(final ResultSet resultSet, final SqlFunction<ResultSet, T> mapper) {
            this.resultSet = requireNonNull(resultSet);
            this.mapper = requireNonNull(mapper);
        }

        @Override
        public boolean hasNext() {
            try {
                return resultSet.next();
            } catch (SQLException sqle) {
                throw new SpeedmentException("Error iterating over a ResultSet", sqle);
            }
        }

        @Override
        public T next() {
            try {
                return mapper.apply(resultSet);
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
        }

    }

    /**
     * Utility classes should not be instantiated.
     */
    private StreamUtil() {
        instanceNotAllowed(getClass());
    }
}

@@ -1121,32 +1121,58 @@
 .util.Iterator;%0A
+import java.util.Objects;%0A
 import java.util
@@ -1674,19 +1674,21 @@
 ter(
-e -%3E e != n
+Objects::nonN
 ull)
@@ -2446,300 +2446,8 @@
 ) %7B%0A
-//        requireNonNull(resultSet);%0A//        requireNonNull(mapper);%0A//        final Iterator%3CT%3E iterator = new ResultSetIterator%3C%3E(resultSet, mapper);%0A//        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.IMMUTABLE + Spliterator.NONNULL), false);%0A
     
@@ -3149,63 +3149,47 @@
 nal.
-isPresent() ? Stream.of(optional.get()) : 
+map(Stream::of).orElseGet(
 Stream
-.
+::
 empty
-(
 );%0A 
@@ -3375,21 +3375,22 @@
        p
-ublic
+rivate
  ResultS
@@ -3426,16 +3426,49 @@
 sultSet,
+%0A                                
  final S
@@ -3494,32 +3494,33 @@
 t, T%3E mapper) %7B%0A
+%0A
             this
@@ -3583,16 +3583,19 @@
 .mapper 
+   
 = requir
@@ -3717,16 +3717,17 @@
  return 
+!
 resultSe
@@ -3728,19 +3728,21 @@
 sultSet.
-nex
+isLas
 t();%0A   
@@ -3751,32 +3751,38 @@
        %7D catch (
+final 
 SQLException sql
@@ -3778,20 +3778,18 @@
 ception 
-sql
 e
+x
 ) %7B%0A    
@@ -3833,31 +3833,52 @@
 ion(
-%22Error iterating over a
+%0A                    %22Error looking ahead in
  Res
@@ -3887,15 +3887,31 @@
 tSet
+.
 %22, 
-sqle
+ex%0A                
 );%0A 
@@ -4016,61 +4016,353 @@
     
-return mapper.apply(resultSet);%0A            %7D catch (
+if (resultSet.next()) %7B%0A                    return mapper.apply(resultSet);%0A                %7D else %7B%0A                    throw new SpeedmentException(%0A                        %22ResultSetIterator#next() was called without %22 +%0A                        %22checking #hasNext() first.%22%0A                    );%0A                %7D%0A            %7D catch (final 
 SQLE
@@ -4406,15 +4406,17 @@
 new 
-Runtime
+Speedment
 Exce

Change hasNext() method in ResultSetIterator (#386)