/* ***** BEGIN LICENSE BLOCK *****
	Copyright (c) 2018-2020 Famibee (famibee.blog38.fc2.com)

	This software is released under the MIT License.
	http://opensource.org/licenses/mit-license.php
** ***** END LICENSE BLOCK ***** */

import {CmnLib, uint, int, getDateStr} from './CmnLib';
import {HArg, IHTag, IVariable, ISetVal, typeProcVal, ISysBase, IData4Vari, IMark} from './CmnInterface';
import {Config} from './Config';
import {Areas} from './Areas';
import {PropParser} from './PropParser';

export class Variable implements IVariable {
	private	hScope	: any	= {sys:{}, save:{}, tmp:{}, mp:{}};
	private	hSave	: any	= this.hScope.save;
	private	hTmp	: any	= this.hScope.tmp;


	constructor(private readonly cfg: Config, hTag: IHTag) {
		//	変数操作
		hTag.let			= o=> this.let(o);			// 変数代入・演算
		hTag.let_abs		= o=> this.let_abs(o);		// 絶対値
		hTag.let_char_at	= o=> this.let_char_at(o);	// 文字列から一字取りだし
		hTag.let_index_of	= o=> this.let_index_of(o);	// 文字列で検索
		hTag.let_length		= o=> this.let_length(o);	// 文字列の長さ
		// let_mlはScriptIteratorにて定義				// インラインテキスト代入
		hTag.let_replace	= o=> this.let_replace(o);	// 正規表現で置換
		hTag.let_round		= o=> this.let_round(o);	// 四捨五入
		hTag.let_search		= o=> this.let_search(o);	// 正規表現で検索
		hTag.let_substr		= o=> this.let_substr(o);	// 文字列から抜きだし

		//	デバッグ・その他
		hTag.clearsysvar	= ()=> this.clearsysvar();	// システム変数の全消去
		hTag.clearvar		= ()=> this.clearvar();		// ゲーム変数の全消去
		hTag.dump_val		= ()=> this.dump_val();		// 変数のダンプ

		// しおり
		hTag.copybookmark	= o=> this.copybookmark(o);	// しおりの複写
		hTag.erasebookmark	= o=> this.erasebookmark(o);// しおりの消去
		//hTag.load			// ScriptIterator.ts内で定義	// しおりの読込
		//hTag.record_place	// ScriptIterator.ts内で定義	// セーブポイント指定
		//hTag.save			// ScriptIterator.ts内で定義	// しおりの保存

		// save:
		this.hSave['sn.userFnTail']	= '';
		this.defTmp('const.sn.bookmark.json', ()=> {
			const a: object[] = [];
			Object.keys(this.data.mark).sort().forEach(k=> {
				const o = {...this.data.mark[k].json};
				for (const key in o) {
					const v = o[key];
					if (typeof v != 'string') continue;
					if (v.substr(0, 10) != 'userdata:/') continue;
					o[key] = cfg.searchPath(v);
				}
				o.place = k;
				a.push(o);
			});
			return JSON.stringify(a);
		});

		// tmp:
		this.hTmp['const.sn.isFirstBoot'] = true;

		this.hTmp['sn.tagL.enabled'] = true;	// 頁末まで一気に読み進むか(l無視)
		this.hTmp['sn.skip.all']	= false;	// falseなら既読のみをスキップ
		this.hTmp['sn.skip.enabled'] = false;	// 次の選択肢(/未読)まで進むが有効か
		this.hTmp['sn.auto.enabled'] = false;	// 自動読みすすみモードかどうか

		this.hTmp['const.sn.last_page_text'] = '';

		//this.hTmp['const.sn.mouse.middle']	// ScriptIterator で定義

		//this.hTmp['const.sn.vctCallStk.length']	// ScriptIterator で定義

/*		this.hTmp['const.Stage.supportsOrientationChange']
			= Stage.supportsOrientationChange;
		if (this.hTmp['const.Stage.supportsOrientationChange']) {
			this.hTmp['const.Stage.orientation']
				= ()=> {return stage.orientation;};
			this.hTmp['const.Stage.deviceOrientation']
				= ()=> {return stage.deviceOrientation;};

			const lenSO:uint = stage.supportedOrientations.length;
			for (let iSO:uint=0; iSO<lenSO; ++iSO) {
				this.hTmp['const.Stage.supportedOrientations.'
					+ stage.supportedOrientations[iSO]
				] = true;
			}
		}
		else {
			//	import flash.display.StageOrientation;
			this.hTmp['const.Stage.orientation'] =
			this.hTmp['const.Stage.deviceOrientation'] =
			//		StageOrientation.DEFAULT;
				'default';
		}
*/
		this.hTmp['const.sn.displayState'] = false;
			// const.flash.display.Stage.displayState

		this.hTmp['const.Date.getTime'] = ()=> (new Date).getTime();
		this.hTmp['const.Date.getDateStr'] = ()=> getDateStr();
		this.hTmp['const.Stage.mouseX'] = ()=> {
//			return stage.mouseX;
			return 0;
		};
		this.hTmp['const.Stage.mouseY'] = ()=> {
//			return stage.mouseY;
			return 0;
		};

		this.hTmp['const.sn.platform'] = JSON.stringify(CmnLib.platform);

		this.clearsysvar();
		this.clearvar();

		// prj.json
		this.hTmp['const.sn.config.window.width'] = cfg.oCfg.window.width;
		this.hTmp['const.sn.config.window.height']= cfg.oCfg.window.height;
		this.hTmp['const.sn.config.book.title'] = cfg.oCfg.book.title;
		this.hTmp['const.sn.config.book.version'] = cfg.oCfg.book.version;

		this.hTmp['const.sn.Math.PI'] = Math.PI;


		if (typeof window == 'undefined') return;
		const win: any = window;
		const ac = win['AudioContext'] ?? win['webkitAudioContext'];
		this.hTmp['const.sn.needClick2Play'] = ()=> new ac().state == 'suspended';

		// ダークモード切り替え検知
		const dmmq = window.matchMedia('(prefers-color-scheme: dark)');
		this.hTmp['const.sn.isDarkMode'] = CmnLib.isDarkMode = dmmq.matches;
		dmmq.addListener(e=> this.hTmp['const.sn.isDarkMode'] = CmnLib.isDarkMode = e.matches);
	}


