001package net.filebot.web;
002
003import static java.util.Arrays.*;
004import static java.util.Collections.*;
005import static java.util.stream.Collectors.*;
006
007import java.io.Serializable;
008import java.net.URL;
009import java.util.Comparator;
010import java.util.List;
011import java.util.Locale;
012import java.util.Objects;
013import java.util.function.Predicate;
014
015public class Artwork implements Serializable {
016
017        protected String[] tags;
018        protected URL url;
019
020        protected String language;
021        protected Double rating;
022
023        public Artwork() {
024                // used by serializer
025        }
026
027        public Artwork(URL url, Locale language, Double rating, Object... tags) {
028                this.tags = stream(tags).filter(Objects::nonNull).map(Object::toString).toArray(String[]::new);
029                this.url = url;
030                this.language = getLanguageCode(language);
031                this.rating = rating;
032        }
033
034        public List<String> getTags() {
035                return unmodifiableList(asList(tags));
036        }
037
038        public URL getUrl() {
039                return url;
040        }
041
042        public Locale getLanguage() {
043                return language == null ? null : Locale.forLanguageTag(language);
044        }
045
046        public double getRating() {
047                return rating == null ? 0 : rating;
048        }
049
050        public boolean has(Predicate<String> predicate) {
051                return stream(tags).anyMatch(predicate);
052        }
053
054        public boolean matches(Object... tags) {
055                if (tags == null || tags.length == 0) {
056                        return true;
057                }
058
059                return stream(tags).filter(Objects::nonNull).map(Object::toString).allMatch(tag -> {
060                        return tag.equalsIgnoreCase(language) || has(tag::equalsIgnoreCase);
061                });
062        }
063
064        public String getExtension() {
065                String path = url.getPath();
066                int position = path.lastIndexOf('.');
067                if (position > 0 && position > path.lastIndexOf('/')) {
068                        return path.substring(position + 1);
069                }
070                return null;
071        }
072
073        @Override
074        public int hashCode() {
075                return url.hashCode();
076        }
077
078        @Override
079        public boolean equals(Object other) {
080                if (other instanceof Artwork) {
081                        Artwork artwork = (Artwork) other;
082                        return url.sameFile(artwork.url);
083                }
084                return false;
085        }
086
087        @Override
088        public String toString() {
089                return "[" + String.join("/", tags) + ", " + language + ", " + rating + ", " + url + "]";
090        }
091
092        public static Comparator<Artwork> ratingOrder() {
093                return Comparator.comparing(Artwork::getRating, reverseOrder());
094        }
095
096        public static Comparator<Artwork> noLanguageOrder() {
097                return Comparator.comparingInt(a -> a.language == null ? 0 : 1);
098        }
099
100        public static Comparator<Artwork> languageOrder(Locale... locale) {
101                // prefer no language
102                if (locale == null || locale.length == 0) {
103                        return noLanguageOrder();
104                }
105
106                // prefer language in order
107                List<String> code = stream(locale).map(Artwork::getLanguageCode).distinct().collect(toList());
108
109                Comparator<Artwork> languageOrder = Comparator.comparingInt(a -> {
110                        int index = code.indexOf(a.language);
111                        return index >= 0 ? index : Integer.MAX_VALUE;
112                });
113
114                // then prefer no language over other languages
115                return languageOrder.thenComparing(noLanguageOrder());
116        }
117
118        public static Comparator<Artwork> relevanceOrder(Locale... locale) {
119                // prefer language in order
120                Comparator<Artwork> order = languageOrder(locale);
121
122                // then prefer higher rated ones
123                return order.thenComparing(ratingOrder());
124        }
125
126        private static String getLanguageCode(Locale locale) {
127                return locale == null || locale.getLanguage().isEmpty() ? null : locale.getLanguage();
128        }
129
130}