// varTmplの有無のチェック
function isTmpltLi($li, tmplNm){
	if($li.find('.varTmpl[name=' + tmplNm + ']').length>0){
		return true;
	}
	return false;
}

// 変数のコードテンプレートをコピー
function copyVarTmplt(tmplNm) {
	$('.varTmpl[name=' + tmplNm + ']').each(function() {
        let $tmplRow = $(this);
       	let $Li = $tmplRow.closest('li');
        let $prevLi = $Li.prev();
		let $nextLi = $Li.next();

		// 最終のLiを検索
		var $posLi = $Li;
		var $posNextLi = $posLi.next();
		
		while(isTmpltLi($posNextLi, tmplNm)){
			$posLi = $posNextLi;
			$posNextLi = $posLi.next();
		}
		
		// 挿入位置を検索
		var $pos = $posLi.find('.varTmpl[name=' + tmplNm + ']').first();
		var $next = $pos.next();
		
		while($next.hasClass('varTmplCpy') || ($next.hasClass('varTmpl') && $next.attr("name")==tmplNm )){
			$pos = $next;
			$next = $next.next();
		}
		
		let $copy = $tmplRow.clone();

		// user-select: none が指定されている要素を除去
		$copy.find('.no-select').remove();
		$copy.find('._m').remove();

		// classの_varのnameを変更
		$copy.removeClass('varTmpl');
		$copy.addClass('varTmplCpy');

		// コピーの回数
		var cnt = 1;
		let m_cnt = $tmplRow.attr('m_cnt');
		if(m_cnt){
			cnt = parseInt(m_cnt, 10);
			cnt++;
		}
	
		$tmplRow.attr('m_cnt', cnt);	// 例: "1-"
		let prefix = cnt + "-";
		
		// _var 名置換
		$copy.find('._var').each(function() {
			let curNm = $(this).attr('name');
			if (curNm) {
				$(this).attr('name', prefix + curNm);
			}
		});
	
		if($tmplRow.hasClass('addCR') && isTmpltLi($prevLi, tmplNm)==false && isTmpltLi($nextLi, tmplNm)==true){
		    // １行目の場合は改行を2つ追加
		    $copy.removeClass('addCR');
		    var newline = document.createTextNode('\n');
		    var newline2 = document.createTextNode('\n');
		    $pos.after(newline, newline2, $copy[0]);
		} else if ($tmplRow.hasClass('addCR')) {
		    // 通常の改行を1つ追加
		    $copy.removeClass('addCR');
		    var newline = document.createTextNode('\n');
		    $pos.after(newline, $copy[0]);
		} else{
		 	// 改行なしでそのまま挿入
			$copy.insertAfter($pos);
		}
	});
}

// ファイル保存
function saveFile(fnm, content) {
    const blob = new Blob([content], { type: 'text/html' });
    const url = URL.createObjectURL(blob);
    const $a = $('<a>')
        .attr('href', url)
        .attr('download', fnm)
        .css('display', 'none')
        .appendTo('body');

    $a[0].click(); // jQueryオブジェクトからDOM要素を取り出してクリック
    $a.remove();   // 後片付け
    URL.revokeObjectURL(url); // メモリ解放
}

// 例、loadScript('path/to/your/script.js')
// loadConst2("OPE");
// alert(typeof C2_OPE);
function loadScript(uri) {
    var script = document.createElement('script');
    script.src = uri;
    script.type = 'text/javascript';
    script.async = true;  // スクリプトを非同期に実行
    document.head.appendChild(script);
        
    return new Promise((resolve, reject) => {
		script.onload = function() { 
			//alert(uri + " is loaded.");
			resolve("OK");
		};
	});
}

async function loadConst2(nm) {
    if (typeof window["C2_" + nm] === 'undefined') {
    	var uri = "./const2/" + nm + ".js";
    	await loadScript(uri).then((message) =>{
    		//alert(typeof C2_OPE);
    		null;
    	});
    }
}

function scrollToId_Evt(ele){
	let $ele = $(ele);
	let id = $ele.attr("m_ref_id");
	let scrollFlg = true;
	
	if(id === null || id === undefined){
		id = $ele.attr("id");
		scrollFlg = false;
	}

	// idが定義されない場合、処理終了
	if(id === null || id === undefined){
		return;
	}
	
	scrollToId(id, scrollFlg);
}

