/*
 * This File is one of the examples from Java Object Oriented Programming
 * Do not reproduce this code for others or use it in a commercial setting without prior permission from the author.
 */
package salesApplication;

import datasource.DataSource;
import datasource.FileDataSource;
import java.util.List;
import products.Item;
import products.Notepad;
import static salesApplication.CompanyInfo.*;


/**
 *
 * @author Matthew Gregory
 * @website www.matthewgregory-author.com.au
 *
 */

public class TestPriceList {
    public static void main(String[] args) {
        DataSource ds = new FileDataSource();
        PriceList demo = ds.retrieveList("Demo");
        List<Item> demoList = demo.getList();
                
        //Print out a list of all the writing implements with a 20% discount.
//        //First attempt at writing code
//        for (Item p:demoList){
//            //remove everything that is not a writing implement
//            if (p instanceof WritingImplement){
//                //Apply a 20% discount to the price of all the remaining products.
//                p.setPrice(p.getPrice()*0.8);
//                //Print all the products in the list
//                System.out.println(p);
//            }
//        }
        
//        //built in lambda methods for collections
//        //remove everything that is not a writing implement
//        demoList.removeIf(p->!(p instanceof WritingImplement));
//        //Apply a 20% discount to the price of all the remaining products.
//        demoList.replaceAll(p->{p.setPrice(p.getPrice()*0.8);return p;});
//        //Print all the products in the list
//        demoList.forEach(p->System.out.println(p));
        
//        //Using existing priceList methods
//        //remove everything that is not a writing implement
//        demo=demo.filterList(p->(p instanceof WritingImplement));
//        //Apply a 20% discount to the price of all the remaining products.
//        demo=demo.applyDiscount(p->{p.setPrice(p.getPrice()*0.8);return p;});
//        //Print all the products in the list
//        demo.printList();

//        //Using the streams functionality
//        //Convert collection to a stream
//        Stream<Item> initialStream =demoList.stream();
//        //remove everything that is not a writing implement
//        Stream<Item> WritingImplementStream =initialStream
//                .filter(p->(p instanceof WritingImplement));
//        //Apply a 20% discount to the price of all the remaining products.
//        Stream<Item> WritingImplementDiscountStream =WritingImplementStream
//                .map(p->{p.setPrice(p.getPrice()*0.8);return p;});
//        //Print all the products in the list
//        WritingImplementDiscountStream.forEach(p->System.out.println(p));
        
//        //Chaining the streams methods.
//        demoList.stream()
//                .filter(p->(p instanceof WritingImplement))
//                .map(p->{p.setPrice(p.getPrice()*0.8);return p;})
//                .forEach(p->System.out.println(p));

        //Re-using Lambda expressions
//        UnaryOperator<Item> clearanceSale = p->{p.setPrice(p.getPrice()*0.8);return p;};
//        System.out.println("Discounted Writing Implements");
//        demoList.stream()
//                .filter(p->(p instanceof WritingImplement))
//                .map(clearanceSale)
//                .forEach(p->System.out.println(p));
//        System.out.println();
//        System.out.println("Discounted Notepads");
//        demoList.stream()
//                .filter(p->(p instanceof Notepad))
//                .map(clearanceSale)
//                .forEach(p->System.out.println(p));  
        //Examples with saved lambda expressions
//        demoList.stream()
//                .filter(p->(p instanceof Notepad))
//                .map(clearanceSale)
//                .forEach(p->System.out.println(p));  
        //More examples
//        System.out.println("Writing Implements Clearance Sale.");
//        demoList.stream()
//                .filter(isWritingImplement)
//                .map(clearanceSale)
//                .forEach(print);  
//        System.out.println();
//        System.out.println("Tax Invoice for taxable items.");
//        demoList.stream()
//                .filter(isTaxable)
//                .forEach(printTax);  

        //Sharing Lambda expressions
//        System.out.println("Discounted Writing Implements");
//        demoList.stream()
//                .filter(p->(p instanceof WritingImplement))
//                .map(clearanceSale)
//                .forEach(p->System.out.println(p));
//        System.out.println();
//        System.out.println("Discounted Notepads");
//        demoList.stream()
//                .filter(p->(p instanceof Notepad))
//                .map(halfPriceSale)
//                .forEach(p->System.out.println(p));

                
        //Referencing methods in a lambda expression
        //1. instance methods
//        demoList.stream()
//                .filter(p->(p instanceof WritingImplement))
//                .map(clearanceSale)
//                .forEach(Item::printProduct);//Use '::' not '.'

        //2. static methods
//        demoList.stream()
//                .filter(p->(p instanceof WritingImplement))
//                .map(clearanceSale)
//                .forEach(System.out::println);
        //3. costructors
        //Take a look at the addProduct method that has been added
        //to the price list object - it accepts a lambda expression
        //of type Supplier to construct the object that will be added.
//        demo.addProduct(()->(new Product("Stapler","Large reliable stapler",6)));
//        demo.printList();
        //We have also added a no-arg constuctor
//        demo.addProduct(Product::new);
//        demo.printList();
        
        //4. methods of another instance
        //Check out the new ManageTax and it's printTaxInvoices method
//        ManageTax tax= new ManageTax();
//        demoList.stream()
//                .filter(p->(p instanceof WritingImplement))
//                .map(clearanceSale)
//                .forEach(tax::printTaxInvoice);
    }
}
