use(require(“atomy”)) use(require(“io”)) use(require(“dynamic”))

require(“json”) require(“fileutils”)

use(require(“anatomy/html”)) data = require(“anatomy/data”)

omit-aux-var? = dynamic(false)

def(omit-aux?):

omit-aux-var?

fn(tag-url(t)):

t target match:
  .anchor(x):
    url(t part, x)

  .self:
    url(t part)

  .url(x):
    x

fn(block-style(style, content)):

style match:
  .tt:
    <pre: over(content)

  .verbatim:
    <pre(.verbatim): over(content)

  .class(*classes):
    <div(class = classes join(" ")): over(content)

  .classed(style, *classes):
    h = block-style(style, content)
    h attributes[.class] = classes join(" ")
    h

  .with-data(style, attrs):
    h = block-style(style, content)
    attrs each [key, val]:
      h attributes[i"data-#{key}"] = val
    h

  .id(style, id):
    h = block-style(style, content)
    h attributes[.id] = id
    h

  .unordered-list:
    <ul: over(content)

  .list-item:
    <li: over(content)

  .header(depth):
    <"h#{depth}": over(content)

  .inset:
    <div(style = "margin: 0 2em 1em"): over(content)

  .centered:
    <div(style = "text-align: center"): over(content)

  .margin-note:
    <blockquote: over(content)

  nil:
    <div: over(content)

fn(element-style(style, content)):

style match:
  .italic:
    <em: over(content)

  .bold:
    <strong: over(content)

  .tt:
    <code: over(content)

  .superscript:
    <sup: over(content)

  .subscript:
    <sub: over(content)

  .smaller:
    <span(style = "font-size: 80%"): over(content)

  .larger:
    <span(style = "font-size: 120%"): over(content)

  .strike:
    <span(style = "text-decoration: line-through"): over(content)

  .class(*classes):
    <span(class = classes join(" ")): over(content)

  .classed(style, *classes):
    h = element-style(style, content)
    h attributes[.class] = classes join(" ")
    h

  .id(style, id):
    h = element-style(style, content)
    h attributes[.id] = id
    h

  .with-data(style, attrs):
    h = element-style(style, content)
    attrs each [key, val]:
      h attributes[i"data-#{key}"] = val
    h

  .button:
    <button: over(content)

  .hyperlink(url):
    <a(href = url): over(content)

  .image(file):
    <img(src = file, alt = over(content))

  .image(file, width):
    <img(src = file, alt = over(content), width = width)

  .font-awesome(*classes):
    <i(class = (["fa"] + classes) join(" ")): over(content)

  .svg(file):
    <object(data = file, type = "image/svg+xml", width = "100%", height = "100%"):
      <param(name = "src", value = file)

  .script-src(url):
    <script(src = url) {}

  .async-script-src(url):
    <script(async = true, defer = true, src = url) {}

  .aux:
    unless(^(omit-aux?)):
      over(content)

  .newline:
    <br

  .picture(default, mapping):
    sources =
      mapping collect [media, src]:
        <source(srcset = src, media = media)

    <picture:
      sources + [<img(src = default, alt = over(content))]

def(over(i & data Itemization)):

i elements collect [name, body]:
  <dl:
    [ <dt: over(name)
      <dd: over(body)
    ]

def(over(l & data OrderedList)):

<ol:
  l elements collect [body]:
    <li: over(body)

def(over(l & data List)):

<ul:
  l elements collect [body]:
    <li: over(body)

def(over(p & data Paragraph)):

<p: over(p content)

def(over(b & data Block)):

block-style(b style, b content)

def(over(t & data Target)):

<a(name = t name): nil

def(over(p & data Reference)):

if(p tag)
  then:
    <a(href = tag-url(p tag)):
      with(omit-aux? = true):
        over(p content)
  else:
    <a(.undefined): over(p content)

def(over(r & data ResolveElement)):

error(.did-not-resolve(r))

def(over(e & data Element)):

element-style(e style, e content)

def(over(nil)): nil def(over(s & String)): s def(over(a & Array)):

a collect [x]: over(x)

def(filename(p)): p tag name + “.html”

def(top(p)):

condition:
  p parent:
    if(p parent split-sections? && !(p parent inlined?))
      then: p
      else: top(p parent)

  otherwise:
    p

def(url(p, anchor = nil)):

condition:
  (top(p) != p):
    (url(top(p)) + "#") + (anchor || p tag name)

  anchor:
    (filename(p) + "#") + anchor

  otherwise:
    filename(p)

def(toc-leaf(current-part, part)):

classes = []

when(part == current-part):
  classes << "current"

when(part contains-part?(current-part)):
  classes << "active"

<li(class = classes join(" ")):
  <a(href = url(part)):
    over(part title)

  unless(part omit-children-from-table-of-contents? || part parts empty?):
    <ol:
      part parts collect &.(Self toc-leaf(current-part, _))

def(render(part, out = “.”, done = Set new)):

when(done include?(part)):
  return

done << part

tags-file = i"#{Dir tmpdir}/#{part top tag name}-tags.js"

