Index: gs3-extensions/solr/trunk/src/src/java/org/greenstone/gsdl3/util/SolrQueryWrapper.java
===================================================================
--- gs3-extensions/solr/trunk/src/src/java/org/greenstone/gsdl3/util/SolrQueryWrapper.java	(revision 25865)
+++ gs3-extensions/solr/trunk/src/src/java/org/greenstone/gsdl3/util/SolrQueryWrapper.java	(revision 25866)
@@ -25,4 +25,10 @@
  *********************************************************************/
 package org.greenstone.gsdl3.util;
+
+import java.lang.reflect.Type;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
 
 import org.apache.log4j.Logger;
@@ -36,11 +42,13 @@
 import org.greenstone.LuceneWrapper3.SharedSoleneQueryResult;
 
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+
 public class SolrQueryWrapper extends SharedSoleneQuery
 {
-
 	static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.SolrQueryWrapper.class.getName());
-
 	protected int max_docs = 100;
-
+	protected ArrayList<String> _facets = new ArrayList<String>();
+	protected ArrayList<String> _facetQueries = new ArrayList<String>();
 	SolrServer solr_core = null;
 
@@ -48,4 +56,5 @@
 	{
 		super();
+		start_results = 0;
 	}
 
@@ -60,7 +69,32 @@
 	}
 
+	public void addFacet(String facet)
+	{
+		if (!_facets.contains(facet))
+		{
+			_facets.add(facet);
+		}
+	}
+
+	public void clearFacets()
+	{
+		_facets.clear();
+	}
+
+	public void addFacetQuery(String facetQuery)
+	{
+		if (!_facetQueries.contains(facetQuery))
+		{
+			_facetQueries.add(facetQuery);
+		}
+	}
+
+	public void clearFacetQueries()
+	{
+		_facetQueries.clear();
+	}
+
 	public boolean initialise()
 	{
-
 		if (solr_core == null)
 		{
@@ -70,10 +104,8 @@
 		}
 		return true;
-
 	}
 
 	public SharedSoleneQueryResult runQuery(String query_string)
 	{
-
 		if (query_string == null || query_string.equals(""))
 		{
@@ -85,4 +117,74 @@
 		SolrQueryResult solr_query_result = new SolrQueryResult();
 		solr_query_result.clear();
+
+		if (_facetQueries.size() > 0)
+		{
+			HashMap<String, ArrayList<String>> grouping = new HashMap<String, ArrayList<String>>();
+			for (String currentQuery : _facetQueries)
+			{
+				//Facet queries are stored in JSON, so we have to decode it
+				Gson gson = new Gson();
+				Type type = new TypeToken<List<String>>()
+				{
+				}.getType();
+				List<String> queryElems = gson.fromJson(currentQuery, type);
+
+				//Group each query segment by the index it uses
+				for (String currentQueryElement : queryElems)
+				{
+					String decodedQueryElement = null;
+					try
+					{
+						decodedQueryElement = URLDecoder.decode(currentQueryElement, "UTF-8");
+					}
+					catch (Exception ex)
+					{
+						continue;
+					}
+
+					int colonIndex = currentQueryElement.indexOf(":");
+					String indexShortName = currentQueryElement.substring(0, colonIndex);
+					
+					if(grouping.get(indexShortName) == null)
+					{
+						grouping.put(indexShortName, new ArrayList<String>());
+					}
+					grouping.get(indexShortName).add(decodedQueryElement);
+				}
+			}
+
+			//Construct the facet query string to add to the regular query string
+			StringBuilder facetQueryString = new StringBuilder();
+			int keysetCounter = 0;
+			for (String key : grouping.keySet())
+			{
+				StringBuilder currentFacetString = new StringBuilder("(");
+				int groupCounter = 0;
+				for(String queryElem : grouping.get(key))
+				{
+					currentFacetString.append(queryElem);
+					
+					groupCounter++;
+					if(groupCounter < grouping.get(key).size())
+					{
+						currentFacetString.append(" OR ");
+					}
+				}
+				currentFacetString.append(")");
+				
+				facetQueryString.append(currentFacetString);
+				
+				keysetCounter++;
+				if(keysetCounter < grouping.keySet().size())
+				{
+					facetQueryString.append(" AND ");
+				}
+			}
+			
+			if(facetQueryString.length() > 0)
+			{
+				query_string += " AND " + facetQueryString;
+			}
+		}
 
 		ModifiableSolrParams solrParams = new ModifiableSolrParams();
@@ -91,14 +193,21 @@
 		solrParams.set("rows", (end_results - start_results) + 1);
 		solrParams.set("fl", "docOID score");
+		
+		if (_facets.size() > 0)
+		{
+			solrParams.set("facet", "true");
+			for (int i = 0; i < _facets.size(); i++)
+			{
+				solrParams.add("facet.field", _facets.get(i));
+			}
+		}
 
 		try
 		{
 			QueryResponse solrResponse = solr_core.query(solrParams);
-
 			SolrDocumentList hits = solrResponse.getResults();
 
 			if (hits != null)
 			{
-
 				logger.info("*** hits size = " + hits.size());
 				logger.info("*** num docs found = " + hits.getNumFound());
@@ -108,5 +217,5 @@
 				logger.info("*** max docs = " + max_docs);
 
-				// numDocsFound is the total number of mactching docs in the collection
+				// numDocsFound is the total number of matching docs in the collection
 				// as opposed to the number of documents returned in the hits list
 
@@ -139,7 +248,10 @@
 				solr_query_result.setEndResults(0);
 			}
+
+			solr_query_result.setFacetResults(solrResponse.getFacetFields());
 		}
 		catch (SolrServerException server_exception)
 		{
+			server_exception.printStackTrace();
 			solr_query_result.setError(SolrQueryResult.SERVER_ERROR);
 		}
@@ -148,4 +260,15 @@
 	}
 
+	//Greenstone universe operates with a base of 1 for "start_results"
+	//But Solr operates from 0
+	public void setStartResults(int start_results)
+	{
+		if (start_results < 0)
+		{
+			start_results = 0;
+		}
+		this.start_results = start_results - 1;
+	}
+
 	public void cleanUp()
 	{
