defmodule Outlook.Articles.InternalTree do
  use Ecto.Type

  alias Outlook.InternalTree.InternalNode
  alias Outlook.InternalTree.TranslationUnit
  alias Outlook.InternalTree.Basic

  def type, do: :string

  def cast(tree) when is_list(tree) do
    {:ok, tree}
  end

  def cast(_), do: :error

  def load(tree) when is_binary(tree) do
    {:ok, Jason.decode!(tree, keys: :atoms) |> from_json}
  end

  def dump(tree) when is_list(tree) do
    {:ok, Basic.clean_eph(tree) |> Jason.encode!()}
  end

  def dump(_), do: :error


  defp from_json([%{status: _} = node | rest]) do
    [ %TranslationUnit{
        status: String.to_atom(node.status),
        nid: node.nid,
        content: node.content
      } | from_json(rest) ]
  end

  defp from_json([%{type: "element"} = node | rest]) do
    [ %InternalNode{
        name: node.name,
        attributes: node.attributes,
        type: String.to_atom(node.type),
        nid: node.nid,
        content: from_json(node.content)
      } | from_json(rest) ]
  end

  defp from_json([%{type: _} = node | rest]) do
    [ %InternalNode{
        name: node.name,
        attributes: node.attributes,
        type: String.to_atom(node.type),
        nid: node.nid,
        content: node.content
      } | from_json(rest) ]
  end

  defp from_json([]), do: []
end
