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