// 例、onclick="scrollToId('MCS_0149_5')"
function scrollToId(id, scrollFlg){
	// 対象の要素を取得
	var trgtEle = document.getElementById(id);
	var $trgtEle= $(trgtEle);
	
	if(scrollFlg){
		// 親要素を取得
		var prntEle = $trgtEle.closest('pre').get(0);

		// 要素の位置を取得
		const rect = trgtEle.getBoundingClientRect();
		const parentRect = prntEle.getBoundingClientRect();
		const offsetTop = rect.top - parentRect.top + prntEle.scrollTop;
		// 要素の位置までスクロール
		prntEle.scrollTo({ top: offsetTop - 8, behavior: 'smooth' });
	}

	let setMarkFlg = true;
	if($trgtEle.hasClass("mark")){
		setMarkFlg = false;
	}
	
	// highlight表示を
    let $eles = $('.mark'); // クラス名を持つ要素を取得
    $eles.removeClass("mark");
    
	if(setMarkFlg == true){
		$eles = $('#' + id + ', [m_ref_id="' +  id + '"]');
		$eles.addClass("mark");
	}
}

function getLvl($cur_lvl){
	var lvl_num = "";
	
	// 要素の _lvlX を取得
	if($cur_lvl.hasClass("_lvl1")){
		lvl_num = "_lvl1";
	}
	else if($cur_lvl.hasClass("_lvl2")){
		lvl_num = "_lvl2";
	}
	else if($cur_lvl.hasClass("_lvl3")){
		lvl_num = "_lvl3";
	}
	else if($cur_lvl.hasClass("_lvl4")){
		lvl_num = "_lvl4";
	}
	
	return lvl_num;
}

function toggle_tree2(ele, initFlg){
	$ele = $(ele);
	
	// 前の_lvl 要素を検索
	$cur_lvl = $ele.prevAll("._lvl").first();
	var lvl_num = getLvl($cur_lvl);
	
	if($cur_lvl.length>0){
		// 次の_lvl 要素を検索
		$next_lvl = $ele.nextAll("._lvl" + "."+lvl_num).first();
		
		if($next_lvl.length>0 && getLvl($next_lvl) >= lvl_num){			
			$chd_lvls = $ele.nextUntil("."+lvl_num).not(':last');
			if($chd_lvls.length > 0 && $chd_lvls.last().hasClass("pln")){
				$chd_lvls = $chd_lvls.not(':last');
			}
		}else{
			// 終了前
			$chd_lvls = $ele.nextUntil();
		}
		
		if( (initFlg == false && $ele.hasClass("collpdBtn")) || (initFlg == true && $ele.hasClass("expdBtn"))){
			// 閉めるボタン
			//$next_lvl.addClass("collpd");		// collapse非表示
			$chd_lvls.addClass("collpd");		// collapse非表示
		}
		else{
			// 展開
			//$next_lvl.removeClass("collpd");
			$chd_lvls.removeClass("collpd");
		}
	}
	
	if(initFlg == false){
		if($ele.hasClass("collpdBtn")){
			// 閉めるボタン
			$ele.removeClass("collpdBtn");
			$ele.addClass("expdBtn");
		}
		else{
			// 展開
			$ele.removeClass("expdBtn");
			$ele.addClass("collpdBtn");
		}
	}
}

function toggle_tree(ele){
	toggle_tree2(ele, false);
}

function popup(url) {
    window.open(url, '_blank', 'menubar=0,width=1000,height=500,top=100,left=100');
}

// ClipBoardへコピー
function copyToClipboard(codeId, display_varnm = 1) {
    // コピー対象をJavaScript上で変数として定義する
    var copyTarget = document.getElementById(codeId);
	copyToClipboard_Target(copyTarget, null, display_varnm);
}

/*
 * file_nm: null: clipboard
 * display_varnm: 1:変換しない	2:変数名を表示 3:{A}～へ変更
 */