	private	data	: IData4Vari	= {sys:{}, mark:{}, kidoku:{}};
	private	hSys	: any;
	private	hAreaKidoku	: {[name: string]: Areas}	= {};
	setSys(sys: ISysBase) {
		sys.initVal(this.data, this.hTmp, data=> {
			this.data = data;
			this.hSys = this.hScope.sys = this.data.sys;

			for (const fn in this.data.kidoku) {
				const areas = new Areas();
				areas.hAreas = {...this.data.kidoku[fn]};
				this.hAreaKidoku[fn] = areas;
			}

			sessionStorage.clear();
			this.flush_ = (this.cfg.oCfg.debug.variable)
				? ()=> {
					const oSys: any = {};
					Object.keys(this.hSys).forEach(k=> {
						const v = this.hSys[k];
						oSys['sys:'+ k] = (v instanceof Function) ?v(): v;
					});
					sessionStorage[this.cfg.getNs() +'sys'] = JSON.stringify(oSys);

					const oSave: any = {};
					Object.keys(this.hSave).forEach(k=> {
						const v = this.hSave[k];
						oSave['save:'+ k] = (v instanceof Function) ?v(): v;
					});
					sessionStorage[this.cfg.getNs() +'save'] = JSON.stringify(oSave);

					const oTmp: any = {};
					Object.keys(this.hTmp).forEach(k=> {
						const v = this.hTmp[k];
						oTmp[k] = (v instanceof Function) ?v(): v;
					});
					sessionStorage[this.cfg.getNs() +'tmp'] = JSON.stringify(oTmp);

					const oMp: any = {};
					Object.keys(this.hScope.mp).forEach(k=> {
						const v = this.hScope.mp[k];
						oMp[k] = (v instanceof Function) ?v(): v;
					});
					sessionStorage[this.cfg.getNs() +'mp'] = JSON.stringify(oMp);

					const oMark: any = {};
					Object.keys(this.data.mark).forEach(k=> {
						const v = this.data.mark[k];
						oMark[k] = (v instanceof Function) ?v(): v;
					});
					sessionStorage[this.cfg.getNs() +'mark'] = JSON.stringify(oMark);

					const oKidoku: any = {};
					Object.keys(this.data.kidoku).forEach(k=> {
						const v = this.data.kidoku[k];
						oKidoku[k] = (v instanceof Function) ?v(): v;
					});
					sessionStorage[this.cfg.getNs() +'kidoku'] = JSON.stringify(oKidoku);

					sys.flush();
				}
				: ()=> sys.flush();
		});
	}
	private flush_	= ()=> {};
	flush() {this.flush_();}	// 先にこのメソッドへの参照を配ってしまうので、中身を入れ替える

