
# https://github.com/Evizero/UnicodePlots.jl


# don't warn on unsupported... there's just too many warnings!!
warnOnUnsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing

# --------------------------------------------------------------------------------------

const _canvas_type = Ref(:auto)

function _canvas_map()
    KW(
        :braille => UnicodePlots.BrailleCanvas,
        :ascii => UnicodePlots.AsciiCanvas,
        :block => UnicodePlots.BlockCanvas,
        :dot => UnicodePlots.DotCanvas,
        :density => UnicodePlots.DensityCanvas,
    )
end


# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
function rebuildUnicodePlot!(plt::Plot, width, height)
    plt.o = []

    for sp in plt.subplots
        xaxis = sp[:xaxis]
        yaxis = sp[:yaxis]
        xlim =  axis_limits(xaxis)
        ylim =  axis_limits(yaxis)

        # make vectors
        xlim = [xlim[1], xlim[2]]
        ylim = [ylim[1], ylim[2]]

        # we set x/y to have a single point, since we need to create the plot with some data.
        # since this point is at the bottom left corner of the plot, it shouldn't actually be shown
        x = Float64[xlim[1]]
        y = Float64[ylim[1]]

        # create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
        ct = _canvas_type[]
        canvas_type = if ct == :auto
            isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
        else
            _canvas_map()[ct]
        end

        # special handling for spy
        if length(sp.series_list) == 1
            series = sp.series_list[1]
            if series[:seriestype] == :spy
                push!(plt.o, UnicodePlots.spy(
                    series[:z].surf,
                    width = width,
                    height = height,
                    title = sp[:title],
                    canvas = canvas_type
                ))
                continue
            end
        end

        # # make it a bar canvas if plotting bar
        # if any(series -> series[:seriestype] == :bar, series_list(sp))
        #     canvas_type = UnicodePlots.BarplotGraphics
        # end

        o = UnicodePlots.Plot(x, y, canvas_type;
            width = width,
            height = height,
            title = sp[:title],
            xlim = xlim,
            ylim = ylim,
            border = isijulia() ? :ascii : :solid
        )

        # set the axis labels
        UnicodePlots.xlabel!(o, xaxis[:guide])
        UnicodePlots.ylabel!(o, yaxis[:guide])

        # now use the ! functions to add to the plot
        for series in series_list(sp)
            addUnicodeSeries!(o, series.plotattributes, sp[:legend] != :none, xlim, ylim)
        end

        # save the object
        push!(plt.o, o)
    end
end


# add a single series
function addUnicodeSeries!(o, plotattributes::KW, addlegend::Bool, xlim, ylim)
    # get the function, or special handling for step/bar/hist
    st = plotattributes[:seriestype]
    if st == :histogram2d
        UnicodePlots.densityplot!(o, plotattributes[:x], plotattributes[:y])
        return
    end

    if st in (:path, :straightline)
        func = UnicodePlots.lineplot!
    elseif st == :scatter || plotattributes[:markershape] != :none
        func = UnicodePlots.scatterplot!
    # elseif st == :bar
    #     func = UnicodePlots.barplot!
    elseif st == :shape
        func = UnicodePlots.lineplot!
    else
        error("Linestyle $st not supported by UnicodePlots")
    end

    # get the series data and label
    x, y = if st == :straightline
        straightline_data(plotattributes)
    elseif st == :shape
        shape_data(series)
    else
        [collect(float(plotattributes[s])) for s in (:x, :y)]
    end
    label = addlegend ? plotattributes[:label] : ""

    # if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
    color = plotattributes[:linecolor] in UnicodePlots.color_cycle ? plotattributes[:linecolor] : :auto

    # add the series
    x, y = Plots.unzip(collect(Base.Iterators.filter(xy->isfinite(xy[1])&&isfinite(xy[2]), zip(x,y))))
    func(o, x, y; color = color, name = label)
end

# -------------------------------

# since this is such a hack, it's only callable using `png`... should error during normal `show`
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
    fn = addExtension(fn, "png")

    # make some whitespace and show the plot
    println("\n\n\n\n\n\n")
    gui(plt)

    # @osx_only begin
    @static if Sys.isapple()
        # BEGIN HACK

        # wait while the plot gets drawn
        sleep(0.5)

        # use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
        # TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
        run(`screencapture -R50,600,700,420 $fn`)

        # END HACK (phew)
        return
    end

    error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
end

# -------------------------------

# we don't do very much for subplots... just stack them vertically

function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
    w, h = plt[:size]
    plt.attr[:color_palette] = [RGB(0,0,0)]
    rebuildUnicodePlot!(plt, div(w, 10), div(h, 20))
end

function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
    unicodeplots_rebuild(plt)
    foreach(x -> show(io, x), plt.o)
    nothing
end


function _display(plt::Plot{UnicodePlotsBackend})
    unicodeplots_rebuild(plt)
    map(show, plt.o)
    nothing
end