function copyToClipboard_Target(copyTarget, file_nm, display_varnm) {
	// no-selectの内容を待機
	var noSelEles = $(copyTarget).find('.no-select');
	const noSelTxts = new Array(noSelEles.length);
	
	for (let i = 0; i < noSelEles.length; i++) {
		$ele = $(noSelEles[i]);
		//alert($ele.text());
		noSelTxts[i] = $ele.text();
		$ele.text("");
	}

	// 変数の内容を待機
	let varTxts = [];
	let varEles = [];

	if(display_varnm != 1){
		let dict = {};
		varEles = $(copyTarget).find('._var');
		varTxts = new Array(varEles.length);

		for (let i = 0; i < varEles.length; i++) {
			$ele = $(varEles[i]);
			varTxts[i] = $ele.text();
			//alert($ele.prop("name"));		// null
			//alert($ele.attr("name"));		// OK
			
			varNm = $ele.attr("name");
			
			if(display_varnm == 2){
				$ele.text(varNm);
			}

			if(display_varnm == 3){
				$ele.text(getPosReplaceVar(varNm, dict));
			}
		}
	}
	
	// 内容出力
    navigator.clipboard.writeText(copyTarget.innerText.replace(/\u00A0/g, ' '));

    // コピー対象のテキストを選択する
    //copyTarget.select();

    // 選択しているテキストをクリップボードにコピーする
    //document.execCommand("Copy");
    
    // no-selectの内容を復旧
	for (let i = 0; i < noSelEles.length; i++) {
		$ele = $(noSelEles[i]);
		$ele.text(noSelTxts[i]);
	}

	if(display_varnm != 1){	
		// 変数の内容を復旧
		for (let i = 0; i < varEles.length; i++) {
			$ele = $(varEles[i]);
			$ele.text(varTxts[i]);
		}
	}
}

// 頭文字を大文字へ変更
function firstUpper(s)
{
    return s && s[0].toUpperCase() + s.slice(1);
}

function firstLower(s)
{
    return s && s[0].toLowerCase() + s.slice(1);
}


// Proper
function properCase(str, removeUnderBar) {
	if(typeof removeUnderBar === 'undefined'){
		removeUnderBar = false;
	}
	
    str = str.toLowerCase().replace(/\b\w/g, function(char) {
        return char.toUpperCase();
    }).replace(/_\w/g, function(char) {
        return char.toUpperCase();
    });
    
    if(removeUnderBar){
		str = str.replaceAll("_", "");
	}
	
	return str;
}

// 半角→全角(英数字)
function replaceHalfToFull(str){
  return str.replace(/[!-~]/g, function(s){
    return String.fromCharCode(s.charCodeAt(0) + 0xFEE0);
  });
}

// 全角→半角(英数字)
function replaceFullToHalf(str){
  return str.replace(/[！-～]/g, function(s){
    return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
  });
}

// 順番数字を算出
// cur: 現在値、orgVal: 開始の順番値、変更後の値
function getSeq(curOrgVal, val, orgVal){
	var orgValh = replaceFullToHalf(orgVal);
	var fullWidthFlg = false;
		
	if( orgValh != orgVal){
		fullWidthFlg = true;	// 全角出力
	}
	
	curOrgVal =  replaceFullToHalf(curOrgVal);
	val =  replaceFullToHalf(val);
	
	var tmp = Number(curOrgVal) - Number(orgValh) + Number(val);
	
	if(fullWidthFlg == true){
		tmp = replaceHalfToFull( String(tmp) );
	}

	return tmp;
}

$(document).ready(function(){
	// 保存
	$('._flnmBtn').click(function() {
	    var $target = $(event.target);
	    
	    var $flnm = $target.closest('._flnm');
	    var flId = $flnm.attr("name");
	    var flNm = $flnm.text().replace(/\u00A0/g, ' ');

		var $rgn = $flnm.closest('tr._src');
	    var $eles = $rgn.find('._fl[name="' + flId + '"]');
	    var content = "";

		// no-selectの内容を待機
		var noSelEles = $eles.find('.no-select');
		const noSelTxts = new Array(noSelEles.length);

		for (let i = 0; i < noSelEles.length; i++) {
			$ele = $(noSelEles[i]);
			//alert($ele.text());
			noSelTxts[i] = $ele.text();
			$ele.text("");
		}
		
		// 選択内容を選択
		if ($eles.length > 0) {
		    content = $eles
		        .filter(':visible')
		        .map(function() {
		            return this.innerText.replace(/\u00A0/g, ' ');
		        })
		        .get()
		        .join('\n');
		}

		// no-selectの内容を復旧
		for (let i = 0; i < noSelEles.length; i++) {
			$ele = $(noSelEles[i]);
			$ele.text(noSelTxts[i]);
		}

		// ファイルを保存
	    saveFile(flNm, content);
	});
	
	// テンプレート
	$('.tmpl').click(function() {
		var $target = $(event.target);
		
		$('#txt_TmplDialog_Val1').text(decodeURIComponent($target.text().replace(/\+/g, ' ')));
		tmplDialog.showModal();
	});
	
	// _midx
	$('._midx').each(function(idx, ele) {
		$ele = $(ele);
		
		 // インデックス文字列を取得（m_idxstr → m_index の順で）
		var s_idx = $ele.attr('m_idxstr') ;
		if( s_idx == null) s_idx = $ele.attr('m_index') ;
		
		var s_html = "<span class='no-select i'>" + s_idx + "．" + "</span>";
		
		var $prevEle = $ele.prev();
		$ele.before(s_html);
	});
	
	// expdBtn
	$('.expdBtn').each(function(idx, ele) {
		toggle_tree2(ele, true);
	});
	
	// markdown処理
    var md = window.markdownit({ html: true });
	mermaid.initialize({ startOnLoad: true });

	function convertMarkdownToHtml($ele) {
		var markdownText = $ele.text();
		var html = md.render(markdownText);
		//alert(html);
		$ele.html(html);
		
		//<pre><code class="language-mermaid"
		const codeMermaids = $ele.find('code.language-mermaid');
		
		for (let i = 0; i < codeMermaids.length; i++) {
			$code = $(codeMermaids[i]);
			$pre = $code.closest('pre');
			$pre.html("<div class='mermaid'>" + $code.text() + "</div>")
		}
	
		mermaid.init();
		
	}

	$('.markdown').each(function(idx, ele){
		$ele = $(ele);
		convertMarkdownToHtml($ele);
	});

	setupOptDialog();
	setupVarDialog();
	setupModeDialog();
	
	// id
	$('.todo, .e, .i, .refMrk').click(function() {
		scrollToId_Evt(this);
	});
});