	setDoRecProc(doRecProc: (doRec: boolean)=> void) {
		this.doRecProc = doRecProc;
	}
	private	doRecProc = (_doRec: boolean)=> {};

	defTmp(name: string, fnc: typeProcVal): void {this.hTmp[name] = fnc;};
	cloneMp(): object {return {...this.hScope.mp}}
	setMp(mp: object) {this.hScope.mp = mp;}
	setMark(place: number, mark: IMark) {this.data.mark[place] = mark; this.flush()}
	readonly	getMark = (place: number)=> this.data.mark[place];
	cloneSave(): object {return {...this.hScope.save}}
	mark2save(mark: IMark) {
		this.hSave = this.hScope.save = {...mark.hSave};
		this.$doRecLog	= this.hSave['sn.doRecLog'] ?? false;
	}


	// 既読系
	loadScrWork(fn: string): void {
		if (! (fn in this.hAreaKidoku)) this.hAreaKidoku[fn] = new Areas;
	}
	getAreaKidoku = (fn: string): Areas=> this.hAreaKidoku[fn];
	saveKidoku(): void {
		for (const fn in this.hAreaKidoku) {
			this.data.kidoku[fn] = {...this.hAreaKidoku[fn].hAreas};
		}
		this.flush();
	}


		// しおり
	// しおりの複写
	private copybookmark(hArg: HArg) {
		if (! ('from' in hArg)) throw 'fromは必須です';
		if (! ('to' in hArg)) throw 'toは必須です';

		const from = Number(hArg.from);
		const to = Number(hArg.to);
		if (from != to) this.setMark(to, {...this.data.mark[from]});

		return false;
	}

	// しおりの消去
	private erasebookmark(hArg: HArg) {
		const place = hArg.place;
		if (! place) throw 'placeは必須です';

		delete this.data.mark[place];
		this.flush();

		return false;
	}


		//	変数操作
	// 変数代入・演算
	private let(hArg: HArg) {
		if (! hArg.name) throw 'nameは必須です';

		let autocast = true;
		if (hArg.cast) {
			//switch (trim(hArg.cast)) {
			switch (hArg.cast) {
			case 'num':
				CmnLib.argChk_Num(hArg, 'text', NaN);
				break;
			case 'int':
				hArg.text = String(int(CmnLib.argChk_Num(hArg, 'text', NaN)));
				break;
			case 'uint':
				hArg.text = String(uint(CmnLib.argChk_Num(hArg, 'text', NaN)));
				break;
			case 'bool':
				CmnLib.argChk_Boolean(hArg, 'text', false);
				break;
			case 'str':
				autocast = false;
				break;
			default:
				throw 'cast【'+ hArg.cast +'】は未定義です';
			}
		}

		this.setVal(hArg.name, hArg.text, autocast);

		return false;
	}

	// 絶対値
	private let_abs(hArg: HArg) {
		const n = CmnLib.argChk_Num(hArg, 'text', 0);
		//hArg.text = Math.abs(n);
		hArg.text = String((n < 0) ?-n :n);
			// JavaScriptのMath.abs()で絶対値を取得しないほうが良い理由 | iwb.jp https://iwb.jp/javascript-math-abs-deprecated/
			// 数値以外だとほとんどがNaNを返し、booleanは0や1を返しているため使い方によってはバグの原因になることがある。
		this.let(hArg);

		return false;
	}

	// 文字列から一字取りだし
	private let_char_at(hArg: HArg) {
		hArg.text = (hArg.text ?? '').charAt(CmnLib.argChk_Num(hArg, 'pos', 0));
		this.let(hArg);

		return false;
	}

	// 文字列で検索
	private let_index_of(hArg: HArg) {
		const val = hArg.val;
		if (! val) throw 'valは必須です';
		const start = CmnLib.argChk_Num(hArg, 'start', 0);

		hArg.text = String((hArg.text ?? '').indexOf(val, start));
		this.let(hArg);

		return false;
	}

	// 文字列の長さ
	private let_length(hArg: HArg) {
		hArg.text = String((hArg.text ?? '').length);
		this.let(hArg);

		return false;
	}

