
# https://github.com/spencerlyon2/PlotlyJS.jl

supportedArgs(::PlotlyJSBackend) = [
    :annotation,
    # :axis,
    :background_color,
    :color_palette,
    :fillrange,
    :fillcolor,
    :fillalpha,
    :foreground_color,
    :group,
    :label,
    :layout,
    :legend,
    :seriescolor, :seriesalpha,
    :linecolor,
    :linestyle,
    :linetype,
    :linewidth,
    :linealpha,
    :markershape,
    :markercolor,
    :markersize,
    :markeralpha,
    :markerstrokewidth,
    :markerstrokecolor,
    :markerstrokestyle,
    :n,
    :bins,
    :nc,
    :nr,
    # :pos,
    # :smooth,
    :show,
    :size,
    :title,
    :windowtitle,
    :x,
    :xlabel,
    :xlims,
    :xticks,
    :y,
    :ylabel,
    :ylims,
    # :yrightlabel,
    :yticks,
    :xscale,
    :yscale,
    :xflip,
    :yflip,
    :z,
    :marker_z,
    :tickfont,
    :guidefont,
    :legendfont,
    :grid,
    :levels,
    :xerror,
    :yerror,
    :ribbon,
    :quiver,
    :orientation,
    :polar,
  ]
supportedAxes(::PlotlyJSBackend) = [:auto, :left]
supportedTypes(::PlotlyJSBackend) = [:none, :line, :path, :scatter, :steppre, :steppost,
                                   :hist2d, :hist, :density, :bar, :contour, :surface, :path3d, :scatter3d,
                                   :pie, :heatmap] #,, :sticks, :hexbin, :hline, :vline]
supportedStyles(::PlotlyJSBackend) = [:auto, :solid, :dash, :dot, :dashdot]
supportedMarkers(::PlotlyJSBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
                                     :pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
supportedScales(::PlotlyJSBackend) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
subplotSupported(::PlotlyJSBackend) = true
stringsSupported(::PlotlyJSBackend) = true

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

function _initialize_backend(::PlotlyJSBackend; kw...)
    @eval begin
        import PlotlyJS
        export PlotlyJS
    end

    for (mime, fmt) in PlotlyJS._mimeformats
        # mime == "image/png" && continue  # don't use plotlyjs's writemime for png
        @eval Base.writemime(io::IO, m::MIME{symbol($mime)}, p::Plot{PlotlyJSBackend}) = writemime(io, m, p.o)
    end

    # override IJulia inline display
    if isijulia()
        IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
    end
end

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

function _create_plot(pkg::PlotlyJSBackend, d::KW)
    # TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
    # TODO: initialize the plot... title, xlabel, bgcolor, etc
    # o = PlotlyJS.Plot(PlotlyJS.GenericTrace[], PlotlyJS.Layout(),
    #                   Base.Random.uuid4(), PlotlyJS.ElectronDisplay())
    # T = isijulia() ? PlotlyJS.JupyterPlot : PlotlyJS.ElectronPlot
    # o = T(PlotlyJS.Plot())
    o = PlotlyJS.plot()

    Plot(o, pkg, 0, d, KW[])
end


function _add_series(::PlotlyJSBackend, plt::Plot, d::KW)
    syncplot = plt.o

    # add to the data array
    pdict = plotly_series(d, plt.plotargs)
    typ = pop!(pdict, :type)
    gt = PlotlyJS.GenericTrace(typ; pdict...)
    PlotlyJS.addtraces!(syncplot, gt)

    push!(plt.seriesargs, d)
    plt
end


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


function _add_annotations{X,Y,V}(plt::Plot{PlotlyJSBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
    # set or add to the annotation_list
    if !haskey(plt.plotargs, :annotation_list)
        plt.plotargs[:annotation_list] = Any[]
    end
    append!(plt.plotargs[:annotation_list], anns)
end

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

function _before_update_plot(plt::Plot{PlotlyJSBackend})
end

# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{PlotlyJSBackend}, d::KW)
    pdict = plotly_layout(d)
    syncplot = plt.o
    w,h = d[:size]
    PlotlyJS.relayout!(syncplot, pdict, width = w, height = h)
end


function _update_plot_pos_size(plt::AbstractPlot{PlotlyJSBackend}, d::KW)
end

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

# accessors for x/y data

# function getxy(plt::Plot{PlotlyJSBackend}, i::Int)
#   d = plt.seriesargs[i]
#   d[:x], d[:y]
# end

function setxy!{X,Y}(plt::Plot{PlotlyJSBackend}, xy::Tuple{X,Y}, i::Integer)
  d = plt.seriesargs[i]
  ispolar = get(plt.plotargs, :polar, false)
  xsym = ispolar ? :t : :x
  ysym = ispolar ? :r : :y
  d[xsym], d[ysym] = xy
  # TODO: this is likely ineffecient... we should make a call that ONLY changes the plot data
  PlotlyJS.restyle!(plt.o, i, KW(xsym=>(d[xsym],), ysym=>(d[ysym],)))
  plt
end

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

function _create_subplot(subplt::Subplot{PlotlyJSBackend}, isbefore::Bool)
  # TODO: build the underlying Subplot object.  this is where you might layout the panes within a GUI window, for example
  true
end

function _expand_limits(lims, plt::Plot{PlotlyJSBackend}, isx::Bool)
  # TODO: call expand limits for each plot data
end

function _remove_axis(plt::Plot{PlotlyJSBackend}, isx::Bool)
  # TODO: if plot is inner subplot, might need to remove ticks or axis labels
end

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

# function Base.writemime(io::IO, m::MIME"text/html", plt::AbstractPlot{PlotlyJSBackend})
#     Base.writemime(io, m, plt.o)
# end

# function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{PlotlyJSBackend})
#     println("here!")
#     writemime_png_from_html(io, plt)
# end

function Base.display(::PlotsDisplay, plt::Plot{PlotlyJSBackend})
    display(plt.o)
end

function Base.display(::PlotsDisplay, plt::Subplot{PlotlyJSBackend})
    error()
end
