/*
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.dynamicPageList; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import org.junit.*; import gplx.core.strings.*; import gplx.xowa.apps.cfgs.*; import gplx.xowa.wikis.nss.*; import gplx.langs.htmls.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*;
public class Dpl_xnde_tst {
	private final    Dpl_xnde_fxt fxt = new Dpl_xnde_fxt();
	@Before public void init() {fxt.Clear();}
	@Test   public void Ctg() {
		fxt.Init__create_ctg("Ctg_0", "B", "A");
		fxt.Exec__parse("<DynamicPageList>category=Ctg_0</DynamicPageList>");
		fxt.Test__html(fxt.Make__html__itms__null("B", "A"));
	}
	@Test   public void Ctg_multiple() {
		fxt.Init__create_ctg_pages("Ctg_0", Dpl_page_mok.new_(101, "A"), Dpl_page_mok.new_(102, "B"));
		fxt.Init__create_ctg_pages("Ctg_1", Dpl_page_mok.new_(101, "A"));
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "category=Ctg_1"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("A"));
	}
	@Test   public void Ctg_multiple_none() {	// PURPOSE: page must be in both categories
		fxt.Init__create_ctg("Ctg_0", "A");
		fxt.Init__create_ctg("Ctg_1", "B");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "category=Ctg_1"
		, "</DynamicPageList>"
		);
		fxt.Test__html("No pages meet these criteria.");
	}
	@Test   public void Ctg_multiple_ignore_invalid() {	// PURPOSE: ignore invalid category titles; PAGE:en.n:Category:Egypt DATE:2016-10-18
		fxt.Init__create_ctg_pages("Ctg_0", Dpl_page_mok.new_(101, "A"));
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "category={{{2}}}"	// ignore invalid titles
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("A"));	// should not return nothing
	}
	@Test   public void Notcategory() {
		fxt.Init__create_ctg_pages("Ctg_0", Dpl_page_mok.new_(101, "A"), Dpl_page_mok.new_(102, "B"));
		fxt.Init__create_ctg_pages("Ctg_1", Dpl_page_mok.new_(101, "A"));
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "notcategory=Ctg_1"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("B"));
	}
	@Test  public void Ctg_ascending() {
		fxt.Init__create_ctg("Ctg_0", "B", "A");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "order=ascending"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("A", "B"));
	}
	@Test  public void Ctg_ws() {
		fxt.Init__create_ctg("Ctg_0", "B", "A");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "  category  =  Ctg_0  "
		, "  order  =  ascending  "
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("A", "B"));
	}
	@Test  public void Ctg_descending() {
		fxt.Init__create_ctg("Ctg_0", "A", "B");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "order=descending"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("B", "A"));
	}
	@Test  public void Nofollow() {
		fxt.Init__create_ctg("Ctg_0", "A", "B");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "nofollow=true"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html(" rel=\"nofollow\"", "A", "B"));
	}
	@Test  public void Invalid_key() {
		fxt.Init__create_ctg("Ctg_0", "A", "B");
		fxt.Init__warns("dynamic_page_list:unknown_key: page=Test page key=invalid_key");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "invalid_key=invalid_val"
		, "category=Ctg_0"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("A", "B"));
	}
	@Test  public void No_results() {
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "</DynamicPageList>"
		);
		fxt.Test__html("No pages meet these criteria.");
	}
	@Test  public void Suppress_errors() {
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "suppresserrors=true"
		, "</DynamicPageList>"
		);
		fxt.Test__html("");
	}
	@Test  public void Count() {
		fxt.Init__create_ctg("Ctg_0", "A", "B", "C");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "count=2"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("A", "B"));
	}
	@Test  public void Offset() {
		fxt.Init__create_ctg("Ctg_0", "A", "B", "C");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "offset=2"
		, "count=2"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("C"));
	}
	@Test  public void Ns() {
		fxt.Init__create_ctg("Ctg_0", "Talk:A B", "B");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "namespace=Talk"
		, "</DynamicPageList>"
		);
		fxt.Test__html(Gfh_utl.Replace_apos_concat_lines
		( "<ul>"
		, "  <li><a href='/wiki/Talk:A_B' title='Talk:A B'>A B</a></li>"
		,  "</ul>"
		));
	}
	@Test  public void Show_ns() {
		fxt.Init__create_ctg("Ctg_0", "Talk:A");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "shownamespace=true"
		, "</DynamicPageList>"
		);
		fxt.Test__html(Gfh_utl.Replace_apos_concat_lines
		( "<ul>"
		, "  <li><a href='/wiki/Talk:A' title='Talk:A'>Talk:A</a></li>"
		,  "</ul>"
		));

		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "shownamespace=false"
		, "</DynamicPageList>"
		);
		fxt.Test__html(Gfh_utl.Replace_apos_concat_lines
		( "<ul>"
		, "  <li><a href='/wiki/Talk:A' title='Talk:A'>A</a></li>"
		,  "</ul>"
		));
	}
	@Test  public void Comment() {	// PURPOSE: comment should be ignored; en.n:Portal:Federally_Administered_Tribal_Areas; DATE:2014-01-18
		fxt.Init__create_ctg("Ctg_0", "B", "A");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "<!--category=Ctg_0-->"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("B", "A"));
	}
	@Test  public void Error_skip_line() {	// PURPOSE: error should skip rest of line; was failing with array out of bounds; en.n:Portal:Austria/Wikipedia; DATE:2014-01-18
		fxt.Init__warns("dynamic_page_list:unknown_key: page=Test page key=Ctg_0 order");	// ignore warning message
		fxt.Exec__parse("<DynamicPageList> category=Ctg_0 order=descending</DynamicPageList>");
		fxt.Test__html("No pages meet these criteria.");
	}
	@Test  public void Atr_has_template() {	// PURPOSE: attribute also has template; DATE:2014-01-31
		fxt.Init__create_ctg("Test_page", "B", "A");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category={{PAGENAME}}"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("B", "A"));
	}
	@Test  public void Err_page_ns_doesnt_exist() {// PURPOSE: check that <dpl> is not enabled if wiki does not have Page / Index ns; PAGE:fr.w:Wikipedia:Le_Bistro/novembre_2006 DATE:2014-11-28
		// reset categories to (a) remove ns for Page / Index; (b) add back Category (else null error)
		fxt.Wiki().Ns_mgr().Clear();
		fxt.Wiki().Ns_mgr().Add_new(14, "Category").Init();

		fxt.Wiki().Cfg_parser().Xtns().Itm_pages().Reset();	// must reset to clear cached valid ns_page from previous tests
		fxt.Fxt().Test_parse_page_wiki_str("<dynamicpagelist>category=a</dynamicpagelist>", "No pages meet these criteria.");
		fxt.Wiki().Cfg_parser().Xtns().Itm_pages().Reset();	// must reset to clear cached invalid ns_page for next tests

		// reset categories for rest of tests
		fxt.Wiki().Ns_mgr().Add_new(0, "").Init();	// call .Clear() to remove ns for Page / Index
	}
	@Test  public void Ordermethod__invalid() {	// PURPOSE: do not fail if ordermethod is invalid; PAGE:sr.d:Викиречник:Википројекат_1001_арапска_реч/Списак_уноса; DATE:2015-10-16
		fxt.Init__create_ctg("Ctg_0", "A", "B", "C");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "ordermethod=ascending"	// should not throw error
		, "ordermethod=sortkey"
		, "</DynamicPageList>"
		);
		fxt.Test__html(fxt.Make__html__itms__null("A", "B", "C"));
	}
	@Test  public void Encode_spaces() {// PURPOSE:encode spaces in href; PAGE:en.q:Wikiquote:Speedy_deletions DATE:2016-01-19
		fxt.Init__create_ctg("Ctg_0", "A B");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "nofollow=true"
		, "</DynamicPageList>"
		);
		fxt.Test__html(Gfh_utl.Replace_apos_concat_lines
		( "<ul>"
		, "  <li><a href='/wiki/A_B' title='A B' rel='nofollow'>A B</a></li>"	// "/wiki/A_B" not "/wiki/A B"
		,  "</ul>"
		));
	}
	@Test  public void Encode_quotes() {// PURPOSE:encode quotes; PAGE:en.b:Wikibooks:Alphabetical_classification/All_Books; DATE:2016-01-21
		fxt.Init__create_ctg("Ctg_0", "A\"B");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "category=Ctg_0"
		, "nofollow=true"
		, "</DynamicPageList>"
		);
		fxt.Test__html(Gfh_utl.Replace_apos_concat_lines
		( "<ul>"
		, "  <li><a href='/wiki/A%22B' title='A&quot;B' rel='nofollow'>A&quot;B</a></li>"	// "/wiki/A_B" not "/wiki/A B"
		,  "</ul>"
		));
	}
	@Test   public void Err__bad_key_causes_out_of_bound() {	// PURPOSE: bad key causes out of bounds error; PAGE:de.n:Portal:Brandenburg DATE:2016-04-21
		fxt.Init__warns("dynamic_page_list:unknown_key: page=Test page key=<DynamicPageList>category", "dynamic_page_list:unknown_key: page=Test page key=<DynamicPageList>category");
		fxt.Exec__parse
		( "<DynamicPageList>"
		, "<DynamicPageList>category=A</DynamicPageList>a=b c=d"
		, "<DynamicPageList>category=B</DynamicPageList>"
		);
		fxt.Test__html("No pages meet these criteria.");
	}
}
class Dpl_page_mok {
	public Dpl_page_mok(int id, String ttl) {this.id = id; this.ttl = ttl;}
	public int Id() {return id;} private int id;
	public String Ttl() {return ttl;} private String ttl;
	public static Dpl_page_mok new_(int id, String ttl) {return new Dpl_page_mok(id, ttl);}
}
class Dpl_xnde_fxt {	
	private final    Xop_fxt fxt = new Xop_fxt();
	private final    Bry_bfr bfr = Bry_bfr_.New();
	private String exec__raw;
	private int next_id;
	public void Clear() {
		next_id = 100;
		fxt.Reset();
		this.exec__raw = String_.Empty;
		this.expd_warns = String_.Ary_empty;
		fxt.App().Usr_dlg().Gui_wkr().Clear();
		fxt.Wiki().Hive_mgr().Clear();
		fxt.Wiki().Db_mgr().Save_mgr().Clear();	// NOTE: must clear to reset next_id to 0; Init__create_ctg assumes clean slate from 0
		fxt.Wiki().Xtn_mgr().Xtn_proofread().Enabled_y_();
		fxt.Wiki().Db_mgr().Load_mgr().Clear(); // must clear; otherwise fails b/c files get deleted, but wiki.data_mgr caches the Xowd_regy_mgr (the .reg file) in memory;
		fxt.Wiki().Ns_mgr().Add_new(Xowc_xtn_pages.Ns_page_id_default, "Page").Add_new(Xowc_xtn_pages.Ns_index_id_default, "Index").Init();
		Io_mgr.Instance.InitEngine_mem();
	}
	public Xowe_wiki Wiki() {return fxt.Wiki();}
	public Xop_fxt Fxt() {return fxt;}
	public void Init__warns(String... v) {expd_warns = v;} private String[] expd_warns;
	public void Init__create_ctg(String ctg, String... ttls) {
		int len = ttls.length;
		Dpl_page_mok[] ary = new Dpl_page_mok[len];
		for (int i = 0; i < len; i++)
			ary[i] = Dpl_page_mok.new_(++next_id, ttls[i]);
		Init__create_ctg_pages(ctg, ary);
	}
	public void Init__create_ctg_pages(String ctg_ttl, Dpl_page_mok... pages) {
		Xoctg_catpage_ctg ctg = new Xoctg_catpage_ctg(1, Bry_.new_u8(ctg_ttl));
		int pages_len = pages.length;
		Xoctg_catpage_tmp tmp = new Xoctg_catpage_tmp();
		for (int i = 0; i < pages_len; i++) {
			Dpl_page_mok page = pages[i];
			int id = page.Id();
			String ttl_str = page.Ttl();
			Xoa_ttl ttl = fxt.Wiki().Ttl_parse(Bry_.new_u8(ttl_str));
			Xoae_page page_obj = fxt.Wiki().Data_mgr().Load_page_by_ttl(ttl);
			if (page_obj.Db().Page().Exists_n()) {
				fxt.Init_page_create(ttl_str, ttl_str);
				fxt.Init_id_create (id, 0, 0, false, 5, Xow_ns_.Tid__main, ttl_str);
			}
			byte tid = gplx.xowa.addons.wikis.ctgs.Xoa_ctg_mgr.Tid__page;
			Xoctg_catpage_itm catpage_itm = Xoctg_catpage_itm.New_by_ttl(tid, page.Id(), ttl);
			tmp.Add(catpage_itm);
		}
		tmp.Make_by_ctg(ctg);
		Xoctg_catpage_mgr catpage_mgr = fxt.Wiki().Ctg__catpage_mgr();
		catpage_mgr.Cache__add(Bry_.new_u8("Category:" + ctg_ttl), ctg);
	}
	public String Make__html__itms__null(String... pages) {return this.Make__html(null, pages);}
	public String Make__html(String itm_html, String... pages) {
		bfr.Add_str_a7("<ul>").Add_byte_nl();
		int pages_len = pages.length;
		for (int i = 0; i < pages_len; i++) {
			String page = pages[i];
			bfr.Add_str_a7("  <li><a href=\"/wiki/").Add_str_a7(page).Add_str_a7("\" title=\"").Add_str_a7(page).Add_str_a7("\"");
			if (itm_html != null) bfr.Add_str_a7(itm_html);
			bfr.Add_str_a7(">").Add_str_a7(page).Add_str_a7("</a></li>").Add_byte_nl();
		}
		bfr.Add_str_a7("</ul>").Add_byte_nl();
		return bfr.To_str_and_clear();
	}
	public void Exec__parse(String... raw_lines) {this.exec__raw = String_.Concat_lines_nl_skip_last(raw_lines);}
	public void Test__html(String expd) {
		fxt.Test_parse_page_wiki_str(exec__raw, expd);
		fxt.tst_Warn(expd_warns);
	}
}
