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

namespace EvoBoat.EvoAlg.IntProg
{
    /// <summary>
    /// Basic integer programming problem
    /// </summary>
    public class IntProgProblem<S> : IProblem<S, IntVector>
        where S : ISolution<IntVector>      
    {
        public string Name { get; set; }
        public Func<IntVector, double> Func { get; set; }

        protected double? optimum;
        public double? Optimum
        {
            get { return optimum; }
        }

        protected int dimension;
        public int Dimension
        {
            get { return dimension; }
        }

        protected IntVector lowers, uppers, ranges;
        public IntVector Lowers
        {
            get { return lowers; }
        }
        public IntVector Uppers
        {
            get { return uppers; }
        }
        public IntVector Ranges
        {
            get { return ranges; }
        }

        public IntProgProblem(int dimension, int lower, int upper, string name = null, double? optimum = null)
        {
            this.dimension = dimension;
            this.lowers = IntVector.Create(dimension, lower);
            this.uppers = IntVector.Create(dimension, upper);
            this.ranges = IntVector.Create(dimension, upper - lower);
            this.Name = (name != null) ? name : "Integer programming";
            this.optimum = optimum;
        }

        public IntProgProblem(IntVector lowers, IntVector uppers, string name = null, double? optimum = null)
        {
            if (lowers.Length != uppers.Length)
                throw new ArgumentException("Inequal lengthes");
            this.dimension = lowers.Length;
            this.lowers = lowers;
            this.uppers = uppers;
            this.ranges = uppers - lowers;
            this.Name = (name != null) ? name : "Integer programming";
            this.optimum = optimum;
        }

        public override string ToString()
        {
            return Name;
        }

        public virtual double Evaluate(IntVector x)
        {
            return Func(x);
        }
        public virtual double Evaluate(S sol)
        {
            sol.Fit = Func(sol.Content);
            return sol.Fit;
        }

        public bool IsFeasible(IntVector x)
        {
            for (int d = 0; d < dimension; d++)
                if (x[d] < lowers[d] || x[d] > uppers[d])
                    return false;
            return true;
        }
    }
}
