using Lucene.Net.Analysis;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Support;
using Lucene.Net.Util;
using NUnit.Framework;
using System.Globalization;
using System.IO;
using System.Text;

namespace Lucene.Net.Codecs.Pulsing
{
    /*
	 * 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.
	 */

    /// <summary>
    /// Pulses 10k terms/docs, 
    /// originally designed to find JRE bugs (https://issues.apache.org/jira/browse/LUCENE-3335)
    /// 
    /// @lucene.experimental
    /// </summary>
    // LUCENENET TODO: This was marked with the Nightly attribute in Java Lucene
    public class Test10KPulsings : LuceneTestCase
    {
        [Test]
        public virtual void Test10kPulsed()
        {
            // we always run this test with pulsing codec.
            Codec cp = TestUtil.AlwaysPostingsFormat(new Pulsing41PostingsFormat(1));

            DirectoryInfo f = CreateTempDir("10kpulsed");
            BaseDirectoryWrapper dir = NewFSDirectory(f);
            dir.CheckIndexOnClose = false; // we do this ourselves explicitly
            RandomIndexWriter iw = new RandomIndexWriter(Random(), dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetCodec(cp));

            Document document = new Document();
            FieldType ft = new FieldType(TextField.TYPE_STORED);

            switch (TestUtil.NextInt(Random(), 0, 2))
            {
                case 0:
                    ft.IndexOptions = IndexOptions.DOCS_ONLY;
                    break;
                case 1:
                    ft.IndexOptions = IndexOptions.DOCS_AND_FREQS;
                    break;
                default:
                    ft.IndexOptions = IndexOptions.DOCS_AND_FREQS_AND_POSITIONS;
                    break;
            }

            Field field = NewField("field", "", ft);
            document.Add(field);

            //NumberFormat df = new DecimalFormat("00000", new DecimalFormatSymbols(Locale.ROOT));

            for (int i = 0; i < 10050; i++)
            {
                //field.StringValue = df.format(i);
                field.SetStringValue(i.ToString("00000", CultureInfo.InvariantCulture));
                iw.AddDocument(document);
            }

            IndexReader ir = iw.Reader;
            iw.Dispose();

            TermsEnum te = MultiFields.GetTerms(ir, "field").GetIterator(null);
            DocsEnum de = null;

            for (int i = 0; i < 10050; i++)
            {
                //string expected = df.format(i);
                string expected = i.ToString("00000", CultureInfo.InvariantCulture);
                assertEquals(expected, te.Next().Utf8ToString());
                de = TestUtil.Docs(Random(), te, null, de, DocsFlags.NONE);
                assertTrue(de.NextDoc() != DocIdSetIterator.NO_MORE_DOCS);
                assertEquals(DocIdSetIterator.NO_MORE_DOCS, de.NextDoc());
            }
            ir.Dispose();

            TestUtil.CheckIndex(dir);
            dir.Dispose();
        }

        /// <summary>
        /// a variant, that uses pulsing, but uses a high TF to force pass thru to the underlying codec
        /// </summary>
        [Test]
        public virtual void Test10kNotPulsed()
        {
            // we always run this test with pulsing codec.
            int freqCutoff = TestUtil.NextInt(Random(), 1, 10);
            Codec cp = TestUtil.AlwaysPostingsFormat(new Pulsing41PostingsFormat(freqCutoff));

            DirectoryInfo f = CreateTempDir("10knotpulsed");
            BaseDirectoryWrapper dir = NewFSDirectory(f);
            dir.CheckIndexOnClose = false; // we do this ourselves explicitly
            RandomIndexWriter iw = new RandomIndexWriter(Random(), dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetCodec(cp));

            Document document = new Document();
            FieldType ft = new FieldType(TextField.TYPE_STORED);

            switch (TestUtil.NextInt(Random(), 0, 2))
            {
                case 0:
                    ft.IndexOptions = IndexOptions.DOCS_ONLY;
                    break;
                case 1:
                    ft.IndexOptions = IndexOptions.DOCS_AND_FREQS;
                    break;
                default:
                    ft.IndexOptions = IndexOptions.DOCS_AND_FREQS_AND_POSITIONS;
                    break;
            }

            Field field = NewField("field", "", ft);
            document.Add(field);

            //NumberFormat df = new DecimalFormat("00000", new DecimalFormatSymbols(Locale.ROOT));

            int freq = freqCutoff + 1;

            for (int i = 0; i < 10050; i++)
            {
                StringBuilder sb = new StringBuilder();
                for (int j = 0; j < freq; j++)
                {
                    //sb.Append(df.format(i));
                    sb.Append(i.ToString("00000", CultureInfo.InvariantCulture));
                    sb.Append(' '); // whitespace
                }
                field.SetStringValue(sb.ToString());
                iw.AddDocument(document);
            }

            IndexReader ir = iw.Reader;
            iw.Dispose();

            TermsEnum te = MultiFields.GetTerms(ir, "field").GetIterator(null);
            DocsEnum de = null;

            for (int i = 0; i < 10050; i++)
            {
                //string expected = df.format(i);
                string expected = i.ToString("00000", CultureInfo.InvariantCulture);
                assertEquals(expected, te.Next().Utf8ToString());
                de = TestUtil.Docs(Random(), te, null, de, DocsFlags.NONE);
                assertTrue(de.NextDoc() != DocIdSetIterator.NO_MORE_DOCS);
                assertEquals(DocIdSetIterator.NO_MORE_DOCS, de.NextDoc());
            }
            ir.Dispose();

            TestUtil.CheckIndex(dir);
            dir.Dispose();
        }
    }
}