// Optionのタイトルを取得
function getOptTitle(eleVal, opts){
	for(let i = 0; i < opts.length; i++) {
		if(opts[i].split(":")[0] == eleVal){
			return opts[i].split(":")[1];
		}
	}
	
	return null;
}

function setModeBefore(){
	// class = "_m" 項目を取得ループ
	$('._m').each(function(idx, ele) {
		$ele = $(ele);
		var eleVal = $ele.attr('m_value');
		var eleOpts = $ele.attr('m_option');
		var opts = eleOpts.split(',');
		var eleTitle = getOptTitle(eleVal, opts);
		
		var s_html = "<span class='no-select' m_value='" + eleVal + "' title='" + eleOpts + "'>[" + $ele.attr("title") + ": 「" + eleVal + ":" + eleTitle + "」]</span>";
		
		var $prevEle = $ele.prev();
		if($prevEle.hasClass("no-select")){
			if( eleVal != $prevEle.attr('m_value')){
				$prevEle.remove();
				$ele.before(s_html);
			}
		}
		else{
			$ele.before(s_html);
		}
	});
}

let dict_mode = {}; // 空の辞書を作成

function setDictMode($ele){
  dict_mode = {}; // 毎回初期化

  // 親の <pre> 要素を取得
  const $pre = $ele.closest('pre');

  // _m クラスを持つ要素をすべて取得
  const $defs = $pre.find('._m');
	
  // 各要素から name と m_value を取得して辞書に格納
  $defs.each(function () {
    const $def = $(this);
    const name = $def.attr('name');
    const value = $def.attr('m_value');

    if (name) {
      dict_mode[name] = value;
    }
  });
}

// Mode更新
// $ele def定義
function setMode($ele, $rgn, slowFlg){
	let modeNm;
	let tgts;
	
	// $rgn が null なら、先に初期化しておく
	if ($rgn == null && $ele != null) {
		// pre取得 ※ソースの単位
		varDialog_pre = $ele.closest('pre');
		setDictMode($ele);
		$rgn = varDialog_pre;
	}

	if ($ele == null) {
		for (let key in dict_mode) {
			if ($rgn.hasClass(key)) {
				modeNm = key;
				tgts = $rgn;
				break;
			}
		}
	} else {
	  modeNm = $ele.attr('name');
	  tgts = $rgn.find('.' + modeNm);
	}
	
	// class= <modeNm> の項目を取得 ループ
	tgts.each(function(index) {
		// class= <name> + <val> 表示 以外の項目を不表示
		var $ele = $(this);
		var $tgt = $ele;
		
		// 行単位で表示制御
		if( $ele.hasClass("mline")){
			$tgt = $ele.closest('li');
		}
		
		// $tgtが_m_の親がない 又は 表示する時
		// _m_ _m1_ _m1_y mnow ※ 現在値
		// 親モード存在しない OR 親モード＝表示
		if( checkParShow($ele)){
			if($ele.hasClass( modeNm + dict_mode[modeNm])){
				$ele.addClass("mnow");
				if(slowFlg) $tgt.show('slow');
				else $tgt.show();
				
				// 最も浅い階層の ._m_ をすべて取得
				let shallowTargets = $ele.find('._m_').filter(function() {
						return $(this).closest('._m_')[0] === this;
				});

				for (let subTgt of shallowTargets) {
					if ($tgt[0] !== subTgt) {
						setMode(null, $(subTgt), false);
					}
				}
			}
			else{
				$ele.removeClass("mnow");
				if(slowFlg) $tgt.hide('slow');
				else $tgt.hide();
			}
		}
		else{
			$ele.removeClass("mnow");
			if(slowFlg) $tgt.hide('slow');
			else $tgt.hide();
		}
	});
	
	setModeBefore();
}

