// ************************************************************************
        private bool DumpValuesFunc(IEnumerable <int> enumValues)
        {
            Interlocked.Increment(ref _count);
            StringBuilder sb = new StringBuilder();

            foreach (int val in enumValues)
            {
                sb.Append(val);
                sb.Append(", ");
            }

            int[] values = enumValues.ToArray();
            Array.Sort(values);


            PermutationOuelletLexico3 <int> p = new PermutationOuelletLexico3 <int>(values);
            long index = p.GetIndexOfValues(enumValues.ToArray());

            sb.Append($", Index: {index}");


            WriteLine(sb.ToString());

            return(false);
        }
        // ************************************************************************
        public void ExecuteForEachPermutation(Action <int[]> action)
        {
            //			Console.WriteLine($"Thread {System.Threading.Thread.CurrentThread.ManagedThreadId} started: {_indexFirst} {_indexLastExclusive}");

            long index = _indexFirst;

            PermutationOuelletLexico3 <int> permutationOuellet = new PermutationOuelletLexico3 <int>(_sortedValues);

            permutationOuellet.GetValuesForIndex(index);
            action(permutationOuellet.Result);
            index++;

            int[] values = permutationOuellet.Result;
            while (index < _indexLastExclusive)
            {
                PermutationSaniSinghHuttunen.NextPermutation(values);
                action(values);
                index++;
            }

            //			Console.WriteLine($"Thread {System.Threading.Thread.CurrentThread.ManagedThreadId} ended: {DateTime.Now.ToString("yyyyMMdd_HHmmss_ffffff")}");
        }
        // ************************************************************************
        private int RunTest()
        {
            try
            {
                bool canRun = false;
                lock (_lockObj)
                {
                    if (!IsTestRunning)
                    {
                        canRun        = true;
                        IsTestRunning = true;
                    }
                }

                if (!canRun)
                {
                    MessageBox.Show("Already running test. Please try later.");
                    return(0);
                }

                Action <IEnumerable <int> > actionToDoOnPermutation = null;
                Predicate <int[]>           funcToDoOnPermutation   = null;    // Direct function for Sam to be fair (I do not want to add an additional indirection)

                switch (EnumAction)
                {
                case EnumAction.Nothing_BestForPerformanceTest:
                    actionToDoOnPermutation = DoNothing;
                    funcToDoOnPermutation   = DoNothingFunc;
                    break;

                case EnumAction.CountItemWithBugWithMultithreadedCode:
                    actionToDoOnPermutation = IncreaseCount;
                    funcToDoOnPermutation   = IncreaseCountFunc;
                    break;

                case EnumAction.CountItemSafeInterlockedIncrement:
                    actionToDoOnPermutation = IncreaseCountSafeInterlockedIncrement;
                    funcToDoOnPermutation   = IncreaseCountSafeInterlockedIncrementFunc;
                    break;

                case EnumAction.CountItemSafeSpinLock:
                    actionToDoOnPermutation = IncreaseCountSafeSpinLock;
                    funcToDoOnPermutation   = IncreaseCountSafeSpinLockFunc;
                    break;

                case EnumAction.DumpPermutatedValuesAndCount:
                    actionToDoOnPermutation = DumpValues;
                    funcToDoOnPermutation   = DumpValuesFunc;

                    if (CountOfElementsToPermute > 5)
                    {
                        var result = MessageBox.Show(
                            "The count of item to permute is greater than 5, it could take long to dump every items, are you sure you want to continue?",
                            "Warning",
                            MessageBoxButton.OKCancel);
                        if (result == MessageBoxResult.Cancel)
                        {
                            return(0);
                        }
                    }

                    break;
                }

                EnumAlgoPermutation algoPermutation = AlgoPermutation;
                EnumAlgoPermutation algoPermutationActive;

                _testCount++;
                WriteLine($"Test {_testCount} started. Count {CountOfElementsToPermute}!. Action: {EnumUtil.GetEnumDescription(EnumAction)}.");

                int[]     values;
                Stopwatch stopwatch = new Stopwatch();

                // Eric OuelletHeap Algorithm
                algoPermutationActive = EnumAlgoPermutation.OuelletHeap;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();
                    PermutationOuellet.ForAllPermutation(values, (vals) =>
                    {
                        actionToDoOnPermutation?.Invoke(vals);
                        return(false);
                    });
                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                // Eric OuelletHeap indexed Algorithm
                algoPermutationActive = EnumAlgoPermutation.OuelletIndexed;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();
                    var permutationGenerator = new PermutationOuelletLexico <int>(values);

                    // int[] result = new int[values.Length];
                    for (long i = 0; i < permutationGenerator.MaxIndex; i++)
                    {
                        permutationGenerator.GetSortedValuesFor(i);
                        {
                            actionToDoOnPermutation?.Invoke(permutationGenerator.Result);
                        }
                    }
                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }


                // Eric OuelletHeap indexed Algorithm v2
                algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv2;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();
                    var permutationGenerator = new PermutationOuelletLexico2 <int>(values);

                    // int[] result = new int[values.Length];
                    for (long i = 0; i < permutationGenerator.MaxIndex; i++)
                    {
                        permutationGenerator.GetSortedValuesFor(i);
                        {
                            actionToDoOnPermutation?.Invoke(permutationGenerator.Result);
                        }
                    }
                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                // Eric OuelletHeap indexed Algorithm v3
                algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv3;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();
                    var permutationGenerator = new PermutationOuelletLexico3 <int>(values);

                    // int[] result = new int[values.Length];
                    for (long i = 0; i < permutationGenerator.MaxIndex; i++)
                    {
                        permutationGenerator.GetValuesForIndex(i);
                        {
                            actionToDoOnPermutation?.Invoke(permutationGenerator.Result);
                        }
                    }
                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                //// Eric OuelletHeap indexed Algorithm v4
                //algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv4;
                //if (algoPermutation.HasFlag(algoPermutationActive))
                //{
                //	_count = 0;
                //	values = GetValues();
                //	stopwatch.Reset();
                //	stopwatch.Start();
                //	var permutationGenerator = new PermutationOuelletLexico4<int>(values);

                //	// int[] result = new int[values.Length];
                //	for (int i = 0; i < permutationGenerator.MaxIndex; i++)
                //	{
                //		permutationGenerator.GetValuesForIndex(i);
                //		{
                //			actionDumpValues?.Invoke(permutationGenerator.Result);
                //		}
                //	}
                //	stopwatch.Stop();
                //	WriteResult(algoPermutationActive, stopwatch);
                //}

                algoPermutationActive = EnumAlgoPermutation.SaniSinghHuttunen;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();
                    do
                    {
                        actionToDoOnPermutation?.Invoke(values);
                    }while (PermutationSaniSinghHuttunen.NextPermutation(values));

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv3HuttunenST;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();

                    PermutationMixOuelletSaniSinghHuttunen mix = new PermutationMixOuelletSaniSinghHuttunen(values);
                    mix.ExecuteForEachPermutation(actionToDoOnPermutation);

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                algoPermutationActive = EnumAlgoPermutation.SimpleVar;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();

                    do
                    {
                        actionToDoOnPermutation?.Invoke(values);
                    }while (!PermutationSimpleVar.NextPermutation(values));
                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                algoPermutationActive = EnumAlgoPermutation.SimpleVarUnsafe;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();
                    PermutationSimpleVarUnsafe permutations = new PermutationSimpleVarUnsafe();
                    permutations.Permutate(0, values.Length, (int[] vals) =>
                    {
                        actionToDoOnPermutation?.Invoke(vals);
                    });
                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                // ErezRobinson Algorithm
                algoPermutationActive = EnumAlgoPermutation.ErezRobinson;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();
                    foreach (var vals in PermutationErezRobinson.QuickPerm(values))
                    {
                        actionToDoOnPermutation?.Invoke(vals);
                    }

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }


                algoPermutationActive = EnumAlgoPermutation.Sam;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();

                    var pf = new PermutationFinder <int>();
                    pf.Evaluate(values, funcToDoOnPermutation);

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }


                algoPermutationActive = EnumAlgoPermutation.Ziezi;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();

                    PermutationZiezi.EnumeratePermutation(values, actionToDoOnPermutation);

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }


                // Pengyang linq algorithm
                algoPermutationActive = EnumAlgoPermutation.Pengyang;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();
                    foreach (var vals in PermutationPengyang.GetPermutations(values, values.Length))
                    {
                        actionToDoOnPermutation?.Invoke(vals);
                    }

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                algoPermutationActive = EnumAlgoPermutation.OuelletIndexedMT;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();

                    int[] result = new int[values.Length];
                    Parallel.For <PermutationOuelletLexico <int> >
                    (
                        0,
                        Factorial.GetFactorial(values.Length),
                        () => new PermutationOuelletLexico <int>(GetValues()),
                        (index, state, permutationOuellet) =>
                    {
                        permutationOuellet.GetSortedValuesFor(index);
                        actionToDoOnPermutation?.Invoke(permutationOuellet.Result);
                        return(permutationOuellet);
                    },
                        (permutationOuellet) => { }
                    );

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                algoPermutationActive = EnumAlgoPermutation.OuelletIndexedv3MT;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();

                    int[] result = new int[values.Length];
                    Parallel.For <PermutationOuelletLexico3 <int> >
                    (
                        0,
                        Factorial.GetFactorial(values.Length),
                        () => new PermutationOuelletLexico3 <int>(GetValues()),
                        (index, state, permutationOuellet) =>
                    {
                        permutationOuellet.GetValuesForIndex(index);
                        actionToDoOnPermutation?.Invoke(permutationOuellet.Result);
                        return(permutationOuellet);
                    },
                        (permutationOuellet) => { }
                    );

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                algoPermutationActive = EnumAlgoPermutation.OuelletHuttunenMT;
                if (algoPermutation.HasFlag(algoPermutationActive))
                {
                    WriteIntro(algoPermutationActive);
                    _count = 0;
                    values = GetValues();
                    stopwatch.Reset();
                    stopwatch.Start();

                    PermutationMixOuelletSaniSinghHuttunen.ExecuteForEachPermutationMT(values, actionToDoOnPermutation);

                    stopwatch.Stop();
                    WriteResult(algoPermutationActive, stopwatch);
                }

                WriteLine("Test " + _testCount + " ended.");
                WriteLine("---------------------------------------------------------------");
                return(_count);
            }
            finally
            {
                IsTestRunning = false;
            }
        }