#! lua
-- GCW 23/02/2018
do
 local target, src = arg[1], arg[2]
 local title = src:match "[^%.]+$" or ""
 local execute, getenv, exit in os
 local bind_dir, theme = getenv "bind$dir" , getenv "bind$theme"
 local libfmt, join = "%s.bin.%s", "%s.%s"
 local xhtml = dofile (libfmt:format(bind_dir,"xhtml"))
 local m_e = "%s.bin.MultiError -t %s.Templates -e \"%s\"\0"
 local complain = \ (s)
      execute (m_e:format (bind_dir, bind_dir, s)) end -- function
 if not theme then
    complain "No theme chosen"
    exit ( )
 end -- if
 if not xhtml then
   complain "Cannot load xhtml library"
   exit ( )
 end -- if
 if not src then
  complain "No source directory"
  exit ( )
 end -- if
 if not target then
  complain "No target directory"
  exit ( )
 end -- if
 local chap_pat = "^(%d%d)(.+)$"
 local chap_fmt = "%02d%s"
 local ch = { }
 local chapname = \ (n,s) ch[tonumber (n)] = s end -- function
 local dir in riscos
 for leaf,_ in dir (src) do leaf:gsub (chap_pat, chapname) end -- for
 if #ch == 0 then complain "No chapters" end -- if

-- global defs ---------
TAG = xhtml.TAG
MONOTAG = xhtml.MONOTAG
link = xhtml.link
BEGIN = xhtml.BEGIN
END = xhtml.END

local code = dofile (join:format (theme,"!code"))
if not code then
 complain "Cannot find !code in theme"
 exit ( )
end -- if

local sections = { }
for i = 1, #ch do sections[i] = { } end -- for

-- deal with images
local transform
do
  local filetype, dim, sys, $ in riscos
  local b = dim (256)
  local get = \ (file, n)
              local input, read in io
              input (file);local s = read (n);input ( )
              => s
              end -- function
  local little = \ (s, n)
                local lo, hi = s:byte (n, n+1)
                => lo + hi<<8
                end -- function
  local big = \ (s, n)
              local c0, c1, c2, c3 = s:byte (n, n+3)
              => (((c0<<8) + c1)<<8 + c2)<<8 + c3
              end -- function
  local oo = {
  [0x695] = \ (x) -- gif
              local s = get (x, 10)
              => little (s, 7), little (s, 9)
              end; -- function
  [0xb60] = \ (x) -- png
               local s = get (x, 24)
               => big (s, 17), big (s, 21)
              end; -- function
  [0xc85] = \ (x) -- jpeg
               $[b] = x..'\0'
               local r0, r1, r2, r3 = sys ("JPEG_FileInfo", 1, b)
               => r2, r3
               end; -- function
         }
  local readsize = \ (x)
             local f = oo[filetype (x)]
             if f then => f (x)
             else => nil, nil
             end -- if
             end -- function
  
  local input,read in io
  
  readfile = \ (f)
     input (f)
     local s = read "*all"
     input ( )
     => s
  end -- function
  
  local imgpat = "!img%s+([^\n%s]+)"
  local linkpat = "!link%s+([^\n%s]+)%s+(%b{})"
  local codepat1 = "!code%s+(%b{})"
  local codepat2 = "!code%s+@(%S+)"
  local quotepat = "__([^_]+)__"
  local imgfmt = [[<img src="%s" alt="%s" width="%d" height="%d">]]
  local imgfmt0 = [[<img src="%s" alt="%s">]]
  local linkfmt = [[<a href="%s">%s</a>]]
  local codefmt = "<p><pre>%s</pre>"
  local quotefmt = "<cite>%s</cite>"
  local slashdot, dotdot = "[/%.]","%.%."
  local unixify = { ["/"] = "."; ["."] = "/"; }
  local readimg = \ (x)
              local w, h = readsize (join:format (target, x))
              x = x:gsub (dotdot, "^")
              x = x:gsub (slashdot, unixify)
              if w and h then
               => imgfmt:format (x, x, w, h)
              else
               => imgfmt0:format (x, x)
              end -- if
              end -- function
  local readlink = \ (x, y)
        if not y then
           complain "Missing brace after !link?"
           exit ( )
        end -- if
        y = y:sub (2, -2)
        => linkfmt:format (x, y)
        end -- function
  local readcode1 = \ (x)
         if not x then
           complain "Missing brace after !code?"
           exit ( )
         end -- if
         x = x:sub (2, -2)
         => codefmt:format (x) end -- function
  local entity = {
    ["<"] = "&lt;",
    [">"] = "&gt;",
    ["&"] = "&amp;",
    ["_"] = "&#95;",
    ["{"] = "&#123;",
    ["}"] = "&#125;",
    ["!"] = "&#33;",
                 }
  local clean = \ (s) => s:gsub("[<>&_{}!]", entity) end
  local readcode2 = \ (x)
         if not x then
           complain "Missing @ before filename?"
           exit ( )
         end -- if
         => codefmt:format (clean (readfile (join:format (src, x))))
         end -- function
  
  local readquote = \ (x) => quotefmt:format (x) end -- function
  
  
  transform = \ (s)
              s = s:gsub(codepat1, readcode1)
              s = s:gsub(codepat2, readcode2)
              s = s:gsub(imgpat, readimg)
              s = s:gsub(quotepat, readquote)
              => s:gsub (linkpat, readlink) end -- function

