defmodule Azan.SunriseTime do
@moduledoc """
Documentation for `SunriseTime`.
"""
alias Azan.{
CalculationParameter,
Coordinate,
DateUtils,
PolarCircleResolution,
SolarTime,
TimeComponent
}
use TypedStruct
typedstruct do
field :sunrise, number()
field :date, Date.t()
field :calculation_parameter, CalculationParameter.t()
field :coordinate, Coordinate.t()
end
def find!(%__MODULE__{
sunrise: sunrise,
date: date,
coordinate: coordinate,
calculation_parameter: %CalculationParameter{
polar_circle_resolution: polar_circle_resolution
}
})
when polar_circle_resolution !== :unresolved and not is_number(sunrise) do
find_safe_time(polar_circle_resolution, date, coordinate)
end
def find!(%__MODULE__{
sunrise: sunrise,
date: date,
coordinate: coordinate,
calculation_parameter: %CalculationParameter{
polar_circle_resolution: polar_circle_resolution
}
})
when polar_circle_resolution !== :unresolved and is_number(sunrise) do
case find_naive_time!(sunrise, date) do
{:error, _} ->
find_safe_time(polar_circle_resolution, date, coordinate)
naive_time ->
naive_time
end
end
def find!(%__MODULE__{
sunrise: sunrise,
date: date,
calculation_parameter: %CalculationParameter{
polar_circle_resolution: :unresolved
}
}) do
sunrise |> find_naive_time!(date)
end
def find(sunrise, date, coordinate) do
find(sunrise, date, %CalculationParameter{}, coordinate)
end
def find(
sunrise,
date,
%CalculationParameter{} = calculation_parameter,
%Coordinate{} = coordinate
) do
case %__MODULE__{
sunrise: sunrise,
date: date,
calculation_parameter: calculation_parameter,
coordinate: coordinate
}
|> find!() do
{:error, reason} ->
{:error, reason}
sunrise_time ->
{:ok, sunrise_time}
end
end
def find_naive_time!(sunrise, date) do
sunrise |> TimeComponent.new() |> TimeComponent.create_utc_datetime(date)
end
def find_naive_time(sunrise, date) do
case find_naive_time!(sunrise, date) do
{:error, reason} ->
{:error, reason}
naive_time ->
{:ok, naive_time}
end
end
def find_safe_time(polar_circle_resolution, date, coordinate) do
%PolarCircleResolution{solar_time: %SolarTime{sunrise: new_sunrise}} =
polar_circle_resolution
|> PolarCircleResolution.polar_circle_resolved_values(date, coordinate)
TimeComponent.new(new_sunrise)
|> TimeComponent.create_utc_datetime(date)
end
def adjust(datetime, %CalculationParameter{
adjustments: %{sunrise: adjustment},
method_adjustments: %{sunrise: method_adjustment},
rounding: rounding
}) do
adjustment = adjustment |> DateUtils.sum_adjustment(method_adjustment)
datetime |> DateUtils.rounded_time(adjustment, rounding)
end
end