     mandatory: %{},
     optional: %{},
   ]
+
+  @type header :: {non_neg_integer, non_neg_integer, non_neg_integer}
+
+  @spec new(header, map, map) :: t
 
   def new({command_id, command_status, sequence_number}, mandatory_fields, optional_fields) do
     %Pdu{

defmodule SMPPEX.Pdu do
  alias SMPPEX.Protocol.TlvFormat
  alias SMPPEX.Pdu

  @type t :: %Pdu{
    command_id: integer,
    command_status: integer,
    sequence_number: integer,
    mandatory: map(),
    optional: map()
  }

  defstruct [

    }
  end

  @spec command_id(t) :: non_neg_integer

  def command_id(pdu) do
    pdu.command_id
  end

  @spec command_status(t) :: non_neg_integer

  def command_status(pdu) do
    pdu.command_status
  end

  @spec sequence_number(t) :: non_neg_integer

  def sequence_number(pdu) do
    pdu.sequence_number
  end

  @spec mandatory_field(t, integer | atom) :: any

  def mandatory_field(pdu, name) when is_atom(name) do
    pdu.mandatory[name]
  end

  def mandatory_field(pdu, id) when is_integer(id) do
    case CommandNames.name_by_id(id) do
      {:ok, name} -> pdu.mandatory[name]
      :unknown -> nil
    end
  end

  @spec optional_field(t, integer | atom) :: any

  def optional_field(pdu, id) when is_integer(id) do
    pdu.optional[id]
