using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EvoBoat.EvoAlg.WWO;

namespace EvoBoat.EvoAlg.Perm
{
    public class Perm_WWOAlg<P,S> : COMB_WWOAlg<P, S, PermVector, int>
        where P : PermProblem<S>
        where S : VecSolution<PermVector, int>, new()
    {
        public static Func<EAlg<P, S, PermVector, int>, S, int, S, S> ReflectFunc = (alg, sol, index, exSol) =>
        {
            int[] arr = new int[alg.Problem.Dimension];
            bool[] flag = new bool[alg.Problem.Dimension];
            for (int d = 0; d < alg.Problem.Dimension; d++)
                if (alg.Rand.Next() % 2 == 0)
                {
                    arr[d] = exSol.Content[d];
                    flag[arr[d]] = true;
                }
            for (int d = 0, d1 = 0; d < alg.Problem.Dimension; d++)
                if (!flag[exSol.Content[d]])
                {
                    while (flag[sol.Content[d1]])
                        d1++;
                    arr[d] = sol.Content[d1++];
                }
            S sol1 = new S() { Content = new PermVector(arr) };
            alg.Evaluate(sol1);            
            return sol1;
        };

        public Perm_WWOAlg() : base()
        { }

        public Perm_WWOAlg(P problem, int seed = 0) : base(problem, seed)
        {
            this.Factory = new PermSolutionFactory<P, S>(problem);
        }

        public override void SetFactory()
        {
            if (Problem == null)
                throw new ArgumentNullException("Please assign the problem instance before set the factory");
            Factory = new PermSolutionFactory<P, S>(Problem);
        }

        public override double MoveP(S sol, int index, int d)
        {
            if (d < Problem.Dimension)
            {
                int d1 = Rand.Next(d, Problem.Dimension);
                sol.Content.Reverse(d, d1);
            }
            return 0;
        }

        public override double MoveB(S sol, int index, int d)
        {
            int d1 = RandomSelectIndex(Problem.Dimension, d);
            sol.Content.Swap(d, d1);
            return 0;
        }

        public override S Reflect(S sol, int index)
        {
            return ReflectFunc(this, sol, index, best);
        }
    }
}
