## This program fixes the documentation putting the types in each module.
## At the moment, all types are in types.nim to allow cyclic definitions,
## and all members are public to allow access in the appropriate modules.
## 
## We signal that we want to move types with the TYPES type, like this:
## 
## when defined(nimdoc):
##    type TYPES* = MyType1 | MyType2 | MyType3
## 
## Furthermore, we hide all members that have "## private" in their docs.
## 
## All of this is a hacky workaround that we hope won't be necessary
## in the future.
##
## Usage: nim r fixdocs.nim htmldocs/*

import sugar
import os, strutils, sequtils, tables, algorithm, strformat


var types_menu: Table[string, string]
var types_html: Table[string, string]

proc strip_privates(s: string): string =
    var lines: seq[string]
    var private = false
    for line in s.split '\n':
        if ("*" in line and ":" in line) or "</pre>" in line:
            private = false
        if "## private" in line:
            private = true
        if not private:
            lines.add line
    return lines.join "\n"


for f in os.commandLineParams():
    if f.rsplit("/", 1)[^1] == "types.html":
        let html = readFile(f)
        for item in html.split("<li><a class=\"reference\"")[1 ..< ^0]:
            let name = item.split({'"','#'}, 3)[2]
            types_menu[name] = "<li><a class=\"reference\"" & item.split("</ul>", 1)[0]
        for item in html.split("\n<div id=\"")[1 ..< ^0]:
            let name = item.split('"',1)[0]
            # TODO: check if RST can produce a bare "\n</div>"
            types_html[name] = "<div id=\"" & item.split("\n</div>", 1)[0] & "</div>"

var type_to_module: Table[string, string]

for f in os.commandLineParams():
    if not f.endswith ".html":
        continue
    var types: seq[string]
    var lines = readFile(f).split("\n")
    var menu_line = 0
    var last_menu_line = 0
    var types_line = ""
    for i,line in lines:
        # if "reference reference-toplevel" in line and line.endswith ">Types</a>":
        if line.startswith "    title=\"TYPES = ":
            types_line = line
            menu_line = i - 1
        elif types_line != "":
            types_line &= line
        if "</a>" in types_line:
            types = types_line.split({'"','='})[3].split({'|',' '}).filterIt it != ""
            last_menu_line = i
            break
    if types.len == 0:
        continue
    
    for tname in types:
        type_to_module[tname] = f.rsplit("/", 1)[^1].split('.')[0]

    types.sort(order = Descending)

    assert menu_line != 0

    # types_id is usually "TYPES" but for some reason it's "TYPES_2" sometimes,
    # so we'll extract the id from the href before we delete it
    let types_id = lines[menu_line].rsplit("#",1)[1].split("\"")[0]
    for i in menu_line .. last_menu_line:
        lines.delete menu_line

    for tname in types:
        var parts = types_menu[tname].split('"')
        parts[5] = parts[5].strip_privates
        lines.insert(parts.join("\""), menu_line)

    var body_line = lines.find &"<div id=\"{types_id}\">"
    while lines[body_line] != "</div>":
        lines.delete body_line
    lines.delete body_line

    for tname in types:
        var ids = types_html[tname].split "<span class=\"Identifier\">"
        lines.insert(types_html[tname].strip_privates, body_line)

    writeFile(f, lines.join "\n")

dump type_to_module

for f in os.commandLineParams():
    let is_html = f.endswith ".html"
    let is_idx = f.endswith ".idx"
    if not (is_html or is_idx):
        continue
    var sep = if is_html: "\"" else: "\t"
    let is_index = f.rsplit("/", 1)[^1] == "theindex.html"
    let contents = readFile(f)
    var changed = contents
    for tname, module in type_to_module:
        changed = changed.replace(
            &"{sep}types.html#{tname}{sep}",
            &"{sep}{module}.html#{tname}{sep}")
        if is_index:
            for seps in ["\"\"", "><"]:
                changed = changed.replace(
                    &"{seps[0]}types: {tname}{seps[1]}",
                    &"{seps[0]}{module}: {tname}{seps[1]}")
    if contents != changed:
        writeFile(f, changed)