	// 正規表現で置換
	private let_replace(hArg: HArg) {
		if (! hArg.reg) throw 'regは必須です';

		const flags = hArg.flags;
		const reg = (! flags)
			? new RegExp(hArg.reg)
			: new RegExp(hArg.reg, flags);
		hArg.text = String(hArg.text ?? '').replace(reg, String(hArg.val));
		this.let(hArg);

		return false;
	}

	// 四捨五入
	private let_round(hArg: HArg) {
		const n = CmnLib.argChk_Num(hArg, 'text', 0);
		hArg.text = String(Math.round(n));
		this.let(hArg);

		return false;
	}

	// 正規表現で検索
	private let_search(hArg: HArg) {
		if (! hArg.reg) throw 'regは必須です';

		const flags = hArg.flags;
		const reg = (! flags)
			? new RegExp(hArg.reg)
			: new RegExp(hArg.reg, flags);
		hArg.text = String((hArg.text ?? '').search(reg));
		this.let(hArg);

		return false;
	}

	// 文字列から抜きだし
	private let_substr(hArg: HArg) {
		const i = CmnLib.argChk_Num(hArg, 'pos', 0);
		hArg.text = (hArg.len != 'all')
			? (hArg.text ?? '').substr(i, int(CmnLib.argChk_Num(hArg, 'len', 1)))
			: (hArg.text ?? '').substr(i);
		this.let(hArg);

		return false;
	}


// デバッグ・その他
	// システム変数の全消去
	private clearsysvar() {
		const sys = this.hSys = this.hScope['sys'] = this.data.sys = {};

		const is_nw = (typeof process !== 'undefined');
		if (is_nw) {
		//	//	this.setVal_Sub('sys:const.sn.window.x', stage.nativeWindow.x);
		//	//	this.setVal_Sub('sys:const.sn.window.y', stage.nativeWindow.y);
		}
		else {
			this.setVal_Nochk('sys', 'const.sn.window.x', 0);
			this.setVal_Nochk('sys', 'const.sn.window.y', 0);
		}

		// 文字表示Waitをかけるか
		this.setVal_Nochk('sys', 'sn.tagCh.doWait', true);
		this.setVal_Nochk('sys', 'sn.tagCh.doWait_Kidoku', true);	// 【既読】
		// 文字表示Wait時間
		this.setVal_Nochk('sys', 'sn.tagCh.msecWait', this.cfg.oCfg.init.tagch_msecwait);
		this.setVal_Nochk('sys', 'sn.tagCh.msecWait_Kidoku', this.cfg.oCfg.init.tagch_msecwait);
			// 【既読】
		// 文字表示Wait中スキップのモード
		this.setVal_Nochk('sys', 'sn.tagCh.canskip', true);

		// スキップのモード
		this.setVal_Nochk('sys', 'sn.skip.mode', 's');	// l, p, s

		// 自動読みすすみモード時の改ページ時のウェイト
		//	//	runFirst_sys_an_auto_msecPageWait('sn.auto.msecPageWait', '');
		this.setVal_Nochk('sys', 'sn.auto.msecPageWait', CmnLib.argChk_Num(sys, 'sn.auto.msecPageWait', this.cfg.oCfg.init.auto_msecpagewait ?? 3500));
		this.setVal_Nochk('sys', 'sn.auto.msecPageWait_Kidoku', CmnLib.argChk_Num(sys, 'sn.auto.msecPageWait', this.cfg.oCfg.init.auto_msecpagewait ?? 3500));
		// 自動読みすすみモード時の行クリック待ち時のウェイト
		this.setVal_Nochk('sys', 'sn.auto.msecLineWait', 500);
		this.setVal_Nochk('sys', 'sn.auto.msecLineWait_Kidoku', 500);	// 【既読】

		//	SoundMixer.soundTransform = new SoundTransform(
		//		(sys['flash.media.SoundMixer.soundTransform.volume'] = 1)
		//	);
		this.setVal_Nochk('sys', 'const.sn.sound.BGM.volume', 1);
		this.setVal_Nochk('sys', 'const.sn.sound.SE.volume', 1);
		this.setVal_Nochk('sys', 'const.sn.sound.SYS.volume', 1);
		for (const fn in this.data.kidoku) this.data.kidoku[fn].hAreas = {};


		this.setVal_Nochk('sys', 'TextLayer.Back.Alpha', 0.5);


		this.hScope['mark'] = this.data.mark = {};
		this.setVal_Nochk('sys', 'const.sn.save.place', 1);


		this.flush();

		return false;
	}

