Path = require "sitegen.path"

dollar_temp = "z000sitegen_markdown00dollar0000"

-- a constructor for quote delimited strings
simple_string = (delim) ->
  import P from require "lpeg"

  inner = P("\\#{delim}") + "\\\\" + (1 - P delim)
  inner = inner^0
  P(delim) * inner * P(delim)

lua_string = ->
  import P, C, Cmt, Cb, Cg from require "lpeg"
  check_lua_string = (str, pos, right, left) ->
    #left == #right

  string_open = P"[" * P"="^0 * "["
  string_close = P"]" * P"="^0 * "]"

  valid_close = Cmt C(string_close) * Cb"string_open", check_lua_string

  Cg(string_open, "string_open") *
    (1 - valid_close)^0 * string_close

-- returns a pattern that parses a cosmo template. Can be used to have
-- pre-processors ignore text that would be handled by cosmo
parse_cosmo = ->
  import P, R, Cmt, Cs, V from require "lpeg"
  curly = P {
    P"{" * (
      simple_string("'") +
      simple_string('"') +
      lua_string! +
      V(1) +
      (P(1) - "}")
    )^0 * P"}"
  }

  alphanum = R "az", "AZ", "09", "__"
  P"$" * alphanum^1 * (curly)^-1

escape_cosmo = (str) ->
  escapes = {}
  import P, R, Cmt, Cs, V from require "lpeg"

  counter = 0

  cosmo = parse_cosmo! / (tpl) ->
    counter += 1
    key = "#{dollar_temp}_#{counter}"
    escapes[key] = tpl
    key

  patt = Cs (cosmo + P(1))^0 * P(-1)
  str = patt\match(str) or str, escapes
  str, escapes

unescape_cosmo = (str, escapes) ->
  import P, R, Cmt, Cs from require "lpeg"

  escape_patt = P(dollar_temp) * P("_") * R("09")^1 / (key) ->
    escapes[key] or error "bad key for unescape_cosmo"

  patt = Cs (escape_patt + P(1))^0 * P(-1)
  assert patt\match(str)

needs_shell_escape = (str) -> not not str\match "[^%w_-]"
shell_escape = (str) -> str\gsub "'", "''"

_prepare_command = (cmd, ...) ->
  args = for x in *{...}
    if needs_shell_escape x then "'#{shell_escape x}'" else x

  args = table.concat args, " "
  "#{cmd} #{args}"

write_exec = (cmd, content) ->
  fname = os.tmpname!
  f = assert io.popen _prepare_command(cmd, fname), "w"

  with f\write content
    f\close!

  fname

class PandocRenderer extends require "sitegen.renderers.html"
  @escape_cosmo: escape_cosmo
  @unescape_cosmo: unescape_cosmo
  @parse_cosmo: parse_cosmo

  source_ext: "md"
  ext: "html"
  cmd: "pandoc --mathjax --lua-filter pygments.lua >"
  pandoc: (content) => Path.read_file write_exec @@cmd, content

  render: (page, md_source) =>
    md_source = page\pipe "renderer.markdown.pre_render", md_source
    md_source, escapes = escape_cosmo md_source

    html_source = assert @pandoc md_source
    html_source = unescape_cosmo html_source, escapes

    super page, html_source
