001package net.filebot.web;
002
003import static java.util.Arrays.*;
004import static java.util.Collections.*;
005import static net.filebot.util.RegularExpressions.*;
006
007import java.io.Serializable;
008import java.util.List;
009import java.util.Locale;
010
011import net.filebot.Cache;
012import net.filebot.Cache.TypedCache;
013import net.filebot.CacheType;
014
015public abstract class AbstractEpisodeListProvider implements EpisodeListProvider {
016
017        protected abstract List<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception;
018
019        protected abstract SeriesData fetchSeriesData(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception;
020
021        @Override
022        public List<SearchResult> search(String query, Locale locale) throws Exception {
023                return getSearchCache(locale).computeIfAbsent(query.toLowerCase(locale), it -> {
024                        return fetchSearchResult(query, locale);
025                });
026        }
027
028        @Override
029        public List<SearchResult> lookup(String id, Locale locale) throws Exception {
030                // handle as numeric series id
031                SearchResult series = id(id);
032                if (series != null) {
033                        return singletonList(series);
034                }
035
036                // handle as search query
037                return search(id, locale);
038        }
039
040        @Override
041        public SearchResult id(String query) throws Exception {
042                if (DIGIT.matcher(query).matches()) {
043                        return new SearchResult(Integer.parseInt(query));
044                }
045                return null;
046        }
047
048        @Override
049        public SortOrder vetoRequestParameter(SortOrder order) {
050                return order == null ? SortOrder.Airdate : order;
051        }
052
053        @Override
054        public Locale vetoRequestParameter(Locale locale) {
055                return getLanguageCode(locale) == null ? Locale.ENGLISH : locale;
056        }
057
058        @Override
059        public List<Episode> getEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception {
060                return getSeriesData(searchResult, sortOrder, locale).getEpisodeList();
061        }
062
063        @Override
064        public List<Episode> getEpisodeList(int id, SortOrder order, Locale locale) throws Exception {
065                return getEpisodeList(new SearchResult(id), order, locale);
066        }
067
068        @Override
069        public SeriesInfo getSeriesInfo(SearchResult searchResult, Locale locale) throws Exception {
070                return getSeriesData(searchResult, null, locale).getSeriesInfo();
071        }
072
073        @Override
074        public SeriesInfo getSeriesInfo(int id, Locale locale) throws Exception {
075                return getSeriesInfo(new SearchResult(id), locale);
076        }
077
078        @Override
079        public List<? extends SearchResult> getIndex() throws Exception {
080                return emptyList();
081        }
082
083        protected SeriesData getSeriesData(SearchResult searchResult, SortOrder order, Locale locale) throws Exception {
084                // override preferences if requested parameters are not supported
085                SortOrder requestOrder = vetoRequestParameter(order);
086                Locale requestLanguage = vetoRequestParameter(locale);
087
088                return getDataCache(requestOrder, requestLanguage).computeIfAbsent(searchResult.getId(), it -> {
089                        return fetchSeriesData(searchResult, requestOrder, requestLanguage);
090                });
091        }
092
093        protected String getLanguageCode(Locale locale) {
094                if (locale == null) {
095                        return null;
096                }
097
098                String language = locale.getLanguage();
099
100                // Note: ISO 639 is not a stable standard— some languages' codes have changed.
101                // Locale's constructor recognizes both the new and the old codes for the languages whose codes have changed,
102                // but this function always returns the old code.
103                switch (language) {
104                case "iw":
105                        return "he"; // Hebrew
106                case "in":
107                        return "id"; // Indonesian
108                case "":
109                        return null; // empty language code
110                default:
111                        return language;
112                }
113        }
114
115        protected Cache getCache(String section) {
116                return Cache.getCache(getName() + "_" + section, CacheType.Daily);
117        }
118
119        protected TypedCache<List<SearchResult>> getSearchCache(Locale locale) {
120                return getCache("search_" + getLanguageCode(locale)).castList(SearchResult.class);
121        }
122
123        protected TypedCache<SeriesData> getDataCache(SortOrder order, Locale locale) {
124                return getCache("data_" + order.ordinal() + "_" + getLanguageCode(locale)).cast(SeriesData.class);
125        }
126
127        protected static class SeriesData implements Serializable {
128
129                public SeriesInfo seriesInfo;
130                public Episode[] episodeList;
131
132                public SeriesData() {
133                        // used by serializer
134                }
135
136                public SeriesData(SeriesInfo seriesInfo, List<Episode> episodeList) {
137                        this.seriesInfo = seriesInfo;
138                        this.episodeList = episodeList.toArray(new Episode[0]);
139                }
140
141                public SeriesInfo getSeriesInfo() {
142                        return seriesInfo.clone();
143                }
144
145                public List<Episode> getEpisodeList() {
146                        return unmodifiableList(asList(episodeList));
147                }
148        }
149
150}