# ShippingCostCalculator.java

    package com.university.bookstore.visitor;

    import com.university.bookstore.model.AudioBook;
    import com.university.bookstore.model.EBook;
    import com.university.bookstore.model.Magazine;
    import com.university.bookstore.model.Material;
    import com.university.bookstore.model.Media;
    import com.university.bookstore.model.PrintedBook;
    import com.university.bookstore.model.VideoMaterial;

    /**
     * Concrete visitor implementation for calculating shipping costs.
     * Demonstrates the Visitor pattern by providing different shipping
     * cost calculations based on material type.
     *
     * <p>Shipping costs vary by material type:
     * - Physical items: $0.50 per 100g
     * - Digital items: $0 (instant download)
     * - Magazines: $2 flat rate</p>
     *
     * @author Navid Mohaghegh
     * @version 2.0
     * @since 2024-09-15
     */
    public class ShippingCostCalculator implements MaterialVisitor {

        private static final double PHYSICAL_ITEM_RATE = 0.50; // per 100g
        private static final double MAGAZINE_FLAT_RATE = 2.00;
        private static final double DIGITAL_ITEM_RATE = 0.00;

        private double totalShippingCost = 0.0;

        /**
         * Calculates shipping cost for a printed book based on weight.
         * Assumes average book weight of 500g.
         *
         * @param book the printed book
         */
        @Override
        public void visit(PrintedBook book) {
            // Assume average book weight of 500g
            double weightInHundredGrams = 5.0;
            double cost = weightInHundredGrams * PHYSICAL_ITEM_RATE;
            totalShippingCost += cost;
        }

        /**
         * Calculates flat rate shipping cost for magazines.
         *
         * @param magazine the magazine
         */
        @Override
        public void visit(Magazine magazine) {
            totalShippingCost += MAGAZINE_FLAT_RATE;
        }

        /**
         * Calculates shipping cost for audio books.
         * Physical CDs: weight-based, Digital: free
         *
         * @param audioBook the audio book
         */
        @Override
        public void visit(AudioBook audioBook) {
            if (audioBook.getQuality() == Media.MediaQuality.PHYSICAL) {
                // Assume CD weight of 100g
                double weightInHundredGrams = 1.0;
                double cost = weightInHundredGrams * PHYSICAL_ITEM_RATE;
                totalShippingCost += cost;
            } else {
                // Digital download - no shipping cost
                totalShippingCost += DIGITAL_ITEM_RATE;
            }
        }

        /**
         * Calculates shipping cost for video materials.
         * Physical DVDs: weight-based, Digital: free
         *
         * @param video the video material
         */
        @Override
        public void visit(VideoMaterial video) {
            if (video.getQuality() == Media.MediaQuality.PHYSICAL) {
                // Assume DVD weight of 150g
                double weightInHundredGrams = 1.5;
                double cost = weightInHundredGrams * PHYSICAL_ITEM_RATE;
                totalShippingCost += cost;
            } else {
                // Digital download - no shipping cost
                totalShippingCost += DIGITAL_ITEM_RATE;
            }
        }

        /**
         * Calculates shipping cost for e-books.
         * E-books are always digital downloads with no shipping cost.
         *
         * @param ebook the e-book
         */
        @Override
        public void visit(EBook ebook) {
            // E-books are always digital - no shipping cost
            totalShippingCost += DIGITAL_ITEM_RATE;
        }

        /**
         * Gets the total shipping cost calculated so far.
         *
         * @return the total shipping cost
         */
        public double getTotalShippingCost() {
            return totalShippingCost;
        }

        /**
         * Resets the shipping cost calculator for a new calculation.
         */
        public void reset() {
            totalShippingCost = 0.0;
        }

        /**
         * Calculates shipping cost for a single material.
         *
         * @param material the material to calculate shipping for
         * @return the shipping cost for this material
         */
        public double calculateShippingCost(Material material) {
            reset();

            // Use pattern matching or instanceof to determine the correct visit method
            if (material instanceof PrintedBook) {
                visit((PrintedBook) material);
            } else if (material instanceof Magazine) {
                visit((Magazine) material);
            } else if (material instanceof AudioBook) {
                visit((AudioBook) material);
            } else if (material instanceof VideoMaterial) {
                visit((VideoMaterial) material);
            } else if (material instanceof EBook) {
                visit((EBook) material);
            } else {
                throw new IllegalArgumentException("Unknown material type: " + material.getClass().getSimpleName());
            }

            return totalShippingCost;
        }
    }