/* Generated by Streams Studio: November 30, 2016 at 10:33:19 AM EST */
package com.ibm.streams.watsonexplorer.operators;

import java.util.Set;

import org.apache.log4j.Logger;

import com.ibm.streams.operator.OperatorContext.ContextCheck;
import com.ibm.streams.operator.OutputTuple;
import com.ibm.streams.operator.StreamSchema;
import com.ibm.streams.operator.StreamingInput;
import com.ibm.streams.operator.StreamingOutput;
import com.ibm.streams.operator.Tuple;
import com.ibm.streams.operator.TupleAttribute;
import com.ibm.streams.operator.compile.OperatorContextChecker;
import com.ibm.streams.operator.model.OutputPortSet;
import com.ibm.streams.operator.model.OutputPorts;
import com.ibm.streams.operator.model.Parameter;
import com.ibm.streams.operator.model.PrimitiveOperator;
import com.ibm.streams.operator.model.OutputPortSet.WindowPunctuationOutputMode;
import com.ibm.streams.watsonexplorer.RestParameters;
import com.ibm.streams.watsonexplorer.SearchResult;

@PrimitiveOperator(name = "SearchFacet", namespace = "com.ibm.streamsx.watsonexplorer", description = CASearchFacetOperator.DESC)
public class CASearchFacetOperator extends AbstractSearchOperator {

	private static final String DEFAULT_FACET_ATTR_NAME = "facet";

	private TupleAttribute<Tuple, String> facetAttr;
	private String facet;

	private Logger logger = Logger.getLogger(CASearchFacetOperator.class);

	@Parameter(optional = true, description = "Specifies the facets that should be used when perform facet computation."
			+ " This parameter should not be set if the **facetAttr** parameter is specified.")
	public void setFacet(String facet) {
		this.facet = facet;
	}

	@Parameter(optional = true, description = "Specifies the name of the input attribute that contains the facets that should be"
			+ " used for facet computation. This parameter should should not be set if the **facet** parameter is specified."
			+ " If this parameter is not specified and the **facet** parameter is not specified, the operator will look for an"
			+ " input attribute named *facet*.")
	public void setFacetAttr(TupleAttribute<Tuple, String> facetAttr) {
		this.facetAttr = facetAttr;
	}


	public String getFacet() {
		return facet;
	}

	public TupleAttribute<Tuple, String> getFacetAttr() {
		return facetAttr;
	}

	@ContextCheck(compile = true)
	public static void checkSearchFacetParams(OperatorContextChecker checker) {
		checker.checkExcludedParameters("facet", "facetAttr");
		
		Set<String> paramNames = checker.getOperatorContext().getParameterNames();		
		if (!paramNames.contains("facet") && !paramNames.contains("facetAttr")) {
			StreamSchema inputPortSchema = checker.getOperatorContext().getStreamingInputs().get(0).getStreamSchema();
			if (inputPortSchema.getAttribute("facet") == null) {
				checker.setInvalidContext("Either the 'facet' or 'facetAttr' parameters must be specified, "
						+ "or an attribute named \"facet\" must be present on the input port", new Object[0]);
			}
		}
	}

	@Override
	public final void process(StreamingInput<Tuple> inputStream, Tuple tuple) throws Exception {
		StreamingOutput<OutputTuple> outStream = getOutput(0);
		OutputTuple outTuple = outStream.newTuple();
		outTuple.assign(tuple);
		
		String query = queryAttr == null ? tuple.getString(DEFAULT_QUERY_ATTR_NAME) : queryAttr.getValue(tuple);
		logger.trace("query=" + query);

		String facet = facetAttr == null ? tuple.getString(DEFAULT_FACET_ATTR_NAME) : facetAttr.getValue(tuple);
		logger.trace("facet=" + facet);

		RestParameters params = new RestParameters();
		params.put("query", query);
		params.put("facet", facet);
		
		if(!getOperatorContext().getParameterNames().contains("collectionName")) {
			addCollectionName(params, tuple);
		}
		
		SearchResult result = caClient.searchFacet(params);

		outTuple.setString(getResultAttrName(), result.getContent());
		outStream.submit(outTuple);
	}
	
	static final String DESC = "This operator uses the Watson"
			+ " Explorer Content Analytics `/search/facet` REST API to search for documents that satisfy the specified query and return only"
			+ " the facets. The facets that should be used for facet computation should either be specified via the **facet** parameter"
			+ " or can be streamed in at runtime by specifying an input attribute via the **facetAttr** parameter.\\n\\n"
			+ " More information about the available parameters for this REST API can found in the Content Analytics REST API documentation in"
			+ " the Content Analytics installation directory: `<ES_INSTALL_PATH>/docs/api/rest/search/facet`.";
}
