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);
}
}