package model; import strategy.SortingStrategy; import iterator.AlbumIterator; import iterator.PhotoIterator; import java.util.*; /** * A model that represents a photo album. *

* This class is responsible for managing the photos in the album, as well as * the sorting strategy used to sort the photos. * The model notifies its listeners when the model changes. * It also provides methods to add and delete photos, * as well as to navigate through the photos. * * @author Yuri Tatishchev * @version 0.1 2025-03-26 * @see Photo * @see SortingStrategy * @see AlbumIterator * @see PhotoIterator * @see ModelChangeListener */ public class PhotoAlbumModel { private List photos; private SortingStrategy sortingStrategy; private final List listeners; private AlbumIterator iterator; /** * A listener interface for model changes. * The method {@link #onModelChanged()} is called when the model changes. */ public interface ModelChangeListener { /** * Called when the model changes. */ void onModelChanged(); } public PhotoAlbumModel() { photos = new ArrayList<>(); listeners = new ArrayList<>(); iterator = new PhotoIterator(photos); } /** * Adds a photo to the album. * Resets the iterator and notifies the listeners. * * @param photo the photo to add */ public void addPhoto(Photo photo) { photos.add(photo); sortPhotos(); notifyListeners(); } /** * Deletes a photo from the album by name. * If the deleted photo is the current photo or the album is empty, * the iterator is reset. * * @param name the name of the photo to delete */ public void deletePhoto(String name) { Photo currentPhoto = iterator.current(); photos.removeIf(photo -> photo.name().equals(name)); if (photos.isEmpty() || (currentPhoto != null && currentPhoto.name().equals(name))) { iterator = new PhotoIterator(photos); } notifyListeners(); } /** * Sets the sorting strategy for the photos. * Sorts the photos using the new strategy and resets the iterator. * * @param strategy the sorting strategy to set */ public void setSortingStrategy(SortingStrategy strategy) { this.sortingStrategy = strategy; sortPhotos(); iterator = new PhotoIterator(photos); notifyListeners(); } private void sortPhotos() { if (sortingStrategy != null) { photos = sortingStrategy.sort(photos); iterator = new PhotoIterator(photos); } } /** * Adds a listener for model changes. * * @param listener the listener to add */ public void addListener(ModelChangeListener listener) { listeners.add(listener); } /** * Notifies all listeners that the model has changed, * calling the {@link ModelChangeListener#onModelChanged()} method. */ private void notifyListeners() { for (ModelChangeListener listener : listeners) { listener.onModelChanged(); } } /** * Returns an unmodifiable list of photos in the album. * * @return an unmodifiable list of photos */ public List getPhotos() { return Collections.unmodifiableList(photos); } /** * Returns the photo in the album that the iterator is currently pointing to. * * @return the current photo */ public Photo getCurrentPhoto() { try { return iterator.current(); } catch (NoSuchElementException e) { return null; } } /** * Returns whether there is a next photo in the album. * * @return {@code true} if there is a next photo, {@code false} otherwise */ public boolean hasNext() { return iterator.hasNext(); } /** * Returns whether there is a previous photo in the album. * * @return {@code true} if there is a previous photo, {@code false} otherwise */ public boolean hasPrevious() { return iterator.hasPrevious(); } /** * Advances the iterator to the next photo in the album. * Notifies the listeners. * * @return the next photo or {@code null} if there is no next photo */ public Photo next() { try { Photo next = iterator.next(); notifyListeners(); return next; } catch (NoSuchElementException e) { return null; } } /** * Advances the iterator to the previous photo in the album. * Notifies the listeners. * * @return the previous photo or {@code null} if there is no previous photo */ public Photo previous() { try { Photo prev = iterator.previous(); notifyListeners(); return prev; } catch (NoSuchElementException e) { return null; } } }