# Magazine.java

    package com.university.bookstore.model;

    /**
     * Represents a magazine in the store inventory.
     * Demonstrates inheritance from Material base class.
     *
     * @author Navid Mohaghegh
     * @version 2.0
     * @since 2024-09-15
     */
    public class Magazine extends Material {

        private final String issn;
        private final String publisher;
        private final int issueNumber;
        private final String frequency;
        private final String category;

        /**
         * Frequency of magazine publication.
         */
        public enum PublicationFrequency {
            DAILY("Daily"),
            WEEKLY("Weekly"),
            BIWEEKLY("Bi-weekly"),
            MONTHLY("Monthly"),
            QUARTERLY("Quarterly"),
            ANNUAL("Annual");

            private final String label;

            PublicationFrequency(String label) {
                this.label = label;
            }

            @Override
            public String toString() {
                return label;
            }
        }

        /**
         * Creates a new Magazine.
         *
         * @param issn International Standard Serial Number
         * @param title magazine title
         * @param publisher publishing company
         * @param price price per issue
         * @param year publication year
         * @param issueNumber issue number
         * @param frequency publication frequency
         * @param category magazine category/genre
         */
        public Magazine(String issn, String title, String publisher, double price,
                        int year, int issueNumber, String frequency, String category) {
            super(validateIssn(issn), title, price, year, MaterialType.MAGAZINE);
            this.issn = this.id;
            this.publisher = validateStringField(publisher, "Publisher");
            this.issueNumber = validateIssueNumber(issueNumber);
            this.frequency = validateStringField(frequency, "Frequency");
            this.category = validateStringField(category, "Category");
        }

        private static String validateIssn(String issn) {
            if (issn == null) {
                throw new NullPointerException("ISSN cannot be null");
            }

            String cleaned = issn.replaceAll("-", "").trim();

            if (cleaned.length() != 8) {
                throw new IllegalArgumentException(
                    "ISSN must be 8 characters. Provided: " + issn);
            }

            return cleaned;
        }

        private int validateIssueNumber(int issueNumber) {
            if (issueNumber <= 0) {
                throw new IllegalArgumentException(
                    "Issue number must be positive. Provided: " + issueNumber);
            }
            return issueNumber;
        }

        @Override
        public String getCreator() {
            return publisher;
        }

        @Override
        public String getDisplayInfo() {
            return String.format("%s - Issue #%d (%s %d) - %s, $%.2f",
                title, issueNumber, frequency, year, category, price);
        }

        @Override
        public double getDiscountRate() {
            int currentYear = java.time.Year.now().getValue();
            int currentMonth = java.time.LocalDate.now().getMonthValue();

            if (year < currentYear || (year == currentYear && issueNumber < currentMonth - 2)) {
                return 0.25;
            }
            return 0.0;
        }

        /**
         * Calculates annual subscription cost with discount.
         *
         * @return annual subscription price
         */
        public double calculateAnnualSubscription() {
            int issuesPerYear = getIssuesPerYear();
            double fullPrice = price * issuesPerYear;
            return fullPrice * 0.85;
        }

        private int getIssuesPerYear() {
            switch (frequency.toUpperCase()) {
                case "DAILY": return 365;
                case "WEEKLY": return 52;
                case "BI-WEEKLY": return 26;
                case "MONTHLY": return 12;
                case "QUARTERLY": return 4;
                case "ANNUAL": return 1;
                default: return 12;
            }
        }

        public String getIssn() {
            return issn;
        }

        public String getPublisher() {
            return publisher;
        }

        public int getIssueNumber() {
            return issueNumber;
        }

        public String getFrequency() {
            return frequency;
        }

        public String getCategory() {
            return category;
        }

        @Override
        public String toString() {
            return String.format("Magazine[ISSN=%s, Title='%s', Publisher='%s', Issue=%d, %s, Category='%s', Price=$%.2f, Year=%d]",
                issn, title, publisher, issueNumber, frequency, category, price, year);
        }
    }