// Path: s01/s01e03-consumers/src/main/java/net/safedata/java8/training/consumer/service/ProductService.java
// public class ProductService {
// 
//     public void displayAppleTablets() {
//         final Section tablets = getTabletsSection();
//         processAppleTablets(tablets);
//     }
// 
//     private Section getTabletsSection() {
//         return StoreSetup.getDefaultStore()
//                          .getStoreSections()
//                          .stream()
//                          .filter(tablets())
//                          .findFirst()
//                          .orElseThrow(() -> new IllegalArgumentException("There's no section named 'Tablets'"));
//     }
// 
//     private void processAppleTablets(final Section tablets) {
//         final List<Product> products = tablets.getProducts()
//                                               .orElseThrow(() -> new IllegalArgumentException("There are no products"));
// 
//         /*
//             Q:  when to use an inline lambda expression and when to use methods?
//             A:  • use a method:
//                     - if the lambda expression needs to be a statement lambda
//                         and / or
//                     - if it needs to be reused
//                 • usa an inline lambda - if the lambda expression can be written on a single line
//         */
// 
//         // Single Responsibility Principle / Separation of Concerns
//         products.stream()                       // 0 - obtaining a stream from the collection
//                 .filter(appleProducts())        // 1 - filtering stage
//                 .forEach(consumeProduct());     // 2 - processing / consuming stage
//     }
// 
//     private Consumer<Product> consumeProduct() {
//         return System.out::println;
//     }
// 
//     private Predicate<Product> appleProducts() {
//         return product -> product.getName().contains("Apple");
//     }
// 
//     private Predicate<Section> tablets() {
//         return section -> section.getName().equals(StoreSection.Tablets);
//     }
// }
// 
// Path: domain-model/src/main/java/net/safedata/java8/training/model/Product.java
// public class Product extends AbstractEntity {
// 
//     private final int id;
//     private final String name;
//     private final double price;
//     private final Discount discount;
//     private final List<String> tags;
// 
//     public Product(final int id, final String name, final double price, final Discount discount,
//                    final List<String> tags) {
//         this.id = id;
//         this.name = name;
//         this.price = price;
//         this.discount = discount;
//         this.tags = tags;
//     }
// 
//     public Product(final int id, final String name, final double price, final Discount discount) {
//         this.id = id;
//         this.name = name;
//         this.price = price;
//         this.discount = discount;
//         this.tags = null;
//     }
// 
//     public Product(final int id, final String name, final double price) {
//         this.id = id;
//         this.name = name;
//         this.price = price;
//         this.discount = null;
//         this.tags = null;
//     }
// 
//     public int getId() {
//         return id;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public double getPrice() {
//         return price;
//     }
// 
//     public Optional<Discount> getDiscount() {
//         return Optional.ofNullable(discount);
//     }
// 
//     public Optional<List<String>> getTags() {
//         return Optional.ofNullable(tags);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (!(o instanceof Product)) return false;
//         Product product = (Product) o;
//         return id == product.id &&
//                 Objects.equals(name, product.name) &&
//                 Objects.equals(price, product.price);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(id, name, price);
//     }
// 
//     @Override
//     public String toString() {
//         return id + ", " + name + ": " + price;
//     }
// }


