/*
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.pfuncs.ttls; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.core.primitives.*; import gplx.xowa.xtns.pfuncs.times.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.kwds.*;
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*;
public class Pfunc_titleparts extends Pf_func_base {
	@Override public boolean Func_require_colon_arg() {return true;}
	@Override public void Func_evaluate(Bry_bfr bfr, Xop_ctx ctx, Xot_invk caller, Xot_invk self, byte[] src) {// REF.MW:ParserFunctions_body.php
		// get argx
		int args_len = self.Args_len();
		byte[] argx = Eval_argx(ctx, src, caller, self); if (argx == null) return; // no argx; return empty
		Xoa_ttl argx_as_ttl = Xoa_ttl.Parse(ctx.Wiki(), argx, 0, argx.length); // transform to title in order to upper first, replace _, etc..
		if (argx_as_ttl == null)	{bfr.Add(argx); return;}	// NOTE: argx_as_ttl will be null if invalid, such as [[a|b]]; PAGE:en.w:owl and {{taxobox/showtaxon|Dinosauria}}
		else						argx = argx_as_ttl.Full_txt_w_ttl_case();
		// get parts_len
		byte[] parts_len_ary = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, args_len, 0);
		int parts_len = parts_len_ary == Bry_.Empty ? Int_.Min_value : Bry_.To_int_or(parts_len_ary, Int_.Max_value);
		if (parts_len == Int_.Max_value) {// len is not an int; EX: "a";
			ctx.Msg_log().Add_itm_none(Pfunc_titleparts_log.Len_is_invalid, src, caller.Src_bgn(), caller.Src_end());
			bfr.Add(argx);
			return;
		}
		// get parts_bgn
		byte[] parts_bgn_arg = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, args_len, 1);
		int parts_bgn = parts_bgn_arg == Bry_.Empty ? 0 : Bry_.To_int_or(parts_bgn_arg, Int_.Min_value);
		if (parts_bgn == Int_.Min_value) {// parts_bgn is not an int; EX: "a"
			ctx.Msg_log().Add_itm_none(Pfunc_titleparts_log.Bgn_is_invalid, src, caller.Src_bgn(), caller.Src_end());
			parts_bgn = 0;	// NOTE: do not return
		}
		else if (parts_bgn > 0) parts_bgn -= List_adp_.Base1;	// adjust for base1
		bfr.Add(TitleParts(argx, parts_len, parts_bgn));
	}
	private byte[] TitleParts(byte[] src, int parts_len, int parts_bgn) {
		// find dlm positions; EX: ab/cde/f/ will have -1,2,6,8
		synchronized (dlms_ary) {// LOCK:static-obj; DATE:2016-07-06
			int src_len = src.length; int dlms_ary_len = 1;	// 1 b/c dlms_ary[0] will always be -1
			for (int i = 0; i < src_len; i++) {
				if (src[i] == Byte_ascii.Slash) dlms_ary[dlms_ary_len++] = i;
			}
			dlms_ary[dlms_ary_len] = src_len;	// put src_len into last dlms_ary; makes dlms_ary[] logic easier
			// calc bgn_idx; must occur before adjust parts_len
			int bgn_idx = parts_bgn > -1 ? parts_bgn : parts_bgn + dlms_ary_len;			// negative parts_bgn means calc from end of dlms_ary_len; EX a/b/c|1|-1 means start from 2
			if (	bgn_idx < 0																// bgn_idx can be negative when parts_len is negative and greater than array; EX: {{#titleparts:a/b|-1|-2}} results in dlms_ary_len of 1 and parts_bgn of -2 which will be parts_bgn of -1
				||	bgn_idx > dlms_ary_len) return Bry_.Empty;							// if bgn > len, return ""; EX: {{#titleparts:a/b|1|3}} should return ""
			// adjust parts_len for negative/null
			if		(parts_len == Int_.Min_value) parts_len = dlms_ary_len;					// no parts_len; default to dlms_ary_len
			else if (parts_len < 0)	{														// neg parts_len; shorten parts now and default to rest of String; EX: a/b/c|-1 -> makes String a/b/c and get 2 parts
				dlms_ary_len += parts_len;
				parts_len = dlms_ary_len;
				if (parts_len < 1) return Bry_.Empty;									// NOTE: if zerod'd b/c of neg length, return empty; contrast with line below; EX: a/b/c|-4
			}		
			if (parts_len == 0) return src;													// if no dlms, return orig
			// calc idxs for extraction
			int bgn_pos = dlms_ary[bgn_idx] + 1; // +1 to start after slash
			int end_idx = bgn_idx + parts_len;
			int end_pos = end_idx > dlms_ary_len ? dlms_ary[dlms_ary_len] : dlms_ary[end_idx];
			if (end_pos < bgn_pos) return Bry_.Empty;
			return Bry_.Mid(src, bgn_pos, end_pos);
		}
	}	private static final    int[] dlms_ary = new Int_ary_bldr(255).Set(0, -1).Xto_int_ary();	// set pos0 to -1; makes +1 logic easier
	@Override public int Id() {return Xol_kwd_grp_.Id_xtn_titleparts;}
	@Override public Pf_func New(int id, byte[] name) {return new Pfunc_titleparts().Name_(name);}
}