function checkParShow($ele){
	var $par_mode = $ele.parent().closest('._m_');
	
	if( $par_mode.length ==0){
		return true;
	}

	if( $par_mode.hasClass('mnow')){
		return checkParShow($par_mode);
	}else{
		return false;
	}
}

// 変数置換Dialog設定
function setupModeDialog(){
	var modeDialog = document.getElementById('modeDialog');
	var $curModeEle = null;
	
	// class = "_m" 項目を取得ループ(定義)
	$('._m').each(function(index) {
		var $ele = $(this);
		
		// class = "_m" 項目の名称<name>と値<val>を取得		
		setMode($ele, null, false);
	});
	
	$('._m').click(function() {
		var $ele = $(this);
		var eleName = $ele.attr('name');
		var eleTitle = $ele.attr('title');
		var eleVal = $ele.attr('m_value');
		var eleOpts = $ele.attr('m_option');
			
		// Modeを取得
		$('#lbl_ModeDialog_ModeNm').text(eleTitle);
		
		var $cmb = $('#cmb_ModeDialog_Mode');
		
		$cmb.children('option').remove();
		
		var opts = eleOpts.split(',');
		
		for(let i = 0; i < opts.length; i++) {
  			$cmb.append($("<option>").val(opts[i].split(":")[0]).text(opts[i]));
		}

		$cmb.val(eleVal);
		
		$curModeEle= $ele;
		modeDialog.showModal();
	});

	$('._ml').click(function() {
		var $ele = $(this);
		var eleName = $ele.attr('name');
		var scope = "pre";
		
		// pre取得
		$pre = $ele.closest('pre');
		$rgn = $pre;
		
		if(eleName.startsWith('_g_')){
			scope = "tr";
		}
		
		if(eleName.startsWith('_g2_')){
			scope = "tbody";
		}
		
		if(scope=="tr"){
			$rgn = $pre.closest('tr');
		}
		
		if(scope=="tbody"){
			$rgn = $pre.closest('tbody');
		}
		
		// Linkするeleを取得
		$rgn.find("._m[name='" + eleName +"']").click();
	});
		
	$('#btn_ModeDialog_Cancle').click(function() {
		// Mode Dialogをクローズ
		modeDialog.close();
	});
	
	 $('#btn_ModeDialog_OK').click(function() {
	 	var $cmb = $('#cmb_ModeDialog_Mode');
	 	$curModeEle.attr('m_value',$cmb.val());
	 	setMode($curModeEle, null, true);
	 	
		// Mode Dialogをクローズ
		modeDialog.close();
	});

	$('#btn_TmplDialog_OK').click(function() {
		// Tmpl Dialogをクローズ
		tmplDialog.close();
	});
}

