module LaTeXDatax
using  Unitful, UnitfulLatexify, Latexify

export @datax

"""
```julia
@datax
```

Print the arguments to a data file to be read by pgfkeys. Best used with the
[`datax` LaTeX package](https://ctan.org/pkg/datax). Variables can be supplied
either by name or as assignments, and meta-arguments are supplied using the
`:=` operator.

The meta-arguments include all the keyword arguments from `Latexify.jl` and
`UnitfulLatexify.jl` (for instance `unitformat := :siunitx`, `fmt := "%.2e"`),
as well as a few extra:

# Meta-arguments
* `filename`: The path to a file that will be written.
* `io`: an `IO` object to write to instead of a file. Overrides the `filename`
  argument. If neither this nor `filename` is given, `stdout` is used.
* `permissions`: Defaults to `"w"`. Can be given as `"a"` to append to a file
  instead of overwriting. Only meaningful with a `filename` argument.

# Examples
```julia
julia> a = 2;
julia> b = 3.2u"m";
julia> @datax a b c=3*a d=27 unitformat:=:siunitx
\\pgfkeyssetvalue{/datax/a}{\\num{2}}
\\pgfkeyssetvalue{/datax/b}{\\SI{3.2}{\\meter}}
\\pgfkeyssetvalue{/datax/c}{\\num{6}}
\\pgfkeyssetvalue{/datax/d}{\\num{27}}

```
"""
macro datax(args...)
    esc(datax_helper(args...))
end

function datax_helper(args...)
    metaargs = Expr[]
    names = Symbol[]
    values = Any[]
    for a in args
        if a isa Symbol
            push!(names, a)
            push!(values, a)
            continue
        end
        if a.head == :(=)
            push!(names, a.args[1])
            push!(values, a.args[2])
            continue

        end
        if a.head == :(:=)
            push!(metaargs, Expr(:kw,a.args[1],a.args[2]))
            continue
        end
        error("I don't know what to do with argument $a")
    end

    names = Expr(:tuple, QuoteNode.(names)...)
    values = Expr(:tuple, values...)
    quote
        LaTeXDatax.datax($names,$values;$(metaargs...))
        nothing
    end
end

function datax(names, values; kwargs...)
    if haskey(kwargs, :io)
        datax(kwargs[:io], names, values; kwargs...)
        return nothing
    end
    if haskey(kwargs, :filename)
        datax(kwargs[:filename], names, values; kwargs...)
        return nothing
    end
    datax(stdout, names, values; kwargs...)
    return nothing
end

datax(io::IO, names, values; kwargs...) = printkeyval.(Ref(io),names,values; kwargs...)

function datax(filename::String, names, values; permissions="w", kwargs...)
    if haskey(kwargs,:overwrite)
        if kwargs[:overwrite]
            permissions = "w"
        else
            permissions = "a"
        end
    end
    open(filename, permissions) do io
        permissions == "w" && println(io, "% Autogenerated by LaTeXDatax.jl, will be overwritten")
        datax(io, names, values; kwargs...)
    end
end

function printkeyval(io::IO, name, value; kwargs...)
    print(io, "\\pgfkeyssetvalue{/datax/", name, "}{")
    printdata(io, value; kwargs...)
    print(io, "}\n")
    return nothing
end

printdata(io::IO, v::String; kwargs...) = print(io, v)
printdata(io::IO, v::Number; kwargs...) = print(io, latexify(v*u"one"; kwargs...))
printdata(io::IO, v; kwargs...) = print(io, latexify(v; kwargs...))

end # module
