// This file is part of Jiffy released under the MIT license.
// See the LICENSE file for more information.

#include <set>
#include <string>

#include <assert.h>

#include "erl_nif.h"

#define MAP_TYPE_PRESENT \
    ((ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION >= 6) \
    || (ERL_NIF_MAJOR_VERSION > 2))

#define BEGIN_C extern "C" {
#define END_C }

BEGIN_C

int
make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out,
	int ret_map, int dedupe_keys)
{
    ERL_NIF_TERM ret;
    ERL_NIF_TERM key;
    ERL_NIF_TERM val;

    std::set<std::string> seen;

#if MAP_TYPE_PRESENT

    ERL_NIF_TERM old_val;

    if(ret_map) {
        ret = enif_make_new_map(env);
        while(enif_get_list_cell(env, pairs, &val, &pairs)) {
            if(!enif_get_list_cell(env, pairs, &key, &pairs)) {
                assert(0 == 1 && "Unbalanced object pairs.");
            }
            if(!enif_get_map_value(env, ret, key, &old_val)) {
                if(!enif_make_map_put(env, ret, key, val, &ret)) {
                    return 0;
                }
            }
        }
        *out = ret;
        return 1;
    }
#endif

    ret = enif_make_list(env, 0);
    while(enif_get_list_cell(env, pairs, &val, &pairs)) {
        if(!enif_get_list_cell(env, pairs, &key, &pairs)) {
            assert(0 == 1 && "Unbalanced object pairs.");
        }
        if(dedupe_keys) {
            ErlNifBinary bin;
            if(!enif_inspect_binary(env, key, &bin)) {
                return 0;
            }
            std::string skey((char*) bin.data, bin.size);
            if(seen.count(skey) == 0) {
                seen.insert(skey);
                val = enif_make_tuple2(env, key, val);
                ret = enif_make_list_cell(env, val, ret);
            }
        } else {
            val = enif_make_tuple2(env, key, val);
            ret = enif_make_list_cell(env, val, ret);
        }
    }
    *out = enif_make_tuple1(env, ret);

    return 1;
}

END_C