// 選択Dialog設定
// <span class='_opt' m_const2='OPE' m_null='y' m_input='y'>crossJoin</span>
function setupOptDialog(){
	var optDialog = document.getElementById('optDialog');
	var const2_nms = [];
	var optDialog_target;

	// 置換変数処理用パラメータ
	var varDialog_rgn;
	var varScope;		// 0:pre,1:tr,2:tbody
	var varDialog_target;
	var varDialog_name;
	
	// 定数定義をロード
	$('._opt').each(function(index) {
		var $ele = $(this);
		var m_const2 = $ele.attr('m_const2');
		
		if(const2_nms.indexOf(m_const2) == -1){
			const2_nms.push(m_const2);
			loadConst2(m_const2);
		}
	});
	
	$('._opt').click(function() {
		var $ele = $(this);
		
		var m_const2 = $ele.attr('m_const2');
		var m_null = $ele.attr('m_null');
		var m_input = $ele.attr('m_input');
		
		var v2 = window["C2_" + m_const2];
		
		// Dialogの表示設定
		$('#lbl_OptDialog_title').text(v2.label);
		
		var $dlg_help = $('#lbl_OptDialog_help');
		$dlg_help.attr('title', v2.help);
		$dlg_help.off('click');
		$dlg_help.click(function() {
			popup(v2.help);
		});
		
		var $cmb = $('#cmb_OptDialog');
		var $txt = $('#txt_OptDialog');
		$txt.hide();
		
		$cmb.children('option').remove();
		
		if(m_input == 'Y'){
			$cmb.append($("<option>").val("-----").text( "----- : 手入力"));
		}
		
		for(let i = 0; i < v2.options.length; i++) {
			if (v2.options[i].label === null || v2.options[i].label === "") {
				$cmb.append($("<option>").val(v2.options[i].id).text(v2.options[i].id));
			}else{
				$cmb.append($("<option>").val(v2.options[i].id).text(v2.options[i].id + " : " + v2.options[i].label));
			}
		}
		
		// 置換変数として定義がある場合
		if($ele.hasClass("_var")){
			var varInfo = getVarInfo($ele);
			varDialog_rgn = varInfo.varDialog_rgn;
			varScope = varInfo.varScope;
			varDialog_target = varInfo.varDialog_target;
			varDialog_name = varInfo.varDialog_name;
		}
		
		// 選択Dialog表示
		optDialog_target = $ele;
		$cmb.val(optDialog_target.text());
		$cmb.attr('m_const2', m_const2);
		optDialog.showModal();
	});

	$('#cmb_OptDialog').change(function() {
        // 選択された値を取得
        var val = $(this).val();
        var $txt = $('#txt_OptDialog');
        
        var $opt_help = $('#lbl_OptDialog_opt_help');
        
        var m_const2 = $(this).attr('m_const2');
        var v2 = window["C2_" + m_const2];
        
        $opt_help.text("");
        
		for(let i = 0; i < v2.options.length; i++) {
			if (v2.options[i].id === val) {
				$opt_help.text(v2.options[i].help);
				break;
			}
		}
        
        if(val == "-----"){		// 手入力
        	$txt.show();
        }else{
        	$txt.hide();
        }
    });
    
	$('#btn_OptDialog_Cancle').click(function() {
		optDialog.close();
	});

	$('#btn_OptDialog_OK').click(function() {
		var $cmb = $('#cmb_OptDialog');
		var $txt = $('#txt_OptDialog');
		
		var val = $cmb.val();
		if(val == "-----"){		// 手入力
			val = $txt.val();
		}
		
		if(optDialog_target.hasClass("_var")){
			set_vars_action(val, varDialog_rgn, varDialog_name, varDialog_target);
		}else{
			// 置換変数ではない時
			optDialog_target.text(val);
		}
		
		optDialog.close();
	});	 
}

function getDialogRgn($target){
	// 変数の範囲
	var varScope = "pre";
	
	// pre取得
	var varDialog_rgn = $target.closest('pre');
	
	if(varDialog_rgn.length == 0){
		varDialog_rgn = $target.closest('td._src');
	}
	
	var $varObj = $target.closest('._var');
	varDialog_target = $varObj;
	varDialog_name = $varObj.attr('name');
	
	if(varDialog_name.startsWith('vg_')){
		varScope = "tr";
		varDialog_rgn = varDialog_rgn.closest('tr._src');
	}
	
	if(varDialog_name.startsWith('vg2_')){
		varScope = "tbody";
		varDialog_rgn = varDialog_rgn.closest('tbody');
	}
}

// 変数名を取得
function getVarNm(varNm){
  subfix = getVarSubfix(varNm); // サフィックスを取得

  if(subfix != ""){
    varNm = varNm.substring(0, varNm.length - subfix.length); // サフィックスを削除
  }

  return varNm; // サフィックスを除いた変数名を返す
}

function getVarSubfix(varNm) {
  const suffixes = ["PVLF", "PULF", "UL", "UF", "PU", "PV", "LF", "U", "L", "P"];
  return suffixes.find(suffix => varNm.endsWith(suffix)) || "";
}

// 変数名をA、B、Cの位置置換変数へ変換
function getPosReplaceVar(varNm, dict){
  subfix = getVarSubfix(varNm);         // サフィックスを取り出す（例: "PV"）
  varNm = getVarNm(varNm);              // サフィックスを除いた本体（例: "abc"）

  if (!(varNm in dict)){                // まだ辞書に登録されていなければ
    dict[varNm] = Object.keys(dict).length; // 順番に番号を割り振る（0, 1, 2...）
  }

  // 例: dict[varNm] = 0 → 65 = "A" → "{APV}"
  if(subfix == ""){
	return "{" + String.fromCharCode(65 + dict[varNm]) + "}"; 
  }else{
  	return "{" + String.fromCharCode(65 + dict[varNm]) + "." + subfix + "}"; 
  }

}

