-module(word).
-export([
  insert_edit/1,
  deletion_edit/1,
  transposition_edit/1,
  alteration_edit/1
]).

pos_foldl(Fun, Initial, List) -> pos_foldl(Fun, Initial, 0, list_to_binary(List)).
pos_foldl(Fun, Accum, Count, Binary) ->
  case Binary of
    <<Before:Count/binary>> -> Fun(Before, <<>>, Accum);
    <<Before:Count/binary, After/binary>> ->
      pos_foldl(Fun, Fun(Before, After, Accum), Count + 1, Binary)
  end.

deletion_edit(Word) ->
  lists:reverse(pos_foldl(fun
    (_, <<>>, Accum) -> Accum;
    (Before, <<_:1/binary, After/binary>>, Accum) -> [<<Before/binary, After/binary>> | Accum]
  end, [], Word)).

transposition_edit(Word) ->
  lists:reverse(pos_foldl(fun
    (_, <<>>, Accum) -> Accum;
    (_, <<_:1/binary>>, Accum) -> Accum;
    (Before, <<A:1/binary, B:1/binary, After/binary>>, Accum) ->
      [<<Before/binary, B/binary, A/binary, After/binary>> | Accum]
  end, [], Word)).

edit(EFun, Word) ->
  lists:reverse(pos_foldl(fun(Before, After, Accum) ->
    lists:foldl(fun (Letter, L) ->
      case EFun(Before, After, Letter) of
        skip -> L;
        B -> [B | L]
      end
    end, Accum, lists:seq($a, $z))
  end, [], Word)).

insert_edit(Word) ->
  edit(fun(Before, After, Letter) -> <<Before/binary, Letter/integer, After/binary>> end, Word).

alteration_edit(Word) ->
  edit(fun
    (_Before, <<>>, _Letter) -> skip;
    (Before, <<_:1/binary, After/binary>>, Letter) -> <<Before/binary, Letter/integer, After/binary>>
  end, Word).