const build_options = @import("build_options");
const std = @import("std");
const e = @cImport({
    @cInclude("erl_nif.h");
});
const proj = @cImport({
    @cInclude("proj.h");
});

/// nif: convert_crs_to_crs/4
fn convert_crs_to_crs(env: ?*e.ErlNifEnv,
                      argc: c_int,
                      argv: [*c]const c_ulong) callconv(.C) e.ERL_NIF_TERM {
    if(argc != 4) {
        std.log.err("wrong number of arguments", .{});
        return e.enif_make_badarg(env);
    }

    const STR_SIZE = 100;

    var crs_from: [100]u8 = undefined;

    if(e.enif_get_string(env, argv[0], &crs_from, STR_SIZE, e.ERL_NIF_LATIN1) == 0) {
        std.log.err("cannot get string crs_from", .{});
        return e.enif_make_badarg(env);
    }

    var crs_to: [100]u8 = undefined;

    if(e.enif_get_string(env, argv[1], &crs_to, STR_SIZE, e.ERL_NIF_LATIN1) == 0) {
        std.log.err("cannot get string crs_to", .{});
        return e.enif_make_badarg(env);
    }

    var pt_from: f64 = 0.0;
    if(e.enif_get_double(env, argv[2], &pt_from) == 0) {
        std.log.err("cannot get pt_from", .{});
        return e.enif_make_badarg(env);
    }

    var pt_to: f64 = 0.0;
    if(e.enif_get_double(env, argv[3], &pt_to) == 0) {
        std.log.err("cannot get pt_to", .{});
        return e.enif_make_badarg(env);
    }

    //const C = proj.PJ_DEFAULT_CTX;
    const C = proj.proj_context_create();
    defer _ = proj.proj_context_destroy(C);

    //const P0 = proj.proj_create_crs_to_crs(C, @ptrCast([*c] const u8, &crs_from), @ptrCast([*c] const u8, &crs_to), null);
    const P0 = proj.proj_create_crs_to_crs(C, &crs_from, &crs_to, null);
    defer _ = proj.proj_destroy(P0);

    // This will ensure that the order of coordinates for the input CRS
    // will be longitude, latitude, whereas EPSG:4326 mandates latitude,
    // longitude
    const P = proj.proj_normalize_for_visualization(C, P0);
    defer _ = proj.proj_destroy(P);

    const a = proj.proj_coord(pt_from, pt_to, 0, 0);
    const b = proj.proj_trans(P, proj.PJ_FWD, a);

    // var tuple_slice = [_]f64{ 0.0, 0.0 };

    // tuple_slice[0] = b.enu.e;
    // tuple_slice[1] = b.enu.n;

    //return tuple_slice;

    return e.enif_make_tuple2(env,
                              e.enif_make_double(env, b.enu.e),
                              e.enif_make_double(env, b.enu.n));
}



export var nif_funcs = [_]e.ErlNifFunc{
    .{.name = "convert_crs_to_crs",
      .arity = 4,
      .fptr = convert_crs_to_crs,
      .flags = 0}
};

const entry = e.ErlNifEntry{
    .major = 2,
    .minor = 16,
    .name = if(build_options.use_elixir) "Elixir.ProjNif" else "proj_nif",
    .num_of_funcs = 1,
    .funcs = &(nif_funcs[0]),
    .load = null,
    .reload = null,
    .upgrade = null,
    .unload = null,
    .vm_variant = "beam.vanilla",
    .options = 1,
    .sizeof_ErlNifResourceTypeInit = @sizeOf(e.ErlNifResourceTypeInit),
    .min_erts = "erts-12.0"
};

export fn nif_init() *const e.ErlNifEntry {
    return &entry;
}

//e.ERL_NIF_INIT(proj_nif, nif_funcs, null, null, null, null);
