using Lucene.Net.Search.Suggest.Fst;
using Lucene.Net.Search.Suggest.Jaspell;
using Lucene.Net.Search.Suggest.Tst;
using Lucene.Net.Util;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;

namespace Lucene.Net.Search.Suggest
{
    /*
     * 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.
     */

    public class PersistenceTest : LuceneTestCase
    {
        public readonly string[] keys = new string[] {
            "one",
            "two",
            "three",
            "four",
            "oneness",
            "onerous",
            "onesimus",
            "twofold",
            "twonk",
            "thrive",
            "through",
            "threat",
            "foundation",
            "fourier",
            "fourty"
        };

        [Test]
        public void TestTSTPersistence()
        {
            RunTest(typeof(TSTLookup), true);
        }

        [Test]
        public void TestJaspellPersistence()
        {
            RunTest(typeof(JaspellLookup), true);
        }

        [Test]
        public void TestFSTPersistence()
        {
            RunTest(typeof(FSTCompletionLookup), false);
        }

        private void RunTest(Type lookupClass,
            bool supportsExactWeights)
        {

            // Add all input keys.
            Lookup lookup = (Lookup)Activator.CreateInstance(lookupClass);
            Input[] keys = new Input[this.keys.Length];
            for (int i = 0; i < keys.Length; i++)
                keys[i] = new Input(this.keys[i], i);
            lookup.Build(new InputArrayIterator(keys));

            // Store the suggester.
            DirectoryInfo storeDir = CreateTempDir(this.GetType().Name);
            lookup.Store(new FileStream(Path.Combine(storeDir.FullName, "lookup.dat"), FileMode.OpenOrCreate));

            // Re-read it from disk.
            lookup = (Lookup)Activator.CreateInstance(lookupClass);
            lookup.Load(new FileStream(Path.Combine(storeDir.FullName, "lookup.dat"), FileMode.Open));

            // Assert validity.
            Random random = Random();
            long previous = long.MinValue;
            foreach (Input k in keys)
            {
                IList<Lookup.LookupResult> list = lookup.DoLookup(TestUtil.BytesToCharSequence(k.term, random).ToString(), false, 1);
                assertEquals(1, list.size());
                Lookup.LookupResult lookupResult = list[0];
                assertNotNull(k.term.Utf8ToString(), lookupResult.Key);

                if (supportsExactWeights)
                {
                    assertEquals(k.term.Utf8ToString(), k.v, lookupResult.Value);
                }
                else
                {
                    assertTrue(lookupResult.Value + ">=" + previous, lookupResult.Value >= previous);
                    previous = lookupResult.Value;
                }
            }
        }
    }
}
