public void Write_page(Bry_bfr rv, Xoae_page page, Xop_ctx ctx) {
   synchronized (thread_lock_1) {
     this.page = page;
     this.wiki = page.Wikie();
     this.app = wiki.Appe();
     ctx.Page_(page); // HACK: must update page for toc_mgr; WHEN: Xoae_page rewrite
     Bry_fmtr fmtr = null;
     if (mgr.Html_capable()) {
       wdata_lang_wtr.Page_(page);
       byte view_mode = page_mode;
       switch (page_mode) {
         case Xopg_page_.Tid_edit:
           fmtr = mgr.Page_edit_fmtr();
           break;
         case Xopg_page_.Tid_html:
           fmtr = mgr.Page_read_fmtr();
           view_mode = Xopg_page_.Tid_read;
           break; // set view_mode to read, so that "read" is highlighted in HTML
         case Xopg_page_.Tid_read:
           fmtr = mgr.Page_read_fmtr();
           // ctx.Page().Redlink_list().Clear();	// not sure if this is the best place to put it,
           // but redlinks (a) must only fire once; (b) must fire before html generation; (c)
           // cannot fire during edit (preview will handle separately); NOTE: probably put in to
           // handle reusable redlink lists; redlink lists are now instantiated per page, so clear
           // is not useful
           break;
       }
       Bry_bfr page_bfr =
           wiki.Utl__bfr_mkr()
               .Get_m001(); // NOTE: get separate page rv to output page; do not reuse tmp_bfr b/c
                            // it will be used inside Fmt_do
       Xoh_wtr_ctx hctx = null;
       if (page_mode == Xopg_page_.Tid_html
           && wiki.App().Api_root().Wiki().Hdump().Html_mode().Tid_is_hdump_save()) {
         hctx = Xoh_wtr_ctx.Hdump;
         Write_body(page_bfr, ctx, hctx, page);
         Write_page_by_tid(
             ctx,
             hctx,
             page_mode,
             rv,
             mgr.Page_html_fmtr(),
             Gfh_utl.Escape_html_as_bry(page_bfr.To_bry_and_clear()));
       } else {
         hctx = Xoh_wtr_ctx.Basic;
         Write_body(page_bfr, ctx, hctx, page);
         Write_page_by_tid(ctx, hctx, view_mode, rv, fmtr, page_bfr.To_bry_and_rls());
         new gplx.xowa.addons.apps.scripts.Xoscript_mgr().Write(rv, wiki, page);
         if (page_mode
             == Xopg_page_
                 .Tid_html) // if html, write page again, but wrap it in html skin this time
         Write_page_by_tid(
               ctx,
               hctx,
               page_mode,
               rv,
               mgr.Page_html_fmtr(),
               Gfh_utl.Escape_html_as_bry(rv.To_bry_and_clear()));
         wdata_lang_wtr.Page_(null);
       }
     } else Write_body(rv, ctx, Xoh_wtr_ctx.Basic, page);
     this.page = null;
   }
 }
  private void Write_body_wikitext(
      Bry_bfr bfr,
      Xoae_app app,
      Xowe_wiki wiki,
      byte[] data_raw,
      Xop_ctx ctx,
      Xoh_wtr_ctx hctx,
      Xoae_page page,
      byte page_tid,
      int ns_id) {
    // dump and exit if pre-generated html from html dumps
    byte[] hdump_data = page.Db().Html().Html_bry();
    if (Bry_.Len_gt_0(hdump_data)) {
      bfr.Add(hdump_data);
      return;
    }

    // dump and exit if MediaWiki message;
    if (ns_id
        == Xow_ns_
            .Tid__mediawiki) { // if MediaWiki and wikitext, must be a message; convert args back to
                               // php; DATE:2014-06-13
      bfr.Add(Gfs_php_converter.Xto_php(tmp_bfr, Bool_.N, data_raw));
      return;
    }

    // if [[File]], add boilerplate header; note that html is XOWA-generated so does not need to be
    // tidied
    if (ns_id == Xow_ns_.Tid__file)
      app.Ns_file_page_mgr()
          .Bld_html(wiki, ctx, page, bfr, page.Ttl(), wiki.Cfg_file_page(), page.File_queue());

    // get separate bfr; note that bfr already has <html> and <head> written to it, so this can't be
    // passed to tidy; DATE:2014-06-11
    Bry_bfr tidy_bfr = wiki.Utl__bfr_mkr().Get_m001();

    // write wikitext
    if (page.Html_data().Skip_parse()) {
      tidy_bfr.Add(page.Html_data().Custom_body());
    } else {
      if (page.Root()
          != null) { // NOTE: will be null if blank; occurs for one test:
                     // Logo_has_correct_main_page; DATE:2015-09-29
        page.Html_data()
            .Toc_mgr()
            .Clear(); // NOTE: always clear tocs before writing html; toc_itms added when writing
                      // html_hdr; DATE:2016-07-17
        wiki.Html_mgr()
            .Html_wtr()
            .Write_doc(tidy_bfr, ctx, hctx, page.Root().Data_mid(), page.Root());
        if (wiki.Html_mgr().Html_wtr().Cfg().Toc__show())
          gplx.xowa.htmls.core.wkrs.tocs.Xoh_toc_wtr.Write_toc(tidy_bfr, page, hctx);
      }
    }

    // if [[Category]], add catpage data
    if (ns_id == Xow_ns_.Tid__category) tidy_bfr.Add_safe(page.Html_data().Catpage_data());
    // if (ns_id == Xow_ns_.Tid__category) wiki.Ctg__catpage_mgr().Write_catpage(tidy_bfr, page,
    // hctx);

    // tidy html
    wiki.Html_mgr().Tidy_mgr().Exec_tidy(tidy_bfr, !hctx.Mode_is_hdump(), page.Url_bry_safe());

    // add back to main bfr
    bfr.Add_bfr_and_clear(tidy_bfr);
    tidy_bfr.Mkr_rls();

    // handle Categories at bottom of page; note that html is XOWA-generated so does not need to be
    // tidied
    int ctgs_len = page.Wtxt().Ctgs__len();
    if (ctgs_enabled
        && ctgs_len > 0 // skip if no categories found while parsing wikitext
        && !wiki.Html_mgr()
            .Importing_ctgs() // do not show categories if importing categories, page will wait for
                              // category import to be done; DATE:2014-10-15
        && !hctx.Mode_is_hdump() // do not dump categories during hdump; DATE:2016-10-12
    ) {
      if (app.Mode().Tid_is_gui())
        app.Usr_dlg().Prog_many("", "", "loading categories: count=~{0}", ctgs_len);
      Xoctg_pagebox_itm[] pagebox_itms = wiki.Ctg__pagebox_wtr().Get_catlinks_by_page(wiki, page);
      boolean hidden_enabled = wiki.App().Api_root().Addon().Wikis__ctgs__hidden_enabled();
      wiki.Ctg__pagebox_wtr().Write_pagebox(hidden_enabled, bfr, wiki, page, pagebox_itms);
    }

    // translate if variants are enabled
    Xol_vnt_mgr vnt_mgr = wiki.Lang().Vnt_mgr();
    if (vnt_mgr.Enabled())
      bfr.Add(
          vnt_mgr.Convert_lang()
              .Parse_page(vnt_mgr.Cur_itm(), page.Db().Page().Id(), bfr.To_bry_and_clear()));
  }