package com.browseengine.bobo.facets;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import com.browseengine.bobo.api.BoboSegmentReader;
import com.browseengine.bobo.api.BrowseSelection;
import com.browseengine.bobo.api.BrowseSelection.ValueOperation;
import com.browseengine.bobo.api.FacetAccessible;
import com.browseengine.bobo.api.FacetSpec;
import com.browseengine.bobo.facets.filter.EmptyFilter;
import com.browseengine.bobo.facets.filter.RandomAccessAndFilter;
import com.browseengine.bobo.facets.filter.RandomAccessFilter;
import com.browseengine.bobo.facets.filter.RandomAccessNotFilter;
import com.browseengine.bobo.facets.filter.RandomAccessOrFilter;
import com.browseengine.bobo.sort.DocComparatorSource;
/**
* FacetHandler definition
*
*/
public abstract class FacetHandler<D> {
public static class FacetDataNone implements Serializable {
private static final long serialVersionUID = 1L;
public static FacetDataNone instance = new FacetDataNone();
private FacetDataNone() {
}
}
protected final String _name;
private final Set<String> _dependsOn;
private final Map<String, FacetHandler<?>> _dependedFacetHandlers;
private TermCountSize _termCountSize;
public static enum TermCountSize {
small, medium, large
}
/**
* Constructor
* @param name name
* @param dependsOn Set of names of facet handlers this facet handler depend on for loading
*/
public FacetHandler(String name, Set<String> dependsOn) {
_name = name;
_dependsOn = new HashSet<String>();
if (dependsOn != null) {
_dependsOn.addAll(dependsOn);
}
_dependedFacetHandlers = new HashMap<String, FacetHandler<?>>();
_termCountSize = TermCountSize.large;
}
public FacetHandler<D> setTermCountSize(String termCountSize) {
setTermCountSize(TermCountSize.valueOf(termCountSize.toLowerCase()));
return this;
}
public FacetHandler<D> setTermCountSize(TermCountSize termCountSize) {
_termCountSize = termCountSize;
return this;
}
public TermCountSize getTermCountSize() {
return _termCountSize;
}
/**
* Constructor
* @param name name
*/
public FacetHandler(String name) {
this(name, null);
}
/**
* Gets the name
* @return name
*/
public final String getName() {
return _name;
}
/**
* Gets names of the facet handler this depends on
* @return set of facet handler names
*/
public final Set<String> getDependsOn() {
return _dependsOn;
}
/**
* Adds a list of depended facet handlers
* @param facetHandler depended facet handler
*/
public final void putDependedFacetHandler(FacetHandler<?> facetHandler) {
_dependedFacetHandlers.put(facetHandler._name, facetHandler);
}
/**
* Gets a depended facet handler
* @param name facet handler name
* @return facet handler instance
*/
public final FacetHandler<?> getDependedFacetHandler(String name) {
return _dependedFacetHandlers.get(name);
}
/**
* Load information from an index reader, initialized by {@link BoboSegmentReader}
* @param reader reader
* @throws IOException
*/
abstract public D load(BoboSegmentReader reader) throws IOException;
public FacetAccessible merge(FacetSpec fspec, List<FacetAccessible> facetList) {
return new CombinedFacetAccessible(fspec, facetList);
}
@SuppressWarnings("unchecked")
public D getFacetData(BoboSegmentReader reader) {
return (D) reader.getFacetData(_name);
}
public D load(BoboSegmentReader reader, BoboSegmentReader.WorkArea workArea) throws IOException {
return load(reader);
}
public void loadFacetData(BoboSegmentReader reader, BoboSegmentReader.WorkArea workArea)
throws IOException {
reader.putFacetData(_name, load(reader, workArea));
}
public void loadFacetData(BoboSegmentReader reader) throws IOException {
reader.putFacetData(_name, load(reader));
}
/**
* Gets a filter from a given selection
* @param sel selection
* @return a filter
* @throws IOException
* @throws IOException
*/
public RandomAccessFilter buildFilter(BrowseSelection sel) throws IOException {
String[] selections = sel.getValues();
String[] notSelections = sel.getNotValues();
Properties prop = sel.getSelectionProperties();
RandomAccessFilter filter = null;
if (selections != null && selections.length > 0) {
if (sel.getSelectionOperation() == ValueOperation.ValueOperationAnd) {
filter = buildRandomAccessAndFilter(selections, prop);
if (filter == null) {
filter = EmptyFilter.getInstance();
}
} else {
filter = buildRandomAccessOrFilter(selections, prop, false);
if (filter == null) {
return EmptyFilter.getInstance();
}
}
}
if (notSelections != null && notSelections.length > 0) {
RandomAccessFilter notFilter = buildRandomAccessOrFilter(notSelections, prop, true);
if (filter == null) {
filter = notFilter;
} else {
RandomAccessFilter andFilter = new RandomAccessAndFilter(
Arrays.asList(new RandomAccessFilter[] { filter, notFilter }));
filter = andFilter;
}
}
return filter;
}
abstract public RandomAccessFilter buildRandomAccessFilter(String value,
Properties selectionProperty) throws IOException;
public RandomAccessFilter buildRandomAccessAndFilter(String[] vals, Properties prop)
throws IOException {
ArrayList<RandomAccessFilter> filterList = new ArrayList<RandomAccessFilter>(vals.length);
for (String val : vals) {
RandomAccessFilter f = buildRandomAccessFilter(val, prop);
if (f != null) {
filterList.add(f);
} else {
return EmptyFilter.getInstance();
}
}
if (filterList.size() == 1) return filterList.get(0);
return new RandomAccessAndFilter(filterList);
}
public RandomAccessFilter buildRandomAccessOrFilter(String[] vals, Properties prop, boolean isNot)
throws IOException {
ArrayList<RandomAccessFilter> filterList = new ArrayList<RandomAccessFilter>(vals.length);
for (String val : vals) {
RandomAccessFilter f = buildRandomAccessFilter(val, prop);
if (f != null && !(f instanceof EmptyFilter)) {
filterList.add(f);
}
}
RandomAccessFilter finalFilter;
if (filterList.size() == 0) {
finalFilter = EmptyFilter.getInstance();
} else {
finalFilter = new RandomAccessOrFilter(filterList);
}
if (isNot) {
finalFilter = new RandomAccessNotFilter(finalFilter);
}
return finalFilter;
}
/**
* Gets a FacetCountCollector
* @param sel selection
* @param fspec facetSpec
* @return a FacetCountCollector
*/
abstract public FacetCountCollectorSource getFacetCountCollectorSource(BrowseSelection sel,
FacetSpec fspec);
/**
* Override this method if your facet handler have a better group mode like the SimpleFacetHandler.
*/
public FacetCountCollectorSource getFacetCountCollectorSource(BrowseSelection sel,
FacetSpec ospec, boolean groupMode) {
return getFacetCountCollectorSource(sel, ospec);
}
/**
* Gets the field value
* @param id doc
* @param reader index reader
* @return array of field values
* @see #getFieldValue(BoboSegmentReader,int)
*/
abstract public String[] getFieldValues(BoboSegmentReader reader, int id);
public int getNumItems(BoboSegmentReader reader, int id) {
throw new UnsupportedOperationException("getNumItems is not supported for this facet handler: "
+ getClass().getName());
}
public Object[] getRawFieldValues(BoboSegmentReader reader, int id) {
return getFieldValues(reader, id);
}
/**
* Gets a single field value
* @param id doc
* @param reader index reader
* @return first field value
* @see #getFieldValues(BoboSegmentReader,int)
*/
public String getFieldValue(BoboSegmentReader reader, int id) {
String[] values = getFieldValues(reader, id);
if (values == null || values.length == 0) {
return null;
}
return values[0];
}
/**
* builds a comparator to determine how sorting is done
* @return a sort comparator
*/
abstract public DocComparatorSource getDocComparatorSource();
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}