Coverage Summary for Class: Issue (org.kitodo.production.model.bibliography.course)
Class |
Class, %
|
Method, %
|
Line, %
|
Issue |
100%
(1/1)
|
27,8%
(10/36)
|
25,6%
(34/133)
|
/*
* (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/
package org.kitodo.production.model.bibliography.course;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.kitodo.api.dataformat.mets.KitodoUUID;
/**
* The class Issue represents the regular appearance of one (or the) issue of a
* newspaper.
*
* <p>
* Newspapers, especially bigger ones, can have several issues that may differ
* in time of publication (morning issue, evening issue, …), geographic
* distribution (Edinburgh issue, London issue, …) and/or their days of
* appearance (weekday issue: Mon—Fri, weekend issue: Sat, sports supplement:
* Mon, property market: Wed, broadcasting programme: Thu). Furthermore there
* may be exceptions in either that an issue didn’t appear on a date where, due
* to the day of week, it usually does (i.e. on holidays) or an issue may have
* appeared where, due to the day of week, it should not have.
*
* <p>
* Each issue can be modeled by one Issue object each, which are held by a Block
* object which provides the dates of first and last appearance.
*/
public class Issue {
private static final int APPEARED = 1;
private static final int NOT_APPEARED = 0;
private String id;
/**
* Course of appearance this issue is in.
*/
private final Course course;
/**
* Dates with issue on days of week without regular appearance.
*
* <p>
* Implementors note: SortedSet and SortedMap do not declare HashCode &
* Equals and cannot be used in a sensible way here.
*/
private Set<LocalDate> additions;
/**
* Days of week of regular appearance. JodaTime uses int in [1 = monday … 7
* = Sunday]
*
* <p>
* Implementors note: SortedSet and SortedMap do not declare HashCode &
* Equals and cannot be used in a sensible way here.
*/
private Set<Integer> daysOfWeek;
/**
* Dates of days without issue on days of regular appearance (i.e. holidays)
*
* <p>
* Implementors note: SortedSet and SortedMap do not declare HashCode &
* Equals and cannot be used in a sensible way here.
*/
private Set<LocalDate> exclusions;
/**
* Issue name, i.e. “Evening issue”
*/
private String heading;
/**
* Empty issue constructor.
*
* @param course
* course of appearance this issue is in
*/
public Issue(Course course) {
this.course = course;
this.heading = "";
this.additions = new HashSet<>();
this.daysOfWeek = new HashSet<>();
this.exclusions = new HashSet<>();
this.id = KitodoUUID.randomUUID();
}
/**
* Issue constructor with the option to set the issue heading.
*
* @param course
* course of appearance this issue is in
* @param heading
* issue heading
*/
public Issue(Course course, String heading) {
this.course = course;
this.heading = heading;
this.additions = new HashSet<>();
this.daysOfWeek = new HashSet<>();
this.exclusions = new HashSet<>();
this.id = KitodoUUID.randomUUID();
}
/**
* Gets issue id.
*
* @return value of id
*/
public String getId() {
return id;
}
/**
* Adds a LocalDate to the set of exclusions.
*
* @param addition
* date to add
* @return true if the set was changed
*/
public boolean addAddition(LocalDate addition) {
course.clearProcesses();
return additions.add(addition);
}
/**
* Adds the given dayOfWeek to the Set of daysOfWeek.
*
* @param dayOfWeek
* An int representing the day of week (1 = monday … 7 = sunday)
* @return true if the Set was changed
*/
private boolean addDayOfWeek(DayOfWeek dayOfWeek) {
boolean modified = daysOfWeek.add(dayOfWeek.getValue());
if (modified) {
course.clearProcesses();
}
return modified;
}
/**
* Adds a LocalDate to the set of exclusions.
*
* @param exclusion
* date to add
* @return true if the set was changed
*/
public boolean addExclusion(LocalDate exclusion) {
course.clearProcesses();
return exclusions.add(exclusion);
}
/**
* Creates a copy of the object. All instance variables will be copied—this
* is done in the getter methods—so that modifications to the copied object
* will not impact to the copy master.
*
* @param course
* course the copy shall belong to
* @return a copy of this object for the new course
*/
public Issue clone(Course course) {
Issue copy = new Issue(course);
copy.heading = heading;
copy.additions = new HashSet<>(additions);
copy.daysOfWeek = new HashSet<>(daysOfWeek);
copy.exclusions = new HashSet<>(exclusions);
return copy;
}
/**
* Determines how many stampings of
* this issue physically appeared without generating a list of
* IndividualIssue objects.
*
* @param firstAppearance
* first day of the time range to inspect
* @param lastAppearance
* last day of the time range to inspect
* @return the count of issues
* @throws IllegalArgumentException
* if lastAppearance is null
*/
public long countIndividualIssues(LocalDate firstAppearance, LocalDate lastAppearance) {
long numberOfIndividualIssues = 0;
for (LocalDate day = firstAppearance; !day.isAfter(lastAppearance); day = day.plusDays(1)) {
if (isMatch(day)) {
numberOfIndividualIssues += 1;
}
}
return numberOfIndividualIssues;
}
/**
* Getter function for the Set of additions.
*
* @return the set of additions
*/
public Set<LocalDate> getAdditions() {
return additions;
}
/**
* Getter function for the Set of days of week the issue regularly appears.
*
* @return the set of days of week the issue regularly appears
*/
public Set<Integer> getDaysOfWeek() {
return daysOfWeek;
}
/**
* Getter function for the Set of exclusions.
*
* @return the set of exclusions
*/
public Set<LocalDate> getExclusions() {
return exclusions;
}
/**
* Getter function for the issue’s name.
*
* @return the issue’s name
*/
public String getHeading() {
return heading;
}
/**
* Returns whether the issue regularly appeared on the given day of week.
*
* @param dayOfWeek
* day of week to look up
* @return whether the issue appeared on that day of week
*/
public boolean isDayOfWeek(int dayOfWeek) {
return daysOfWeek.contains(dayOfWeek);
}
/**
* Returns whether the issue appeared on a given
* LocalDate, taking into consideration the daysOfWeek of regular
* appearance, the Set of exclusions and the Set of additions.
*
* @param date
* a LocalDate to examine
* @return whether the issue appeared that day
*/
public boolean isMatch(LocalDate date) {
return daysOfWeek.contains(date.getDayOfWeek().getValue()) && !exclusions.contains(date) || additions.contains(date);
}
/**
* Can be used to determine whether the issue
* regularly appears on Mondays.
*
* @return true, if the issue regularly appears on Mondays.
*/
public boolean isMonday() {
return daysOfWeek.contains(DayOfWeek.MONDAY.getValue());
}
/**
* Can be used to determine whether the issue
* regularly appears on Tuesdays.
*
* @return true, if the issue regularly appears on Tuesdays.
*/
public boolean isTuesday() {
return daysOfWeek.contains(DayOfWeek.TUESDAY.getValue());
}
/**
* Can be used to determine whether the issue
* regularly appears on Wednesdays.
*
* @return true, if the issue regularly appears on Wednesdays.
*/
public boolean isWednesday() {
return daysOfWeek.contains(DayOfWeek.WEDNESDAY.getValue());
}
/**
* Can be used to determine whether the issue
* regularly appears on Sundays.
*
* @return true, if the issue regularly appears on Thursdays.
*/
public boolean isThursday() {
return daysOfWeek.contains(DayOfWeek.THURSDAY.getValue());
}
/**
* Can be used to determine whether the issue
* regularly appears on Fridays.
*
* @return true, if the issue regularly appears on Fridays.
*/
public boolean isFriday() {
return daysOfWeek.contains(DayOfWeek.FRIDAY.getValue());
}
/**
* Can be used to determine whether the issue
* regularly appears on Saturdays.
*
* @return true, if the issue regularly appears on Saturdays.
*/
public boolean isSaturday() {
return daysOfWeek.contains(DayOfWeek.SATURDAY.getValue());
}
/**
* Can be used to determine whether the issue
* regularly appears on Sundays.
*
* @return true, if the issue regularly appears on Sundays.
*/
public boolean isSunday() {
return daysOfWeek.contains(DayOfWeek.SUNDAY.getValue());
}
/**
* Recalculates for each Issue
* the daysOfWeek of its regular appearance within the given interval of
* time. This is especially sensible to detect the underlying regularity
* after lots of individual issues whose existence is known have been added
* one by one as additions.
*
* @param firstAppearance
* first day of the date range
* @param lastAppearance
* last day of the date range
*/
void recalculateRegularity(LocalDate firstAppearance, LocalDate lastAppearance) {
Set<LocalDate> remainingAdditions = new HashSet<>();
Set<LocalDate> remainingExclusions = new HashSet<>();
@SuppressWarnings("unchecked")
HashSet<LocalDate>[][] subsets = new HashSet[DayOfWeek.SUNDAY.getValue()][APPEARED + 1];
for (int dayOfWeek = DayOfWeek.MONDAY.getValue(); dayOfWeek <= DayOfWeek.SUNDAY.getValue(); dayOfWeek++) {
subsets[dayOfWeek - 1][NOT_APPEARED] = new HashSet<>();
subsets[dayOfWeek - 1][APPEARED] = new HashSet<>();
}
for (LocalDate day = firstAppearance; !day.isAfter(lastAppearance); day = day.plusDays(1)) {
subsets[day.getDayOfWeek().getValue() - 1][isMatch(day) ? APPEARED : NOT_APPEARED].add(day);
}
for (int dayOfWeek = DayOfWeek.MONDAY.getValue(); dayOfWeek <= DayOfWeek.SUNDAY.getValue(); dayOfWeek++) {
if (subsets[dayOfWeek - 1][APPEARED].size() > subsets[dayOfWeek - 1][NOT_APPEARED].size()) {
daysOfWeek.add(dayOfWeek);
remainingExclusions.addAll(subsets[dayOfWeek - 1][NOT_APPEARED]);
} else {
daysOfWeek.remove(dayOfWeek);
remainingAdditions.addAll(subsets[dayOfWeek - 1][APPEARED]);
}
}
additions = remainingAdditions;
exclusions = remainingExclusions;
}
/**
* Removes the given LocalDate from the set of addition.
*
* @param addition
* date to remove
* @return true if the Set was changed
*/
public boolean removeAddition(LocalDate addition) {
course.clearProcesses();
return additions.remove(addition);
}
/**
* Removes the given dayOfWeek from the Set of daysOfWeek.
*
* @param dayOfWeek
* An int representing the day of week (1 = monday … 7 = sunday)
*/
private void removeDayOfWeek(DayOfWeek dayOfWeek) {
boolean modified = daysOfWeek.remove(dayOfWeek.getValue());
if (modified) {
course.clearProcesses();
}
}
/**
* Removes the given LocalDate from the set of exclusions.
*
* @param exclusion
* date to remove
* @return true if the Set was changed
*/
public boolean removeExclusion(LocalDate exclusion) {
course.clearProcesses();
return exclusions.remove(exclusion);
}
/**
* Set whether this issue appeared on mondays.
* @param isMonday boolean representing appearance
*/
public void setMonday(boolean isMonday) {
if (isMonday) {
addDayOfWeek(DayOfWeek.MONDAY);
} else {
removeDayOfWeek(DayOfWeek.MONDAY);
}
}
/**
* Set whether this issue appeared on tuesdays.
* @param isTuesday boolean representing appearance
*/
public void setTuesday(boolean isTuesday) {
if (isTuesday) {
addDayOfWeek(DayOfWeek.TUESDAY);
} else {
removeDayOfWeek(DayOfWeek.TUESDAY);
}
}
/**
* Set whether this issue appeared on wednesdays.
* @param isWednesday boolean representing appearance
*/
public void setWednesday(boolean isWednesday) {
if (isWednesday) {
addDayOfWeek(DayOfWeek.WEDNESDAY);
} else {
removeDayOfWeek(DayOfWeek.WEDNESDAY);
}
}
/**
* Set whether this issue appeared on thursdays.
* @param isThursday boolean representing appearance
*/
public void setThursday(boolean isThursday) {
if (isThursday) {
addDayOfWeek(DayOfWeek.THURSDAY);
} else {
removeDayOfWeek(DayOfWeek.THURSDAY);
}
}
/**
* Set whether this issue appeared on fridays.
* @param isFriday boolean representing appearance
*/
public void setFriday(boolean isFriday) {
if (isFriday) {
addDayOfWeek(DayOfWeek.FRIDAY);
} else {
removeDayOfWeek(DayOfWeek.FRIDAY);
}
}
/**
* Set whether this issue appeared on saturdays.
* @param isSaturday boolean representing appearance
*/
public void setSaturday(boolean isSaturday) {
if (isSaturday) {
addDayOfWeek(DayOfWeek.SATURDAY);
} else {
removeDayOfWeek(DayOfWeek.SATURDAY);
}
}
/**
* Set whether this issue appeared on sundays.
* @param isSunday boolean representing appearance
*/
public void setSunday(boolean isSunday) {
if (isSunday) {
addDayOfWeek(DayOfWeek.SUNDAY);
} else {
removeDayOfWeek(DayOfWeek.SUNDAY);
}
}
/**
* Setter method for the issue’s name.
*
* @param heading
* heading to be used
*/
public void setHeading(String heading) {
if (!Objects.equals(this.heading, heading)) {
course.clearProcesses();
}
this.heading = heading;
}
/**
* Provides returns a string that contains a concise
* but informative representation of this issue that is easy for a person to
* read.
*
* @return a string representation of the issue
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(heading);
result.append(" (");
result.append(daysOfWeek.contains(DayOfWeek.MONDAY.getValue()) ? 'M' : '-');
result.append(daysOfWeek.contains(DayOfWeek.TUESDAY.getValue()) ? 'T' : '-');
result.append(daysOfWeek.contains(DayOfWeek.WEDNESDAY.getValue()) ? 'W' : '-');
result.append(daysOfWeek.contains(DayOfWeek.THURSDAY.getValue()) ? 'T' : '-');
result.append(daysOfWeek.contains(DayOfWeek.FRIDAY.getValue()) ? 'F' : '-');
result.append(daysOfWeek.contains(DayOfWeek.SATURDAY.getValue()) ? 'S' : '-');
result.append(daysOfWeek.contains(DayOfWeek.SUNDAY.getValue()) ? 'S' : '-');
result.append(") +");
if (additions.size() <= 5) {
result.append(additions.toString());
} else {
result.append("[…(");
result.append(additions.size());
result.append(")…]");
}
result.append(" -");
if (exclusions.size() <= 5) {
result.append(exclusions.toString());
} else {
result.append("[…(");
result.append(exclusions.size());
result.append(")…]");
}
return result.toString();
}
/**
* Returns a hash code for the object which depends on the content of its
* variables. Whenever Issue objects are held in HashSet objects, a
* hashCode() is essentially necessary.
*
* <p>
* The method was generated by Eclipse using right-click → Source → Generate
* hashCode() and equals()…. If you will ever change the classes’ fields,
* just re-generate it.
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int hashCode = 1;
hashCode = prime * hashCode + id.hashCode();
hashCode = prime * hashCode + ((additions == null) ? 0 : additions.hashCode());
hashCode = prime * hashCode + ((daysOfWeek == null) ? 0 : daysOfWeek.hashCode());
hashCode = prime * hashCode + ((exclusions == null) ? 0 : exclusions.hashCode());
hashCode = prime * hashCode + ((heading == null) ? 0 : heading.hashCode());
return hashCode;
}
/**
* Returns whether two individual issues are equal; the decision depends on
* the content of its variables.
*
* <p>
* The method was generated by Eclipse using right-click → Source → Generate
* hashCode() and equals()…. If you will ever change the classes’ fields,
* just re-generate it.
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Issue)) {
return false;
}
Issue other = (Issue) obj;
return id.equals(other.id) && course.equals(other.course)
&& Objects.equals(additions, other.additions) && Objects.equals(daysOfWeek, other.daysOfWeek)
&& Objects.equals(exclusions, other.exclusions) && Objects.equals(heading, other.heading);
}
}