package com.marklogic.client.example.cookbook;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.xml.namespace.QName;

import com.marklogic.client.DatabaseClient;
import com.marklogic.client.DatabaseClientFactory;
import com.marklogic.client.DatabaseClientFactory.Authentication;
import com.marklogic.client.DocumentIdentifier;
import com.marklogic.client.QueryManager;
import com.marklogic.client.QueryOptionsManager;
import com.marklogic.client.XMLDocumentManager;
import com.marklogic.client.config.search.MatchDocumentSummary;
import com.marklogic.client.config.search.MatchLocation;
import com.marklogic.client.config.search.MatchSnippet;
import com.marklogic.client.config.search.StringQueryDefinition;
import com.marklogic.client.config.search.ValueConstraint;
import com.marklogic.client.config.search.impl.ValueConstraintImpl;
import com.marklogic.client.io.InputStreamHandle;
import com.marklogic.client.io.QueryOptionsHandle;
import com.marklogic.client.io.SearchHandle;

/**
 * StringOptionsSearch illustrates searching for documents and iterating over results
 * with string criteria referencing a constraint defined by options.
 */
public class StringOptionsSearch {
	static final private String OPTIONS_NAME = "products";

	static final private String[] filenames = {"curbappeal.xml", "flipper.xml", "justintime.xml"};

	public static void main(String[] args) throws IOException {
		Properties props = loadProperties();

		// connection parameters for writer and admin users
		String         host            = props.getProperty("example.host");
		int            port            = Integer.parseInt(props.getProperty("example.port"));
		String         writer_user     = props.getProperty("example.writer_user");
		String         writer_password = props.getProperty("example.writer_password");
		String         admin_user      = props.getProperty("example.admin_user");
		String         admin_password  = props.getProperty("example.admin_password");
		Authentication authType        = Authentication.valueOf(
				props.getProperty("example.authentication_type").toUpperCase()
				);

		run(host, port, admin_user, admin_password, writer_user, writer_password, authType);
	}

	public static void run(String host, int port, String admin_user, String admin_password, String writer_user, String writer_password, Authentication authType) {
		System.out.println("example: "+StringOptionsSearch.class.getName());

		configure( host, port, admin_user,  admin_password,  authType );
		search(    host, port, writer_user, writer_password, authType );

		tearDownExample(host, port, admin_user, admin_password, authType);
	}

	public static void configure(String host, int port, String user, String password, Authentication authType) {
		// connect the client
		DatabaseClient client = DatabaseClientFactory.connect(host, port, user, password, authType);

		// create a manager for writing query options
		QueryOptionsManager optionsMgr = client.newQueryOptionsManager();

		// create and initialize a handle with query options
		QueryOptionsHandle writeHandle = new QueryOptionsHandle();
		ValueConstraint constraint = new ValueConstraintImpl("industry");
		constraint.addElementIndex(new QName("industry"));
		writeHandle.add(constraint);

		// write the query options to the database
		optionsMgr.writeOptions(OPTIONS_NAME, writeHandle);

		// release the client
		client.release();
	}

	public static void search(String host, int port, String user, String password, Authentication authType) {
		// connect the client
		DatabaseClient client = DatabaseClientFactory.connect(host, port, user, password, authType);

		setUpExample(client);

		// create a manager for searching
		QueryManager queryMgr = client.newQueryManager();

		// create a search definition
		StringQueryDefinition querydef = queryMgr.newStringDefinition(OPTIONS_NAME);
		querydef.setCriteria("neighborhood industry:\"Real Estate\"");

		// create a handle for the search results
		SearchHandle resultsHandle = new SearchHandle();

		// run the search
		queryMgr.search(querydef, resultsHandle);

		System.out.println("Matched "+resultsHandle.getTotalResults()+
				" documents with '"+querydef.getCriteria()+"'\n");

		// iterate over the result documents
		MatchDocumentSummary[] docSummaries = resultsHandle.getMatchResults();
		System.out.println("Listing "+docSummaries.length+" documents:\n");
		for (MatchDocumentSummary docSummary: docSummaries) {
// temporarary workaround for known problem
if (true) continue;

			// iterate over the match locations within a result document
			MatchLocation[] locations = docSummary.getMatchLocations();
			System.out.println("Matched "+locations.length+" locations in "+docSummary.getUri()+":");
			for (MatchLocation location: locations) {

				// iterate over the snippets at a match location
				for (MatchSnippet snippet : location.getSnippets()) {
					boolean isHighlighted = snippet.isHighlighted();

					if (isHighlighted)
						System.out.print("[");
					System.out.print(snippet.getText());
					if (isHighlighted)
						System.out.print("]");
				}
				System.out.println();
			}
		}

		// release the client
		client.release();
	}

	// set up by writing the document content and options used in the example query
	public static void setUpExample(DatabaseClient client) {
		XMLDocumentManager docMgr = client.newXMLDocumentManager();

		DocumentIdentifier docId = client.newDocId(null);

		InputStreamHandle contentHandle = new InputStreamHandle();

		for (String filename: filenames) {
			InputStream docStream = StringOptionsSearch.class.getClassLoader().getResourceAsStream(
					"data"+File.separator+filename);
			if (docStream == null)
				throw new RuntimeException("Could not read document example");

			docId.setUri("/example/"+filename);

			contentHandle.set(docStream);

			docMgr.write(docId, contentHandle);
		}
	}

	// clean up by deleting the documents and query options used in the example query
	public static void tearDownExample(
			String host, int port, String user, String password, Authentication authType) {
		DatabaseClient client = DatabaseClientFactory.connect(host, port, user, password, authType);

		XMLDocumentManager docMgr = client.newXMLDocumentManager();

		DocumentIdentifier docId = client.newDocId(null);

		for (String filename: filenames) {
			docId.setUri("/example/"+filename);

			docMgr.delete(docId);
		}

		QueryOptionsManager optionsMgr = client.newQueryOptionsManager();

		optionsMgr.deleteOptions(OPTIONS_NAME);

		client.release();
	}

	// get the configuration for the example
	public static Properties loadProperties() throws IOException {
		String propsName = "Example.properties";
		InputStream propsStream =
			StringOptionsSearch.class.getClassLoader().getResourceAsStream(propsName);
		if (propsStream == null)
			throw new RuntimeException("Could not read example properties");

		Properties props = new Properties();
		props.load(propsStream);

		return props;
	}

}

@@ -4497,70 +4497,81 @@
 ) %7B%0A
-// temporarary workaround for known problem%0Aif (true) continue
+%09%09%09String uri = docSummary.getUri();%0A%09%09%09int score = docSummary.getScore()
 ;%0A%0A%09
@@ -4767,29 +4767,34 @@
 n %22+
-docSummary.getUri()+%22
+uri+%22 with %22+score+%22 score
 :%22);

remove early exit