function getVarInfo($target){
	var varDialog_rgn;
	var varScope;		// 0:pre,1:tr,2:tbody
	var varDialog_target;
	var varDialog_name;
	
	// 変数の範囲
	varScope = "pre";
	
	// pre取得
	varDialog_rgn = $target.closest('pre');

	if(varDialog_rgn.length == 0){
		varDialog_rgn = $target.closest('td._src');
	}
	
	varDialog_target = $target.closest('._var');
	varDialog_name = varDialog_target.attr('name');
	
	if(varDialog_name.startsWith('vg_')){
		varScope = "tr";
		varDialog_rgn = varDialog_rgn.closest('tr._src');
	}
	
	if(varDialog_name.startsWith('vg2_')){
		varScope = "tbody";
		varDialog_rgn = varDialog_rgn.closest('tbody');
	}
	
	varDialog_name = getVarNm(varDialog_name);
	
	return {
		varDialog_rgn: varDialog_rgn,
		varScope: varScope,
		varDialog_target: varDialog_target,
		varDialog_name: varDialog_name
	};
}

// 変数置換Dialog設定
function setupVarDialog(){
	var varDialog = document.getElementById('varDialog');
	var varDialog_rgn;
	var varScope;		// 0:pre,1:tr,2:tbody
	var varDialog_target;
	var varDialog_name;
	var varDict = {};	// Title Dictionary
	
	/// タイトル設定
	// Title Dictionary作成
	$('._var').not('._opt').each(function(index) {
		var $eleVar = $(this);
		if($eleVar.attr('title')){
			varDict[$eleVar.attr('name')]=$eleVar.attr('title');
		}
	});

	$('._var').not('._opt').each(function(index) {
		var $eleVar = $(this);
		if(!$eleVar.attr('title')){
			$eleVar.attr('title', varDict[$eleVar.attr('name')]);
		}
	});
	
	// イベントを「動的に追加される要素」にも効かせたい場合は、イベントの委譲
	$(document).on('click', '._var:not(._opt)', function(event) {
		var $target = $(event.target);
		
		if($target.hasClass("_opt") == false){
			//$('#VarDialog_val').val($target.text());

			var varInfo = getVarInfo($target);
			varDialog_rgn = varInfo.varDialog_rgn;
			varScope = varInfo.varScope;
			varDialog_target = varInfo.varDialog_target;
			varDialog_name = varInfo.varDialog_name;

			var lblVarNm = varDialog_target.attr("title");
			
			if(varDialog_target.attr('inptval')){
				$('#VarDialog_val').val(varDialog_target.attr('inptval'));
			}else{
				$('#VarDialog_val').val(varDialog_target.text());
			}
			
			if(!lblVarNm){
				lblVarNm = "変更後の値を入力してください。";
			}

			$('#lbl_VarDialog_varNm').text(lblVarNm);
			
			// var1を取得
			varDialog.showModal();
		}
	});
	
	$('#btn_VarDialog_Add').click(function() {
		let $varTmpl = varDialog_target.closest('.varTmpl');

        if ($varTmpl.length > 0 ) {
        	let tmplNm = $varTmpl.attr("name");
            copyVarTmplt(tmplNm);
        }
		else {
			alert("変数のテンプレートがありませんでした。");
		}
	});
	
	 $('#btn_VarDialog_Cancle').click(function() {
		// var1を取得
		varDialog.close();
	});

	 $('#btn_VarDialog_OK').click(function() {
	 	var tmp = $('#VarDialog_val').val();
		set_vars_action(tmp, varDialog_rgn, varDialog_name, varDialog_target);
		
		// var1を取得
		varDialog.close();
	});
}

