using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EvoBoat.EvoAlg.BBO
{
    public class Num_EBOAlg<S> : EBOAlg<NumOptProblem<S>, S, Vector, double>
        where S : VecSolution<Vector, double>, new()
    {
        public Num_EBOAlg() : base()
        { }

        public Num_EBOAlg(NumOptProblem<S> problem, int seed = 0) : base(problem, seed)
        {
            this.Factory = new VectorSolutionFactory<NumOptProblem<S>, S>(problem);
        }

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

        public override double Blend(S sol, int d, S sol1, S sol2)
        {
            return sol1.Content[d] + Rand.NextDouble() * (sol2.Content[d] - sol.Content[d]);
        }

        public override void Repair(S sol, int index, int d, double oldv)
        {
            if (sol.Content[d] < Problem.Lowers[d] || sol.Content[d] > Problem.Uppers[d])
                sol.Content[d] = Problem.Lowers[d] + Rand.NextDouble() * Problem.Ranges[d];
        }

        public static Num_EBOAlg<S> ERingBiogeoAlg()
        {
            return new Num_EBOAlg<S>() { Name = "RingEBO", FunSetToplogy = SetRingTopology };
        }

        public static Num_EBOAlg<S> ERingBiogeoAlg(NumOptProblem<S> problem, int seed = 0)
        {
            return new Num_EBOAlg<S>(problem, seed) { Name = "RingEBO", FunSetToplogy = SetRingTopology };
        }

        public static Num_EBOAlg<S> ERandBiogeoAlg(int kSize = 3)
        {
            Num_EBOAlg<S> alg = new Num_EBOAlg<S>() { Name = "RandEBO" };
            alg.FunSetToplogy = SetRandomTopology(alg.Rand, kSize);
            return alg;
        }

        public static Num_EBOAlg<S> ERandBiogeoAlg(NumOptProblem<S> problem, int kSize = 3, int seed = 0)
        {
            Num_EBOAlg<S> alg = new Num_EBOAlg<S>(problem, seed) { Name = "RandEBO" };
            alg.FunSetToplogy = SetRandomTopology(alg.Rand, kSize);
            return alg;
        }
    }
}
