summaryrefslogtreecommitdiff
path: root/lib/irc/mask.ex
blob: 7f68d1a1cbeebb2826fd5030df8dc74ecbb79a7a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
defmodule Irc.Mask do
  alias Irc.Addressable

  @type t :: %__MODULE__{nick: nil | String.t(), user: nil | String.t(), host: nil | String.t(), server: nil | String.t()}
  defstruct [:nick, :user, :host, :server, {:__private__, %{owner: nil, owner_module: nil}}]

  @spec parse(String.t) :: {:ok, t()} | {:error, :invalid_mask}
  def parse(string) do
    cond do
      String.contains?(string, "!") -> parse_user_mask(string)
      String.contains?(string, ".") -> parse_server_mask(string)
      true -> {:error, :invalid_mask}
    end
  end

  def parse(string, module, pid) do
    case parse(string) do
      {:ok, x} -> {:ok, set_owner(x, module, pid)}
      error -> error
    end
  end

  @spec equal?(Addressable.t(), Addressable.t()) :: boolean
  def equal?(a, b) do
    import Addressable
    (owner(a) == owner(b)) && (nick(a) == nick(b))
  end

  def from_addressable(addressable) do
    import Addressable
    new(nick(addressable),
      user(addressable),
      host(addressable)
    )
    |> set_owner(owner_module(addressable), owner(addressable))
  end

  def new(nick, user, host) do
    %__MODULE__{nick: nick, user: user, host: host}
  end

  def set_owner(t = %{__private__: private = %{owner: nil, owner_module: nil}}, module, pid) when is_atom(module) and is_pid(pid) do
    private = private
    |> Map.put(:owner, pid)
    |> Map.put(:owner_module, module)
    %{t | __private__: private}
  end

  def to_string(%__MODULE__{server: nil, nick: nick, user: user, host: host}) do
    Enum.join([nick, "!", user, "@", host])
  end

  def to_string(%__MODULE__{server: server}), do: server

  defp parse_user_mask(string) do
    case String.split(string, ~r/[!@]/, parts: 3) do
      [nick, user, host] ->
        {:ok, %__MODULE__{nick: nick, user: user, host: host}}
      _ ->
        {:error, :invalid_mask}
    end
  end

  defp parse_server_mask(string) do
    {:ok, %__MODULE__{server: string}}
  end

  defimpl String.Chars, for: __MODULE__ do
    @moduledoc false
    defdelegate to_string(struct), to: Irc.Mask
  end

  defimpl Irc.Addressable, for: __MODULE__ do
    def nick(%{nick: nick}), do: nick
    def user(%{user: user}), do: user
    def host(%{host: host}), do: host
  end

  defimpl Inspect, for: __MODULE__ do
    @moduledoc false
    import Inspect.Algebra

    def inspect(struct, _opts) do
      concat(["#Irc.Mask<", Irc.Mask.to_string(struct), ">"])
    end
  end

end