# License of this file:
# Consider this file an extension of tinyexr.h (3-clause BSD)

# import memfiles
import tinyexr_c
import arr_ref
import ../float16/float16

# import std/strutils

{.compile: "miniz.c".}
# Can't include implementation because it's cpp, we'll compile it separately
{.compile("impl.cpp", "-std=c++11 -I.").}
{.passL:"-lstdc++".}

proc free(p: pointer) {.header: "stdlib.h", importc, nodecl, raises: [], gcsafe.}

proc isEXR*(p: pointer, len: int): bool =
    IsEXRFromMemory(p, len.csize_t) == TINYEXR_SUCCESS

proc getEXRDimensions*(p: pointer, len: int): (int, int) =
    var version: EXRVersion
    var ret = ParseEXRVersionFromMemory(version, p, len.csize_t)
    assert ret == TINYEXR_SUCCESS, "Can't read EXR version"
    var header: EXRHeader
    header.InitEXRHeader
    var err: const_cstring
    ret = ParseEXRHeaderFromMemory(header, version, p, len.csize_t, err)
    if ret != TINYEXR_SUCCESS:
        if err != nil:
                echo "error: " & $err
                FreeEXRErrorMessage(err)
        else:
            echo "undefined exr error"
    else:
        let width = 1 + header.data_window.max_x - header.data_window.min_x
        let height = 1 + header.data_window.max_y - header.data_window.min_y
        discard header.FreeEXRHeader
        return (width.int, height.int)

proc decodeEXR*(p: pointer, len: int): (int, int, ArrRef[uint16]) =
    # TODO: avoid copying by using the internal API directly
    # TODO: decode float16 directly
    # TODO: why can't I use "float16" on the type?
    var img: ptr UncheckedArray[float32]
    var width: int32
    var height: int32
    var err: const_cstring
    let ret = LoadEXRFromMemory(img, width, height, p, len.csize_t, err)
    if ret != TINYEXR_SUCCESS:
        if err != nil:
            let errs = $err
            FreeEXRErrorMessage(err)
            raise newException(ValueError, errs)
        else:
            raise newException(ValueError, "Undefined tinyEXR error")

    var imglen = width*height*4
    var pixels = newArrRef[uint16](imglen)
    # pixels[0].addr.copyMem(img, imglen*sizeof(Float16))
    for i in 0 ..< imglen:
        pixels[i] = img[i].tofloat16(clamp=true).uint16
    free(img)
    return (width.int, height.int, pixels)