module doc_reform.meta.metadoc;
template DocReformAbstraction() {
  import
    std.datetime,
    std.getopt,
    std.file,
    std.path,
    std.process;
  import
    doc_reform.meta,
    doc_reform.meta.metadoc_harvest,
    doc_reform.meta.metadoc_harvests_authors,
    doc_reform.meta.metadoc_harvests_topics,
    doc_reform.meta.metadoc_summary,
    doc_reform.meta.metadoc_from_src,
    doc_reform.meta.conf_make_meta_structs,
    doc_reform.meta.conf_make_meta_toml,
    doc_reform.meta.conf_make_meta_json,
    doc_reform.meta.defaults,
    doc_reform.meta.doc_debugs,
    doc_reform.meta.rgx,
    doc_reform.source.paths_source,
    doc_reform.source.read_config_files,
    doc_reform.source.read_source_files,
    doc_reform.output.hub;
  mixin DocReformRgxInit;
  mixin contentJSONtoDocReformStruct;
  mixin DocReformBiblio;
  mixin DocReformRgxInitFlags;
  mixin outputHub;
  enum headBody { header, body_content, insert_file_list, image_list }
  enum makeMeta { make, meta }
  enum docAbst  { doc_abstract_obj, doc_has }
  static auto rgx = Rgx();
  auto DocReformAbstraction(E,P,O,M)(
    E _env,
    P program_info,
    O _opt_action,
    M _manifest
  ){
    ConfCompositePlus _make_and_meta_struct;
    { /+ document config file +/
      auto _config_document_struct = readConfigDoc!()(_manifest, _env);
      _make_and_meta_struct = _config_document_struct.configParseTOMLreturnDocReformStruct!()(_make_and_meta_struct, _manifest);
    }
    { /+ local site config +/
      auto _config_local_site_struct = readConfigSite!()(_manifest, _env);
      _make_and_meta_struct = _config_local_site_struct.configParseTOMLreturnDocReformStruct!()(_make_and_meta_struct, _manifest);
    }
    /+ ↓ read file (filename with path) +/
    /+ ↓ file tuple of header and content +/
    if ((_opt_action.debug_do)
    || (_opt_action.very_verbose)
    ) {
      writeln("step1 commence → (get document header & body & insert file list & if needed image list)"
      );
    }
    auto _header_body_insertfilelist_imagelist
      = DocReformRawMarkupContent!()(_opt_action, _manifest.src.path_and_fn);
    static assert(!isTypeTuple!(_header_body_insertfilelist_imagelist));
    static assert(_header_body_insertfilelist_imagelist.length==4);
    if ((_opt_action.debug_do)
    || (_opt_action.very_verbose)
    ) {
      writeln("- step1 complete");
    }
    debug(header_and_body) {
      writeln(header);
      writeln(_header_body_insertfilelist_imagelist.length);
      writeln(_header_body_insertfilelist_imagelist.length[headBody.body_content][0]);
    }
    /+ ↓ split header into make and meta +/
    if ((_opt_action.debug_do)
    || (_opt_action.very_verbose)
    ) {
      writeln("step2 commence → (read document header - toml, return struct)");
    }
    _make_and_meta_struct =
    docHeaderMakeAndMetaTupTomlExtractAndConvertToStruct!()(
      _make_and_meta_struct,
      _header_body_insertfilelist_imagelist[headBody.header],
      _manifest,
    );
    if ((_opt_action.debug_do)
    || (_opt_action.very_verbose)
    ) {
      writeln("- step2 complete");
    }
    /+ ↓ document abstraction: process document, return abstraction as tuple +/
    if ((_opt_action.debug_do)
    || (_opt_action.very_verbose)
    ) {
      writeln("step3 commence → (document abstraction (da); da keys; segnames; doc_matters)");
    }
    auto da = DocReformDocAbstraction!()(
      _header_body_insertfilelist_imagelist[headBody.body_content],
      _make_and_meta_struct,
      _opt_action,
      _manifest,
      true,
    );
    static assert(!isTypeTuple!(da));
    static assert(da.length==2);
    auto doc_abstraction = da[docAbst.doc_abstract_obj]; /+ head ~ toc ~ body ~ endnotes_seg ~ glossary ~ bibliography ~ bookindex ~ blurb; +/
    auto _doc_has_struct = da[docAbst.doc_has];
    if ((_opt_action.debug_do)
    || (_opt_action.very_verbose)
    ) {
      writeln("- step3 complete");
    }
    if ((_opt_action.debug_do)
    || (_opt_action.very_verbose)
    ) {
      writeln("step4 commence → (doc_matters)");
    }
    struct DocumentMatters {
      auto generator_program() {
        struct Prog_ {
          auto name() {
            return program_info.name;
          }
          auto ver() {
            return program_info.ver;
          }
          auto name_and_version() {
            return format(
              "%s-%s",
              program_info.name,
              program_info.ver,
            );
          }
          auto url_home() {
            return "http://sisudoc.org";
          }
          auto url_git() {
            return "https://git.sisudoc.org/software/sisu";
          }
        }
        return Prog_();
      }
      auto generated_time() {
        auto _st = Clock.currTime(UTC());
        auto _time = _st.year.to!string
          ~ "-" ~ _st.month.to!int.to!string // prefer as month number
          ~ "-" ~ _st.day.to!string
          ~ " [" ~ _st.isoWeek.to!string ~ "/" ~ _st.dayOfWeek.to!int.to!string ~ "]"
          ~ " " ~ _st.hour.to!string
          ~ ":" ~ _st.minute.to!string
          ~ ":" ~ _st.second.to!string;
        return _time;
      }
      auto conf_make_meta() {
        return _make_and_meta_struct;
      }
      auto has() {
        return _doc_has_struct;
      }
      auto env() {
        struct Env_ {
          auto pwd() {
            return _manifest.env.pwd;
          }
          auto home() {
            return _manifest.env.home;
          }
        }
        return Env_();
      }
      auto opt() {
        struct Opt_ {
          auto action() {
            /+ getopt options, commandline instructions, raw
             - processing instructions --epub --html etc.
             - command line config instructions --output-path
            +/
            return _opt_action;
          }
        }
        return Opt_();
      }
      auto src() {
        return _manifest.src;
      }
      auto src_path_info() {
        return DocReformPathsSRC!()(_manifest.env.pwd, _manifest.src.file_with_absolute_path); // would like (to have and use) relative path
      }
      auto pod() {
        return _manifest.pod;
      }
      auto sqlite() {
        struct SQLite_ {
          string filename() {
            return _opt_action.sqlite_filename;
          }
        }
        return SQLite_();
      }
      auto output_path() {
        return _manifest.output.path;
      }
      auto srcs() {
        struct SRC_ {
          auto file_insert_list() {
            return _header_body_insertfilelist_imagelist[headBody.insert_file_list];
          }
          auto image_list() {
            return _doc_has_struct.imagelist;
          }
        }
        return SRC_();
      }
    }
    auto doc_matters = DocumentMatters();
    if ((_opt_action.debug_do)
    || (_opt_action.very_verbose)
    ) {
      writeln("- step4 complete");
    }
    auto t = tuple(doc_abstraction, doc_matters);
    static assert(t.length==2);
    return t;
  }
}