#!/usr/bin/env rdmd
/+
  - read in file .sst .ssi .ssm
  - loop twice
    - first
      - check for and skip code blocks
      - use unique code marker for endnote markers in text and give an endnote
        number ★1, increment
      - extract all endnotes in array
    - second
      - check that the footnote marker number count matches the number of notes
        in the array
        - if they match either:
            - substitute each endnote marker with the array footnote[number-1]
            - substitute each endnote marker with footnote
              as inlined footnote markup (footnote number not needed)
        - if they do not match exit
  - check whether changes have been made
    - if so write file with inline footnotes in sub-directory converted_output_/
      using the same name as the original file
    - else, exit
+/
import std.stdio;
import std.file;
import std.array : split;
import std.exception;
import core.stdc.errno;
import std.regex;
import std.format;
import std.conv;
void main(string[] args) {
  static comment                 = ctRegex!(`^%+ `);
  static block_tic_code_open     = ctRegex!("^`{3} code(?:[.](?P<syntax>[a-z][0-9a-z#+_]+))?(?:[(](?P<attrib>[ a-zA-Z0-9;:,]*)[)])?");
  static block_tic_close         = ctRegex!("^(`{3})$","m");
  static block_curly_code_open   = ctRegex!(`^(?:code(?:[.](?P<syntax>[a-z][0-9a-z_]+))?(?:[(](?P<attrib>[ a-zA-Z0-9;:,]*)[)])?[{][ ]*$)`);
  static block_curly_code_close  = ctRegex!(`^([}]code)`);
  auto rgx_endnote_ref           = ctRegex!(`([~]\^)(?P<tail>[)\]]? |$)`, "gm");
  auto rgx_endnote               = ctRegex!(`^\^~\s+(.+|\n)`, "gm");
  foreach(arg; args[1..$]) {
    if (
      !(arg.match(regex(r"--\w+")))
      && arg.match(regex(r"\w+?\.ss[itm]"))
    ) {
      writeln(arg);
      string filename                  = arg;
      try {
        string[] contents, endnotes, endnote_refs;
        string text                    = filename.readText;
        string[] paragraphs            = text.split("\n\n");
        int endnote_ref_count          = 0;
        int[string] type = [
          "curly_code"                 : 0,
          "tic_code"                   : 0,
        ];
        foreach (paragraph; paragraphs) { /+ loop to gather binary endnotes +/
          if ( !( type["curly_code"] == 1 || type["tic_code"] == 1)
            && paragraph.match(rgx_endnote)
          ) {
            endnotes ~= replaceAll!(m => m[1])
              (paragraph, rgx_endnote);
          } else {
            if ( type["curly_code"] == 1 || type["tic_code"] == 1
              || paragraph.matchFirst(block_curly_code_open)
              || paragraph.matchFirst(block_tic_code_open)
            ) { /+ code blocks identified, no munging +/
              if ( type["curly_code"] == 1
                && paragraph.matchFirst(block_curly_code_close)
              ) {
                type["curly_code"] = 0;
              } else if (type["tic_code"] == 1
                && paragraph.matchFirst(block_tic_close)
              ) {
                type["tic_code"] = 0;
              } else if (paragraph.matchFirst(block_curly_code_open)) {
                type["curly_code"] = 1;
              } else if (paragraph.matchFirst(block_tic_code_open)) {
                type["tic_code"] = 1;
              }
              contents ~= paragraph;
            } else { /+ regular content, not a code block +/
              if (auto m = paragraph.matchAll(rgx_endnote_ref)) {
                foreach (n; m) {
                  endnote_ref_count++; // endnote_refs ~= (n.captures[1]);
                }
              }
              paragraph = replaceAll!(m => " \\\\ " )
                (paragraph, regex(r"\s*<(?:/\s*|:)?br>\s*")); // (paragraph, regex(r"(<br>)"));
              contents ~= paragraph;
            }
          }
        }
        {
          import std.outbuffer;
          auto buffer = new OutBuffer();
          if (endnotes.length == endnote_ref_count) {
            // writeln("endnote ref count:         ", endnote_ref_count);
            // writeln("number of binary endnotes: ", endnotes.length);
            int endnote_count = -1;
            foreach (content; contents) { /+ loop to inline endnotes +/
              content = replaceAll!(m => "~{ " ~ endnotes[++endnote_count] ~ " }~" ~ m["tail"] )
                (content, rgx_endnote_ref); // endnote_ref cannot occur in a code block or else fail
              buffer.write(content ~ "\n\n");
            }
            if (buffer) {
              try {
                string dir_out = "converted_output_";
                string path_and_file_out = dir_out ~ "/" ~ filename;
                dir_out.mkdirRecurse;
                auto f = File(path_and_file_out, "w");
                f.write(buffer);
                writeln("wrote: ", path_and_file_out);
              } catch (FileException ex) {
                writeln("did not write file");
                // Handle errors
              }
            }
          } else {
            foreach (content; contents) { /+ loop to inline endnotes +/
              buffer.write(content ~ "\n\n");
            }
          }
        }
      } catch (ErrnoException ex) {
        switch(ex.errno) {
          case EPERM:
          case EACCES: // Permission denied
            break;
          case ENOENT: // File does not exist
            break;
          default:     // Handle other errors
            break;
        }
      }
    }
  }
}