package com.browseengine.bobo.facets.impl;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.log4j.Logger;

import com.browseengine.bobo.api.BoboIndexReader;
import com.browseengine.bobo.api.BrowseSelection;
import com.browseengine.bobo.api.FacetSpec;
import com.browseengine.bobo.facets.FacetCountCollector;
import com.browseengine.bobo.facets.FacetCountCollectorSource;
import com.browseengine.bobo.facets.FacetHandler;
import com.browseengine.bobo.facets.FacetHandler.FacetDataNone;
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;

public class BucketFacetHandler extends FacetHandler<FacetDataNone>{
  private static Logger logger = Logger.getLogger(BucketFacetHandler.class);
  private final Map<String,String[]> _predefinedBuckets;
  private final String _dependOnFacetName;
  private FacetHandler<?> _dependOnFacetHandler;
  String _name;
  
  public BucketFacetHandler(String name, Map<String,String[]> predefinedBuckets, String dependsOnFacetName)
  {
    super(name, new HashSet<String>(Arrays.asList(new String[]{dependsOnFacetName})));
    _name = name;
    _predefinedBuckets = predefinedBuckets;
    _dependOnFacetName  = dependsOnFacetName;
    _dependOnFacetHandler = null;
  }
  

  
  @Override
  public DocComparatorSource getDocComparatorSource() {
    return _dependOnFacetHandler.getDocComparatorSource();
  }
  
  @Override
  public String[] getFieldValues(BoboIndexReader reader, int id) {
    return _dependOnFacetHandler.getFieldValues(reader, id);
  }
  
  @Override
  public Object[] getRawFieldValues(BoboIndexReader reader,int id){
    return _dependOnFacetHandler.getRawFieldValues(reader, id);
  }

  @Override
  public RandomAccessFilter buildRandomAccessFilter(String bucketString, Properties prop) throws IOException
  {
      String[] elems = _predefinedBuckets.get(bucketString);
  
      if(elems == null || elems.length==0) return  EmptyFilter.getInstance();
      if(elems.length == 1) return _dependOnFacetHandler.buildRandomAccessFilter(elems[0], prop);
      return _dependOnFacetHandler.buildRandomAccessOrFilter(elems, prop, false);
  }
  
  
  @Override
  public RandomAccessFilter buildRandomAccessAndFilter(String[] bucketStrings,Properties prop) throws IOException
  {
    List<RandomAccessFilter> filterList = new LinkedList<RandomAccessFilter>();
    for (String bucketString : bucketStrings){
    	String[] vals = _predefinedBuckets.get(bucketString);
    	RandomAccessFilter filter = _dependOnFacetHandler.buildRandomAccessOrFilter(vals, prop, false);
    	if (filter==EmptyFilter.getInstance()) return EmptyFilter.getInstance();
    	filterList.add(filter);
    }
    if (filterList.size()==0) return EmptyFilter.getInstance();
    if (filterList.size()==1) return filterList.get(0);
    return new RandomAccessAndFilter(filterList);
  }

  @Override
  public RandomAccessFilter buildRandomAccessOrFilter(String[] bucketStrings,Properties prop,boolean isNot) throws IOException
  {
	if (isNot){
		RandomAccessFilter excludeFilter = buildRandomAccessAndFilter(bucketStrings, prop);
		return new RandomAccessNotFilter(excludeFilter);
	}
	else{
		Set<String> selections = new HashSet<String>();
		for (String bucket : bucketStrings){
			String[] vals = _predefinedBuckets.get(bucket);
			if (vals!=null){
				for (String val : vals){
				  selections.add(val);
				}
			}
		}
		if (selections!=null && selections.size()>0){
			String[] sels = selections.toArray(new String[0]);
			if (selections.size()==1){
			  return _dependOnFacetHandler.buildRandomAccessFilter(sels[0], prop);
			}
			else{
			  return _dependOnFacetHandler.buildRandomAccessOrFilter(sels, prop, false);
			}
		}
		else{
			return EmptyFilter.getInstance();
		}
	}
  }

  @Override
  public FacetCountCollectorSource getFacetCountCollectorSource(final BrowseSelection sel, final FacetSpec ospec) 
  {
    return new FacetCountCollectorSource() 
    {
      @Override
      public FacetCountCollector getFacetCountCollector(BoboIndexReader reader, int docBase)
      {
        FacetSpec elemSpec = new FacetSpec();
        elemSpec.setCustomComparatorFactory(ospec.getCustomComparatorFactory());
        elemSpec.setExpandSelection(ospec.isExpandSelection());
        elemSpec.setOrderBy(ospec.getOrderBy());
        elemSpec.setMaxCount(Integer.MAX_VALUE);
        elemSpec.setMinHitCount(1);
        
        return new BucketFacetCountCollector(_name, _dependOnFacetHandler.getFacetCountCollectorSource(sel, elemSpec).getFacetCountCollector(reader, docBase), ospec, _predefinedBuckets);
      }
    };

  }
  
  public boolean hasPredefinedBuckets()
  {
    return (_predefinedBuckets != null);
  }
  
  @Override
  public FacetDataNone load(BoboIndexReader reader) throws IOException
  {
    _dependOnFacetHandler = this.getDependedFacetHandler(_dependOnFacetName);
    if (_dependOnFacetHandler==null)
    {
      throw new IllegalStateException("bucketFacetHandler need to be supported by other underlying facetHandlers");
    }
    return FacetDataNone.instance;
  } 
}


@@ -653,16 +653,73 @@
 taNone;%0A
+import com.browseengine.bobo.facets.data.FacetDataCache;%0A
 import c
@@ -965,73 +965,8 @@
 er;%0A
-import com.browseengine.bobo.facets.filter.RandomAccessOrFilter;%0A
 impo
@@ -1290,9 +1290,25 @@
 ler%3C
-?
+FacetDataCache%3C?%3E
 %3E _d
@@ -4484,351 +4484,10 @@
 ase)
-%0A      
 %7B%0A
-        FacetSpec elemSpec = new FacetSpec();%0A        elemSpec.setCustomComparatorFactory(ospec.getCustomComparatorFactory());%0A        elemSpec.setExpandSelection(ospec.isExpandSelection());%0A        elemSpec.setOrderBy(ospec.getOrderBy());%0A        elemSpec.setMaxCount(Integer.MAX_VALUE);%0A        elemSpec.setMinHitCount(1);%0A        %0A
     
@@ -4594,13 +4594,10 @@
 el, 
-elemS
+os
 pec)
@@ -4864,24 +4864,32 @@
 ception%0A  %7B%0A
+%09try%7B%0A  
     _dependO
@@ -4904,16 +4904,49 @@
 ndler = 
+(FacetHandler%3CFacetDataCache%3C?%3E%3E)
 this.get
@@ -4995,167 +4995,205 @@
     
-if (_dependOnFacetHandler==null)%0A    %7B%0A      throw new IllegalStateException(%22bucketFacetHandler need to be supported by other underlying
+  FacetDataCache%3C?%3E dataCache = _dependOnFacetHandler.getFacetData(reader);%0A      %0A%09%7D%0A%09catch(Exception e)%7B%0A%09  throw new IOException(%22unable to load dependent
  facet
-H
+ h
 andler
-s%22);%0A    
+: %22+_dependOnFacetName);%0A%09
 %7D%0A  

clean up