MaterialIteratorFactory.java

package com.university.bookstore.iterator;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

import com.university.bookstore.model.Material;

/**
 * Factory for creating different types of material iterators.
 * Provides a centralized way to create iterators with different traversal strategies.
 * 
 * <p>This factory demonstrates the Factory pattern by providing methods to create
 * various types of iterators without exposing the concrete iterator classes.</p>
 * 
 * @author Navid Mohaghegh
 * @version 3.0
 * @since 2024-09-15
 */
public class MaterialIteratorFactory {
    
    /**
     * Creates a type-filtering iterator.
     * 
     * @param materials the list of materials to iterate over
     * @param type the material type to filter for
     * @return iterator for materials of the specified type
     */
    public MaterialIterator createTypeIterator(List<Material> materials, Material.MaterialType type) {
        return new MaterialTypeIterator(materials, type);
    }
    
    /**
     * Creates a price-sorted iterator.
     * 
     * @param materials the list of materials to iterate over
     * @param ascending true for ascending order, false for descending
     * @return iterator for materials sorted by price
     */
    public MaterialIterator createPriceSortedIterator(List<Material> materials, boolean ascending) {
        return new PriceSortedIterator(materials, ascending);
    }
    
    /**
     * Creates a price range iterator.
     * 
     * @param materials the list of materials to iterate over
     * @param minPrice the minimum price (inclusive)
     * @param maxPrice the maximum price (inclusive)
     * @return iterator for materials within the price range
     */
    public MaterialIterator createPriceRangeIterator(List<Material> materials, double minPrice, double maxPrice) {
        return new PriceRangeIterator(materials, minPrice, maxPrice);
    }
    
    /**
     * Creates an e-book iterator.
     * 
     * @param materials the list of materials to iterate over
     * @return iterator for e-books only
     */
    public MaterialIterator createEBookIterator(List<Material> materials) {
        return new MaterialTypeIterator(materials, Material.MaterialType.E_BOOK);
    }
    
    /**
     * Creates an expensive materials iterator.
     * 
     * @param materials the list of materials to iterate over
     * @param threshold the minimum price threshold
     * @return iterator for materials above the price threshold
     */
    public MaterialIterator createExpensiveIterator(List<Material> materials, double threshold) {
        return new PriceRangeIterator(materials, threshold, Double.MAX_VALUE);
    }
    
    /**
     * Creates a cheap materials iterator.
     * 
     * @param materials the list of materials to iterate over
     * @param threshold the maximum price threshold
     * @return iterator for materials below the price threshold
     */
    public MaterialIterator createCheapIterator(List<Material> materials, double threshold) {
        return new PriceRangeIterator(materials, 0.0, threshold);
    }
    
    /**
     * Creates a book iterator.
     * 
     * @param materials the list of materials to iterate over
     * @return iterator for books only
     */
    public MaterialIterator createBookIterator(List<Material> materials) {
        return new MaterialTypeIterator(materials, Material.MaterialType.BOOK);
    }
    
    /**
     * Creates a magazine iterator.
     * 
     * @param materials the list of materials to iterate over
     * @return iterator for magazines only
     */
    public MaterialIterator createMagazineIterator(List<Material> materials) {
        return new MaterialTypeIterator(materials, Material.MaterialType.MAGAZINE);
    }
    
    /**
     * Creates an audio book iterator.
     * 
     * @param materials the list of materials to iterate over
     * @return iterator for audio books only
     */
    public MaterialIterator createAudioBookIterator(List<Material> materials) {
        return new MaterialTypeIterator(materials, Material.MaterialType.AUDIO_BOOK);
    }
    
    /**
     * Creates a video iterator.
     * 
     * @param materials the list of materials to iterate over
     * @return iterator for videos only
     */
    public MaterialIterator createVideoIterator(List<Material> materials) {
        return new MaterialTypeIterator(materials, Material.MaterialType.VIDEO);
    }
    
    /**
     * Collects all materials from an iterator into a list.
     * 
     * @param iterator the iterator to collect from
     * @return list of all materials from the iterator
     */
    public List<Material> collectAll(MaterialIterator iterator) {
        List<Material> result = new ArrayList<>();
        iterator.reset();
        while (iterator.hasNext()) {
            result.add(iterator.next());
        }
        return result;
    }
    
    /**
     * Finds the first material matching a predicate.
     * 
     * @param iterator the iterator to search
     * @param predicate the predicate to test
     * @return Optional containing the first matching material
     */
    public Optional<Material> findFirst(MaterialIterator iterator, Predicate<Material> predicate) {
        iterator.reset();
        while (iterator.hasNext()) {
            Material material = iterator.next();
            if (predicate.test(material)) {
                return Optional.of(material);
            }
        }
        return Optional.empty();
    }
    
    /**
     * Finds all materials matching a predicate.
     * 
     * @param iterator the iterator to search
     * @param predicate the predicate to test
     * @return list of all matching materials
     */
    public List<Material> findAll(MaterialIterator iterator, Predicate<Material> predicate) {
        List<Material> result = new ArrayList<>();
        iterator.reset();
        while (iterator.hasNext()) {
            Material material = iterator.next();
            if (predicate.test(material)) {
                result.add(material);
            }
        }
        return result;
    }
    
    /**
     * Counts materials matching a predicate.
     * 
     * @param iterator the iterator to count
     * @param predicate the predicate to test
     * @return the count of matching materials
     */
    public int count(MaterialIterator iterator, Predicate<Material> predicate) {
        int count = 0;
        iterator.reset();
        while (iterator.hasNext()) {
            Material material = iterator.next();
            if (predicate.test(material)) {
                count++;
            }
        }
        return count;
    }
    
    /**
     * Checks if any material matches a predicate.
     * 
     * @param iterator the iterator to check
     * @param predicate the predicate to test
     * @return true if any material matches
     */
    public boolean anyMatch(MaterialIterator iterator, Predicate<Material> predicate) {
        iterator.reset();
        while (iterator.hasNext()) {
            Material material = iterator.next();
            if (predicate.test(material)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Checks if all materials match a predicate.
     * 
     * @param iterator the iterator to check
     * @param predicate the predicate to test
     * @return true if all materials match
     */
    public boolean allMatch(MaterialIterator iterator, Predicate<Material> predicate) {
        iterator.reset();
        while (iterator.hasNext()) {
            Material material = iterator.next();
            if (!predicate.test(material)) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Gets the total count of materials in an iterator.
     * 
     * @param iterator the iterator to count
     * @return the total count
     */
    public int getTotalCount(MaterialIterator iterator) {
        return iterator.getTotalCount();
    }
    
    /**
     * Gets the remaining count of materials in an iterator.
     * 
     * @param iterator the iterator to check
     * @return the remaining count
     */
    public int getRemainingCount(MaterialIterator iterator) {
        return iterator.getRemainingCount();
    }
    
    @Override
    public String toString() {
        return "MaterialIteratorFactory[Available iterators: Type, PriceSorted, PriceRange, EBook, Expensive, Cheap, Book, Magazine, AudioBook, Video]";
    }
}