content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE QuasiQuotes #-}
  {-# LANGUAGE RecordWildCards #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  -- |
  -- Module      : $header$
  -- Copyright   : (c) Laurent P René de Cotret, 2019 - present
  -- License     : GNU GPL, version 2 or above
  -- Maintainer  : laurent.decotret@outlook.com
  -- Stability   : internal
  -- Portability : portable
  --
  -- Rendering Bokeh code blocks
  module Text.Pandoc.Filter.Plot.Renderers.Bokeh
    ( bokeh,
      bokehSupportedSaveFormats,
    )
  where
  
  import Data.Monoid (Any (..))
  import qualified Data.Text as T
  import Text.Pandoc.Filter.Plot.Renderers.Prelude
  
  bokeh :: PlotM Renderer
  bokeh = do
    cmdargs <- asksConfig bokehCmdArgs
    return
      $ Renderer
        { rendererToolkit = Bokeh,
          rendererCapture = appendCapture bokehCaptureFragment,
          rendererCommand = bokehCommand cmdargs,
          rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -c "import bokeh; import selenium"|],
          rendererSupportedSaveFormats = bokehSupportedSaveFormats,
          rendererChecks = [bokehCheckIfShow],
          rendererLanguage = "python",
          rendererComment = mappend "# ",
          rendererScriptExtension = ".py"
        }
  
  bokehSupportedSaveFormats :: [SaveFormat]
  bokehSupportedSaveFormats = [PNG, SVG, HTML]
  
  bokehCommand :: Text -> OutputSpec -> Text
  bokehCommand cmdargs OutputSpec {..} = [st|#{pathToExe oExecutable} #{cmdargs} "#{oScriptPath}"|]
  
  -- | Check if `bokeh.io.show()` calls are present in the script,
  -- which would halt pandoc-plot
  bokehCheckIfShow :: Script -> CheckResult
  bokehCheckIfShow s =
    if getAny $ mconcat showPresent
      then CheckFailed "encountered a call to `bokeh.io.show`."
      else CheckPassed
    where
      showPresent =
        (\n -> Any (T.isInfixOf n s))
          <$> [ "bokeh.io.show(",
                "show("
              ]
  
  bokehCaptureFragment :: FigureSpec -> FilePath -> Script
  bokehCaptureFragment FigureSpec {..} fname =
    [st|
  from bokeh.io import export_png, export_svgs, save
  from bokeh.models import Model
  from bokeh.resources import CDN
  
  # The heuristic to determine the current Model is to find all objects which are
  # at least subclasses of bokeh.models.Model, and then find the one which was
  # created last. This is a dirty hack, so if you're reading this, don't hesitate to
  # suggest something else.
  __current_model = [obj for obj in globals().values() if isinstance(obj, Model)][-1]
  #{write}
  |]
    where
      write = case saveFormat of
        HTML -> [st|save(__current_model, filename=r"#{fname}", resources=CDN)|]
        SVG -> [st|__current_model.output_backend="svg"; export_svgs(__current_model, filename=r"#{fname}")|]
        PNG -> [st|export_png(obj = __current_model, filename=r"#{fname}")|]
        fmt -> errorWithoutStackTrace $ "Save format not supported: " <> show fmt
  