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

XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.

You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.

The terms of each license can be found in the source code repository:

GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.wbases; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import gplx.core.brys.fmtrs.*;
import gplx.xowa.langs.*;
import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.itms.*; import gplx.xowa.xtns.wbases.hwtrs.*; import gplx.xowa.xtns.wbases.claims.itms.times.*;
public class Wdata_prop_val_visitor implements Wbase_claim_visitor {
	private Wdata_wiki_mgr wdata_mgr; private Xoae_app app; private Bry_bfr bfr;
	private Xol_lang_itm lang;
	private final    Bry_bfr tmp_time_bfr = Bry_bfr_.Reset(255); private final    Bry_fmtr tmp_time_fmtr = Bry_fmtr.new_();
	private Wdata_hwtr_msgs msgs;
	public Wdata_prop_val_visitor(Xoae_app app, Wdata_wiki_mgr wdata_mgr) {this.app = app; this.wdata_mgr = wdata_mgr;}
	public void Init(Bry_bfr bfr, Wdata_hwtr_msgs msgs, byte[] lang_key) {
		this.bfr = bfr; this.msgs = msgs;
		this.lang = app.Lang_mgr().Get_by(lang_key);
		if (lang == null) lang = app.Lang_mgr().Lang_en();	// TEST: needed for one test; DATE:2016-10-20
	}
	public void Visit_str(Wbase_claim_string itm) {Write_str(bfr, itm.Val_bry());}
	public static void Write_str(Bry_bfr bfr, byte[] bry) {bfr.Add(bry);}
	public void Visit_time(Wbase_claim_time itm) {
		Write_time(bfr, tmp_time_bfr, tmp_time_fmtr, msgs, Bry_.Empty, -1, itm.Time_as_date());	// for now, don't bother passing ttl; only used for error msg; DATE:2015-08-03
	}
	public static void Write_time(Bry_bfr bfr, Bry_bfr tmp_bfr, Bry_fmtr tmp_fmtr, Wdata_hwtr_msgs msgs, byte[] page_url, int pid, Wbase_date date) {
		try {
			Wbase_date_.To_bfr(bfr, tmp_fmtr, tmp_bfr, msgs, date);
			if (date.Calendar_is_julian()) bfr.Add_byte_space().Add(msgs.Time_julian());
		} catch (Exception e) {
			Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to write time; ttl=~{0} pid=~{1} err=~{2}", page_url, pid, Err_.Message_gplx_log(e));
		}
	}
	public void Visit_monolingualtext(Wbase_claim_monolingualtext itm)	{Write_langtext(bfr, itm.Text());}
	public static void Write_langtext(Bry_bfr bfr, byte[] text) {bfr.Add(text);}			// phrase only; PAGE:en.w:Alberta; EX: {{#property:motto}} -> "Fortis et libre"; DATE:2014-08-28
	public void Visit_entity(Wbase_claim_entity itm) {Write_entity(bfr, wdata_mgr, lang.Key_bry(), itm.Page_ttl_db());}
	public static void Write_entity(Bry_bfr bfr, Wdata_wiki_mgr wdata_mgr, byte[] lang_key, byte[] entity_ttl_db) {
		Wdata_doc entity_doc = wdata_mgr.Doc_mgr.Get_by_xid_or_null(entity_ttl_db);
		if (entity_doc == null) return;	// NOTE: wiki may refer to entity that no longer exists; EX: {{#property:p1}} which links to Q1, but p1 links to Q2 and Q2 was deleted; DATE:2014-02-01
		byte[] label = entity_doc.Label_list__get(lang_key);
		if (label == null && !Bry_.Eq(lang_key, Xol_lang_itm_.Key_en))	// NOTE: some properties may not exist in language of wiki; default to english; DATE:2013-12-19
			label = entity_doc.Label_list__get(Xol_lang_itm_.Key_en);
		if (label != null)	// if label is still not found, don't add null reference
			bfr.Add(label);
	}
	public void Visit_quantity(Wbase_claim_quantity itm) {Write_quantity(bfr, wdata_mgr, lang, itm.Amount(), itm.Lbound(), itm.Ubound(), itm.Unit());}
	public static void Write_quantity(Bry_bfr bfr, Wdata_wiki_mgr wdata_mgr, Xol_lang_itm lang, byte[] val_bry, byte[] lo_bry, byte[] hi_bry, byte[] unit) {
		// get val, lo, hi; NOTE: must handle large numbers; EX:{{#property:P1082}} PAGE:en.w:Earth; DATE:2015-08-02; NOTE: must handle decimals; PAGE:en.w:Malinao,_Aklan; DATE:2016-11-08
		Decimal_adp val = Decimal__parse_or(val_bry, null); if (val == null) throw Err_.new_wo_type("wbase:quanity val can not be null");
		Decimal_adp lo = Decimal__parse_or(lo_bry, val);
		Decimal_adp hi = Decimal__parse_or(hi_bry, val);

		// fmt val
		if (lo.Eq(hi) && hi.Eq(val))// lo, hi, val are same; print val only;
			bfr.Add(lang.Num_mgr().Format_num_by_decimal(val));			// amount; EX: 1,234
		else {
			Wdata_hwtr_msgs msgs = wdata_mgr.Hwtr_mgr().Msgs();
			Decimal_adp lo_dif = val.Subtract(lo);
			Decimal_adp hi_dif = hi.Subtract(val);
			if (lo_dif.Eq(hi_dif)) {	// lo_dif, hi_dif are same; print val±dif
				bfr.Add(lang.Num_mgr().Format_num_by_decimal(val));		// amount;	EX: 1,234
				bfr.Add(msgs.Sym_plusminus());							// symbol:	EX: ±
				bfr.Add(lang.Num_mgr().Format_num_by_decimal(lo_dif));	// amount;	EX: 4
			}
			else {					// lo_dif, hi_dif are diff; print lo - hi; this may not be what MW does
				bfr.Add(lang.Num_mgr().Format_num_by_decimal(lo));		// lo;		EX: 1,230
				bfr.Add_byte(Byte_ascii.Dash);							// dash:	EX: -
				bfr.Add(lang.Num_mgr().Format_num_by_decimal(hi));		// hi;		EX: 1,238
			}
		}

		// output unit
		int unit_qid_bgn = unit == null ? Bry_find_.Not_found : Bry_find_.Find_fwd(unit, Wikidata_url);
		if (unit_qid_bgn == Bry_find_.Not_found) {}			// entity missing; output nothing; EX:"unit":"1"; PAGE:en.w:Malinao,_Aklan DATE:2016-11-08																
		else {												// entity exists; EX:"http://www.wikidata.org/entity/Q11573" (meter)
			bfr.Add_byte_space();
			byte[] xid = Bry_.Mid(unit, Wikidata_url.length);
			Wdata_doc entity_doc = wdata_mgr.Doc_mgr.Get_by_xid_or_null(xid);
			bfr.Add(entity_doc.Label_list__get_or_fallback(lang));
		}
	}
	private static Decimal_adp Decimal__parse_or(byte[] bry, Decimal_adp or) {	// handle missing lbound / ubound; DATE:2016-12-03
		return bry == null ? or : Decimal_adp_.parse(String_.new_u8(Normalize_for_decimal(bry)));
	}
	public static byte[] Normalize_for_decimal(byte[] bry) { // remove leading "+" and any commas; was Bry_.To_long_or(val_bry, Byte_ascii.Comma_bry, 0, val_bry.length, 0)
		if (bry == null) return null;
		Bry_bfr bfr = null;
		int len = bry.length;
		for (int i = 0; i < len; i++) {
			byte b = bry[i];
			switch (b) {
				case Byte_ascii.Plus:
					if (i == 0) {
						if (bfr == null) bfr = Bry_bfr_.New();
					}
					else {
						throw Err_.new_wo_type("invalid decimal format; plus must be at start of String", "raw", bry);
					}
					break;
				case Byte_ascii.Comma:
					if (bfr == null) {
						bfr = Bry_bfr_.New();
						bfr.Add_mid(bry, 0, i);
					}
					break;
				default:
					if (bfr != null)
						bfr.Add_byte(b);
					break;
			}
		}
		return bfr == null ? bry : bfr.To_bry_and_clear();
	}
	public void Visit_globecoordinate(Wbase_claim_globecoordinate itm) {Write_geo(Bool_.N, bfr, wdata_mgr.Hwtr_mgr().Lbl_mgr(), msgs, itm.Lat(), itm.Lng(), itm.Alt(), itm.Prc(), itm.Glb());}
	public static void Write_geo(boolean wikidata_page, Bry_bfr bfr, Wdata_lbl_mgr lbl_mgr, Wdata_hwtr_msgs msgs, byte[] lat, byte[] lng, byte[] alt, byte[] prc, byte[] glb) {
		// get precision
		int precision_int = -1;
		if (Bry_.Eq(prc, Object_.Bry__null) || Bry_.Eq(prc, Byte_ascii.Num_0_bry))	// "null" or "0" should be 1; PAGE:ru.w:Лысково_(Калужская_область) DATE:2016-11-24
			precision_int = 1;
		else {
			Decimal_adp precision_frac = Decimal_adp_.parse(String_.new_a7(prc));
			precision_int = Math_.Log10(Decimal_adp_.One.Divide(precision_frac).To_int());		// convert precision to log10 integer; EX: .00027777 -> 3600 -> 3
		}

		// build String
		gplx.xowa.xtns.mapSources.Map_dd2dms_func.Deg_to_dms(bfr, Bool_.N, lat, precision_int);
		bfr.Add_byte_comma().Add_byte_space();
		gplx.xowa.xtns.mapSources.Map_dd2dms_func.Deg_to_dms(bfr, Bool_.Y, lng, precision_int);

		// write globe if any
		if (wikidata_page) {
			byte[] glb_ttl = Wdata_lbl_itm.Extract_ttl(glb);
			if (glb_ttl != null) {
				byte[] glb_lbl = lbl_mgr.Get_text__ttl(glb_ttl, glb);
				bfr.Add_byte_space().Add_byte(Byte_ascii.Paren_bgn);
				Wdata_hwtr_mgr.Write_link_wikidata(bfr, glb_ttl, glb_lbl);
				bfr.Add_byte(Byte_ascii.Paren_end);
			}
		}
	}

	private static final    byte[] Wikidata_url = Bry_.new_a7("http://www.wikidata.org/entity/");
	public void Visit_system(Wbase_claim_value itm) {}
}
