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