lib/utilities/genealogy.ex

defmodule Utilities.Genealogy do
  @moduledoc """
  Genealogy tree server implementation. A genealogy tree is a directed grapgh that points
  from parent chromosome to child chromosome and shows the transitions of the evolution from
  first population to last population.
  """
  use GenServer

  def init(_opts) do
    {:ok, Graph.new()}
  end

  def handle_cast({:add_chromosomes, chromosomes}, genealogy) do
    {:noreply, Graph.add_vertices(genealogy, chromosomes)}
  end

  # Child is mutant of Parent
  def handle_cast({:add_chromosome, parent, child}, genealogy) do
    new_genealogy = genealogy |> Graph.add_edge(parent, child)
    {:noreply, new_genealogy}
  end

  # Child is crossover of Parents
  def handle_cast({:add_chromosome, parent_a, parent_b, child}, genealogy) do
    new_genealogy =
      genealogy |> Graph.add_edge(parent_a, child) |> Graph.add_edge(parent_b, child)

    {:noreply, new_genealogy}
  end

  def handle_call(:get_tree, _, genealogy) do
    {:reply, genealogy, genealogy}
  end

  def start_link(opts) do
    GenServer.start(__MODULE__, opts, name: __MODULE__)
  end

  def add_chromosomes(chromosomes) do
    GenServer.cast(__MODULE__, {:add_chromosomes, chromosomes})
  end

  def add_chromosome(parent, child) do
    GenServer.cast(__MODULE__, {:add_chromosome, parent, child})
  end

  def add_chromosome(parent_a, parent_b, child) do
    GenServer.cast(__MODULE__, {:add_chromosome, parent_a, parent_b, child})
  end

  def get_tree() do
    GenServer.call(__MODULE__, :get_tree)
  end
end