Merge commit '77d3a60869e7a780c6ae069e51530e1eacece5e2'
[fanfix.git] / searchable / BasicSearchable.java
1 package be.nikiroo.fanfix.searchable;
2
3 import java.io.IOException;
4 import java.net.URL;
5 import java.util.List;
6
7 import org.jsoup.helper.DataUtil;
8 import org.jsoup.nodes.Document;
9
10 import be.nikiroo.fanfix.Instance;
11 import be.nikiroo.fanfix.data.MetaData;
12 import be.nikiroo.fanfix.supported.BasicSupport;
13 import be.nikiroo.fanfix.supported.SupportType;
14
15 /**
16 * This class supports browsing through stories on the supported websites. It
17 * will fetch some {@link MetaData} that satisfy a search query or some tags if
18 * supported.
19 *
20 * @author niki
21 */
22 public abstract class BasicSearchable {
23 private SupportType type;
24 private BasicSupport support;
25
26 /**
27 * Create a new {@link BasicSearchable} of the given type.
28 *
29 * @param type
30 * the type, must not be NULL
31 */
32 public BasicSearchable(SupportType type) {
33 setType(type);
34 support = BasicSupport.getSupport(getType(), null);
35 }
36
37 /**
38 * Find the given tag by its hierarchical IDs.
39 * <p>
40 * I.E., it will take the tag A, subtag B, subsubtag C...
41 *
42 * @param ids
43 * the IDs to look for
44 *
45 * @return the appropriate tag fully filled, or NULL if not found
46 *
47 * @throws IOException
48 * in case of I/O error
49 */
50 public SearchableTag getTag(Integer... ids) throws IOException {
51 SearchableTag tag = null;
52 List<SearchableTag> tags = getTags();
53
54 for (Integer tagIndex : ids) {
55 // ! 1-based index !
56 if (tagIndex == null || tags == null || tagIndex <= 0
57 || tagIndex > tags.size()) {
58 return null;
59 }
60
61 tag = tags.get(tagIndex - 1);
62 fillTag(tag);
63 tags = tag.getChildren();
64 }
65
66 return tag;
67 }
68
69 /**
70 * The support type.
71 *
72 * @return the type
73 */
74 public SupportType getType() {
75 return type;
76 }
77
78 /**
79 * The support type.
80 *
81 * @param type
82 * the new type
83 */
84 protected void setType(SupportType type) {
85 this.type = type;
86 }
87
88 /**
89 * The associated {@link BasicSupport}.
90 * <p>
91 * Mostly used to download content.
92 *
93 * @return the support
94 */
95 protected BasicSupport getSupport() {
96 return support;
97 }
98
99 /**
100 * Get a list of tags that can be browsed here.
101 *
102 * @return the list of tags
103 *
104 * @throws IOException
105 * in case of I/O error
106 */
107 abstract public List<SearchableTag> getTags() throws IOException;
108
109 /**
110 * Fill the tag (set it 'complete') with more information from the support.
111 *
112 * @param tag
113 * the tag to fill
114 *
115 * @throws IOException
116 * in case of I/O error
117 */
118 abstract public void fillTag(SearchableTag tag) throws IOException;
119
120 /**
121 * Search for the given term and return the number of pages of results of
122 * stories satisfying this search term.
123 *
124 * @param search
125 * the term to search for
126 *
127 * @return a number of pages
128 *
129 * @throws IOException
130 * in case of I/O error
131 */
132 abstract public int searchPages(String search) throws IOException;
133
134 /**
135 * Search for the given tag and return the number of pages of results of
136 * stories satisfying this tag.
137 *
138 * @param tag
139 * the tag to search for
140 *
141 * @return a number of pages
142 *
143 * @throws IOException
144 * in case of I/O error
145 */
146 abstract public int searchPages(SearchableTag tag) throws IOException;
147
148 /**
149 * Search for the given term and return a list of stories satisfying this
150 * search term.
151 * <p>
152 * Not that the returned stories will <b>NOT</b> be complete, but will only
153 * contain enough information to present them to the user and retrieve them.
154 * <p>
155 * URL is guaranteed to be usable, LUID will always be NULL.
156 *
157 * @param search
158 * the term to search for
159 * @param page
160 * the page to use for result pagination, index is 1-based
161 *
162 * @return a list of stories that satisfy that search term
163 *
164 * @throws IOException
165 * in case of I/O error
166 */
167 abstract public List<MetaData> search(String search, int page)
168 throws IOException;
169
170 /**
171 * Search for the given tag and return a list of stories satisfying this
172 * tag.
173 * <p>
174 * Not that the returned stories will <b>NOT</b> be complete, but will only
175 * contain enough information to present them to the user and retrieve them.
176 * <p>
177 * URL is guaranteed to be usable, LUID will always be NULL.
178 *
179 * @param tag
180 * the tag to search for
181 * @param page
182 * the page to use for result pagination (see
183 * {@link SearchableTag#getPages()}, remember to check for -1),
184 * index is 1-based
185 *
186 * @return a list of stories that satisfy that search term
187 *
188 * @throws IOException
189 * in case of I/O error
190 */
191 abstract public List<MetaData> search(SearchableTag tag, int page)
192 throws IOException;
193
194 /**
195 * Load a document from its url.
196 *
197 * @param url
198 * the URL to load
199 * @param stable
200 * TRUE for more stable resources, FALSE when they often change
201 *
202 * @return the document
203 *
204 * @throws IOException
205 * in case of I/O error
206 */
207 protected Document load(String url, boolean stable) throws IOException {
208 return load(new URL(url), stable);
209 }
210
211 /**
212 * Load a document from its url.
213 *
214 * @param url
215 * the URL to load
216 * @param stable
217 * TRUE for more stable resources, FALSE when they often change
218 *
219 * @return the document
220 *
221 * @throws IOException
222 * in case of I/O error
223 */
224 protected Document load(URL url, boolean stable) throws IOException {
225 return DataUtil.load(Instance.getCache().open(url, support, stable),
226 "UTF-8", url.toString());
227 }
228
229 /**
230 * Return a {@link BasicSearchable} implementation supporting the given
231 * type, or NULL if it does not exist.
232 *
233 * @param type
234 * the type, can be NULL (will just return NULL, since we do not
235 * support it)
236 *
237 * @return an implementation that supports it, or NULL
238 */
239 static public BasicSearchable getSearchable(SupportType type) {
240 BasicSearchable support = null;
241
242 if (type != null) {
243 switch (type) {
244 case FIMFICTION:
245 // TODO
246 break;
247 case FANFICTION:
248 support = new Fanfiction(type);
249 break;
250 case MANGAFOX:
251 // TODO
252 break;
253 case E621:
254 // TODO
255 break;
256 case YIFFSTAR:
257 // TODO
258 break;
259 case E_HENTAI:
260 // TODO
261 break;
262 case MANGA_LEL:
263 support = new MangaLel();
264 break;
265 case CBZ:
266 case HTML:
267 case INFO_TEXT:
268 case TEXT:
269 case EPUB:
270 break;
271 }
272 }
273
274 return support;
275 }
276 }