/* 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;

using NUnit.Framework;

using StandardAnalyzer = Lucene.Net.Analysis.Standard.StandardAnalyzer;
using Document = Lucene.Net.Documents.Document;
using Field = Lucene.Net.Documents.Field;
using IndexWriter = Lucene.Net.Index.IndexWriter;
using Term = Lucene.Net.Index.Term;
using QueryParser = Lucene.Net.QueryParsers.QueryParser;
using Directory = Lucene.Net.Store.Directory;
using MockRAMDirectory = Lucene.Net.Store.MockRAMDirectory;
using SpanNearQuery = Lucene.Net.Search.Spans.SpanNearQuery;
using SpanQuery = Lucene.Net.Search.Spans.SpanQuery;
using SpanTermQuery = Lucene.Net.Search.Spans.SpanTermQuery;

namespace Lucene.Net.Search
{
	
	
	/// <summary> TestExplanations subclass focusing on basic query types</summary>
    [TestFixture]
	public class TestSimpleExplanations:TestExplanations
	{
		
		// we focus on queries that don't rewrite to other queries.
		// if we get those covered well, then the ones that rewrite should
		// also be covered.
		
		
		/* simple term tests */
		
		[Test]
		public virtual void  TestT1()
		{
			Qtest("w1", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestT2()
		{
			Qtest("w1^1000", new int[]{0, 1, 2, 3});
		}
		
		/* MatchAllDocs */
		
		[Test]
		public virtual void  TestMA1()
		{
			Qtest(new MatchAllDocsQuery(), new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestMA2()
		{
			Query q = new MatchAllDocsQuery();
			q.Boost = 1000;
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		
		/* some simple phrase tests */
		
		[Test]
		public virtual void  TestP1()
		{
			Qtest("\"w1 w2\"", new int[]{0});
		}
		[Test]
		public virtual void  TestP2()
		{
			Qtest("\"w1 w3\"", new int[]{1, 3});
		}
		[Test]
		public virtual void  TestP3()
		{
			Qtest("\"w1 w2\"~1", new int[]{0, 1, 2});
		}
		[Test]
		public virtual void  TestP4()
		{
			Qtest("\"w2 w3\"~1", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestP5()
		{
			Qtest("\"w3 w2\"~1", new int[]{1, 3});
		}
		[Test]
		public virtual void  TestP6()
		{
			Qtest("\"w3 w2\"~2", new int[]{0, 1, 3});
		}
        [Test]
        public virtual void TestP7()
		{
			Qtest("\"w3 w2\"~3", new int[]{0, 1, 2, 3});
		}
		
		/* some simple filtered query tests */
		
		[Test]
		public virtual void  TestFQ1()
		{
			Qtest(new FilteredQuery(qp.Parse("w1"), new ItemizedFilter(new int[]{0, 1, 2, 3})), new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestFQ2()
		{
			Qtest(new FilteredQuery(qp.Parse("w1"), new ItemizedFilter(new int[]{0, 2, 3})), new int[]{0, 2, 3});
		}
		[Test]
		public virtual void  TestFQ3()
		{
			Qtest(new FilteredQuery(qp.Parse("xx"), new ItemizedFilter(new int[]{1, 3})), new int[]{3});
		}
		[Test]
		public virtual void  TestFQ4()
		{
			Qtest(new FilteredQuery(qp.Parse("xx^1000"), new ItemizedFilter(new int[]{1, 3})), new int[]{3});
		}
		[Test]
		public virtual void  TestFQ6()
		{
			Query q = new FilteredQuery(qp.Parse("xx"), new ItemizedFilter(new int[]{1, 3}));
			q.Boost = 1000;
			Qtest(q, new int[]{3});
		}
		
		/* ConstantScoreQueries */
		
		[Test]
		public virtual void  TestCSQ1()
		{
			Query q = new ConstantScoreQuery(new ItemizedFilter(new int[]{0, 1, 2, 3}));
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestCSQ2()
		{
			Query q = new ConstantScoreQuery(new ItemizedFilter(new int[]{1, 3}));
			Qtest(q, new int[]{1, 3});
		}
		[Test]
		public virtual void  TestCSQ3()
		{
			Query q = new ConstantScoreQuery(new ItemizedFilter(new int[]{0, 2}));
			q.Boost = 1000;
			Qtest(q, new int[]{0, 2});
		}
		
		/* DisjunctionMaxQuery */

        [Test]
        public virtual void TestDMQ1()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.0f);
			q.Add(qp.Parse("w1"));
			q.Add(qp.Parse("w5"));
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestDMQ2()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.5f);
			q.Add(qp.Parse("w1"));
			q.Add(qp.Parse("w5"));
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestDMQ3()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.5f);
			q.Add(qp.Parse("QQ"));
			q.Add(qp.Parse("w5"));
			Qtest(q, new int[]{0});
		}
		[Test]
		public virtual void  TestDMQ4()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.5f);
			q.Add(qp.Parse("QQ"));
			q.Add(qp.Parse("xx"));
			Qtest(q, new int[]{2, 3});
		}
		[Test]
		public virtual void  TestDMQ5()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.5f);
			q.Add(qp.Parse("yy -QQ"));
			q.Add(qp.Parse("xx"));
			Qtest(q, new int[]{2, 3});
		}
        [Test]
        public virtual void TestDMQ6()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.5f);
			q.Add(qp.Parse("-yy w3"));
			q.Add(qp.Parse("xx"));
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestDMQ7()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.5f);
			q.Add(qp.Parse("-yy w3"));
			q.Add(qp.Parse("w2"));
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestDMQ8()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.5f);
			q.Add(qp.Parse("yy w5^100"));
			q.Add(qp.Parse("xx^100000"));
			Qtest(q, new int[]{0, 2, 3});
		}
		[Test]
		public virtual void  TestDMQ9()
		{
			DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.5f);
			q.Add(qp.Parse("yy w5^100"));
			q.Add(qp.Parse("xx^0"));
			Qtest(q, new int[]{0, 2, 3});
		}
		
		/* MultiPhraseQuery */
		
		[Test]
		public virtual void  TestMPQ1()
		{
			MultiPhraseQuery q = new MultiPhraseQuery();
			q.Add(Ta(new System.String[]{"w1"}));
			q.Add(Ta(new System.String[]{"w2", "w3", "xx"}));
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestMPQ2()
		{
			MultiPhraseQuery q = new MultiPhraseQuery();
			q.Add(Ta(new System.String[]{"w1"}));
			q.Add(Ta(new System.String[]{"w2", "w3"}));
			Qtest(q, new int[]{0, 1, 3});
		}
		[Test]
		public virtual void  TestMPQ3()
		{
			MultiPhraseQuery q = new MultiPhraseQuery();
			q.Add(Ta(new System.String[]{"w1", "xx"}));
			q.Add(Ta(new System.String[]{"w2", "w3"}));
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestMPQ4()
		{
			MultiPhraseQuery q = new MultiPhraseQuery();
			q.Add(Ta(new System.String[]{"w1"}));
			q.Add(Ta(new System.String[]{"w2"}));
			Qtest(q, new int[]{0});
		}
		[Test]
		public virtual void  TestMPQ5()
		{
			MultiPhraseQuery q = new MultiPhraseQuery();
			q.Add(Ta(new System.String[]{"w1"}));
			q.Add(Ta(new System.String[]{"w2"}));
			q.Slop = 1;
			Qtest(q, new int[]{0, 1, 2});
		}
		[Test]
		public virtual void  TestMPQ6()
		{
			MultiPhraseQuery q = new MultiPhraseQuery();
			q.Add(Ta(new System.String[]{"w1", "w3"}));
			q.Add(Ta(new System.String[]{"w2"}));
			q.Slop = 1;
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		
		/* some simple tests of boolean queries containing term queries */
		
		[Test]
		public virtual void  TestBQ1()
		{
			Qtest("+w1 +w2", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ2()
		{
			Qtest("+yy +w3", new int[]{2, 3});
		}
		[Test]
		public virtual void  TestBQ3()
		{
			Qtest("yy +w3", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ4()
		{
			Qtest("w1 (-xx w2)", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ5()
		{
			Qtest("w1 (+qq w2)", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ6()
		{
			Qtest("w1 -(-qq w5)", new int[]{1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ7()
		{
			Qtest("+w1 +(qq (xx -w2) (+w3 +w4))", new int[]{0});
		}
		[Test]
		public virtual void  TestBQ8()
		{
			Qtest("+w1 (qq (xx -w2) (+w3 +w4))", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ9()
		{
			Qtest("+w1 (qq (-xx w2) -(+w3 +w4))", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ10()
		{
			Qtest("+w1 +(qq (-xx w2) -(+w3 +w4))", new int[]{1});
		}
		[Test]
		public virtual void  TestBQ11()
		{
			Qtest("w1 w2^1000.0", new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ14()
		{
			BooleanQuery q = new BooleanQuery(true);
			q.Add(qp.Parse("QQQQQ"), Occur.SHOULD);
			q.Add(qp.Parse("w1"), Occur.SHOULD);
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ15()
		{
			BooleanQuery q = new BooleanQuery(true);
			q.Add(qp.Parse("QQQQQ"), Occur.MUST_NOT);
			q.Add(qp.Parse("w1"), Occur.SHOULD);
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ16()
		{
			BooleanQuery q = new BooleanQuery(true);
			q.Add(qp.Parse("QQQQQ"), Occur.SHOULD);
			q.Add(qp.Parse("w1 -xx"), Occur.SHOULD);
			Qtest(q, new int[]{0, 1});
		}
        [Test]
        public virtual void TestBQ17()
		{
			BooleanQuery q = new BooleanQuery(true);
			q.Add(qp.Parse("w2"), Occur.SHOULD);
			q.Add(qp.Parse("w1 -xx"), Occur.SHOULD);
			Qtest(q, new int[]{0, 1, 2, 3});
		}
		[Test]
		public virtual void  TestBQ19()
		{
			Qtest("-yy w3", new int[]{0, 1});
		}
		
		[Test]
		public virtual void  TestBQ20()
		{
			BooleanQuery q = new BooleanQuery();
			q.MinimumNumberShouldMatch = 2;
			q.Add(qp.Parse("QQQQQ"), Occur.SHOULD);
			q.Add(qp.Parse("yy"), Occur.SHOULD);
			q.Add(qp.Parse("zz"), Occur.SHOULD);
			q.Add(qp.Parse("w5"), Occur.SHOULD);
			q.Add(qp.Parse("w4"), Occur.SHOULD);
			
			Qtest(q, new int[]{0, 3});
		}
		
		
		[Test]
		public virtual void  TestTermQueryMultiSearcherExplain()
		{
			// creating two directories for indices
			Directory indexStoreA = new MockRAMDirectory();
			Directory indexStoreB = new MockRAMDirectory();
			
			Document lDoc = new Document();
			lDoc.Add(new Field("handle", "1 2", Field.Store.YES, Field.Index.ANALYZED));
			Document lDoc2 = new Document();
			lDoc2.Add(new Field("handle", "1 2", Field.Store.YES, Field.Index.ANALYZED));
			Document lDoc3 = new Document();
			lDoc3.Add(new Field("handle", "1 2", Field.Store.YES, Field.Index.ANALYZED));
			
			IndexWriter writerA = new IndexWriter(indexStoreA, new StandardAnalyzer(Util.Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED);
			IndexWriter writerB = new IndexWriter(indexStoreB, new StandardAnalyzer(Util.Version.LUCENE_CURRENT), true, IndexWriter.MaxFieldLength.LIMITED);
			
			writerA.AddDocument(lDoc);
			writerA.AddDocument(lDoc2);
			writerA.Optimize();
			writerA.Close();
			
			writerB.AddDocument(lDoc3);
			writerB.Close();
			
			QueryParser parser = new QueryParser(Util.Version.LUCENE_CURRENT, "fulltext", new StandardAnalyzer(Util.Version.LUCENE_CURRENT));
			Query query = parser.Parse("handle:1");
			
			Searcher[] searchers = new Searcher[2];
			searchers[0] = new IndexSearcher(indexStoreB, true);
            searchers[1] = new IndexSearcher(indexStoreA, true);
			Searcher mSearcher = new MultiSearcher(searchers);
			ScoreDoc[] hits = mSearcher.Search(query, null, 1000).ScoreDocs;
			
			Assert.AreEqual(3, hits.Length);
			
			Explanation explain = mSearcher.Explain(query, hits[0].Doc);
			System.String exp = explain.ToString(0);
			Assert.IsTrue(exp.IndexOf("maxDocs=3") > - 1, exp);
			Assert.IsTrue(exp.IndexOf("docFreq=3") > - 1, exp);
			
			query = parser.Parse("handle:\"1 2\"");
			hits = mSearcher.Search(query, null, 1000).ScoreDocs;
			
			Assert.AreEqual(3, hits.Length);
			
			explain = mSearcher.Explain(query, hits[0].Doc);
			exp = explain.ToString(0);
			Assert.IsTrue(exp.IndexOf("1=3") > - 1, exp);
			Assert.IsTrue(exp.IndexOf("2=3") > - 1, exp);
			
			query = new SpanNearQuery(new SpanQuery[]{new SpanTermQuery(new Term("handle", "1")), new SpanTermQuery(new Term("handle", "2"))}, 0, true);
			hits = mSearcher.Search(query, null, 1000).ScoreDocs;
			
			Assert.AreEqual(3, hits.Length);
			
			explain = mSearcher.Explain(query, hits[0].Doc);
			exp = explain.ToString(0);
			Assert.IsTrue(exp.IndexOf("1=3") > - 1, exp);
			Assert.IsTrue(exp.IndexOf("2=3") > - 1, exp);
			mSearcher.Close();
		}
	}
}