unless(part parent):
  tags = search-tags(part) collect [t, d, u]:
    [t, d to-s, u]

  File open(tags-file, "w") [f]:
    f write(i"var SEARCH_TAGS = #{tags to-json};")

part js-additions << tags-file

-- call this early so the template can register its own assets/etc
template = render-part-template(part, out, done)

class =
  if(part style properties empty?)
    then: "normal"
    else: part style properties collect &.to-s join(" ")

File open(i"#{out}/#{filename(part)}", "w") [f]:
  f write("<!DOCTYPE html>")
  f write(
    <html {
      <head:
        <meta("http-equiv" = "Content-Type", content = "text/html; charset=UTF-8")
        <title: StrippedTags new(over(part title))

        when(part mobile-optimized?):
          <meta(name = "viewport", content = "width=device-width, initial-scale=1")

        all-css-additions(part) collect [addition]:
          <link(type = "text/css", rel = "stylesheet", href = addition)

        all-js-additions(part) collect [addition]:
          <script(type = "text/javascript", src = addition) {}

      <body(class = class):
        template

        when(analytics-id = ENV["ANALYTICS_ID"]):
          <script: UnescapedString new(i"
            (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
            (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
            m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
            })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

            ga('create', '#{analytics-id}', 'auto');
            ga('send', 'pageview');
          ")
    })

-- now that everything's generated, copy all recorded assets over (note that
-- templates may register their own assets)
unless(part parent):
  copy-all-assets(part, out)

def(render-part-template(part, out = “.”, done = Set new)):

(part template || Self) template-for(part, out, done)

def(all-part-assets(part)):

assets = Set new(part assets)

assets += part css-additions

assets += part js-additions

part parts collect [sub]:
  assets += all-part-assets(sub)

assets

def(copy-all-assets(part, out)):

all-part-assets(part) each [a]:
  sync-asset-to(a, out)

def(search-js-additions):

Set new(
  [ File expand-path("../js/jquery.js", __FILE__)
    File expand-path("../js/search.js", __FILE__)
  ])

def(template-for(part, out, done)):

part css-additions << File expand-path("../css/anatomy.css", __FILE__)
part css-additions << File expand-path("../css/highlight.css", __FILE__)

part js-additions += search-js-additions

<div(#page):
  <div(#main):
    <div(#content):
      render-part(part, out, done)

  <div(.search):
    <form(action = "javascript:void(0)"):
      <input(
          type = "text"
          placeholder = "Search&hellip;"
          autocomplete = "off"
          #search)

      <ul(.search-results) {}

  with(omit-aux? = true):
    <div(#sidebar):
      <h2:
        <a(href = url(part top)):
          over(part top title)

      <ol(.toc):
        part top parts collect [p]:
          toc-leaf(part, p)

def(render-part(part, out = “.”, done = Set new)):

<div(.section, id = i"section_#{part tag name}"):
  over(part body)

  if(part split-sections? && !(part inlined?))
    then:
      part parts collect [sub]:
        render(sub, out, done)

      when(part toc?):
        <ol(.toc, #table-of-contents):
          part parts collect [sub]:
            toc-leaf(part, sub)
    else:
      part parts collect [sub]:
        render-part(sub, out, done)

def(sync-asset-to(path, outdir)):

if(File directory?(path))
  then:
    subdir = File join(outdir, File basename(path))

    Dir entries(path) each [entry]:
      when((entry != ".") && (entry != "..")):
        sync-asset-to(File join(path, entry), subdir)

  else:
    FileUtils mkdir_p(outdir)
    FileUtils cp(path, File join(outdir, File basename(path)))

def(search-tags(p)):

tags = [
  [ data contents-of(p title)
    <span(.title):
      <a(href = url(p)):
        over(p title)
    url(p)
  ]
]

p tags each-key [tag-name]:
  tag = p find-tag(tag-name)
  url = tag-url(tag)
  tags <<
    [ tag name
      if(tag display)
        then:
          <a(href = url): over(tag display)
        else:
          <span(.tag):
            <code:
              <a(href = url):
                tag name
      url
    ]

p parts each [sub]:
  tags += search-tags(sub) collect [t, d, u]:
    [ t
      if(d is-a?(HTMLElement) && (d attributes[.class] == "with-parent"))
        then: d
        else:
          <span(.with-parent):
            d
            <span(.parent):
              " in "
              <a(href = url(p)):
                over(p title)
      u
    ]

tags

def(all-css-additions(p)):

all-assets = Set new

p css-additions each [file]:
  all-assets << File basename(file)

all-assets += p css-url-additions

p parts each [sub]:
  -- exclude parts that have their own page
  unless(top(sub) == sub):
    all-assets += all-css-additions(sub)

all-assets

def(all-js-additions(p)):

all-assets = Set new

p js-additions each [file]:
  all-assets << File basename(file)

p parts each [sub]:
  -- exclude parts that have their own page
  unless(top(sub) == sub):
    all-assets += all-js-additions(sub)

all-assets