/* Copyright (C) 2013 Prasanna Thirumalai This file is part of StackX. StackX is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. StackX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with StackX. If not, see <http://www.gnu.org/licenses/>. */ package com.prasanna.android.stacknetwork.model; import java.io.Serializable; import java.lang.ref.SoftReference; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import com.prasanna.android.stacknetwork.utils.Validate; public class SearchCriteria implements Serializable { private static final long serialVersionUID = -2988724752735247609L; public static final int DEFAULT_PAGE_SIZE = 15; public static final String Q = "q"; public static final String TITLE = "title"; public static final String TAGGED = "tagged"; public static final String NOT_TAGGED = "nottagged"; public static final String ANSWERS = "answers"; public static final String ACCEPTED = "accepted"; public static final String PAGE = "page"; public static final String PAGESIZE = "pagesize"; public static final String SORT = "sort"; public enum SearchSort { ACTIVITY("activity"), CREATION("creation"), VOTES("votes"), RELEVANCE("relevance"); private final String val; private SearchSort(String val) { this.val = val; } public String getValue() { return val; } public static SearchSort getEnum(String value) { if (value == null) return null; try { return valueOf(value.toUpperCase()); } catch (IllegalArgumentException e) { return null; } } } private static SoftReference<SearchCriteria> self; private final HashMap<String, String> criteria; private HashSet<String> includeTags; private HashSet<String> excludeTags; private int page = 1; public static SearchCriteria newCriteria(String query) { self = new SoftReference<SearchCriteria>(new SearchCriteria(query)); return self.get(); } public static SearchCriteria newCriteria() { self = new SoftReference<SearchCriteria>(new SearchCriteria()); return self.get(); } private SearchCriteria() { criteria = new HashMap<String, String>(); } private SearchCriteria(String query) { criteria = new HashMap<String, String>(); setQuery(query); } public SearchCriteria setQuery(String query) { if (query != null) criteria.put(Q, query); return this; } public SearchCriteria removeQuery() { criteria.remove(Q); return this; } public SearchCriteria setMinAnswers(int minAns) { if (minAns > 0) criteria.put(ANSWERS, String.valueOf(minAns)); return this; } public SearchCriteria removeMinAnswers() { criteria.remove(ANSWERS); return this; } public SearchCriteria clearAnswered() { criteria.remove(ACCEPTED); return this; } public SearchCriteria mustBeAnswered() { criteria.put(ACCEPTED, String.valueOf(true)); return this; } public SearchCriteria sortBy(SearchSort searchSort) { if (searchSort != null) criteria.put(SORT, searchSort.getValue()); return this; } public SearchCriteria setPageSize(int pageSize) { criteria.put(PAGESIZE, String.valueOf(pageSize)); return this; } public SearchCriteria includeTag(String tag) { if (includeTags == null) includeTags = new HashSet<String>(); if (!Validate.isEmptyString(tag)) includeTags.add(tag); return this; } public SearchCriteria includeTags(Collection<String> tags) { if (tags != null) { if (includeTags == null) includeTags = new HashSet<String>(); if (tags.isEmpty()) { includeTags.clear(); criteria.remove(TAGGED); } else includeTags.addAll(tags); } return this; } public SearchCriteria excludeTag(String tag) { if (excludeTags == null) excludeTags = new HashSet<String>(); if (!Validate.isEmptyString(tag)) excludeTags.add(tag); return this; } public SearchCriteria excludeTags(Collection<String> tags) { if (tags != null) { if (excludeTags == null) excludeTags = new HashSet<String>(); if (tags.isEmpty()) { excludeTags.clear(); criteria.remove(NOT_TAGGED); } else excludeTags.addAll(tags); } return this; } public SearchCriteria addIncludedTagsAsSemiColonDelimitedString(String tags) { if (tags != null) criteria.put(TAGGED, tags); return this; } public SearchCriteria addExcludedTagsAsSemiColonDelimitedString(String tags) { if (tags != null) criteria.put(NOT_TAGGED, tags); return this; } public String getQuery() { return criteria.get(Q); } public boolean isAnswered() { return criteria.get(ACCEPTED) != null && Boolean.valueOf(criteria.get(ACCEPTED)); } public int getAnswerCount() { return criteria.get(ANSWERS) == null ? 0 : Integer.valueOf(criteria.get(ANSWERS)); } public String getIncludedTagsAsSemicolonDelimitedString() { return criteria.get(TAGGED); } public String getExcludedTagsAsSemicolonDelimitedString() { return criteria.get(NOT_TAGGED); } public SearchCriteria build() { page = 1; criteria.put(PAGE, String.valueOf(page)); if (!criteria.containsKey(PAGESIZE)) setPageSize(DEFAULT_PAGE_SIZE); if (includeTags != null && !includeTags.isEmpty()) addCriteria(TAGGED, getAsDelimitedString(includeTags, ";")); if (excludeTags != null && !excludeTags.isEmpty()) addCriteria(NOT_TAGGED, getAsDelimitedString(excludeTags, ";")); return this; } private String getAsDelimitedString(HashSet<String> tags, String delim) { StringBuilder sb = new StringBuilder(); Iterator<String> iterator = tags.iterator(); while (iterator.hasNext()) { sb.append(iterator.next()); if (iterator.hasNext()) sb.append(delim); } return sb.toString(); } public String getSort() { return criteria.get(SORT); } public SearchCriteria nextPage() { criteria.put(PAGE, String.valueOf(++page)); return this; } public SearchCriteria queryMustInTitle() { criteria.put(TITLE, criteria.get(Q)); return this; } public String[] getTaggedArray() { String tags = getIncludedTagsAsSemicolonDelimitedString(); if (tags == null) return null; return tags.split(";"); } public String[] getNotTaggedArray() { String tags = getExcludedTagsAsSemicolonDelimitedString(); if (tags == null) return null; return tags.split(";"); } public void addCriteria(String name, String value) { criteria.put(name, value); } public Map<String, String> getMap() { return criteria; } public SearchCriteria clear() { if (criteria != null) criteria.clear(); if (includeTags != null) includeTags.clear(); if (excludeTags != null) excludeTags.clear(); page = 1; return this; } public static SearchCriteria copy(SearchCriteria that) { if (that != null) { SearchCriteria criteria = new SearchCriteria(); criteria.setQuery(that.getQuery()); criteria.setMinAnswers(criteria.getAnswerCount()); if (criteria.isAnswered()) criteria.mustBeAnswered(); String[] tagArray = that.getTaggedArray(); if (tagArray != null) { for (String tag : tagArray) criteria.includeTag(tag); } tagArray = that.getNotTaggedArray(); if (tagArray != null) { for (String tag : that.getNotTaggedArray()) criteria.excludeTag(tag); } return criteria; } return null; } }