#+TITLE: sdp header extract
#+AUTHOR: Ralph Amissah
#+EMAIL: ralph.amissah@gmail.com
#+STARTUP: indent
#+LANGUAGE: en
#+OPTIONS: H:3 num:nil toc:t \n:nil @:t ::t |:t ^:nil _:nil -:t f:t *:t <:t
#+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc
#+OPTIONS: author:nil email:nil creator:nil timestamp:nil
#+PROPERTY: header-args :padline no :exports code :noweb yes
#+EXPORT_SELECT_TAGS: export
#+EXPORT_EXCLUDE_TAGS: noexport
#+FILETAGS: :sdp:niu:ao:
#+TAGS: assert(a) class(c) debug(d) mixin(m) sdp(s) tangle(T) template(t) WEB(W) noexport(n)

[[./sdp.org][sdp]]  [[./][org/]]
* header sdlang                                               :header:sdlang:
** sdlang header parse and extract root Tag                        :root:tag:

#+name: ao_header_extract_sdl
#+BEGIN_SRC d
final private auto headerMakeSDLang(in string src_header) {
  scope(failure) {
    stderr.writefln(
      "%s\n%s\n%s:%s failed here:\n  src_header: %s",
      __MODULE__, __FUNCTION__,
      __FILE__, __LINE__,
      src_header,
    );
  }
  Tag sdl_root_header;
  try {
    sdl_root_header = parseSource(src_header);
  }
  catch(SDLangParseException e) {
    stderr.writeln("SDLang problem with this document header:");
    stderr.writeln(src_header);
    // Error messages of the form:
    // myFile.sdl(5:28): Error: Invalid integer suffix.
    stderr.writeln(e.msg);
  }
  debug(sdlang) {
    writeln("header SDL:");
    writeln(sdl_root_header.toSDLDocument());
  }
  return sdl_root_header;
}
#+END_SRC

