/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.app.xmlui.opensearch;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Map;

import org.apache.avalon.excalibur.pool.Recyclable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.xml.dom.DOMStreamer;
import org.dspace.app.util.OpenSearch;
import org.dspace.app.xmlui.utils.ContextUtil;
import org.dspace.app.xmlui.utils.FeedUtils;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.SearchUtils;
import org.dspace.sort.SortOption;
import org.xml.sax.SAXException;


/**
 * Generate an OpenSearch compliant search results document for DSpace, either scoped by a collection,
 * a community or the whole repository.
 *
 * This class implements the generate() method in order to issue a search using the PostgreSQL indexes.
 * Search params are parsed by AbstractOpenSearchGenerator class.

 * I18N: Feed's are internationalized, meaning that they may contain references
 * to messages contained in the global messages.xml file using cocoon's i18n
 * schema. However the library used to build the feeds does not understand
 * this schema to work around this limitation I created a little hack. It
 * basically works like this, when text that needs to be localized is put into
 * the feed it is always mangled such that a prefix is added to the messages's
 * key. Thus if the key were "xmlui.feed.text" then the resulting text placed
 * into the feed would be "I18N:xmlui.feed.text". After the library is finished
 * and produced it's final result the output is traversed to find these
 * occurrences and replace them with proper cocoon i18n elements.
 *
 * @author Richard Rodgers
 * @author Nestor Oviedo
 */
public class DiscoveryOpenSearchGenerator extends AbstractOpenSearchGenerator
					implements CacheableProcessingComponent, Recyclable
{

    /** the  search service to use */
    private SearchService searchService = null;
    
    /**
     * Setup the Discovery search service. Other paramas are setup in superclass's methods
     */
    public void setup(SourceResolver resolver, Map objectModel, String src,
            Parameters par) throws ProcessingException, SAXException, IOException
    {
        super.setup(resolver, objectModel, src, par);
        
        searchService = SearchUtils.getSearchService();
        if(searchService == null)
            throw new IllegalStateException("Couldn't get a search service instance");
    }
    

    /**
     * Generate the search results document.
     */
    public void generate() throws IOException, SAXException, ProcessingException
    {
        try
        {
            if (resultsDoc == null)
            {
            	Context context = ContextUtil.obtainContext(objectModel);
                DiscoverQuery queryArgs = new DiscoverQuery();

            	Request request = ObjectModelHelper.getRequest(objectModel);
                
            	// Sets the query
                queryArgs.setQuery(query);
                queryArgs.setStart(start);
                queryArgs.setMaxResults(rpp);

                // we want Items only
            	queryArgs.setDSpaceObjectFilter(Constants.ITEM);
                
                // sort info
                if(sort != null)
                {
                    String sortField = this.searchService.toSortFieldIndex(sort.getMetadata(), sort.getType());
                    if(SortOption.ASCENDING.equals( sortOrder ))
                        queryArgs.setSortField(sortField, DiscoverQuery.SORT_ORDER.asc);
                    else
                        queryArgs.setSortField(sortField, DiscoverQuery.SORT_ORDER.desc);
                }

                DiscoverResult queryResults = null;
                if(scope == null)
                    queryResults = SearchUtils.getSearchService().search(context, queryArgs);
                else
                    queryResults = SearchUtils.getSearchService().search(context, scope, queryArgs);

	            // creates the results array and generates the OpenSearch result
	            DSpaceObject[] results = new DSpaceObject[queryResults.getDspaceObjects().size()];
	            queryResults.getDspaceObjects().toArray(results);
	            
	            resultsDoc = OpenSearch.getResultsDoc(format, query, (int) queryResults.getTotalSearchResults(), start, rpp, scope, results, FeedUtils.i18nLabels);
                FeedUtils.unmangleI18N(resultsDoc);
            }

            // Send the SAX events
            DOMStreamer streamer = new DOMStreamer(contentHandler, lexicalHandler);
            streamer.stream(resultsDoc);
        }
        catch (SQLException sqle)
		{
        	throw new SAXException(sqle);
		}
        catch (SearchServiceException se)
		{
			throw new ProcessingException(se);
		}
    }
    
    /**
     * Recycle
     */
    
    public void recycle()
    {
        this.searchService = null;
        super.recycle();
    }
	
}
