• MyTrackContainer.java

  • §
    package MusicLandscape.container;
    
    import MusicLandscape.entities.Track;
    import MusicLandscape.util.MyMatcher;
    
    import java.util.*;
  • §

    This class is the same as in ES06.

    /**
     * Represents a set of tracks and a (possibly empty) subset of those tracks which are selected.
     * <p>
     * This class is a container for unique tracks. It does not accept null tracks, nor can a track which is already
     * contained be added again. Additionally, it supports the notion of selection, meaning that some tracks can be
     * selected. The selection is a subset of all tracks currently held by the container. The selection may at times be
     * empty, and it may at other times contain all tracks.
     * <p>
     * The container provides methods to filter, sort, and retrieve the selection.
     * <p>
     * Tracks can only be removed from this container by removing all currently selected tracks. Removing tracks therefore
     * requires the creation of a proper selection first. The usual process of creating a selection is:
     *
     * <ol>
     *   <li>select ALL tracks (by resetting the selection)</li>
     *   <li>(possibly repeatedly) filter the selection with a matcher. The filter is applied to the current selection!</li>
     *   <li>if desired, sort the selection.</li>
     *   <li>remove selected tracks from container OR retrieve the selection as an array of tracks.</li>
     * </ol>
     *
     * @author Jonas Altrock (ew20b126@technikum-wien.at)
     * @version 1
     * @since ExerciseSheet05
     */
    public class MyTrackContainer {
    
        /**
         * The selected tracks in this container.
         * Initially empty.
         */
        private final List<Track> selection = new ArrayList<>();
    
        /**
         * The tracks in this container.
         * Initially empty.
         */
        private final Set<Track> tracks = new HashSet<>();
  • §
        /**
         * Creates a default MyTrackContainer.<br>
         * A default container has no tracks and an empty selection.
         */
        public MyTrackContainer() {
        }
    
        /**
         * Creates a container from an iterable object of tracks.<br>
         * All tracks of the argument are added to this container.
         * <p>
         * Initially, all tracks are selected.
         *
         * @param t the iterable object of tracks to be added to this container.
         */
        public MyTrackContainer(Iterable<Track> t) {
            for (Track track : t) {
                tracks.add(track);
                selection.add(track);
            }
        }
    
        /**
         * Creates a container from an array of tracks.<br>
         * All tracks of the argument are added to this container.
         * <p>
         * Initially, all tracks are selected.
         *
         * @param t the array of tracks to be added to this container.
         */
        public MyTrackContainer(Track[] t) {
            this(List.of(t));
        }
    
        /**
         * Add a single track.<br>
         * The argument is attempted to be added to this container.
         * <p>
         * If successfully added, it is NOT added to the selection. Tracks already added cannot be added again.
         * Null tracks cannot be added either.
         *
         * @param t the track to add
         * @return whether the argument could be added
         */
        public boolean add(Track t) {
            if (t == null) {
                return false;
            }
            if (tracks.contains(t)) {
                return false;
            }
            tracks.add(t);
            return true;
        }
    
    
        /**
         * Bulk operation to add tracks.<br>
         * All tracks of the argument are added to this container.
         *
         * @param t the tracks to add
         * @return the number of tracks added
         */
        public int addAll(Track[] t) {
            int added = 0;
    
            for (Track track : t) {
                if (add(track)) {
                    added++;
                }
            }
    
            return added;
        }
    
    
        /**
         * Filters the selection.<br>
         * Applies the filter defined by the argument to the selection, keeping only those elements that match.
         * <p>
         * The filter is applied to the selection and the selection only, i.e. the selection cannot grow in size during
         * this operation. If all elements of a selection match the specified filter, the selection remains unchanged.
         *
         * @param matcher the filter defining which of the tracks of the selection to keep.
         * @return the number of elements removed from the selection during this operation.
         */
        public int filter(MyMatcher<Track> matcher) {
            int removed = 0;
    
            for (Iterator<Track> it = selection.iterator(); it.hasNext(); ) {
                Track t = it.next();
    
                if (!matcher.matches(t)) {
                    it.remove();
                    removed++;
                }
            }
    
            return removed;
        }
    
        /**
         * Removes the selected tracks from this container.<br>
         * All currently selected tracks are removed from this container.
         * <p>
         * After this operation all remaining tracks are selected (the selection is reset).
         *
         * @return the number of removed tracks
         */
        public int remove() {
            int removed = selection.size();
    
            for (Track track : selection) {
                tracks.remove(track);
            }
    
            reset();
            return removed;
        }
    
        /**
         * Resets the selection, thereby selecting ALL tracks in this container.
         */
        public void reset() {
            selection.retainAll(List.<Track>of());
            selection.addAll(tracks);
        }
    
        /**
         * Gets the selected tacks.<br>
         * The currently selected tracks of this container are returned as an array of tracks.
         * <p>
         * The tracks are returned in their current order.
         * If the selection is empty an array of size 0 is returned.
         *
         * @return the selected tracks.
         */
        public Track[] selection() {
            return selection.toArray(new Track[0]);
        }
    
    
        /**
         * The number of tracks currently held by this container.<br>
         * Note: this is not the size of the selection.
         *
         * @return the number of tracks
         */
        public int size() {
            return tracks.size();
        }
    
    
        /**
         * Sorts the selection of tracks of this container.<br>
         * The currently selected tracks are sorted in the sense defined by the first argument.
         * <p>
         * The second argument controls the scheme (ascending/descending order).
         *
         * @param theComp the comparator defining the sorting order
         * @param asc     the sorting scheme. true stands for ascending (from smallest to highest element) false for descending.
         */
        public void sort(Comparator<Track> theComp, boolean asc) {
            selection.sort(asc ? theComp : theComp.reversed());
        }
    }