Skip to main content

lib/drone/adapters/sim/state.ex

defmodule Drone.Adapters.Sim.State do
  @moduledoc false

  @type t :: %__MODULE__{
          x: integer(),
          y: integer(),
          z: integer(),
          yaw: integer(),
          flying: boolean(),
          battery: number(),
          speed: integer(),
          mode: :idle | :sdk_mode | :flying | :emergency,
          flight_time_seconds: non_neg_integer(),
          last_command: Drone.Command.t() | nil,
          command_history: [Drone.Command.t()],
          config: map()
        }

  defstruct x: 0,
            y: 0,
            z: 0,
            yaw: 0,
            flying: false,
            battery: 100,
            speed: 0,
            mode: :idle,
            flight_time_seconds: 0,
            last_command: nil,
            command_history: [],
            config: %{
              battery_drain_per_move: 0.5,
              battery_drain_per_takeoff: 2.0,
              battery_drain_per_land: 1.0,
              battery_drain_per_query: 0.0,
              failure_rate: 0.0,
              fail_commands: []
            }

  @spec new(keyword()) :: t()
  def new(opts \\ []) do
    config = %{
      battery_drain_per_move: Keyword.get(opts, :battery_drain_per_move, 0.5),
      battery_drain_per_takeoff: Keyword.get(opts, :battery_drain_per_takeoff, 2.0),
      battery_drain_per_land: Keyword.get(opts, :battery_drain_per_land, 1.0),
      battery_drain_per_query: Keyword.get(opts, :battery_drain_per_query, 0.0),
      failure_rate: Keyword.get(opts, :failure_rate, 0.0),
      fail_commands: Keyword.get(opts, :fail_commands, [])
    }

    %__MODULE__{
      battery: Keyword.get(opts, :battery, 100),
      config: config
    }
  end

  @spec drain_battery(t(), float()) :: t()
  def drain_battery(%__MODULE__{battery: battery} = state, amount) do
    %{state | battery: max(0, battery - amount)}
  end

  @spec push_command(t(), Drone.Command.t()) :: t()
  def push_command(%__MODULE__{command_history: history} = state, cmd) do
    %{state | last_command: cmd, command_history: [cmd | history]}
  end

  @doc """
  Increments the flight time by the given number of seconds.
  Used to simulate time elapsed during command execution.
  """
  @spec add_flight_time(t(), non_neg_integer()) :: t()
  def add_flight_time(%__MODULE__{flight_time_seconds: t} = state, seconds) do
    %{state | flight_time_seconds: t + seconds}
  end
end