#pragma once

#include "OptimizerBase.h"
#include <iostream>

namespace mdd {
	class OptimizerEvolutionary : public OptimizerBase {
	protected:
		static int random_num(double min, double max, double inc = 1.0)
		{
			int range = (max - min) / inc + 1;
			return min + inc * (std::rand() % range);
		}

		Permutation generatePermutation();
		Permutation combine(Permutation par1, Permutation par2, int try_counter = 0);

		std::vector<Permutation> _children;
		std::vector<Permutation> _bests;
		size_t _same_counter = 0;
		Permutation _old_best;

		int _min_generations;
		double _max_fitness;
		size_t _grow_generation;
		size_t _converges;
		double _precision;

		void evolve();
		void evaluate(size_t ignore_len = 0);
		std::vector<double> mutateGene(std::shared_ptr<IInput> input, std::vector<double> seed = std::vector<double>());
		bool configureChild(const json& config) override;

		bool loadStepDB(const json& j) override;
		bool loadDB(const json& j) override;

		void reset() override;
		bool reachAbort(const std::vector<Permutation>& pers) override;

	public:
		OptimizerEvolutionary();
		double update() override;
		std::vector<Permutation> getBests();
		double evaluateFitness(const Permutation& ind);
	};
}