** sdlang header to json                                             :header:
#+name: ao_header_extract_sdl
#+BEGIN_SRC d
private auto headerSDLangToJSON(in char[] src_header) {
  char[][] source_header_arr =
    split(cast(char[]) src_header, rgx.line_delimiter);
  char[] header_clean;
  // TODO
  foreach(header_line; source_header_arr) {
    if (!match(header_line, rgx.comments)) {
      header_clean ~= header_line ~ "\n";
      // writeln(header_line);
    }
  }
  /+ get sdlang tags +/
  auto header_sdlang=headerMakeSDLang(to!string(header_clean));
  debug(sdlang) {
    writeln("--------------");
    stdout.rawWrite( header_sdlang.toSDLDocument() );
    writeln("--------------");
    Value test = header_sdlang.tags["title"][0].values[0];
    assert(test == typeid(string));
    writeln(header_sdlang.maybe.tags["title"]);
    writeln(header_sdlang.maybe.tags["title"][0].maybe.attributes["subtitle"]);
  }
  /+ TODO separate modules? sdlang then json
  return header_sdlang;
  // then do json module?
  +/
  /+ TODO json next +/
  /+ TODO
    auto dochead_make = parseJSON(header_make_jsonstr).object;
    auto dochead_meta = parseJSON(header_meta_jsonstr).object;
    auto hm = to!string(t.captures[1]);
    auto hs = to!string(s.captures[1]);
    if (dochead_make[hm][hs].type() == JSON_TYPE.STRING) {
      dochead_make[hm][hs].str = to!string(s.captures[2]);
    }
    if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
      dochead_meta[hm][hs].str = to!string(s.captures[2]);
    }
  +/
  /+ dochead +/
  string hm;
  string hs;
  /+ make +/
  auto dochead_make = parseJSON(header_make_jsonstr).object;
  if (!(header_sdlang.maybe.tags["make"].empty)) {
    hm = "make";
    hs = "bold";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "breaks";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "cover_image";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "css";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "emphasis";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "footer";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "headings";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "home_button_image";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "home_button_text";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "italics";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "num_top";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "substitute";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "texpdf_font";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_make[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  /+ meta +/
  auto dochead_meta = parseJSON(header_meta_jsonstr).object;
  hm = "title";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    /+ TODO Title REQUIRED +/
    hs = "main";
    if (!(header_sdlang.tags[hm].empty)
    && (header_sdlang.tags[hm][0].values[0].length > 1)) {
      writeln(header_sdlang.tags[hm][0].values[0]);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].values[0]);
        // to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    } else if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    } else {
      writeln("Required header metadata Title, missing");
    }
    hs = "sub";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    } else if (!(header_sdlang.tags[hm][0].maybe.attributes["subtitle"].empty)
    && (header_sdlang.tags[hm][0].attributes["subtitle"][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes["subtitle"][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes["subtitle"][0].value);
    }
    // full title composite (main + sub)
    // hs = "full";
    // dochead_meta[hm][hs] = dochead_meta[hm]["main"] ~ dochead_meta[hm]["sub"];
    hs = "language";
    if (!(header_sdlang.tags[hm][0].maybe.attributes["lang"].empty)
    && (header_sdlang.tags[hm][0].attributes["lang"][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes["lang"][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes["lang"][0].value);
    } else if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "edition";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "note";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  hm = "creator";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    /+ Creator / Author REQUIRED +/
    /+ TODO
    - decide on representation for & deal with multiple authors;
    - author(s) full name;
    - author(s) surname & other parts
    +/
    hs = "author";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "author_email";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "illustrator";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "translator";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  hm = "classify";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    hs = "dewey";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "keywords";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "loc";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "subject";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "topic_register";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  hm = "date";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    hs = "added_to_site";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "available";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "created";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "issued";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "modified";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "published";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "valid";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  hm = "identifier";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    hs = "isbn";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "oclc";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "pg";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  hm = "links";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    /+ TODO
      stuff to fix
    +/
    // hs = "link";
    // if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    // && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
    //   writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
    //   dochead_meta[hm][hs].str =
    //     to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    // }
  }
  hm = "notes";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    hs = "abstract";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "description";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  hm = "original";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    hs = "language";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "source";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "title";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  hm = "publisher";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    hs = "name";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  hm = "rights";
  if (!(header_sdlang.maybe.tags[hm].empty)) {
    hs = "copyright";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "cover";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "illustrations";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
    hs = "license";
    if (!(header_sdlang.tags[hm][0].maybe.attributes[hs].empty)
    && (header_sdlang.tags[hm][0].attributes[hs][0].value.length > 1)) {
      writeln(header_sdlang.tags[hm][0].attributes[hs][0].value);
      dochead_meta[hm][hs].str =
        to!string(header_sdlang.tags[hm][0].attributes[hs][0].value);
    }
  }
  // writeln(dochead_make);
  // writeln(dochead_meta);
  auto t = tuple(dochead_make, dochead_meta);
  static assert(!isTypeTuple!(t));
  return t;
}
#+END_SRC

/+
namespace:name values attributes {
  children
}
+/

** +sdlang header to associative array+                                :header:
#+name: ao_header_extract_sdl
#+BEGIN_SRC d
private auto headerSDLangToHash(in char[] src_header) {
  char[][] source_header_arr =
    split(cast(char[]) src_header, rgx.line_delimiter);
  char[] header_clean;
  string[string] header_make;
  string[string][string] header_metadata;
  foreach(header_line; source_header_arr) {
    if (!match(header_line, rgx.comments)) {
      header_clean ~= header_line ~ "\n";
      // writeln(header_line);
    }
  }
  /+ get sdlang tags +/
  auto header_sdlang=headerMakeSDLang(to!string(header_clean));
  Value test = header_sdlang.tags["title"][0].values[0];
  // assert(test == typeid(string));
  // writeln(header_sdlang.maybe.tags["title"]);
  // writeln(header_sdlang.maybe.tags["title"][0].attributes["subtitle"]);
  if (!(header_sdlang.maybe.tags["make"].empty)) {
    if (!(header_sdlang.tags["make"][0].maybe.attributes["bold"].empty)
    && (header_sdlang.tags["make"][0].attributes["bold"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["bold"][0].value);
      header_make["bold"] =
        to!string(header_sdlang.tags["make"][0].attributes["bold"][0].value);
    } else {
      header_make["bold"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["breaks"].empty)
    && (header_sdlang.tags["make"][0].attributes["breaks"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["breaks"][0].value);
      header_make["breaks"] =
        to!string(header_sdlang.tags["make"][0].attributes["breaks"][0].value);
    } else {
      header_make["breaks"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["cover_image"].empty)
    && (header_sdlang.tags["make"][0].attributes["cover_image"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["cover_image"][0].value);
      header_make["cover_image"] =
        to!string(header_sdlang.tags["make"][0].attributes["cover_image"][0].value);
    } else {
      header_make["cover_image"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["css"].empty)
    && (header_sdlang.tags["make"][0].attributes["css"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["css"][0].value);
      header_make["css"] =
        to!string(header_sdlang.tags["make"][0].attributes["css"][0].value);
    } else {
      header_make["css"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["emphasis"].empty)
    && (header_sdlang.tags["make"][0].attributes["emphasis"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["emphasis"][0].value);
      header_make["emphasis"] =
        to!string(header_sdlang.tags["make"][0].attributes["emphasis"][0].value);
    } else {
      header_make["emphasis"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["footer"].empty)
    && (header_sdlang.tags["make"][0].attributes["footer"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["footer"][0].value);
      header_make["footer"] =
        to!string(header_sdlang.tags["make"][0].attributes["footer"][0].value);
    } else {
      header_make["footer"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["headings"].empty)
    && (header_sdlang.tags["make"][0].attributes["headings"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["headings"][0].value);
      header_make["headings"] =
        to!string(header_sdlang.tags["make"][0].attributes["headings"][0].value);
    } else {
      header_make["headings"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["home_button_image"].empty)
    && (header_sdlang.tags["make"][0].attributes["home_button_image"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["home_button_image"][0].value);
      header_make["home_button_image"] =
        to!string(header_sdlang.tags["make"][0].attributes["home_button_image"][0].value);
    } else {
      header_make["home_button_image"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["home_button_text"].empty)
    && (header_sdlang.tags["make"][0].attributes["home_button_text"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["home_button_text"][0].value);
      header_make["home_button_text"] =
        to!string(header_sdlang.tags["make"][0].attributes["home_button_text"][0].value);
    } else {
      header_make["home_button_text"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["italics"].empty)
    && (header_sdlang.tags["make"][0].attributes["italics"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["italics"][0].value);
      header_make["italics"] =
        to!string(header_sdlang.tags["make"][0].attributes["italics"][0].value);
    } else {
      header_make["italics"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["num_top"].empty)
    && (header_sdlang.tags["make"][0].attributes["num_top"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["num_top"][0].value);
      header_make["num_top"] =
        to!string(header_sdlang.tags["make"][0].attributes["num_top"][0].value);
    } else {
      header_make["num_top"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["substitute"].empty)
    && (header_sdlang.tags["make"][0].attributes["substitute"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["substitute"][0].value);
      header_make["substitute"] =
        to!string(header_sdlang.tags["make"][0].attributes["substitute"][0].value);
    } else {
      header_make["substitute"] = "";
    }
    if (!(header_sdlang.tags["make"][0].maybe.attributes["texpdf_font"].empty)
    && (header_sdlang.tags["make"][0].attributes["texpdf_font"][0].value.length > 1)) {
      writeln(header_sdlang.tags["make"][0].attributes["texpdf_font"][0].value);
      header_make["texpdf_font"] =
        to!string(header_sdlang.tags["make"][0].attributes["texpdf_font"][0].value);
    } else {
      header_make["texpdf_font"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["title"].empty)) {
    /+ Title REQUIRED +/
    if (!(header_sdlang.tags["title"].empty)
    && (header_sdlang.tags["title"][0].values[0].length > 1)) {
      writeln(header_sdlang.tags["title"][0].values[0]);
      header_metadata["title"]["main"] =
        to!string(header_sdlang.tags["title"][0].values[0]);
    } else if (!(header_sdlang.tags["title"][0].maybe.attributes["main"].empty)
    && (header_sdlang.tags["title"][0].attributes["main"][0].value.length > 1)) {
      writeln(header_sdlang.tags["title"][0].attributes["main"][0].value);
      header_metadata["title"]["main"] =
        to!string(header_sdlang.tags["title"][0].attributes["main"][0].value);
    } else {
      writeln("Required header metadata Title, missing");
      header_metadata["title"]["main"] = "";
    }
    if (!(header_sdlang.tags["title"][0].maybe.attributes["sub"].empty)
    && (header_sdlang.tags["title"][0].attributes["sub"][0].value.length > 1)) {
      writeln(header_sdlang.tags["title"][0].attributes["sub"][0].value);
      header_metadata["title"]["sub"] =
        to!string(header_sdlang.tags["title"][0].attributes["sub"][0].value);
    } else if (!(header_sdlang.tags["title"][0].maybe.attributes["subtitle"].empty)
    && (header_sdlang.tags["title"][0].attributes["subtitle"][0].value.length > 1)) {
      writeln(header_sdlang.tags["title"][0].attributes["subtitle"][0].value);
      header_metadata["title"]["sub"] =
        to!string(header_sdlang.tags["title"][0].attributes["subtitle"][0].value);
    } else {
      header_metadata["title"]["sub"] = "";
    }
    // full title composite (main + sub)
    header_metadata["title"]["full"] = header_metadata["title"]["main"] ~ header_metadata["title"]["sub"];
    if (!(header_sdlang.tags["title"][0].maybe.attributes["lang"].empty)
    && (header_sdlang.tags["title"][0].attributes["lang"][0].value.length > 1)) {
      writeln(header_sdlang.tags["title"][0].attributes["lang"][0].value);
      header_metadata["title"]["language"] =
        to!string(header_sdlang.tags["title"][0].attributes["lang"][0].value);
    } else if (!(header_sdlang.tags["title"][0].maybe.attributes["language"].empty)
    && (header_sdlang.tags["title"][0].attributes["language"][0].value.length > 1)) {
      writeln(header_sdlang.tags["title"][0].attributes["language"][0].value);
      header_metadata["title"]["language"] =
        to!string(header_sdlang.tags["title"][0].attributes["language"][0].value);
    } else {
      header_metadata["title"]["language"] = "";
    }
    if (!(header_sdlang.tags["title"][0].maybe.attributes["edition"].empty)
    && (header_sdlang.tags["title"][0].attributes["edition"][0].value.length > 1)) {
      writeln(header_sdlang.tags["title"][0].attributes["edition"][0].value);
      header_metadata["title"]["edition"] =
        to!string(header_sdlang.tags["title"][0].attributes["edition"][0].value);
    } else {
      header_metadata["title"]["edition"] = "";
    }
    if (!(header_sdlang.tags["title"][0].maybe.attributes["note"].empty)
    && (header_sdlang.tags["title"][0].attributes["note"][0].value.length > 1)) {
      writeln(header_sdlang.tags["title"][0].attributes["note"][0].value);
      header_metadata["title"]["note"] =
        to!string(header_sdlang.tags["title"][0].attributes["note"][0].value);
    } else {
      header_metadata["title"]["note"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["creator"].empty)) {
    /+ Creator / Author REQUIRED +/
    /+ TODO
    - decide on representation for & deal with multiple authors;
    - author(s) full name;
    - author(s) surname & other parts
    +/
    if (!(header_sdlang.tags["creator"][0].maybe.attributes["author"].empty)
    && (header_sdlang.tags["creator"][0].attributes["author"][0].value.length > 1)) {
      writeln(header_sdlang.tags["creator"][0].attributes["author"][0].value);
      header_metadata["creator"]["author"] =
        to!string(header_sdlang.tags["creator"][0].attributes["author"][0].value);
    } else {
      header_metadata["creator"]["author"] = "";
    }
    if (!(header_sdlang.tags["creator"][0].maybe.attributes["author_email"].empty)
    && (header_sdlang.tags["creator"][0].attributes["author_email"][0].value.length > 1)) {
      writeln(header_sdlang.tags["creator"][0].attributes["author_email"][0].value);
      header_metadata["creator"]["author_email"] =
        to!string(header_sdlang.tags["creator"][0].attributes["author_email"][0].value);
    } else {
      header_metadata["creator"]["author_email"] = "";
    }
    if (!(header_sdlang.tags["creator"][0].maybe.attributes["illustrator"].empty)
    && (header_sdlang.tags["creator"][0].attributes["illustrator"][0].value.length > 1)) {
      writeln(header_sdlang.tags["creator"][0].attributes["illustrator"][0].value);
      header_metadata["creator"][""] =
        to!string(header_sdlang.tags["creator"][0].attributes["illustrator"][0].value);
    } else {
      header_metadata["creator"]["illustrator"] = "";
    }
    if (!(header_sdlang.tags["creator"][0].maybe.attributes["translator"].empty)
    && (header_sdlang.tags["creator"][0].attributes["translator"][0].value.length > 1)) {
      writeln(header_sdlang.tags["creator"][0].attributes["translator"][0].value);
      header_metadata["creator"]["translator"] =
        to!string(header_sdlang.tags["creator"][0].attributes["translator"][0].value);
    } else {
      header_metadata["creator"][""] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["classify"].empty)) {
    if (!(header_sdlang.tags["classify"][0].maybe.attributes["dewey"].empty)
    && (header_sdlang.tags["classify"][0].attributes["dewey"][0].value.length > 1)) {
      writeln(header_sdlang.tags["classify"][0].attributes["dewey"][0].value);
      header_metadata["classify"]["dewey"] =
        to!string(header_sdlang.tags["classify"][0].attributes["dewey"][0].value);
    } else {
      header_metadata["classify"]["dewey"] = "";
    }
    if (!(header_sdlang.tags["classify"][0].maybe.attributes["keyword"].empty)
    && (header_sdlang.tags["classify"][0].attributes["keyword"][0].value.length > 1)) {
      writeln(header_sdlang.tags["classify"][0].attributes["keyword"][0].value);
      header_metadata["classify"]["keyword"] =
        to!string(header_sdlang.tags["classify"][0].attributes["keyword"][0].value);
    } else {
      header_metadata["classify"]["keyword"] = "";
    }
    if (!(header_sdlang.tags["classify"][0].maybe.attributes["loc"].empty)
    && (header_sdlang.tags["classify"][0].attributes["loc"][0].value.length > 1)) {
      writeln(header_sdlang.tags["classify"][0].attributes["loc"][0].value);
      header_metadata["classify"]["loc"] =
        to!string(header_sdlang.tags["classify"][0].attributes["loc"][0].value);
    } else {
      header_metadata["classify"]["loc"] = "";
    }
    if (!(header_sdlang.tags["classify"][0].maybe.attributes["subject"].empty)
    && (header_sdlang.tags["classify"][0].attributes["subject"][0].value.length > 1)) {
      writeln(header_sdlang.tags["classify"][0].attributes["subject"][0].value);
      header_metadata["classify"]["subject"] =
        to!string(header_sdlang.tags["classify"][0].attributes["subject"][0].value);
    } else {
      header_metadata["classify"]["subject"] = "";
    }
    if (!(header_sdlang.tags["classify"][0].maybe.attributes["topic_register"].empty)
    && (header_sdlang.tags["classify"][0].attributes["topic_register"][0].value.length > 1)) {
      writeln(header_sdlang.tags["classify"][0].attributes["topic_register"][0].value);
      header_metadata["classify"]["topic_register"] =
        to!string(header_sdlang.tags["classify"][0].attributes["topic_register"][0].value);
    } else {
      header_metadata["classify"]["topic_register"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["date"].empty)) {
    if (!(header_sdlang.tags["date"][0].maybe.attributes["added_to_site"].empty)
    && (header_sdlang.tags["date"][0].attributes["added_to_site"][0].value.length > 1)) {
      writeln(header_sdlang.tags["date"][0].attributes["added_to_site"][0].value);
      header_metadata["date"]["added_to_site"] =
        to!string(header_sdlang.tags["date"][0].attributes["added_to_site"][0].value);
    } else {
      header_metadata["date"]["added_to_site"] = "";
    }
    if (!(header_sdlang.tags["date"][0].maybe.attributes["available"].empty)
    && (header_sdlang.tags["date"][0].attributes["available"][0].value.length > 1)) {
      writeln(header_sdlang.tags["date"][0].attributes["available"][0].value);
      header_metadata["date"]["available"] =
        to!string(header_sdlang.tags["date"][0].attributes["available"][0].value);
    } else {
      header_metadata["date"]["available"] = "";
    }
    if (!(header_sdlang.tags["date"][0].maybe.attributes["created"].empty)
    && (header_sdlang.tags["date"][0].attributes["created"][0].value.length > 1)) {
      writeln(header_sdlang.tags["date"][0].attributes["created"][0].value);
      header_metadata["date"]["created"] =
        to!string(header_sdlang.tags["date"][0].attributes["created"][0].value);
    } else {
      header_metadata["date"]["created"] = "";
    }
    if (!(header_sdlang.tags["date"][0].maybe.attributes["issued"].empty)
    && (header_sdlang.tags["date"][0].attributes["issued"][0].value.length > 1)) {
      writeln(header_sdlang.tags["date"][0].attributes["issued"][0].value);
      header_metadata["date"]["issued"] =
        to!string(header_sdlang.tags["date"][0].attributes["issued"][0].value);
    } else {
      header_metadata["date"]["issued"] = "";
    }
    if (!(header_sdlang.tags["date"][0].maybe.attributes["modified"].empty)
    && (header_sdlang.tags["date"][0].attributes["modified"][0].value.length > 1)) {
      writeln(header_sdlang.tags["date"][0].attributes["modified"][0].value);
      header_metadata["date"]["modified"] =
        to!string(header_sdlang.tags["date"][0].attributes["modified"][0].value);
    } else {
      header_metadata["date"]["modified"] = "";
    }
    if (!(header_sdlang.tags["date"][0].maybe.attributes["published"].empty)
    && (header_sdlang.tags["date"][0].attributes["published"][0].value.length > 1)) {
      writeln(header_sdlang.tags["date"][0].attributes["published"][0].value);
      header_metadata["date"]["published"] =
        to!string(header_sdlang.tags["date"][0].attributes["published"][0].value);
    } else {
      header_metadata["date"]["published"] = "";
    }
    if (!(header_sdlang.tags["date"][0].maybe.attributes["valid"].empty)
    && (header_sdlang.tags["date"][0].attributes["valid"][0].value.length > 1)) {
      writeln(header_sdlang.tags["date"][0].attributes["valid"][0].value);
      header_metadata["date"]["valid"] =
        to!string(header_sdlang.tags["date"][0].attributes["valid"][0].value);
    } else {
      header_metadata["date"]["valid"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["identifier"].empty)) {
    if (!(header_sdlang.tags["identifier"][0].maybe.attributes["isbn"].empty)
    && (header_sdlang.tags["identifier"][0].attributes["isbn"][0].value.length > 1)) {
      writeln(header_sdlang.tags["identifier"][0].attributes["isbn"][0].value);
      header_metadata["identifier"]["isbn"] =
        to!string(header_sdlang.tags["identifier"][0].attributes["isbn"][0].value);
    } else {
      header_metadata["identifier"]["isbn"] = "";
    }
    if (!(header_sdlang.tags["identifier"][0].maybe.attributes["oclc"].empty)
    && (header_sdlang.tags["identifier"][0].attributes["oclc"][0].value.length > 1)) {
      writeln(header_sdlang.tags["identifier"][0].attributes["oclc"][0].value);
      header_metadata["identifier"]["oclc"] =
        to!string(header_sdlang.tags["identifier"][0].attributes["oclc"][0].value);
    } else {
      header_metadata["identifier"]["oclc"] = "";
    }
    if (!(header_sdlang.tags["identifier"][0].maybe.attributes["pg"].empty)
    && (header_sdlang.tags["identifier"][0].attributes["pg"][0].value.length > 1)) {
      writeln(header_sdlang.tags["identifier"][0].attributes["pg"][0].value);
      header_metadata["identifier"]["pg"] =
        to!string(header_sdlang.tags["identifier"][0].attributes["pg"][0].value);
    } else {
      header_metadata["identifier"]["pg"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["links"].empty)) {
    /+ TODO
      stuff to fix
    +/
    if (!(header_sdlang.tags["links"][0].maybe.attributes["link"].empty)
    && (header_sdlang.tags["links"][0].attributes["link"][0].value.length > 1)) {
      writeln(header_sdlang.tags["links"][0].attributes["link"][0].value);
      // header_metadata["links"]["list"] =
      //   to!string(header_sdlang.tags["links"][0].attributes["link"][0].value);
      header_metadata["links"]["list"] = "";
    } else {
      header_metadata["links"]["list"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["notes"].empty)) {
    if (!(header_sdlang.tags["notes"][0].maybe.attributes["abstract"].empty)
    && (header_sdlang.tags["notes"][0].attributes["abstract"][0].value.length > 1)) {
      writeln(header_sdlang.tags["notes"][0].attributes["abstract"][0].value);
      header_metadata["notes"]["abstract"] =
        to!string(header_sdlang.tags["notes"][0].attributes["abstract"][0].value);
    } else {
      header_metadata["notes"]["abstract"] = "";
    }
    if (!(header_sdlang.tags["notes"][0].maybe.attributes["description"].empty)
    && (header_sdlang.tags["notes"][0].attributes["description"][0].value.length > 1)) {
      writeln(header_sdlang.tags["notes"][0].attributes["description"][0].value);
      header_metadata["notes"]["description"] =
        to!string(header_sdlang.tags["notes"][0].attributes["description"][0].value);
    } else {
      header_metadata["notes"]["description"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["original"].empty)) {
    if (!(header_sdlang.tags["original"][0].maybe.attributes["language"].empty)
    && (header_sdlang.tags["original"][0].attributes["language"][0].value.length > 1)) {
      writeln(header_sdlang.tags["original"][0].attributes["language"][0].value);
      header_metadata["original"]["language"] =
        to!string(header_sdlang.tags["original"][0].attributes["language"][0].value);
    } else {
      header_metadata["original"]["language"] = "";
    }
    if (!(header_sdlang.tags["original"][0].maybe.attributes["source"].empty)
    && (header_sdlang.tags["original"][0].attributes["source"][0].value.length > 1)) {
      writeln(header_sdlang.tags["original"][0].attributes["source"][0].value);
      header_metadata["original"]["source"] =
        to!string(header_sdlang.tags["original"][0].attributes["source"][0].value);
    } else {
      header_metadata["original"]["source"] = "";
    }
    if (!(header_sdlang.tags["original"][0].maybe.attributes["title"].empty)
    && (header_sdlang.tags["original"][0].attributes["title"][0].value.length > 1)) {
      writeln(header_sdlang.tags["original"][0].attributes["title"][0].value);
      header_metadata["original"]["title"] =
        to!string(header_sdlang.tags["original"][0].attributes["title"][0].value);
    } else {
      header_metadata["original"]["title"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["publisher"].empty)) {
    if (!(header_sdlang.tags["publisher"][0].maybe.attributes["name"].empty)
    && (header_sdlang.tags["publisher"][0].attributes["name"][0].value.length > 1)) {
      writeln(header_sdlang.tags["publisher"][0].attributes["name"][0].value);
      header_metadata["publisher"]["name"] =
        to!string(header_sdlang.tags["publisher"][0].attributes["name"][0].value);
    } else {
      header_metadata["publisher"]["name"] = "";
    }
  }
  if (!(header_sdlang.maybe.tags["rights"].empty)) {
    if (!(header_sdlang.tags["rights"][0].maybe.attributes["copyright"].empty)
    && (header_sdlang.tags["rights"][0].attributes["copyright"][0].value.length > 1)) {
      writeln(header_sdlang.tags["rights"][0].attributes["copyright"][0].value);
      header_metadata["rights"]["copyright"] =
        to!string(header_sdlang.tags["rights"][0].attributes["copyright"][0].value);
    } else {
      header_metadata["rights"]["copyright"] = "";
    }
    if (!(header_sdlang.tags["rights"][0].maybe.attributes["cover"].empty)
    && (header_sdlang.tags["rights"][0].attributes["cover"][0].value.length > 1)) {
      writeln(header_sdlang.tags["rights"][0].attributes["cover"][0].value);
      header_metadata["rights"]["cover"] =
        to!string(header_sdlang.tags["rights"][0].attributes["cover"][0].value);
    } else {
      header_metadata["rights"]["cover"] = "";
    }
    if (!(header_sdlang.tags["rights"][0].maybe.attributes["illustrations"].empty)
    && (header_sdlang.tags["rights"][0].attributes["illustrations"][0].value.length > 1)) {
      writeln(header_sdlang.tags["rights"][0].attributes["illustrations"][0].value);
      header_metadata["rights"]["illustrations"] =
        to!string(header_sdlang.tags["rights"][0].attributes["illustrations"][0].value);
    } else {
      header_metadata["rights"]["illustrations"] = "";
    }
    if (!(header_sdlang.tags["rights"][0].maybe.attributes["license"].empty)
    && (header_sdlang.tags["rights"][0].attributes["license"][0].value.length > 1)) {
      writeln(header_sdlang.tags["rights"][0].attributes["license"][0].value);
      header_metadata["rights"]["license"] =
        to!string(header_sdlang.tags["rights"][0].attributes["license"][0].value);
    } else {
      header_metadata["rights"]["license"] = "";
    }
  }
  writeln("--------------");
  stdout.rawWrite( header_sdlang.toSDLDocument() );
  writeln("--------------");
  /+
  namespace:name values attributes {
    children
  }
  +/
  return header_sdlang;
}
#+END_SRC

** +sdlang header+                                                     :header:
KEEP not used because have problems passing the root sdl Tag to other structs

#+name: ao_header_extract_sdl
#+BEGIN_SRC d
private auto headerSDLang(in char[] src_header) {
  char[][] source_header_arr =
    split(cast(char[]) src_header, rgx.line_delimiter);
  char[] header_clean;
  foreach(header_line; source_header_arr) {
    if (!match(header_line, rgx.comments)) {
      header_clean ~= header_line ~ "\n";
      // writeln(header_line);
    }
  }
  // writeln(header_clean); // consider
  auto header_sdlang=headerMakeSDLang(to!string(header_clean));
  return header_sdlang;
}
#+END_SRC

* header native                                               :header:native:

// mixin SiSUheader;
// auto set_header = HeaderDocMetadataAndMakeNativeToJson(); // reintroduce

** native header document metadata in json                             :json:

#+name: ao_markup_header_extract_native
#+BEGIN_SRC d
auto header_metadata_and_make_jsonstr(
  string header,
  JSONValue[string] dochead_meta,
  JSONValue[string] dochead_make
)
in { }
body {
  scope(exit) {
    destroy(header);
    destroy(dochead_meta);
    destroy(dochead_make);
  }
  if (auto t = match(header, rgx.native_header_main)) {
    char[][] header_obj_spl = split(
      cast(char[]) header,
      rgx.line_delimiter_ws_strip
    );
    auto hm = to!string(t.captures[1]);
    if (match(hm, rgx.main_headers)) {
      foreach (line; header_obj_spl) {
        if (auto m = match(line, rgx.native_header_main)) {
          if (!empty(m.captures[2])) {
            if (hm == "creator") {
              dochead_meta[hm]["author"].str =
                to!string(m.captures[2]);
            } else if (hm == "title") {
              dochead_meta[hm]["main"].str =
                to!string(m.captures[2]);
            } else if (hm == "publisher") {
              dochead_meta[hm]["name"].str =
                to!string(m.captures[2]);
            }
          }
        } else if (auto s = match(line, rgx.native_header_sub)) {
          if (!empty(s.captures[2])) {
            auto hs = to!string(s.captures[1]);
            if ((hm == "make" )
            && (dochead_make[hm].type() == JSON_TYPE.OBJECT)) {
              switch (hm) {
              case "make":
                if (match(hs, rgx.native_subhead_make)) {
                  if (dochead_make[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_make[hm][hs].str = to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              default:
                break;
              }
            } else if (dochead_meta[hm].type() == JSON_TYPE.OBJECT) {
              switch (hm) {
              case "creator":
                if (match(hs, rgx.native_subhead_creator)) {
                  if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "title":
                if (match(hs, rgx.native_subhead_title)) {
                  if ((hs == "subtitle")
                  && (dochead_meta[hm]["sub"].type() == JSON_TYPE.STRING)) {
                    dochead_meta[hm]["sub"].str =
                      to!string(s.captures[2]);
                  } else if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "rights":
                if (match(hs, rgx.native_subhead_rights)) {
                  if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "date":
                if (match(hs, rgx.native_subhead_date)) {
                  if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "original":
                if (match(hs, rgx.native_subhead_original)) {
                  if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "classify":
                if (match(hs, rgx.native_subhead_classify)) {
                  if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "identifier":
                if (match(hs, rgx.native_subhead_identifier)) {
                  if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "notes":
                if (match(hs, rgx.native_subhead_notes)) {
                  if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "publisher":
                if (match(hs, rgx.native_subhead_publisher)) {
                  if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                    dochead_meta[hm][hs].str =
                      to!string(s.captures[2]);
                  }
                } else {
                  writeln("not a valid header type:", hm, ":", hs);
                  destroy(hm);
                  destroy(hs);
                }
                break;
              case "links":
                destroy(hm);
                destroy(hs);
                // if (match(hs, rgx.native_subhead_links)) {
                //   if (dochead_meta[hm][hs].type() == JSON_TYPE.STRING) {
                //     dochead_meta[hm][hs].str = to!string(s.captures[2]);
                //   }
                // } else {
                //   writeln("not a valid header type:", hm, ":", hs);
                //   destroy(hm);
                //   destroy(hs);
                // }
                break;
              default:
                break;
              }
            }
          }
        }
      }
    } else {
      writeln("not a valid header type:", hm);
    }
  }
  auto t = tuple(dochead_meta, dochead_make);
  static assert(!isTypeTuple!(t));
  return t;
}
#+END_SRC

** native header extract to string object                            :string:
#+name: ao_markup_header_extract_native
#+BEGIN_SRC d
private auto native_header_extract(
  char[] line,
  ref int[string] line_occur,
  ref string[string] an_object,
  ref int[string] type
) {
  if (matchFirst(line, rgx.native_header_make)) {   /+ matched header_make +/
    debug(header1) { /+ writeln(line); +/ }
    type["header"]      = State.on;
    type["header_make"] = State.on;
    type["header_meta"] = State.off;
    ++line_occur["header_make"];
    an_object["obj"] ~= line ~= "\n";
  } else if (matchFirst(line, rgx.native_header)) { /+ matched header_metadata +/
    /+ (generic header match and not previously caught by header_make) +/
    debug(header1) { /+ writeln(line); +/ }
    type["header"]      = State.on;
    type["header_make"] = State.off;
    type["header_meta"] = State.on;
    ++line_occur["header_meta"];
    an_object["obj"] ~= line ~= "\n";
  } else if (type["header_make"] == State.on
  && (line_occur["header_make"] > State.off)) {     /+ header_make flag set +/
    if (matchFirst(line, rgx.native_header_sub)) {  /+ sub-header +/
      debug(header1) { /+ writeln(line); +/ }
      ++line_occur["header_make"];
      an_object["obj"] ~= line ~= "\n";
    }
  } else if (type["header_meta"] == State.on
  && (line_occur["header_meta"] > State.off)) {     /+ header_metadata flag set +/
    if (matchFirst(line, rgx.native_header_sub)) {  /+ sub-header +/
      debug(header1) { /+ writeln(line); +/ }
      ++line_occur["header_meta"];
      an_object["obj"] ~= line ~= "\n";
    }
  }
  return an_object;
}
#+END_SRC

** native header reset states                                        :reset:
#+name: ao_markup_header_extract_native
#+BEGIN_SRC d
auto header_reset_states_common(
  ref int[string] line_occur,
  ref string[string] an_object,
  ref int[string] type
) {
  // line_occur["header"] = State.off;
  line_occur["header_make"] = State.off;
  line_occur["header_meta"] = State.off;
  type["header"] = State.off;
  // type["header_make"] = State.off;
  // type["header_meta"] = State.off;
  an_object.remove("obj");
  an_object.remove("is");
  an_object.remove("attrib");
}
#+END_SRC

** native header start                                               :start:
#+name: ao_markup_header_extract_native
#+BEGIN_SRC d
private auto headerContentJSON(in char[] src_header) {
  auto type = flags_type_init;
  type = [
   "header"          : State.off,
   "header_make"     : State.off,
   "header_meta"     : State.off,
  ];
  string[string] an_object;
  int[string] line_occur;
  auto dochead_make = parseJSON(header_make_jsonstr).object;
  auto dochead_meta = parseJSON(header_meta_jsonstr).object;
  auto set_header = HeaderDocMetadataAndMakeNativeToJson();
  char[][] source_header_arr =
    split(cast(char[]) src_header, rgx.line_delimiter);
  foreach(header_line; source_header_arr) {
    if (auto m = matchFirst(header_line, rgx.comment)) {
      /+ matched comment +/
      debug(comment) {
        // tell_l("blue", header_line);
      }
      header_reset_states_common(line_occur, an_object, type);
      // type["header_make"] = State.off;
      // type["header_meta"] = State.off;
    } else if ((matchFirst(header_line, rgx.native_header))
    || (type["header_make"] == State.on
    && (line_occur["header_make"] > State.off))
    || (type["header_meta"] == State.on
    && (line_occur["header_meta"] > State.off))) {
      if (header_line.length == 0) {
        /+ header_make instructions (current line empty) +/
        auto dochead_metadata_and_make =
          set_header.header_metadata_and_make_jsonstr(strip(an_object["obj"]), dochead_meta, dochead_make);
        static assert(!isTypeTuple!(dochead_metadata_and_make));
        dochead_meta = dochead_metadata_and_make[0];
        dochead_make = dochead_metadata_and_make[1];
        header_reset_states_common(line_occur, an_object, type);
        type["header_make"] = State.off;
        type["header_meta"] = State.off;
        writeln(dochead_metadata_and_make);
      } else {
        an_object = native_header_extract(header_line, line_occur, an_object, type);
      }
    } else {
      // writeln(__LINE__);
    }
  }
  auto t = tuple(
    dochead_make,
    dochead_meta,
  );
  return t;
}
#+END_SRC

** +header document metadata+                               :document:metadata:
*** +within abstraction loop+

**** +line exist: header make+                                    :header:make:
# #+name: abs_in_loop_body_not_block_obj
# #+BEGIN_SRC d
#     } else if (line_occur["header_make"] > State.off) {
#       /+ header_make +/
#       // should be caught by sub-header
#       debug(header) {
#         tell_l("red", line);
#       }
#       an_object["obj"] ~= line ~= "\n";
#       ++line_occur["header_make"];
# #+END_SRC

**** +line exist: header metadata+                            :header:metadata:
# #+name: abs_in_loop_body_not_block_obj
# #+BEGIN_SRC d
#     } else if (line_occur["header_meta"] > State.off) {
#       /+ header_metadata +/
#       // should be caught by sub-header
#       debug(header) {                          // para
#         tell_l("red", line);
#       }
#       an_object["obj"] ~= line ~= "\n";
#       ++line_occur["header_meta"];
# #+END_SRC

**** +header_make instructions+                      :header:make:instructions:

# #+name: abs_in_loop_body_not_block_obj_line_empty
# #+BEGIN_SRC d
# if ((type["header_make"] == State.on)
# && (line_occur["header_make"] > State.off)) {
#   /+ header_make instructions (current line empty) +/
#   auto dochead_metadata_and_make =
#     set_header.header_metadata_and_make_jsonstr(strip(an_object["obj"]), dochead_meta, dochead_make);
#   static assert(!isTypeTuple!(dochead_metadata_and_make));
#   dochead_meta = dochead_metadata_and_make[0];
#   dochead_make = dochead_metadata_and_make[1];
#   header_reset_states_common(line_occur, an_object, type);
#   processing.remove("verse");
# #+END_SRC

**** +header_metadata+                                        :header:metadata:

# #+name: abs_in_loop_body_not_block_obj_line_empty
# #+BEGIN_SRC d
# } else if ((type["header_meta"] == State.on)
# && (line_occur["header_meta"] > State.off)) {
#   /+ header_meta (current line empty) +/
#   auto dochead_metadata_and_make =
#     set_header.header_metadata_and_make_jsonstr(strip(an_object["obj"]), dochead_meta, dochead_make);
#   static assert(!isTypeTuple!(dochead_metadata_and_make));
#   dochead_meta = dochead_metadata_and_make[0];
#   dochead_make = dochead_metadata_and_make[1];
#   header_reset_states_common(line_occur, an_object, type);
#   type["header_make"] = State.off;
#   type["header_meta"] = State.off;
#   processing.remove("verse");
# #+END_SRC

* tangles (code structure)                                           :tangle:
** SDLang ao_markup_header_extract.d:              :ao_markup_header_extract.d:
#+BEGIN_SRC d :tangle ../src/sdp/ao_header_extract.d
/+
  extract sdl header return sdl
+/
template SiSUheaderExtractSDLang() {
  private import
    std.regex;
  private import
    ao_rgx;
  struct HeaderExtractSDL {
    mixin RgxInit;
    auto rgx = Rgx();
    <<ao_header_extract_sdl>>
    <<ao_header_extract_sdl_to_json>>
  }
  struct HeaderUseSDL {
    mixin RgxInit;
    auto rgx = Rgx();
    // Tag = sdl_header;
    auto headerUseSDLang(T)(auto T sdl_root_header) {
    // T sdl_root_header;
    // auto headerUseSDLang(Tag sdl_root_header) {
    // private auto headerUseSDLang(Tag sdl_root_header) {
    // private auto headerUseSDLang(in Tag sdl_root_header) {
      // auto sdl_root_header = T;

  // Value is a std.variant.Algebraic
  Value test = sdl_root_header.tags["title"][0].values[0];
  // assert(test == typeid(string));
  writeln(test);

      return sdl_root_header;
    }
  }
}
#+END_SRC
** Native ao_markup_header_extract.d:              :ao_markup_header_extract.d:
#+BEGIN_SRC d :tangle ../src/sdp/ao_header_extract.d
/+
  extract native/orig header return json
+/
template SiSUheaderExtractNative() {
  private import
    std.exception,
    std.regex,
    std.utf,
    std.conv : to;
  private import
    ao_rgx;
  struct HeaderDocMetadataAndMakeNativeToJson {
    mixin SiSUrgxInitFlags;
    mixin RgxInit;
    auto rgx = Rgx();
    enum State { off, on }
    string hm, hs;
    <<ao_markup_header_extract_native>>
  }
}
#+END_SRC