1 package be
.nikiroo
.fanfix
.searchable
;
3 import java
.util
.ArrayList
;
7 * This class represents a tag that can be searched on a supported website.
11 public class SearchableTag
{
14 private boolean complete
;
17 private SearchableTag parent
;
18 private List
<SearchableTag
> children
;
21 * The number of stories result pages this tag can get.
23 * We keep more information than what the getter/setter returns/accepts.
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>
34 * Create a new {@link SearchableTag}.
36 * Note that tags are complete by default.
39 * the ID (usually a way to find the linked stories later on)
41 * the tag name, which can be displayed to the user
43 * the tag is a leaf tag, that is, it will not return subtags
44 * with {@link BasicSearchable#fillTag(SearchableTag)} but will
46 * {@link BasicSearchable#search(SearchableTag, int)}
48 public SearchableTag(String id
, String name
, boolean leaf
) {
49 this(id
, name
, leaf
, true);
53 * Create a new {@link SearchableTag}.
56 * the ID (usually a way to find the linked stories later on)
58 * the tag name, which can be displayed to the user
60 * the tag is a leaf tag, that is, it will not return subtags
61 * with {@link BasicSearchable#fillTag(SearchableTag)} but will
63 * {@link BasicSearchable#search(SearchableTag, int)}
65 * the tag {@link SearchableTag#isComplete()} or not
67 public SearchableTag(String id
, String name
, boolean leaf
, boolean complete
) {
70 this.complete
= leaf
|| complete
;
74 children
= new ArrayList
<SearchableTag
>();
78 * The ID (usually a way to find the linked stories later on).
82 public String
getId() {
87 * The tag name, which can be displayed to the user.
91 public String
getName() {
96 * The fully qualified tag name, which can be displayed to the user.
98 * It will display all the tags that lead to this one as well as this one.
100 * @return the fully qualified name
102 public String
getFqName() {
103 if (parent
!= null) {
104 return parent
.getFqName() + " / " + name
;
111 * Non-complete, non-leaf tags can still be completed via a
112 * {@link BasicSearchable#fillTag(SearchableTag)} operation from a
113 * {@link BasicSearchable}, in order to gain (more?) subtag children.
115 * Leaf tags are always considered complete.
117 * @return TRUE if it is complete
119 public boolean isComplete() {
124 * Non-complete, non-leaf tags can still be completed via a
125 * {@link BasicSearchable#fillTag(SearchableTag)} operation from a
126 * {@link BasicSearchable}, in order to gain (more?) subtag children.
128 * Leaf tags are always considered complete.
131 * TRUE if it is complete
133 public void setComplete(boolean complete
) {
134 this.complete
= isLeaf() || complete
;
138 * The number of items that can be found with this tag if it is searched.
140 * Will report the number of subtags by default.
142 * @return the number of items
144 public long getCount() {
145 long count
= this.count
;
147 count
= children
.size();
154 * The number of items that can be found with this tag if it is searched.
159 public void setCount(long count
) {
164 * The number of stories result pages this tag contains, only make sense if
165 * {@link SearchableTag#isLeaf()} returns TRUE.
167 * Will return -1 if the number is not yet known.
169 * @return the number of pages, or -1
171 public int getPages() {
172 return Math
.max(-1, pages
);
176 * The number of stories result pages this tag contains, only make sense if
177 * {@link SearchableTag#isLeaf()} returns TRUE.
180 * the (positive or 0) number of pages
182 public void setPages(int pages
) {
183 this.pages
= Math
.max(-1, pages
);
187 * This tag is a leaf tag, that is, it will not return other subtags with
188 * {@link BasicSearchable#fillTag(SearchableTag)} but will return stories
189 * with {@link BasicSearchable#search(SearchableTag, int)}.
191 * @return TRUE if it is
193 public boolean isLeaf() {
198 * This tag is a leaf tag, that is, it will not return other subtags with
199 * {@link BasicSearchable#fillTag(SearchableTag)} but will return stories
200 * with {@link BasicSearchable#search(SearchableTag, int)}.
202 * Will reset the number of pages to -1.
207 public void setLeaf(boolean leaf
) {
208 pages
= leaf ?
-1 : -2;
215 * The subtag children of this {@link SearchableTag}.
219 * Note that if {@link SearchableTag#isComplete()} returns false, you can
220 * still fill (more?) subtag children with a {@link BasicSearchable}.
222 * @return the subtag children, never NULL
224 public List
<SearchableTag
> getChildren() {
229 * Add the given {@link SearchableTag} as a subtag child.
234 public void add(SearchableTag tag
) {
236 throw new NullPointerException("tag");
239 for (SearchableTag p
= this; p
!= null; p
= p
.parent
) {
241 throw new IllegalArgumentException(
242 "Tags do not allow recursion");
245 for (SearchableTag p
= tag
; p
!= null; p
= p
.parent
) {
246 if (p
.equals(this)) {
247 throw new IllegalArgumentException(
248 "Tags do not allow recursion");
257 * This {@link SearchableTag} parent tag, or NULL if none.
259 * @return the parent or NULL
261 public SearchableTag
getParent() {
266 * Display a DEBUG {@link String} representation of this object.
269 public String
toString() {
270 String rep
= name
+ " [" + id
+ "]";
275 if (getCount() > 0) {
276 rep
+= " (" + getCount() + ")";
279 if (!children
.isEmpty()) {
282 for (SearchableTag tag
: children
) {
283 if (!tags
.isEmpty()) {
303 public int hashCode() {
304 return getFqName().hashCode();
308 public boolean equals(Object otherObj
) {
309 if (otherObj
instanceof SearchableTag
) {
310 SearchableTag other
= (SearchableTag
) otherObj
;
311 if ((id
== null && other
.id
== null)
312 || (id
!= null && id
.equals(other
.id
))) {
313 if (getFqName().equals(other
.getFqName())) {
314 if ((parent
== null && other
.parent
== null)
315 || (parent
!= null && parent
.equals(other
.parent
))) {