import net.safedata.java8.training.consumer.service.ProductService;
import net.safedata.java8.training.model.Product;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
        display.accept("something");

        final List<String> list = Arrays.asList("I want a holiday, not just a weekend".split(" "));

        // imperative way
        for (final String item : list) {
            System.out.println(item);
        }

        // functional way
        list.forEach(System.out::println);
        list.forEach(item -> System.out.println(item)); // just a matter of taste :)

        final Consumer<Boolean> booleanConsumer = it -> System.out.println("The boolean value is " + Boolean.valueOf(it));
        booleanConsumer.accept(Boolean.TRUE);

        final Consumer<String> aMoreComplexConsumer = value -> {
            if (value.isEmpty()) {
                System.err.println("Cannot process an empty value");
            } else {
                System.out.println("The received value is " + value);
            }
        };

        final Consumer<String> displayedRecommendationConsumer = value -> {
            System.out.println("The value is " + value);
        };
    }

    private static void productConsumers() {
// Path: s01/s01e03-consumers/src/main/java/net/safedata/java8/training/consumer/service/ProductService.java
// public class ProductService {
// 
//     public void displayAppleTablets() {
//         final Section tablets = getTabletsSection();
//         processAppleTablets(tablets);
//     }
// 
//     private Section getTabletsSection() {
//         return StoreSetup.getDefaultStore()
//                          .getStoreSections()
//                          .stream()
//                          .filter(tablets())
//                          .findFirst()
//                          .orElseThrow(() -> new IllegalArgumentException("There's no section named 'Tablets'"));
//     }
// 
//     private void processAppleTablets(final Section tablets) {
//         final List<Product> products = tablets.getProducts()
//                                               .orElseThrow(() -> new IllegalArgumentException("There are no products"));
// 
//         /*
//             Q:  when to use an inline lambda expression and when to use methods?
//             A:  • use a method:
//                     - if the lambda expression needs to be a statement lambda
//                         and / or
//                     - if it needs to be reused
//                 • usa an inline lambda - if the lambda expression can be written on a single line
//         */
// 
//         // Single Responsibility Principle / Separation of Concerns
//         products.stream()                       // 0 - obtaining a stream from the collection
//                 .filter(appleProducts())        // 1 - filtering stage
//                 .forEach(consumeProduct());     // 2 - processing / consuming stage
//     }
// 
//     private Consumer<Product> consumeProduct() {
//         return System.out::println;
//     }
// 
//     private Predicate<Product> appleProducts() {
//         return product -> product.getName().contains("Apple");
//     }
// 
//     private Predicate<Section> tablets() {
//         return section -> section.getName().equals(StoreSection.Tablets);
//     }
// }
// 
// Path: domain-model/src/main/java/net/safedata/java8/training/model/Product.java
// public class Product extends AbstractEntity {
// 
//     private final int id;
//     private final String name;
//     private final double price;
//     private final Discount discount;
//     private final List<String> tags;
// 
//     public Product(final int id, final String name, final double price, final Discount discount,
//                    final List<String> tags) {
//         this.id = id;
//         this.name = name;
//         this.price = price;
//         this.discount = discount;
//         this.tags = tags;
//     }
// 
//     public Product(final int id, final String name, final double price, final Discount discount) {
//         this.id = id;
//         this.name = name;
//         this.price = price;
//         this.discount = discount;
//         this.tags = null;
//     }
// 
//     public Product(final int id, final String name, final double price) {
//         this.id = id;
//         this.name = name;
//         this.price = price;
//         this.discount = null;
//         this.tags = null;
//     }
// 
//     public int getId() {
//         return id;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public double getPrice() {
//         return price;
//     }
// 
//     public Optional<Discount> getDiscount() {
//         return Optional.ofNullable(discount);
//     }
// 
//     public Optional<List<String>> getTags() {
//         return Optional.ofNullable(tags);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (!(o instanceof Product)) return false;
//         Product product = (Product) o;
//         return id == product.id &&
//                 Objects.equals(name, product.name) &&
//                 Objects.equals(price, product.price);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(id, name, price);
//     }
// 
//     @Override
//     public String toString() {
//         return id + ", " + name + ": " + price;
//     }
// }


// Path: s01/s01e03-consumers/src/main/java/net/safedata/java8/training/consumer/ConsumersMain.java
import net.safedata.java8.training.consumer.service.ProductService;
import net.safedata.java8.training.model.Product;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

        display.accept("something");

        final List<String> list = Arrays.asList("I want a holiday, not just a weekend".split(" "));

        // imperative way
        for (final String item : list) {
            System.out.println(item);
        }

        // functional way
        list.forEach(System.out::println);
        list.forEach(item -> System.out.println(item)); // just a matter of taste :)

        final Consumer<Boolean> booleanConsumer = it -> System.out.println("The boolean value is " + Boolean.valueOf(it));
        booleanConsumer.accept(Boolean.TRUE);

        final Consumer<String> aMoreComplexConsumer = value -> {
            if (value.isEmpty()) {
                System.err.println("Cannot process an empty value");
            } else {
                System.out.println("The received value is " + value);
            }
        };

        final Consumer<String> displayedRecommendationConsumer = value -> {
            System.out.println("The value is " + value);
        };
    }

    private static void productConsumers() {
        final ProductService productService = new ProductService();