	// ゲーム変数の全消去
	private clearvar() {
		const mesLayer	= this.hSave['const.sn.mesLayer'] ?? '';
		const doRecLog	= this.hSave['sn.doRecLog'] ?? false;
		const sLog		= this.hSave['const.sn.sLog'] ?? '';

		this.hSave = this.hScope.save = {};

		this.setVal_Nochk('save', 'const.sn.mesLayer', mesLayer);
		this.setVal_Nochk('save', 'sn.doRecLog', doRecLog);
		this.setVal_Nochk('save', 'const.sn.sLog', sLog);

		return false;
	}

	private readonly setVal = (arg_name: string, val: any, autocast = true)=> {
		if (! arg_name) throw '[変数に値セット] nameは必須です';
		if (val == null) throw '[変数に値セット] textは必須です（空文字はOK）';

		const o = PropParser.getValName(arg_name);
		if (o == undefined) throw '[変数参照] name('+ arg_name +')が変数名として異常です';

		const hScope = this.hScope[o.scope];
		if (! hScope) throw '[変数に値セット] scopeが異常【'+ o.scope +'】です';

		const nm = o['name'];
		if (nm.slice(0, 6) == 'const.' && (nm in hScope)) {
			throw '[変数に値セット] 変数【'+ nm +'】は書き換え不可です';
		}

		this.setVal_Nochk(o.scope, nm, val, autocast);
	}
	setVal_Nochk(scope: string, nm: string, val: any, autocast = false) {
		const hScope = this.hScope[scope];
		if (autocast) val = this.castAuto(val);
		hScope[nm] = val;

		const trg = this.hValTrg[scope +':'+ nm];
		if (trg != null) trg(nm, val);

		// if (scope == 'sys') this.flush()
			// 厳密にはここですべきだが、パフォーマンスに問題があるので
			// クリック待ちを期待できるwait、waitclick、s、l、pタグで
			// saveKidoku()をコール。（中で保存しているのでついでに）

		//console.log(`\tlet s[${scope}] n[${nm}]='${val}' trg[${(trg != null)}]`);
	}

	readonly getVal = (arg_name: string, def?: number | string)=> {
		if (! arg_name) throw '[変数参照] nameは必須です';

		const o = PropParser.getValName(arg_name);
		if (o == undefined) throw '[変数参照] name('+ arg_name +')が変数名として異常です';

		const hScope = this.hScope[o['scope']];
		if (! hScope) throw '[変数参照] scopeが異常【'+ o['scope'] +'】です';

		const name = o['name'];
		let val = hScope[name];
		if (! (name in hScope)) {
			val = def;

			const aNm = name.split('.');
			const len = aNm.length;
			let nm = '';
			for (let i=0; i<len; ++i) {
				nm += '.'+ aNm[i];
				const bn = nm.slice(1);
				if (! (bn in hScope)) continue;

				val = JSON.parse(hScope[bn]);
				while (++i < len) {
					if (! (aNm[i] in val)) {val = def; break;}
					val = val[aNm[i]];
				}
				if (val instanceof Object) val = JSON.stringify(val);
				break;
			}
		}
		if (val instanceof Function) val = (val as Function)();
		//console.log('\tget ['+ arg_name +'] -> s['+ o['scope'] +'] a['+ o['at'] +'] n['+ name +'] ret['+ val +']('+ typeof val +')');

		if (o['at'] == '@str') return val;

		return this.castAuto(val);
	}

	private castAuto(val: Object): any {
		const s_val = val as string;
		if (s_val == 'true') return true;
		if (s_val == 'false') return false;
		if (s_val == 'null') return null;
		if (s_val == 'undefined') return undefined;
		this.REG_NUMERICLITERAL.lastIndex = 0;
		if (this.REG_NUMERICLITERAL.test(s_val)) return parseFloat(s_val);

		return val;
	}
	private REG_NUMERICLITERAL	:RegExp	= /^-?[\d\.]+$/;


	// 変数のダンプ
	private readonly dump_val = ()=> {
		const val: any = {tmp:{}, sys:{}, save:{}, mp:{}};
		for (let scope in val) {
			const hVal = this.hScope[scope];
			const hRet = val[scope];
			for (let key in hVal) {
				const v = hVal[key];
				if (Object.prototype.toString.call(v) == '[object Function]') {
					hRet[key] = v();
				}
				else hRet[key] = v;
			}
		}
		console.info('🥟 [dump_val]', val);

		return false;
	}

