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

namespace TSPTest
{
    public class TSP_WWOAlg : COMB_WWOAlg<TSP, VecSolution<PermVector, int>, PermVector, int>
    {
        public TSP_WWOAlg() : base()
        {
            CanFitIncrement = true;
        }

        public TSP_WWOAlg(TSP problem, int seed = 0) : base(problem, seed)
        {
            CanFitIncrement = true;
            this.Factory = new PermSolutionFactory<TSP, VecSolution<PermVector, int>>(problem);
        }

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

        public override double MoveP(VecSolution<PermVector, int> sol, int index, int d)
        {
            if (d < Problem.Dimension)
            {
                int d1 = Rand.Next(d, Problem.Dimension);
                if (d == 0 && d1 == Problem.Dimension - 1)
                    return 0;
                int pre = d - 1, next = d1 + 1;
                if (pre < 0) pre = Problem.Dimension - 1;
                else if (next == Problem.Dimension) next = 0;
                double incr = -Problem.CostMatrix[sol.Content[pre], sol.Content[d]];
                incr += Problem.CostMatrix[sol.Content[pre], sol.Content[d1]];
                incr -= Problem.CostMatrix[sol.Content[d1], sol.Content[next]];
                incr += Problem.CostMatrix[sol.Content[d], sol.Content[next]];
                sol.Content.Reverse(d, d1);
                return incr;
            }
            return 0;
        }

        public override double MoveB(VecSolution<PermVector, int> sol, int index, int d)
        {
            int d1 = RandomSelectIndex(Problem.Dimension, d);
            if (d1 < d)
            {
                int t = d;
                d = d1;
                d1 = t;
            }
            double incr = 0;
            if (d == 0 && d1 == sol.Content.Length - 1)
            {
                incr -= Problem.CostMatrix[sol.Content[0], sol.Content[1]];
                incr += Problem.CostMatrix[sol.Content[sol.Content.Length - 1], sol.Content[1]];
                incr -= Problem.CostMatrix[sol.Content[sol.Content.Length - 2], sol.Content[sol.Content.Length - 1]];
                incr += Problem.CostMatrix[sol.Content[sol.Content.Length - 2], sol.Content[0]];
                sol.Content.Swap(d, d1);
                return incr;
            }
            int pre1 = d - 1, next2 = d1 + 1;
            if (pre1 < 0)
                pre1 = sol.Content.Length - 1;
            if (next2 == sol.Content.Length)
                next2 = 0;
            incr -= Problem.CostMatrix[sol.Content[pre1], sol.Content[d]];
            incr += Problem.CostMatrix[sol.Content[pre1], sol.Content[d1]];
            incr -= Problem.CostMatrix[sol.Content[d1], sol.Content[next2]];
            incr += Problem.CostMatrix[sol.Content[d], sol.Content[next2]];
            if (d + 1 < d1)
            {
                int next1 = d + 1, pre2 = d1 - 1;
                incr -= Problem.CostMatrix[sol.Content[d], sol.Content[next1]];
                incr += Problem.CostMatrix[sol.Content[d1], sol.Content[next1]];
                incr -= Problem.CostMatrix[sol.Content[pre2], sol.Content[d1]];
                incr += Problem.CostMatrix[sol.Content[pre2], sol.Content[d]];
            }
            sol.Content.Swap(d, d1);
            return incr;
        }

        public override VecSolution<PermVector, int> Reflect(VecSolution<PermVector, int> sol, int index)
        {
            return Perm_WWOAlg<TSP, VecSolution<PermVector, int>>.ReflectFunc(this, sol, index, best);
        }
    }
}
