# 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]";
        }
    }