	private	$doRecLog	= false;
	doRecLog() {return this.$doRecLog;}


	private hValTrg	: {[name: string]: ISetVal}	= {
		// sys
		'sys:sn.tagCh.doWait'			: name=>
			this.runFirst_Bool_hSysVal_true(name),
		'sys:sn.tagCh.doWait_Kidoku'	: name=>
			this.runFirst_Bool_hSysVal_true(name),
		'sys:sn.tagCh.msecWait'			: name=>
			this.runFirst_sys_an_tagCh_msecWait(name),
		'sys:sn.tagCh.msecWait_Kidoku'	: name=>
			this.runFirst_sys_an_tagCh_msecWait_Kidoku(name),
		'sys:sn.tagCh.canskip'			: name=>
			this.runFirst_Bool_hSysVal_true(name),

		'sys:sn.auto.msecPageWait'			: name=>
			this.runFirst_sys_an_auto_msecPageWait(name),
		'sys:sn.auto.msecPageWait_Kidoku'	: name=>
			this.runFirst_sys_an_auto_msecPageWait(name),
		'sys:sn.auto.msecLineWait'			: name=>
			this.runFirst_sys_an_auto_msecLineWait(name),
		'sys:sn.auto.msecLineWait_Kidoku'	: name=>
			this.runFirst_sys_an_auto_msecLineWait(name),

		// save
		'save:sn.doRecLog'		: name=> {
			this.doRecProc(
				this.$doRecLog = this.runFirst_Bool_hSaveVal_true(name)
			);
		},
		'save:sn.userFnTail'	: (_name, val)=> this.cfg.userFnTail = val,

		// tmp
		'tmp:sn.tagL.enabled'	: name=>
			this.runFirst_Bool_hTmp_true(name),
		'tmp:sn.skip.all'		: name=>
			this.runFirst_Bool_hTmp_false(name),
		'tmp:sn.skip.enabled'	: name=>
			this.runFirst_Bool_hTmp_false(name),
		'tmp:sn.auto.enabled'	: name=>
			this.runFirst_Bool_hTmp_false(name),
		'tmp:flash.desktop.NativeApplication.nativeApplication.systemIdleMode'	: (
			()=> {
			//	NativeApplication.nativeApplication.systemIdleMode = val;
			}
		),
		'tmp:sn.chkFontMode'
		: ()=> {
			if (this.hTmp['const.sn.onLauncher']) return;
			if (! this.hTmp['const.sn.isDebugger']) return;

			//	Hyphenation.chkFontMode = CmnLib.argChk_Boolean(this.hTmp, name, true)
		}
	};
	defValTrg(name: string, fnc: ISetVal) {this.hValTrg[name] = fnc;}
	private runFirst_Bool_hSysVal_true(name: string): void {
			CmnLib.argChk_Boolean(this.hSys, name, true);
		}
	private runFirst_sys_an_tagCh_msecWait(name: string): void {
			CmnLib.argChk_Num(this.hSys, name, 10);
			if (this.hSys['sn.tagCh.doWait']) {
//				LayerMng.msecChWait = this.hSysVal[name];
			}
		}
	private runFirst_sys_an_tagCh_msecWait_Kidoku(name: string): void {
		CmnLib.argChk_Num(this.hSys, name,
			(this.cfg.oCfg.init.tagch_msecwait == undefined)
				? 10
				: this.cfg.oCfg.init.tagch_msecwait
		);
		if (this.hSys['sn.tagCh.doWait_Kidoku']) {
//			LayerMng.msecChWait = this.hSysVal[name];
		}
	}
	private runFirst_sys_an_auto_msecPageWait(name: string): void {
		CmnLib.argChk_Num(this.hSys, name,
			(this.cfg.oCfg.init.auto_msecpagewait == undefined)
				? 3500
				: this.cfg.oCfg.init.auto_msecpagewait
		);
	}
	private runFirst_sys_an_auto_msecLineWait(name: string): void {
		CmnLib.argChk_Num(this.hSys, name, 500);
	}

	private runFirst_Bool_hSaveVal_true(name: string) {
		return CmnLib.argChk_Boolean(this.hSave, name, true);
	}

	private runFirst_Bool_hTmp_true(name: string): void {
		CmnLib.argChk_Boolean(this.hTmp, name, true);
	}
	private runFirst_Bool_hTmp_false(name: string): void {
		CmnLib.argChk_Boolean(this.hTmp, name, false);
	}

};
