/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.math.bldrs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.math.*;
import gplx.dbs.*;
import gplx.xowa.bldrs.*; import gplx.xowa.parsers.logs.*;
import gplx.xowa.xtns.math.texvcs.*; import gplx.xowa.xtns.math.texvcs.tkns.*;
class Xomath_check_mgr {
	private int count_total, count_xnde_invalid, count_xnde_w_atrs, count_texvc_invalid, count_texvc_adjusted;
	public void Exec(Xowe_wiki wiki) {
		// get db, conn, rdr
		Xob_db_file log_db = Xob_db_file.New__file_make(wiki.Fsys_mgr().Root_dir());
		Db_conn log_conn = log_db.Conn();
		Xop_log_basic_tbl log_tbl = new Xop_log_basic_tbl(log_conn);
		Db_rdr rdr = log_conn.Stmt_select_all(log_tbl.Tbl_name(), log_tbl.flds).Exec_select__rls_auto();

		// loop 
		try {
			while (rdr.Move_next()) {
				// get page_id, src
				int page_id = rdr.Read_int(log_tbl.fld__page_id);
				byte[] src = rdr.Read_bry_by_str(log_tbl.fld__src_str);
				count_total++;

				src = Assert_flanking_math_ndes(page_id, src);
				if (src == null) {
					count_xnde_invalid++;
					continue;
				}
				Check_texvc(page_id, src);
			}
		} finally {rdr.Rls();}
		Gfo_usr_dlg_.Instance.Note_many("", "", "done: total=~{0}, xnde_invalid=~{1} xnde_w_atrs=~{2} texvc_invalid=~{3} texvc_adjusted=~{4}"
		, count_total, count_xnde_invalid, count_xnde_w_atrs, count_texvc_invalid, count_texvc_adjusted);
	}

	private final    byte[] math_lhs_bry = Bry_.new_a7("<math"), math_rhs_bry = Bry_.new_a7("</math>"), nl_repl_bry = Bry_.new_a7("    ");
	private byte[] Assert_flanking_math_ndes(int page_id, byte[] src) {
		// assert "<math" at start
		if (!Bry_.Has_at_bgn(src, math_lhs_bry)) {
			Gfo_usr_dlg_.Instance.Warn_many("", "", "math.check:xnde_invalid b/c '<math' is not at beginning; page_id=~{0}, src=~{1}", page_id, Bry_.Replace(src, Byte_ascii.Nl_bry, nl_repl_bry));
			return null;
		}

		// assert "</math>" at end
		if (!Bry_.Has_at_end(src, math_rhs_bry)) {
			Gfo_usr_dlg_.Instance.Warn_many("", "", "math.check:xnde_invalid b/c '</math>' is not at end; page_id=~{0}, src=~{1}", page_id, Bry_.Replace(src, Byte_ascii.Nl_bry, nl_repl_bry));
			return null;
		}

		// assert "<math>"
		int math_lhs_end = Bry_find_.Find_fwd(src, Byte_ascii.Gt_bry, math_lhs_bry.length);
		if (math_lhs_end != math_lhs_bry.length) {
			count_xnde_w_atrs++;
			Gfo_usr_dlg_.Instance.Log_many("", "", "math.check:xnde_w_atrs; page_id=~{0}, src=~{1}", page_id, Bry_.Replace(src, Byte_ascii.Nl_bry, nl_repl_bry));
		}

		// remove "<math>", "</math>"
		return Bry_.Mid(src, math_lhs_end + 1, src.length - math_rhs_bry.length);
	}

	private final    Texvc_parser parser = new Texvc_parser();
	private final    Texvc_checker checker = new Texvc_checker();
	private final    Texvc_ctx ctx = new Texvc_ctx();
	private final    Bry_bfr tmp_bfr = Bry_bfr_.New();
	private void Check_texvc(int page_id, byte[] src) {
		try {
			Texvc_root root = new Texvc_root();
			ctx.Clear();
			parser.Parse(ctx, root, src);
			checker.Check(src, root);
			tmp_bfr.Clear();
			root.Print_tex_bry(tmp_bfr, src, 0);
			byte[] texvc_bry = tmp_bfr.To_bry_and_clear();
			if (!Bry_.Eq(src, texvc_bry)) {
				count_texvc_adjusted++;
				Gfo_usr_dlg_.Instance.Log_many("", "", "math.check:texvc_adjusted; page_id=~{0}, src=~{1} texvc=~{2}", page_id, Bry_.Replace(src, Byte_ascii.Nl_bry, nl_repl_bry), Bry_.Replace(texvc_bry, Byte_ascii.Nl_bry, nl_repl_bry));
			}
		} catch (Exception exc) {
			count_texvc_invalid++;
			Gfo_usr_dlg_.Instance.Warn_many("", "", "math.check:texvc_invalid; page_id=~{0}, src=~{1} err=~{2}", page_id, Bry_.Replace(src, Byte_ascii.Nl_bry, nl_repl_bry), Err_.Message_gplx_log(exc));
		}
	}
}
