package com.packtpub.hibernatesearch.util;

import java.util.StringTokenizer;

import org.apache.lucene.index.Term;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.QueryWrapperFilter;
import org.hibernate.search.annotations.Factory;
import org.hibernate.search.annotations.Key;
import org.hibernate.search.filter.FilterKey;
import org.hibernate.search.filter.impl.CachingWrapperFilter;

/**
 * Klasa dostarcza logikę filtrującą encje "App" na podstawie tego, czy encja Device znajduje się na ich liście 
 * "supportedDevices". Ta klasa fabryki jest powiązana z encją App za pośrednictwem adnotacji
 * @FullTextFilterDef.
 */
public class DeviceFilterFactory {

	private String deviceName;
	
	/**
	 * Jeżeli fabryka filtrów przyjmuje parametry (np. "deviceName"), albo nie wyłącza buforowania filtrów, które
	 * jest domyślnie włączone, wtedy musi mieć metodę zawierającą adnotację @Key, zwracającą obiekt typu 
	 * FilterKey. Poniższa metoda używa klasy operującej na paremetrze "deviceName" (patrz DeviceFilterKey).    
	 */
	@Key
	public FilterKey getKey() {
		DeviceFilterKey key = new DeviceFilterKey();
		key.setDeviceName(this.deviceName);
		return key;
	}
	
	/**
	 * Gdy adnotacja @FullTextFilterDef połączy fabrykę z daną nazwą a "FullTextQuery.enableFullTextFilter()" zostanie 
	 * wywołany z tą nazwą jako parametrem, poniższa metoda jest odpowiedzialna za zwrócenie filtru implementującego logikę filtrowania.
	 * Adnotacja @Factory wskazuje ją jako odpowiedzialną za utworzenie filtru. 
	 */
	@Factory
	public Filter getFilter() {
		StringTokenizer tokenzier = new StringTokenizer(deviceName.toLowerCase());
		PhraseQuery query = new PhraseQuery();
		while(tokenzier.hasMoreTokens()) {
			// Standardowo wartości pól miały zamienione wielkie litery na małe podczas indeksowania w Lucene. Pamiętaj o  
			// przekonwertowaniu w ten sam sposób słów kluczowych.
			Term term = new Term("supportedDevices.name", tokenzier.nextToken().toLowerCase());
			query.add(term);
		}
		Filter filter = new QueryWrapperFilter(query);
		return new CachingWrapperFilter(filter);
	}
	
	public String getDeviceName() {
		return this.deviceName;
	}
	
	public void setDeviceName(String deviceName) {
		this.deviceName = deviceName.toLowerCase();
	}
	
}
