package mariaJava;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class InAction_Intro121_122 {
	
	public void allInAction121_122() {
		java7InstantiateToInvoke();
		java8PassMethodReference();
		
		java7FilterApples();
		java8FilterApples();
		java8FilterApplesUsingLambdas();
		java8FilterApplesUsingStreams();
	}
	//1.2.1. Methods and lambdas as first-class citizens
	public void java7InstantiateToInvoke() {
		System.out.println("Previously needed to instantiate to invoke method");
		
		File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
			public boolean accept(File file) {
				return file.isHidden();
			}
		});
		System.out.println("Old way to filter files: " + hiddenFiles.length);
	}

	public void java8PassMethodReference() {
		System.out.println("Now pass function as argument");
		
		File[] hiddenFiles = new File(".").listFiles(File::isHidden);
		
		System.out.println("New way to filter: " + hiddenFiles.length);
	}
	
	//1.2.2:
	public void java7FilterApples() {
		System.out.println("Previously need to loop the lists and have multiple methods");
		
		List<Apple> inventory = createInventoryOfApples();

		List<Apple> greenApples = filterGreenApples(inventory);
		System.out.println("No of green apples: " + greenApples.size());
		
		List<Apple> heavyApples = filterHeavyApples(inventory);	
		System.out.println("No of heavy apples: " + heavyApples.size());
	}
	
	private List<Apple> filterHeavyApples(List<Apple> inventory) {
		
		List<Apple> result = new ArrayList<Apple>();
		for(Apple apple:inventory) {
			if (apple.getWeight() > 150) {
				result.add(apple);
			}
		}
		return result;
	
	}
	public List<Apple> filterGreenApples(List<Apple> inventory) {
		
		List<Apple> result = new ArrayList<>();
		for(Apple apple: inventory) {
			if ("green".equals(apple.getColor())) {
				result.add(apple);			}
		}
		return result;
	}
	
	public void java8FilterApples() {
		System.out.println("Now one method is needed, passing the difference as argument");
		
		List<Apple> inventory = createInventoryOfApples();
		
		List<Apple> greenApples = filterApples(inventory, Apple::isGreenApple);
		System.out.println("Green Apples: " + greenApples.size());
		
		List<Apple> heavyApples = filterApples(inventory, Apple::isHeavyApple);
		System.out.println("Heavy apples: " + heavyApples.size());
		
	}
	
	public List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> predicate) {
		
		List<Apple> result = new ArrayList<Apple>();
		
		for(Apple apple: inventory) {
			if(predicate.test(apple)) {
				result.add(apple);
			}
		}
		return result;
	}
	

	
	public void java8FilterApplesUsingLambdas() {
		System.out.println("Use lambdas instead of declaring methods in Apple");
		List<Apple> inventory = createInventoryOfApples();
		
		List<Apple> greenApples = filterApples(inventory, (Apple a) -> "green".equals(a.getColor()));
		System.out.println("Green apples using lambda: " + greenApples.size());
		
		
		List<Apple> heavyApples = filterApples(inventory, (Apple a) -> a.getWeight() > 150);
		System.out.println("Heavy apples using lambda: " + heavyApples.size());
		
		Predicate<Apple> predicate = (Apple a) -> a.getWeight() >150;
		List<Apple> heavyApples2 = filterApples(inventory, predicate);
		System.out.println("Heavy apples using predicate " + heavyApples2.size());
	}
	
	public void java8FilterApplesUsingStreams() {
		System.out.println("Use streams");
		
		List<Apple> inventory = createInventoryOfApples();
		
		List<Apple> heavyApples = inventory.stream()
				.filter((Apple a) -> a.getWeight() >150)
				.collect(Collectors.toList());
		System.out.println("Heavy apples using stream: " + heavyApples.size());
	}

	//---
	private List<Apple> createInventoryOfApples() {
		Apple a1 = new Apple(100, "red");
		Apple a2 = new Apple(140, "red");
		Apple a3 = new Apple(160,  "green");
		
		List<Apple> inventory = new ArrayList<Apple>();
		inventory.add(a1);
		inventory.add(a2);
		inventory.add(a3);
		
		return inventory;
	}
	
}
