lib/excalt/helpers/event_formatter.ex

defmodule Excalt.Helpers.EventFormatter do
  @doc """
  Returns the filtered list of events containing only the events that start and end in the same day.
  The input is the list of events as returned by Excalt.Event.parsed_list!/6).
  """
  @spec intraday_events(events :: [Excalt.Event.t()]) :: {[Excalt.Event.t()], [Excalt.Event.t()]}
  def intraday_events(events) do
    events
    |> Enum.filter(fn e ->
      event = List.first(e.icalendar.events)
      dtstart_date = DateTime.to_date(event.dtstart)
      dtend_date = DateTime.to_date(event.dtend)
      dtstart_date == dtend_date
    end)
    |> Enum.sort(fn a, b ->
      a_event = List.first(a.icalendar.events)
      b_event = List.first(b.icalendar.events)
      a_event.dtstart > b_event.dtstart
    end)
    |> Enum.sort(fn a, b ->
      a_event = List.first(a.icalendar.events)
      b_event = List.first(b.icalendar.events)
      dtstart_a = DateTime.to_date(a_event.dtstart)
      dtstart_b = DateTime.to_date(b_event.dtstart)
      dtstart_a == dtstart_b
    end)
  end

  @doc """
  Returns the filtered list of events containing only the events where the start and end are on a differnt day.
  The input is the list of events as returned by Excalt.Event.parsed_list!/6).
  """
  @spec multiday_events(events :: [Excalt.Event.t()]) :: {[Excalt.Event.t()], [Excalt.Event.t()]}
  def multiday_events(events) do
    Enum.filter(events, fn e ->
      event = List.first(e.icalendar.events)
      dtstart_date = DateTime.to_date(event.dtstart)
      dtend_date = DateTime.to_date(event.dtend)
      dtstart_date != dtend_date
    end)
    |> Enum.sort(fn a, b ->
      a_event = List.first(a.icalendar.events)
      b_event = List.first(b.icalendar.events)
      dtstart_a = DateTime.to_date(a_event.dtstart)
      dtstart_b = DateTime.to_date(b_event.dtstart)
      dtstart_a == dtstart_b
    end)
  end

  @doc """
  Extracts the basic information about a list of events
  """
  def basic_info(events) do
    Enum.map(events, fn e ->
      event = List.first(e.icalendar.events)
      {event.dtstart, event.dtend, event.summary}
    end)
  end

  @doc """
  Formats the list of events by grouping them per day
  """
  def daily_grouping(events) do
    Enum.chunk_by(events, fn {dtstart_a, _, _} ->
      dtstart_a = DateTime.to_date(dtstart_a)
      dtstart_a
    end)
  end

  @doc """
  Formats the list of multiday-events into a human-readable text.
  """
  def multiday_txt(events) do
    multiday_events = events |> multiday_events |> basic_info

    "Multiday events\n" <>
      Enum.reduce(multiday_events, "", fn {dtstart, dtend, summary}, acc ->
        acc <>
          Timex.format!(dtstart, "  %d-%b-%Y", :strftime) <>
          " - " <>
          Timex.format!(dtend, "%d-%b-%Y", :strftime) <> " #{summary}\n"
      end)
  end

  @doc """
  Formats the list of intraday-events into a human-readable text.
  """
  def intraday_txt(events) do
    day_list = events |> intraday_events |> basic_info |> daily_grouping

    "Intraday events:\n" <>
      Enum.reduce(day_list, "", fn day, acc ->
        {day_date, _, _} = List.first(day)

        acc <>
          Timex.format!(day_date, "%a %d-%b-%Y", :strftime) <>
          if DateTime.to_date(day_date) == Date.utc_today(),
            do: " <- today",
            else:
              "" <>
                "\n" <>
                Enum.reduce(day, "", fn {dtstart, dtend, summary}, acc ->
                  acc <>
                    Timex.format!(dtstart, "  %H:%M", :strftime) <>
                    " - " <>
                    Timex.format!(dtend, "%H:%M", :strftime) <> " #{summary}\n"
                end)
      end)
  end
end