package org.podcastpedia.web.searching;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
import org.apache.log4j.Logger;
import org.podcastpedia.common.domain.Episode;
import org.podcastpedia.common.domain.Podcast;
import org.podcastpedia.common.types.OrderByOption;
import org.podcastpedia.common.types.SearchModeType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
public class SearchServiceImpl implements SearchService {
protected static Logger LOG = Logger.getLogger(SearchServiceImpl.class);
@Autowired
private SearchDao searchDao;
public void setSearchDao(SearchDao searchDao) {
this.searchDao = searchDao;
}
/** list of international tex for "return all" - used in quick search bar **/
public static final String[] textGetAllPodcastsI18N = {"Search...", "Căutare...",
"Buscar...", "Suchen...", "Rechercher..."};
@Cacheable(value="searchResults")
public SearchResult getResultsForSearchCriteria(SearchData searchData) throws UnsupportedEncodingException {
SearchResult response = new SearchResult();
if(searchData.getCategId()!=null && searchData.getCategId().size() == 0){
searchData.setCategId(null);
}
searchData.setFirstItemOnPage((searchData.getCurrentPage()-1) * searchData.getNumberResultsPerPage());
LOG.debug("Received request in service to invoke dao to make a search in podcasts " +
" for text : " + searchData.getQueryText());
this.buildSQLQuerySearchText(searchData);
response.setNumberOfItemsPerPage(searchData.getNumberResultsPerPage());
response.setCurrentPage(searchData.getCurrentPage());
if( isTargetPodcasts(searchData) ){
enrichResponseWithPodcasts(searchData, response);
} else {
//if not podcasts it must be episodes then, and episodes is also the default search target
enrichResponseWithEpisodes(searchData, response);
}
return response;
}
private boolean isTargetPodcasts(SearchData searchData) {
return searchData.getSearchTarget() !=null && searchData.getSearchTarget().equals("podcasts");
}
private void enrichResponseWithEpisodes(SearchData searchData,
SearchResult response) {
//first get the number of results for search criteria - this is used for pagination
if(searchData.getNrOfResults() == null){
int numberOfEpisodesFound = searchDao.getNumberOfEpisodesForSearchCriteria(searchData);
response.setNumberOfItemsFound(numberOfEpisodesFound);
int mod = numberOfEpisodesFound % searchData.getNumberResultsPerPage();
int dividedBy = numberOfEpisodesFound / searchData.getNumberResultsPerPage();
int numberOfPages = mod > 0 ? dividedBy +1 : dividedBy;
// Casting to an int implicitly drops any decimal part. No need to call Math.floor().
response.setNumberOfPages(numberOfPages);
} else {
response.setNumberOfPages(searchData.getNrResultPages());
response.setNumberOfItemsFound(searchData.getNrResultPages());
}
List<Episode> episodes = null;
episodes = searchDao.getEpisodesForSearchCriteria(searchData);
response.setEpisodes(episodes);
}
private void enrichResponseWithPodcasts(SearchData searchData, SearchResult response) {
if(searchData.getNrOfResults() == null){
int numberOfPodcastsFound = searchDao.getNumberOfPodcastsForSearchCriteria(searchData);
response.setNumberOfItemsFound(numberOfPodcastsFound);
// Casting to an int implicitly drops any decimal part. No need to call Math.floor().
int mod = numberOfPodcastsFound%searchData.getNumberResultsPerPage();
int dividedBy = numberOfPodcastsFound/searchData.getNumberResultsPerPage();
int numberOfPages = mod > 0 ? dividedBy +1 : dividedBy;
response.setNumberOfPages(numberOfPages);
} else {
response.setNumberOfPages(searchData.getNrResultPages());
response.setNumberOfItemsFound(searchData.getNrOfResults());
}
List<Podcast> podcasts = null;
podcasts = searchDao.getPodcastsForSearchCriteria(searchData);
response.setPodcasts(podcasts);
}
private void buildSQLQuerySearchText(SearchData searchData){
if(searchData.getSearchMode().equals(SearchModeType.NATURAL_MODE.getValue())) {
//if it is the default "return all podcasts" as query text than all podcasts will be returned
//QueryText can be null when the request is coming from quick search on the start page
if(isDefaultSearchText(searchData)) {
searchData.setQueryText(null);
//if no order by is selected in this case
if(searchData.getOrderBy() == null){
//this cannot happen from quick search filters from start page
searchData.setOrderBy(OrderByOption.PUBLICATION_DATE);
}
} else {
//if some words are introduced then we should decide the full text indexing to bring the most relevant in front
searchData.setOrderBy(null);
}
// else it means the user has given some input text for natural mode search
}
if(searchData.getSearchMode().equals(SearchModeType.BOOLEAN_MODE.getValue())){
// modify the condition to put queryText maybe in natural and disable it when selecting
//it means that I am in the boolean search mode
//it means we are in the boolean mode so the string has to be built
StringBuffer queryTextBuffer = new StringBuffer();
//start with the all of these words part
if(searchData.getAllTheseWords()!=null
&& !searchData.getAllTheseWords().trim().equals("")){
String[] allWords = searchData.getAllTheseWords().split(" ");
for(String s: allWords){
queryTextBuffer.append(" " + s);
}
}
// none of these words
if(searchData.getNoneOfTheseWords()!=null
&& !searchData.getNoneOfTheseWords().trim().equals("")){
String[] noneOfWords = searchData.getNoneOfTheseWords().split(" ");
for(String s: noneOfWords){
queryTextBuffer.append(" " + s);
}
}
//any of these words - is simply just added
if(searchData.getAnyOfTheseWords()!=null
&& !searchData.getAnyOfTheseWords().trim().equals("")){
queryTextBuffer.append(" " + searchData.getAnyOfTheseWords());
}
//exact phrase
if(searchData.getExactPhrase()!=null
&& !searchData.getExactPhrase().trim().equals("")){
queryTextBuffer.append(" +" + searchData.getExactPhrase());
}
//set the queryText
searchData.setQueryText(queryTextBuffer.toString());
}
}
private boolean isDefaultSearchText(SearchData searchData) {
return searchData.getQueryText() == null || searchData.getQueryText() != null && Arrays.asList(textGetAllPodcastsI18N).contains(searchData.getQueryText().trim());
}
}