lib/archeometer/reports/generator.ex

defmodule Archeometer.Reports.Generator do
  @moduledoc """
  Generates a report given a configuration and parameters.
  """

  require Logger
  use Archeometer.Repo
  import Archeometer.Reports.Utils

  alias Archeometer.Reports.Page

  def generate(cfg) do
    prepare_paths()
    create_pages(cfg)
    copy_assets()
    copy_images()
  end

  @index_page_name :index

  defp create_pages(cfg) do
    case length(cfg.modules) do
      1 ->
        create_module_page(hd(cfg.modules), cfg)

      _ ->
        page_names = page_names_fn(cfg)

        create_main_page(cfg, page_names)

        Enum.each(cfg.modules, &create_module_page(&1, cfg, page_names))
    end
  end

  defp page_names_fn(cfg) do
    sections =
      Enum.map(
        cfg.modules,
        &module_section_names(&1, cfg.module_page_def)
      )

    mods = Enum.zip(cfg.modules, sections)
    index_name = to_string(@index_page_name)

    index = {
      index_name,
      module_section_names(index_name, cfg.root_page_def)
    }

    [index | mods]
  end

  defp module_section_names(mod, page_def) do
    page_def.(mod)
    |> Map.get(:sections)
    |> Enum.map(&Map.get(&1, :desc))
  end

  defp create_main_page(cfg, page_names) do
    file_name = to_string(@index_page_name)

    file_name
    |> cfg.root_page_def.()
    |> create_page(file_name, page_names, cfg)
  end

  defp create_module_page(module, cfg, page_names \\ []) do
    module
    |> cfg.module_page_def.()
    |> create_page(to_string(module), page_names, cfg)
  end

  defp create_page(%Page.Definition{} = page_def, out_file, page_names, cfg) do
    Logger.info("Creating page #{page_def.id} ...")

    bindings = [app: page_def.id, limit: cfg.limit, db_name: cfg.db_name]

    page_def
    |> render_page(page_names, cfg.renderer, cfg.db_name, bindings)
    |> write_to_file(out_file <> ".html")

    Logger.info("Page #{page_def.id} ready!")
  end

  defp render_page(%Page.Definition{} = page_def, page_names, renderer, db_name, bindings) do
    old_db = setup_default_db(db_name)

    rendered =
      page_def
      |> Page.process(bindings, db_name)
      |> renderer.render(page_names, renderer)

    restore_default_db(old_db)

    rendered
  end

  defp setup_default_db(db_name) do
    old_db = Application.fetch_env(:archeometer, :default_db)
    Application.put_env(:archeometer, :default_db, db_name)
    old_db
  end

  defp restore_default_db({:ok, db}) do
    Application.put_env(:archeometer, :default_db, db)
  end

  defp restore_default_db(:error), do: :ok
end