function set_vars_action(tmp, varDialog_rgn, varDialog_name, varDialog_target){
 	varDialog_rgn.find('[name=' + varDialog_name + ']').each( function() {
 		var this$ = $(this);
 		if(this$.attr('inptval')!== undefined){
			this$.attr('inptval', tmp);
		}
		
 		if(this$.attr('orgval')){
 			this$.text( getSeq(this$.attr('orgval'), tmp, varDialog_target.attr('orgval')));
 		}
 		else if(this$.attr('match') || this$.attr('from_idx') || this$.attr('to_idx') || this$.attr('slice')){ 
 			set_var_text(this$, tmp, null); // 一部抽出
 		}
 		else if(this$.attr('user_conv_nm') && user_conv !== undefined){
	 		// user_conv 関数が存在する場合
				this$.text(user_conv(tmp, this$.attr('user_conv_nm')));
 		}
 		else{
 			 this$.text(tmp);
		}
 	});
 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'L]');
 	set_vars_text(tmps$, tmp, "L");
 	set_inptval(tmps$, tmp);
 	
 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'U]');
 	set_vars_text(tmps$, tmp, "U");
 	set_inptval(tmps$, tmp);
 	
 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'UF]');
 	set_vars_text(tmps$, tmp, "UF");
 	set_inptval(tmps$, tmp);

 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'LF]');
 	set_vars_text(tmps$, tmp, "LF");
 	set_inptval(tmps$, tmp);
 	
 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'P]');
 	set_vars_text(tmps$, tmp, "P");
 	set_inptval(tmps$, tmp);
 	
 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'PU]');
 	set_vars_text(tmps$, tmp, "PU");
 	set_inptval(tmps$, tmp);
 	
 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'PV]');
 	set_vars_text(tmps$, tmp, "PV");
 	set_inptval(tmps$, tmp);

 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'PVLF]');
 	set_vars_text(tmps$, tmp, "PVLF");
 	set_inptval(tmps$, tmp);

 	var tmps$ = varDialog_rgn.find('[name=' + varDialog_name + 'PULF]');
 	set_vars_text(tmps$, tmp, "PULF");
 	set_inptval(tmps$, tmp);
}

function set_vars_text(eles$, text, c_typ){
	eles$.each( function(index, element) {
	 	var ele$ = $(element);
		set_var_text(ele$, text, c_typ);
	});
}

// c_typ: L,U,UF,P,PU
function set_var_text(ele$, text, c_typ){
	if(ele$.attr('match')){ // 一部抽出
		text = text.match(new RegExp(ele$.attr('match')));
	}
	else if(ele$.attr('slice')){ // 分割の部分を抽出
		var tmp_parts = text.split("_");
		var p_parts = ele$.attr('slice').split(",");	// 指定の部分(1～）又は指定範囲
		
		var tmp_val = text;
		
		if(tmp_parts.length >= parseInt(p_parts[0],10)){
			tmp_val = tmp_parts[parseInt(p_parts[0],10) -1];

			var part_to = tmp_parts.length;
					 				
			if(p_parts.length==2 && tmp_parts.length < parseInt(p_parts[1],10)){
				part_to = parseInt(p_parts[1],10);
			}
			
			for (let i = parseInt(p_parts[0],10); i < part_to; i++) {
				tmp_val = tmp_val + "_" + tmp_parts[i];
			}
		}
		
		text = tmp_val;
	}
	
	if(ele$.attr('from_idx') || ele$.attr('to_idx')){
		from_idx = 0;
		
		if(ele$.attr('from_idx')){
			from_idx = Number(ele$.attr('from_idx'));
		}
		
		if(ele$.attr('to_idx')){
			text = text.slice(from_idx,  Number(ele$.attr('to_idx')));
		}else{
			text = text.slice(from_idx);
		}
	}
	
	// 大文字、小文字置換
	if(c_typ == "L"){
		text = text.toLowerCase();
	}
	else if(c_typ == "U"){
		text = text.toUpperCase();
	}
	else if(c_typ == "UL"){
		text = firstUpper(text.toLowerCase());
	}
	else if(c_typ == "UF"){
		text = firstUpper(text);
	}
	else if(c_typ == "LF"){
		text = firstLower(text);
	}
	else if(c_typ == "P"){
		text = properCase(text);
	}
	else if(c_typ == "PU"){
		text = properCase(text, true);
	}
	else if(c_typ == "PV"){
		text = properCase(text.split("_").slice(1).join("_"), true);
	}
	else if(c_typ == "PVLF"){
		text = properCase(text.split("_").slice(1).join("_"), true);
		text = firstLower(text);
	}
	else if(c_typ == "PULF"){
		text = properCase(text, true);
		text = firstLower(text);
	}
	
	// text設定
	ele$.text(text);
}

function set_inptval(tmps$, val){
	tmps$.each( function(index, element) {
	 	var ele$ = $(element);
	 		
 		if(ele$.attr('inptval')){
			ele$.attr('inptval', val);
		}
	});
}