Commit | Line | Data |
---|---|---|
fd69647f NR |
1 | package be.nikiroo.fanfix.searchable; |
2 | ||
3 | import java.util.ArrayList; | |
4 | import java.util.List; | |
5 | ||
6 | /** | |
7 | * This class represents a tag that can be searched on a supported website. | |
8 | * | |
9 | * @author niki | |
10 | */ | |
11 | public class SearchableTag { | |
12 | private String id; | |
13 | private String name; | |
14 | private boolean complete; | |
15 | private long count; | |
e66c9078 NR |
16 | |
17 | private SearchableTag parent; | |
fd69647f NR |
18 | private List<SearchableTag> children; |
19 | ||
76ec935e NR |
20 | /** |
21 | * The number of stories result pages this tag can get. | |
22 | * <p> | |
23 | * We keep more information than what the getter/setter returns/accepts. | |
24 | * <ul> | |
25 | * <li>-2: this tag does not support stories results (not a leaf tag)</li> | |
26 | * <li>-1: the number is not yet known, but will be known after a | |
27 | * {@link BasicSearchable#fillTag(SearchableTag)} operation</li> | |
28 | * <li>X: the number of pages</li> | |
29 | * </ul> | |
30 | */ | |
31 | private int pages; | |
32 | ||
fd69647f NR |
33 | /** |
34 | * Create a new {@link SearchableTag}. | |
76ec935e NR |
35 | * <p> |
36 | * Note that tags are complete by default. | |
fd69647f NR |
37 | * |
38 | * @param id | |
39 | * the ID (usually a way to find the linked stories later on) | |
40 | * @param name | |
41 | * the tag name, which can be displayed to the user | |
76ec935e NR |
42 | * @param leaf |
43 | * the tag is a leaf tag, that is, it will not return subtags | |
44 | * with {@link BasicSearchable#fillTag(SearchableTag)} but will | |
45 | * return stories with | |
46 | * {@link BasicSearchable#search(SearchableTag)} | |
47 | */ | |
48 | public SearchableTag(String id, String name, boolean leaf) { | |
49 | this(id, name, leaf, true); | |
50 | } | |
51 | ||
52 | /** | |
53 | * Create a new {@link SearchableTag}. | |
54 | * | |
55 | * @param id | |
56 | * the ID (usually a way to find the linked stories later on) | |
57 | * @param name | |
58 | * the tag name, which can be displayed to the user | |
59 | * @param leaf | |
60 | * the tag is a leaf tag, that is, it will not return subtags | |
61 | * with {@link BasicSearchable#fillTag(SearchableTag)} but will | |
62 | * return stories with | |
63 | * {@link BasicSearchable#search(SearchableTag)} | |
fd69647f | 64 | * @param complete |
76ec935e | 65 | * the tag {@link SearchableTag#isComplete()} or not |
fd69647f | 66 | */ |
76ec935e | 67 | public SearchableTag(String id, String name, boolean leaf, boolean complete) { |
fd69647f NR |
68 | this.id = id; |
69 | this.name = name; | |
70 | this.complete = complete; | |
71 | ||
76ec935e NR |
72 | setLeaf(leaf); |
73 | ||
fd69647f NR |
74 | children = new ArrayList<SearchableTag>(); |
75 | } | |
76 | ||
76ec935e NR |
77 | /** |
78 | * The ID (usually a way to find the linked stories later on). | |
79 | * | |
80 | * @return the ID | |
81 | */ | |
fd69647f NR |
82 | public String getId() { |
83 | return id; | |
84 | } | |
85 | ||
76ec935e NR |
86 | /** |
87 | * The tag name, which can be displayed to the user. | |
88 | * | |
89 | * @return then name | |
90 | */ | |
fd69647f NR |
91 | public String getName() { |
92 | return name; | |
93 | } | |
94 | ||
95 | /** | |
76ec935e NR |
96 | * Non-complete, non-leaf tags can still be completed via a |
97 | * {@link BasicSearchable#fillTag(SearchableTag)} operation from a | |
fd69647f | 98 | * {@link BasicSearchable}, in order to gain (more?) subtag children. |
76ec935e NR |
99 | * <p> |
100 | * This method does not make sense for leaf tags. | |
fd69647f | 101 | * |
76ec935e | 102 | * @return TRUE if it is complete |
fd69647f NR |
103 | */ |
104 | public boolean isComplete() { | |
105 | return complete; | |
106 | } | |
107 | ||
108 | /** | |
76ec935e NR |
109 | * Non-complete, non-leaf tags can still be completed via a |
110 | * {@link BasicSearchable#fillTag(SearchableTag)} operation from a | |
fd69647f | 111 | * {@link BasicSearchable}, in order to gain (more?) subtag children. |
76ec935e NR |
112 | * <p> |
113 | * This method does not make sense for leaf tags. | |
fd69647f NR |
114 | * |
115 | * @param complete | |
76ec935e | 116 | * TRUE if it is complete |
fd69647f NR |
117 | */ |
118 | public void setComplete(boolean complete) { | |
119 | this.complete = complete; | |
120 | } | |
121 | ||
122 | /** | |
123 | * The number of items that can be found with this tag if it is searched. | |
124 | * <p> | |
125 | * Will report the number of subtags by default. | |
126 | * | |
127 | * @return the number of items | |
128 | */ | |
129 | public long getCount() { | |
130 | long count = this.count; | |
131 | if (count <= 0) { | |
132 | count = children.size(); | |
133 | } | |
134 | ||
135 | return count; | |
136 | } | |
137 | ||
138 | /** | |
139 | * The number of items that can be found with this tag if it is searched, | |
140 | * displayable format. | |
141 | * <p> | |
142 | * Will report the number of subtags by default. | |
143 | * | |
144 | * @return the number of items | |
145 | */ | |
146 | public String getCountDisplay() { | |
147 | long count = this.count; | |
148 | if (count <= 0) { | |
149 | count = children.size(); | |
150 | } | |
151 | ||
152 | if (count > 999999) { | |
153 | return count / 1000000 + "M"; | |
154 | } | |
155 | ||
156 | if (count > 2000) { | |
157 | return count / 1000 + "k"; | |
158 | } | |
159 | ||
160 | return Long.toString(count); | |
161 | } | |
162 | ||
163 | /** | |
164 | * The number of items that can be found with this tag if it is searched. | |
165 | * | |
166 | * @param count | |
167 | * the new count | |
168 | */ | |
169 | public void setCount(long count) { | |
170 | this.count = count; | |
171 | } | |
172 | ||
76ec935e NR |
173 | /** |
174 | * The number of stories result pages this tag contains, only make sense if | |
175 | * {@link SearchableTag#isLeaf()} returns TRUE. | |
176 | * <p> | |
177 | * Will return -1 if the number is not yet known. | |
178 | * | |
179 | * @return the number of pages, or -1 | |
180 | */ | |
181 | public int getPages() { | |
182 | return Math.max(-1, pages); | |
183 | } | |
184 | ||
185 | /** | |
186 | * The number of stories result pages this tag contains, only make sense if | |
187 | * {@link SearchableTag#isLeaf()} returns TRUE. | |
188 | * | |
189 | * @param pages | |
190 | * the (positive or 0) number of pages | |
191 | */ | |
192 | public void setPages(int pages) { | |
193 | this.pages = Math.max(-1, pages); | |
194 | } | |
195 | ||
196 | /** | |
197 | * This tag is a leaf tag, that is, it will not return other subtags with | |
198 | * {@link BasicSearchable#fillTag(SearchableTag)} but will return stories | |
199 | * with {@link BasicSearchable#search(SearchableTag)}. | |
200 | * | |
201 | * @return TRUE if it is | |
202 | */ | |
203 | public boolean isLeaf() { | |
204 | return pages > -2; | |
205 | } | |
206 | ||
207 | /** | |
208 | * This tag is a leaf tag, that is, it will not return other subtags with | |
209 | * {@link BasicSearchable#fillTag(SearchableTag)} but will return stories | |
210 | * with {@link BasicSearchable#search(SearchableTag)}. | |
211 | * <p> | |
212 | * Will reset the number of pages to -1. | |
213 | * | |
214 | * @param leaf | |
215 | * TRUE if it is | |
216 | */ | |
217 | public void setLeaf(boolean leaf) { | |
218 | pages = leaf ? -1 : -2; | |
219 | } | |
220 | ||
fd69647f NR |
221 | /** |
222 | * The subtag children of this {@link SearchableTag}. | |
223 | * <p> | |
224 | * Never NULL. | |
225 | * <p> | |
226 | * Note that if {@link SearchableTag#isComplete()} returns false, you can | |
227 | * still fill (more?) subtag children with a {@link BasicSearchable}. | |
228 | * | |
229 | * @return the subtag children, never NULL | |
230 | */ | |
231 | public List<SearchableTag> getChildren() { | |
232 | return children; | |
233 | } | |
234 | ||
235 | /** | |
236 | * Add the given {@link SearchableTag} as a subtag child. | |
237 | * | |
238 | * @param tag | |
239 | * the tag to add | |
240 | */ | |
241 | public void add(SearchableTag tag) { | |
242 | children.add(tag); | |
e66c9078 NR |
243 | tag.parent = this; |
244 | } | |
245 | ||
246 | /** | |
247 | * This {@link SearchableTag} parent tag, or NULL if none. | |
248 | * | |
249 | * @return the parent or NULL | |
250 | */ | |
251 | public SearchableTag getParent() { | |
252 | return parent; | |
fd69647f NR |
253 | } |
254 | ||
255 | /** | |
256 | * Display a DEBUG {@link String} representation of this object. | |
257 | */ | |
258 | @Override | |
259 | public String toString() { | |
260 | String rep = name + " [" + id + "]"; | |
261 | if (!complete) { | |
262 | rep += "*"; | |
263 | } | |
264 | ||
265 | if (getCount() > 0) { | |
266 | rep += " (" + getCountDisplay() + ")"; | |
267 | } | |
268 | ||
269 | if (!children.isEmpty()) { | |
270 | String tags = ""; | |
271 | int i = 1; | |
272 | for (SearchableTag tag : children) { | |
273 | if (!tags.isEmpty()) { | |
274 | tags += ", "; | |
275 | } | |
276 | ||
277 | if (i > 10) { | |
278 | tags += "..."; | |
279 | break; | |
280 | } | |
281 | ||
282 | tags += tag; | |
283 | i++; | |
284 | } | |
285 | ||
286 | rep += ": " + tags; | |
287 | } | |
288 | ||
289 | return rep; | |
290 | } | |
291 | } |