//! Reat
//!
//! An implementation of Neat in Rust, using a ctrnn.
//! This implementation allows to also mutate tau and theta (see ctrnn).
//!
//! TODO
//!

// %todo TESTS!!!
// %todo DOCUMENTATION!!!
// %todo make a public api that doesn't suck.
//       it should allow to train in parallel and on multiple computers.
//       since we allow the ctrnn to be serialized/deserialized,
//       there should be a way to get the ctrnn and return the fitness value.

#![deny(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

mod ctrnn;
mod evaluation;
mod genes;
mod genome;
mod population;
mod settings;
mod species;

pub use evaluation::Evaluation;
use population::Population;
use serde::{Deserialize, Serialize};
pub use settings::Settings;

#[derive(Serialize, Deserialize, Debug, Clone)]
/// TODO
pub struct Neat {
    population: Population,
    settings: Settings,
    input_size: usize,
    output_size: usize,
}

impl Neat {
    /// Create a new Neat struct to train.
    /// Other than the input and output size of the network, all other values can be controlled in the settings.
    pub fn new(settings: Settings, input_size: usize, output_size: usize) -> Neat {
        let mut population = Population::default(settings.population_size);
        population.create_initial_population(input_size + output_size, &settings);
        Neat {
            population: population,
            settings: settings,
            input_size: input_size,
            output_size: output_size,
        }
    }

    /// Get the ctrnn evaluation.
    pub fn get_ctrnn(&self) -> Vec<impl Evaluation> {
        self.population.get_ctrnn(self.input_size, self.output_size)
    }

    /// evolve the network to make it better, stronger, slower :(
    ///
    /// TODO: currently you are required to have the fitness array return the fitness of each genome in the same order as the get_ctrnn outputs them.
    ///       This should change to make it less error prone.
    pub fn evolve(&mut self, fitness: &[f64]) {
        self.population.evolve(&self.settings, fitness);
    }

    /// get the number of the generation.
    pub fn get_generation(&self) -> usize {
        self.population.get_generation()
    }

    /// get the number of the species alive in the current generation.
    pub fn number_of_species(&self) -> usize {
        self.population.number_of_species()
    }
}
