﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Zad4
{
    public class Solution
    {
        public static int? NumberOfGenes = null;
        public static int? LowerBound = null;
        public static int? UpperBound = null;

        public List<int> Genes { get; }
        public double EvaluationError { get; }
        public double Fitness { get; }
        public int UniquenessHash { get; }

        public Solution()
        {
            this.Genes = Enumerable.Repeat(0, NumberOfGenes.Value).Select(x => GetNewGene()).ToList();

            this.EvaluationError = this.GetEvaluatedError();
            this.Fitness = 1.0 / this.EvaluationError;
            this.UniquenessHash = this.Genes.Aggregate(1, (old, soFar) => old * soFar);
        }

        public Solution(List<int> genes)
        {
            this.Genes = genes.ToList();

            this.EvaluationError = this.GetEvaluatedError();
            this.Fitness = 1.0 / this.EvaluationError;
            this.UniquenessHash = this.Genes.Aggregate(1, (old, soFar) => old * soFar);
        }

        private double GeneToValue(int gene)
        {
            return (gene / 1.0 / int.MaxValue) * (UpperBound.Value - LowerBound.Value) + LowerBound.Value;
        }

        private List<double> GetValuesFromGenes()
        {
            return this.Genes.Select(GeneToValue).ToList();
        }

        private int GetNewGene()
        {
            var r = new Random();

            return r.Next();
        }

        private double GetEvaluatedError()
        {
            return Evaluator.GetErrorForBetas(this.GetValuesFromGenes());
        }

        private double GetFitness()
        {
            return 1.0 / GetEvaluatedError();
        }

        private static string MyFormat(double d)
        {
            return string.Format("{0,14:0.0000000000}", d);
        }

        public override string ToString()
        {
            return "error: " + MyFormat(this.EvaluationError) +
                    "  values:" + string.Join(",  ", this.GetValuesFromGenes().Select(d => MyFormat(d))) +
                    "  genes:"  + string.Join(",  ", this.Genes.Select(d => BitManipulator.GetStringOfBitsFromInt(d)));
        }

        public override bool Equals(object obj)
        {
            return obj is Solution a && a.UniquenessHash == this.UniquenessHash;
        }

        public static bool operator == (Solution a, Solution b)
        {
            return a.Equals(b);
        }

        public static bool operator != (Solution a, Solution b)
        {
            return !(a == b);
        }

        public override int GetHashCode() => this.UniquenessHash;
    }
}
