-module(seq2).
-compile(nowarn_unused_vars).
-compile(nowarn_unused_function).
-export([distinct/2, distinct_by/3, except/3, count_by/3, group_by/3, array_distinct/2, array_distinct_by/3, array_except/3, array_count_by/3, array_group_by/3, list_distinct/2, list_distinct_by/3, list_except/3, list_count_by/3, list_group_by/3]).

distinct(Xs, Comparer) ->
    seq:delay(fun(UnitVar) ->
        HashSet = fable_hashset:create_empty(),
        seq:filter(fun(X) ->
            fable_hashset:add(HashSet, X)
end, Xs)
end)
.

distinct_by(Projection, Xs, Comparer) ->
    seq:delay(fun(UnitVar) ->
        HashSet = fable_hashset:create_empty(),
        seq:filter(fun(X) ->
            fable_hashset:add(HashSet, Projection(X))
end, Xs)
end)
.

except(ItemsToExclude, Xs, Comparer) ->
    seq:delay(fun(UnitVar) ->
        HashSet = fable_hashset:create_from_list(ItemsToExclude),
        seq:filter(fun(X) ->
            fable_hashset:add(HashSet, X)
end, Xs)
end)
.

count_by(Projection, Xs, Comparer) ->
    seq:delay(fun(UnitVar) ->
        Dict = fable_dictionary:create_empty(),
        begin Keys = fable_utils:new_ref([]),
        begin begin Enumerator = fable_utils:get_enumerator(Xs),
        try
            While_loop_0 = fun While_loop_0() ->
                case fable_utils:move_next(Enumerator) of
                    true ->
                        Key = Projection(fable_utils:get_current(Enumerator)),
                        begin OutArg_ref = fable_utils:new_ref(0),
                        OutArg_ref_result = {fable_dictionary:try_get_value(Dict, Key, OutArg_ref), erlang:get(OutArg_ref)},
                        erlang:erase(OutArg_ref),
                        MatchValue = OutArg_ref_result,
                        case erlang:element(1, MatchValue) of
                            true ->
                                fable_dictionary:set_item(Dict, Key, erlang:element(2, MatchValue) + 1)
                            ;
                            false ->
                                begin fable_dictionary:set_item(Dict, Key, 1),
                                put(Keys, get(Keys) ++ [Key]) end
                        end end,
                        While_loop_0()
                    ;
                    false ->
                        ok
                end
end,
            While_loop_0()
        catch
            _:Exn_reason_1 ->
                erlang:error(Exn_reason_1)
        after
            case erlang:is_map(Enumerator) orelse erlang:is_reference(Enumerator) of
                true ->
                    fable_utils:safe_dispose(Enumerator)
                ;
                false ->
                    ok
            end
        end end,
        seq:map(fun(Key_1) ->
            {Key_1, fable_dictionary:get_item(Dict, Key_1)}
end, Keys) end end
end)
.

group_by(Projection, Xs, Comparer) ->
    seq:delay(fun(UnitVar) ->
        Dict = fable_dictionary:create_empty(),
        begin Keys = fable_utils:new_ref([]),
        begin begin Enumerator = fable_utils:get_enumerator(Xs),
        try
            While_loop_2 = fun While_loop_2() ->
                case fable_utils:move_next(Enumerator) of
                    true ->
                        X = fable_utils:get_current(Enumerator),
                        begin Key = Projection(X),
                        begin OutArg_ref = fable_utils:new_ref(undefined),
                        OutArg_ref_result = {fable_dictionary:try_get_value(Dict, Key, OutArg_ref), erlang:get(OutArg_ref)},
                        erlang:erase(OutArg_ref),
                        MatchValue = OutArg_ref_result,
                        case erlang:element(1, MatchValue) of
                            true ->
                                put(erlang:element(2, MatchValue), get(erlang:element(2, MatchValue)) ++ [X])
                            ;
                            false ->
                                begin fable_dictionary:add(Dict, Key, fable_utils:new_ref(erlang:get(fable_utils:new_ref([X])))),
                                put(Keys, get(Keys) ++ [Key]) end
                        end end end,
                        While_loop_2()
                    ;
                    false ->
                        ok
                end
end,
            While_loop_2()
        catch
            _:Exn_reason_3 ->
                erlang:error(Exn_reason_3)
        after
            case erlang:is_map(Enumerator) orelse erlang:is_reference(Enumerator) of
                true ->
                    fable_utils:safe_dispose(Enumerator)
                ;
                false ->
                    ok
            end
        end end,
        seq:map(fun(Key_1) ->
            {Key_1, fable_dictionary:get_item(Dict, Key_1)}
end, Keys) end end
end)
.

array_distinct(Xs, Comparer) ->
    seq:to_array(distinct(Xs, Comparer))
.

array_distinct_by(Projection, Xs, Comparer) ->
    seq:to_array(distinct_by(Projection, Xs, Comparer))
.

array_except(ItemsToExclude, Xs, Comparer) ->
    seq:to_array(except(ItemsToExclude, Xs, Comparer))
.

array_count_by(Projection, Xs, Comparer) ->
    seq:to_array(count_by(Projection, Xs, Comparer))
.

array_group_by(Projection, Xs, Comparer) ->
    seq:to_array(seq:map(fun(TupledArg) ->
        {erlang:element(1, TupledArg), seq:to_array(erlang:element(2, TupledArg))}
end, group_by(Projection, Xs, Comparer)))
.

list_distinct(Xs, Comparer) ->
    Source = distinct(Xs, Comparer),
    fable_utils:to_list(Source)
.

list_distinct_by(Projection, Xs, Comparer) ->
    Source = distinct_by(Projection, Xs, Comparer),
    fable_utils:to_list(Source)
.

list_except(ItemsToExclude, Xs, Comparer) ->
    Source = except(ItemsToExclude, Xs, Comparer),
    fable_utils:to_list(Source)
.

list_count_by(Projection, Xs, Comparer) ->
    Source = count_by(Projection, Xs, Comparer),
    fable_utils:to_list(Source)
.

list_group_by(Projection, Xs, Comparer) ->
    Source_1 = seq:map(fun(TupledArg) ->
        {erlang:element(1, TupledArg), fable_utils:to_list(erlang:element(2, TupledArg))}
end, group_by(Projection, Xs, Comparer)),
    fable_utils:to_list(Source_1)
.
