# MaterialEnhancementService.java

    package com.university.bookstore.decorator;

    import com.university.bookstore.model.EBook;
    import com.university.bookstore.model.Material;

    /**
     * Service for managing material enhancements using the Decorator pattern.
     * Provides methods to apply various decorators to materials and create enhancement packages.
     *
     * <p>This service demonstrates the Decorator pattern in action by providing
     * a high-level interface for dynamically adding features to materials.</p>
     *
     * @author Navid Mohaghegh
     * @version 3.0
     * @since 2024-09-15
     */
    public class MaterialEnhancementService {

        /**
         * Adds gift wrapping to a material.
         *
         * @param material the material to enhance
         * @param style the wrapping style
         * @return the enhanced material with gift wrapping
         * @throws IllegalArgumentException if material or style is null
         */
        public Material addGiftWrapping(Material material, String style) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }
            if (style == null || style.trim().isEmpty()) {
                throw new IllegalArgumentException("Wrapping style cannot be null or empty");
            }

            return new GiftWrappingDecorator(material, style);
        }

        /**
         * Adds expedited delivery to a material.
         *
         * @param material the material to enhance
         * @param deliveryDays the number of days for delivery
         * @return the enhanced material with expedited delivery
         * @throws IllegalArgumentException if material is null or deliveryDays is invalid
         */
        public Material addExpeditedDelivery(Material material, int deliveryDays) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }
            if (deliveryDays < 1) {
                throw new IllegalArgumentException("Delivery days must be at least 1: " + deliveryDays);
            }

            return new ExpeditedDeliveryDecorator(material, deliveryDays);
        }

        /**
         * Adds digital annotations to a material.
         *
         * @param material the material to enhance
         * @return the enhanced material with digital annotations
         * @throws IllegalArgumentException if material is null
         */
        public Material addDigitalAnnotations(Material material) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }

            return new DigitalAnnotationDecorator(material);
        }

        /**
         * Creates a premium package with multiple enhancements.
         *
         * @param material the material to enhance
         * @param giftStyle the gift wrapping style
         * @param deliveryDays the number of days for delivery
         * @return the enhanced material with premium package
         * @throws IllegalArgumentException if material is null or parameters are invalid
         */
        public Material createPremiumPackage(Material material, String giftStyle, int deliveryDays) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }

            Material enhanced = material;
            enhanced = addGiftWrapping(enhanced, giftStyle);
            enhanced = addExpeditedDelivery(enhanced, deliveryDays);

            // Add digital annotations if it's an e-book
            if (material instanceof EBook) {
                enhanced = addDigitalAnnotations(enhanced);
            }

            return enhanced;
        }

        /**
         * Creates a gift package with gift wrapping and expedited delivery.
         *
         * @param material the material to enhance
         * @param giftStyle the gift wrapping style
         * @param deliveryDays the number of days for delivery
         * @return the enhanced material with gift package
         */
        public Material createGiftPackage(Material material, String giftStyle, int deliveryDays) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }

            Material enhanced = material;
            enhanced = addGiftWrapping(enhanced, giftStyle);
            enhanced = addExpeditedDelivery(enhanced, deliveryDays);

            return enhanced;
        }

        /**
         * Creates a digital package with digital annotations (for e-books only).
         *
         * @param material the material to enhance
         * @return the enhanced material with digital package, or original if not an e-book
         */
        public Material createDigitalPackage(Material material) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }

            if (material instanceof EBook) {
                return addDigitalAnnotations(material);
            }

            return material; // Return original if not an e-book
        }

        /**
         * Calculates the total enhancement cost for a material.
         *
         * @param original the original material
         * @param enhanced the enhanced material
         * @return the total enhancement cost
         */
        public double calculateEnhancementCost(Material original, Material enhanced) {
            if (original == null || enhanced == null) {
                throw new IllegalArgumentException("Materials cannot be null");
            }

            return enhanced.getPrice() - original.getPrice();
        }

        /**
         * Gets a summary of enhancements applied to a material.
         *
         * @param material the material to analyze
         * @return enhancement summary
         */
        public String getEnhancementSummary(Material material) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }

            StringBuilder summary = new StringBuilder();

            // Check if there are any enhancements
            if (!hasEnhancements(material)) {
                summary.append("No enhancements applied");
                return summary.toString();
            }

            summary.append("Enhancements:\n");

            // Check for decorators by examining the display info
            String displayInfo = material.getDisplayInfo();
            if (displayInfo.contains("Gift Wrapped")) {
                summary.append("// [OK] Gift Wrapping\n");
            }
            if (displayInfo.contains("Expedited Delivery")) {
                summary.append("// [OK] Expedited Delivery\n");
            }
            if (displayInfo.contains("Digital Annotations")) {
                summary.append("// [OK] Digital Annotations\n");
            }

            double enhancementCost = material.getPrice() - getBasePrice(material);
            summary.append("Total Cost: $").append(String.format("%.2f", material.getPrice()));

            return summary.toString();
        }

        /**
         * Gets the base price of a material (without decorators).
         *
         * @param material the material to analyze
         * @return the base price
         */
        public double getBasePrice(Material material) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }

            Material current = material;
            while (current instanceof MaterialDecorator) {
                current = ((MaterialDecorator) current).getDecoratedMaterial();
            }

            return current.getPrice();
        }

        /**
         * Checks if a material has any enhancements applied.
         *
         * @param material the material to check
         * @return true if enhancements are applied
         */
        public boolean hasEnhancements(Material material) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }

            return material instanceof MaterialDecorator;
        }

        /**
         * Gets the number of decorators applied to a material.
         *
         * @param material the material to analyze
         * @return the decorator count
         */
        public int getEnhancementCount(Material material) {
            if (material == null) {
                return 0;
            }

            int count = 0;
            Material current = material;
            while (current instanceof MaterialDecorator) {
                count++;
                current = ((MaterialDecorator) current).getDecoratedMaterial();
            }

            return count;
        }

        /**
         * Gets the base material (unwraps all decorators).
         *
         * @param material the material to unwrap
         * @return the base material
         */
        public Material getBaseMaterial(Material material) {
            if (material == null) {
                throw new IllegalArgumentException("Material cannot be null");
            }

            Material current = material;
            while (current instanceof MaterialDecorator) {
                current = ((MaterialDecorator) current).getDecoratedMaterial();
            }

            return current;
        }

        /**
         * Checks if a material has a specific type of enhancement.
         *
         * @param material the material to check
         * @param enhancementType the type of enhancement to look for
         * @return true if the enhancement is applied
         */
        public boolean hasEnhancement(Material material, Class<? extends MaterialDecorator> enhancementType) {
            if (material == null || enhancementType == null) {
                return false;
            }

            Material current = material;
            while (current instanceof MaterialDecorator) {
                if (enhancementType.isInstance(current)) {
                    return true;
                }
                current = ((MaterialDecorator) current).getDecoratedMaterial();
            }

            return false;
        }

        @Override
        public String toString() {
            return "MaterialEnhancementService[Available enhancements: Gift Wrapping, Expedited Delivery, Digital Annotations]";
        }
    }