older = \ (s1, s2) --[[
  local a0, _, a2, a3 = sys (8, 23, s1 .. "\0")
  local b0, _, b2, b3 = sys (8, 23, s2 .. "\0")
  if a0 ~= 1 then => true end -- if
  local h1, h2 = a2 & 0xff, b2 & 0xff
  if h1 < h2 then => true end -- if
  if h1 > h2 then => false end -- if
  h1, h2 = a3 & 0xff000000, b3 & 0xff000000
  if h1 < h2 then => true end -- if
  if h1 > h2 then => false end -- if
  h1, h2 = a3 & 0xffffff, b3 & 0xffffff
  => h1 < h2 --]]
  => true
end -- function

end -- do
  
local interp
  do
    local parse
    do
      local secpat = "!section%s+([^{]*)%s*(%b{})"
      local secfmt = "section %s [==[%s]==];"
      local strfmt = "[[%s]]"
      local readsec = \ (x, y)
            if not y then
              complain "Missing brace after !section?"
              exit ( )
            end -- if
            local b = y:sub (2, -2)
            local a = (#x > 0) and strfmt:format (x) or "()"
            => secfmt:format (a, b)
            end -- function
      local toptail = "=>{%s}"
      local errh = \ (x)
             complain ("Parse error: "..x)
             end -- function
      parse = \ (s)
             s = s:gsub (secpat, readsec)
             local f = load (toptail:format (s))
             local ok, val = xpcall (f, errh)
             if ok then => val else exit ( ) end -- if
             end -- function
    end -- do
  
  local bludger = \ (s)
      s = s:gsub ("%s", "_")
      if #s > 16 then s = s:sub (1, 16) end -- if
      => s
      end -- function
  
  local ifmt = "%s.html#%s"
  local a,p,br = TAG.a, MONOTAG.p "",MONOTAG.br ""
  local frame,nav,paradiv,header,titleheader in code
  local ref = \ (x) => ([[id="%s"]]):format (x) end -- function
  
  interp = \ (s, n, ch, sects)
    local sec = sects[n]
  section = \ (x) => \ (y)
          y = transform (y)
          local label
          if x then
            label = bludger (x)
            sec[1+#sec] = {
               link (ifmt:format (ch[n], label)) (x);
               br; }
            => paradiv {
                header (a (ref (label)) (x)); p; y; }
          else
           => paradiv (y)
          end -- if
          end end -- function
  => frame {
         titleheader (title);
         header (ch[n]) ;
         nav (n, ch);
         parse (s or "");
         nav (n, ch);
            }
  end -- function
end -- do

local fetch = \ (n)
   local leaf = chap_fmt:format (n, ch[n])
   local path = join:format (src, leaf)
   => interp (readfile (path), n, ch, sections)
   end -- function

local copyresources
do
  local copy = "copy %s %s F~C~D~P~V"
  copyresources = \ (theme)
    local old,new
    for leaf,_ in dir (theme) do
     if leaf:sub (1,1) ~= "!" then
       old, new = join:format (theme, leaf), join:format (target, leaf)
       execute (copy:format (old, new))
     end -- if
    end -- for
  end -- function
end -- do

local mkcontents
do
  local chstyle = TAG.div [[style="margin-left: 100px;
                            text-align: left;
                            margin-bottom: 4px;
                           "]]
  local secstyle = TAG.div [[style="margin-left: 120px;
                            text-align: left;
                            margin-bottom: 12px;
                          "]]
  local fmt = "%s.html"
  mkcontents = \ (sections, code)
  local frame, header, titleheader in code
  local index = { }, s, secs, chap
  for i = 1, #ch do
    chap = ch[i]
    s = sections[i]
    secs = #s > 0
    index[i] = {
      chstyle (link (fmt:format (chap)) (chap));
      secs and secstyle (s) or "";
      p;
               }
  end -- for
  => frame {
      titleheader (title);
      header "Contents";
      header (index);
             }
  end -- function
end -- do


 -- main loop
local outfmt = "%s.%s/html"
copyresources (theme)
local doc, out
for n = 1,#ch do
  out = outfmt:format (target, ch[n])
  local leaf = chap_fmt:format (n, ch[n])
  if older (out, join:format (src, leaf)) then
    doc = BEGIN(out)
    doc.TITLE = ch[n]
    doc.STYLE = "style.css"
    doc.BODY = fetch (n)
    END (doc)
  end -- if
end -- for
out = outfmt:format (target, "contents")
doc = BEGIN (out)
doc.TITLE = "Contents"
doc.STYLE = "style.css"
doc.BODY = mkcontents (sections, code)
END (doc)
end