
/////////////////////////////////////////////
///// NOA からの継承値 /////////////////////////

// NOA 組込みの場合は patientId() などを直接取得できるが
// 外付けツールにも出来るようあえて以下の仕組みを使う

function noa(){
    if (window.opener.name == "noa"){
        return window.opener;
    } else if (window.opener.name == "tools"){
        return window.top.noa;
    } else if (window.top.noa){
        return window.top.noa;
    } else {
        alert("ERROR *** tools.js: window.opener としての NOA が見つかりません");
        return null;
    }
}

function patientId(){
	return noa().patient_id();
}

function currentDate(){
	return noa().currentDate();
}

function owner(){
	return noa().owner();
}

function cellLabel(){
	return noa().cellLabel();
}

function cellTag(){
	return noa().cellTag();
}

function cellValue(){
	return noa().cellValue();
}

///// NOA からの継承値 /////////////////////////
/////////////////////////////////////////////


var _menuObj; // Global 変数
var _menuTemplate; // Global 変数
function initItemRecords(){
	_menuObj = new Object();
	_menuTemplate = new Object();
}
function addItemRecord(item, rec){
	// array = [owner,value,public,freq,menu] 形式
	// 他人が owner のものも記憶
    if (rec.template){
        if (!_menuTemplate[item]) _menuTemplate[item] = new Object();
        _menuTemplate[item][rec.template] = rec;
    } else {
        _menuObj[item] = rec;
    }
}
function ownerForItem(item){
	// formEditor.js で使われる
	var rec = _menuObj[item];
	return (rec) ? rec.owner : owner();
}
function valueForItem(item){
	var rec = _menuObj[item];
	return (rec) ? rec.value : "";
}
function hasSameItem(item){
	// 同じ item が存在するかどうかを返す
	for (title in _menuObj){
		if (title == item) return true;
	}
	return false;
}
function templateNamesForItem(item){
    // item に対するテンプレート名の配列を返す
	var obj = _menuTemplate[item];
    if (obj){
        var array = new Array();
        for (tempName in obj){
            array.push(tempName);
        }
        return array;
    } else {
        return new Array();
    }
}
function templateFor(item, tempName){
    // item, tempName に対するテンプレートを返す
	var rec = _menuTemplate[item][tempName];
	return (rec) ? rec : "";
}

var _structure = null;
function structure(){
	return _structure;
}
function setFormStructure(obj){
	_structure = obj;
}

function formSeparator(){
	return "<BR/>　";
    //	return "\n　";
}
function initFormatMode(mode){
	var elm = document.getElementById("formatModeArea");
	elm.innerHTML = "";
	var cb = newCHECKBOX(elm, "", "整形 ", (mode) ? 1 : 0);
	cb.setAttribute("onclick", "setFormatMode(this)");
	_formatMode = mode;
}
function setFormatMode(elm){
	_formatMode = (elm.checked) ? true : false;
}
function formatMode(){
	return _formatMode;
}

///////////////////////////////////
/// localStorage による処理 /////////

function loadPinUp(){
    // pinUp の状態を localStorage から読み込みピンを表示
	var elm = document.getElementById("pinUpArea");
    elm.innerHTML = "";
    
    if (isPinUp()){
        var im = newIMAGE(elm, "", "./redPin.png", "?");
        im.style.height = "15px";
    } else {
        var im = newIMAGE(elm, "", "./redgem.png", "?");
        im.style.height = "10px";
        im.style.position = "relative";
        im.style.bottom = "4px";
    }
}
function setPinUp(){
    // ピンを立てる：「確定」しても FORM は消えず NOA も編集モードから抜けない
	var elm = document.getElementById("pinUpArea");
    elm.innerHTML = "";
    
    // ピンの状態を toggle 形式で変化させ status を localStorage に記憶
    if (isPinUp()){
        var im = newIMAGE(elm, "", "./redgem.png", "?");
        im.style.height = "10px";
        im.style.position = "relative";
        im.style.bottom = "4px";
        window.localStorage["formPinStatus"] = "0";
    } else {
        var im = newIMAGE(elm, "", "./redPin.png", "?");
        im.style.height = "15px";
        window.localStorage["formPinStatus"] = "1";
    }
}
function isPinUp(){
    var status = window.localStorage["formPinStatus"];
    
    return (status && status * 1) ? true : false;
}


function setFormTouchAndGo(elm){
    // 確定保存のチェック状態を記憶
    window.localStorage["formTouchAndGo"] = (elm.checked) ? "1" : "0";
}
function isFormTouchAndGo(){
    var status = window.localStorage["formTouchAndGo"];
    
    return (status && status * 1) ? true : false;
}

/// localStorage による処理 /////////
///////////////////////////////////



function cellForLabel(parentObj, label){
	// parentObj の構造中で label と同じ名称の labelを持つ cell を返す
	if (parentObj == null) return null;
    
	for (var i=0,count=parentObj.children.length; i < count; i++){
		var obj = parentObj.children[i];
		var aLabel = trim(obj.label);
		if (obj.hasChild == 0){
			if (isSame(aLabel, label)) return obj;
		} else {
			var anObj = cellForLabel(obj, label);
			if (anObj && isSame(anObj.label, label)) return anObj;
		}
	}
	return null;
}

function setValueForId(parentCell, cellId, label, value){
	// EDITOR: parentCell の中を解析して id に対応する object に value をセット
	var i, num, count = parentCell.children.length;
	for (i=num=0; i < count; i++){
		var cell = parentCell.children[i];
		if ((cell.hasChild != null) && (cell.hasChild > 0))
			setValueForId(cell, cellId, label, value);
		else if (isSame(cell.id, cellId)){
			cell.label = label;
			cell.value = value;
			return;
		}
	}
}

///////////////////////////////////////////////////
///// showFORM() showEditor() 共通に使われる関数 /////

function valueOfRecord(rec){
	// レコード "50|mg|10..20" の中の値 "50" だけを返す
	// レコード "50 MG|mg|10..20" の場合は "50" を返す
	var array = rec.split("|");
	
	var value = array[0];
	var ary = value.split(" ");
	if (ary.length > 1)
		var value = ary[0];
    
	return value;
}

function unitOfRecord(rec){
	// レコード "50|mg|10..20" の中の値 "mg" だけを返す
	// レコード "50 MG|mg|10..20" の場合は "MG" を返す
	var array = rec.split("|");
	
	var value = array[0];
	var ary = value.split(" ");
	if (ary.length > 1)
		var unit = ary[1];
	else
		var unit = (array.length > 1) ? array[1] : "";
    
	return unit;
}

function rangeOfRecord(rec){
	// レコード "50|mg|10..20" の中の値 "10..20" だけを返す
	var array = rec.split("|");
	var range = (array.length > 2) ? array[2] : "";
	return range;
}

function menuOfRecord(rec){
	// レコード "50|mg|10..20|1,2,3" の中の値 "1,2,3" だけを返す
	var array = rec.split("|");
	var menu = (array.length > 3) ? array[3] : null;
	return menu; // ### menu ない場合は "" ではなく null を返す
}

function titleCell(id){
	// タイトルになる cell を生成
	var obj = new Object();
	obj.id = id + ".0";
	obj.label = "項目名";
	obj.value = "単位（オプション）";
	obj.hasChild = 0;
	obj.children = new Array();
	return obj;
}

function buff2cell(id, label, buff){
	// buff を cell に展開
	// cell の持つ属性: id, label, hasChild, value, children
	var parentObj = new Object();
	parentObj.id = id;
	parentObj.label = label;
	parentObj.children = new Array();
	var num = 0;
	var indent = 0;
	var valueBegin = 0;
	
	// タイトルになる cell を生成し最初に追加
	var obj = titleCell(id);
	parentObj.children[num++] = obj; // 子供として追加
	
	for (var i=0,len=buff.length; i < len; i++){
		var ch = buff.charAt(i);
		if (ch == "("){
			if (indent == 0){
				// label があったので cell を生成
				obj = new Object();
				obj.id = id + "." + num;
				obj.label = trim(buff.substring(valueBegin, i));
				obj.value = null;
				obj.children = new Array();
				valueBegin = i+1;
			}
			indent++;
		} else if (ch == ")"){
			indent--;
			if (indent == 0){
				// label に対する value を特定した
				var value = buff.substring(valueBegin, i);
				if (value.indexOf("(") >= 0){
					// value の中にさらに cell の存在を認めた
					obj.hasChild = 1;
					var no = obj.children.length;
					parentObj.children[num++]
					= buff2cell(obj.id, obj.label, value); // 子供として追加
				}
				else {
					// value は単なる文字列だった
					obj.value = value;
					obj.hasChild = 0;
					parentObj.children[num++] = obj; // 子供として追加
				}
				valueBegin = i+1;
			}
		}
	}
	
	parentObj.hasChild = 0;
	parentObj.value = null;
	if (num == 0)
		parentObj.value = buff;
	else
		parentObj.hasChild = 1;
	
	return parentObj;
}

function selectedItem(){
	return document.getElementById("itemPopUp").value;
}

function formHelp(){
	// 別途ヘルプをパネル表示
	window.open("./formHelp.html","Help"
				,"width=450,height=700,scrollbars=yes,resizable=yes");
}

function popUpClicked(){
	// 選択されたメニュー・アイテムが　"...その他" なら新規登録
	if (isSame(item, "...その他")){
		showEditor(1);
		return;
	}
}

function addGroupForId(parentCell, cellId, label, aCell){
	// parentCell へ cellId のセルを挿入して返す
	var newCell = new Object();
	newCell.id = parentCell.id;
	newCell.label = parentCell.label;
	newCell.children = new Array();
	newCell.hasChild = (parentCell.hasChild) ? parentCell.hasChild : 0;
	var i, num, count = parentCell.children.length;
	
	for (i=num=0; i < count; i++){
		var cell = parentCell.children[i];
		cell.id = parentCell.id + "." + num; // id を付け直す
		if ((cell.hasChild != null) && (cell.hasChild > 0))
			newCell.children[num++] = addGroupForId(cell, cellId, label, aCell);
		else
			newCell.children[num++] = cell;
		if (isSame(cell.id, cellId)){
			// 新しい行を挿入 value は不要
			aCell.id = parentCell.id + "." + num; // id を付け直す
			newCell.children[num++] = aCell;
		}
	}
	return newCell;
}

function addTemplate(){
	// 選択ポップアップ名：item を元にテンプレート取得し FORM に追加
	var item = selectedItem();
	var value = valueForItem(item);
    
	if (value.length == 0) return;
	
	// rootObj に obj group を追加
	var rootObj = structure();
	var cellId = "0." + (rootObj.children.length - 1);
	var obj = buff2cell(cellId, item, value); // item に対応する value を構造化
	rootObj = addGroupForId(rootObj, cellId, item, obj);
	setFormStructure(rootObj); // 更新された構造を記憶
    
	var elm = document.getElementById("editorArea");
	elm.innerHTML = "";
	showFormStructure(elm, rootObj);
	
	// 選択されたアイテムの頻度をインクリメント
    updateMenuItems(item, value);
	//incrementFrequency(item);
}

///// showFORM() showEditor() 共通に使われる関数 /////
///////////////////////////////////////////////////


////////////////////////////////
/// neuron.js による処理 /////////

function showItemPopUp(answer){
	// 検査フォーム名のリストをサーバから読込み
	// ### formEditor.js からも使われる
	initItemRecords();
	//alert("showItemPopUp ===\n"+answer); //##
	var menuItems = new Array(); // Grobal 変数
	// サーバが返してきた JSON を解析
	var array = JSON.parse(answer);
	//alert("showItemPopUp:"+encodeObject(array)); //##
    
	for (num in array){
		// array = [{owner:"",value:"",public:"",freq:"",menu:""},,,] 形式
		var rec = array[num];

        addItemRecord(rec.menu, rec);

		if (rec.template) continue; // テンプレート用はメニュー・アイテムに入れない
        
        menuItems.push(rec.menu);
	}
	var items = myMenuItems(menuItems);
	
	// テンプレート選択用ポップアップを更新
	var elm = document.getElementById("popUpArea");
	elm.innerHTML = "";

    var dv = newDIV(elm, "/left-side");
	dv.style.paddingLeft = "10px";
	dv.style.width = "80%";
	var pu = makePopupMenu(dv, "itemPopUp", items, "");
	pu.setAttribute("onchange", "popUpClicked()");
    var bt = newDIV(dv, "/whiteButton");
    bt.innerHTML = "追加";
    bt.style.position = "relative";
    bt.style.top = "2px";
    bt.style.marginLeft = "3px";
	bt.setAttribute("onclick", "addTemplate()");
    
    var dv = newDIV(elm, "/right-side");
	dv.style.padding = "5px 20px 5px 0";
	dv.style.width = "25px";
	var img = newIMAGE(dv, "icon", "./hammer.png", "X");
	img.setAttribute("onclick", "showEditor(0)");

	// FORM を生成しカルテから送られた内容を表示
	showFORM(cellValue());
	
	function myMenuItems(menuItems){
		// menuItems のうち、自分のものと共有されたもののみを配列に入れ返す
		var array = new Array();
		var count = menuItems.length;
		for (var i=0; i < count; i++){
			array.push(menuItems[i]);
		}
		return array;
	}
}
function getItems(){
	// サーバから検査フォーム名のリストを取り寄せ _itemArray として保存
    // ### FORM 用メニューは第２因子が tag ではなく cellLabel() ###
    // cellLabel() は "検査" -- MenuTalbe から tag=="検査" を取り出す
	NRGetMenu(owner(), cellLabel(), showItemPopUp);
}

function updateMenuItems(title, items){
	// サーバのメニュー項目を更新
    // ## 頻度更新にもこれを使う
    // ## そうしないと public を元にしている場合 ohashi に val="" を書きこんでしまう
	var val = encodeSTRING(items);
	NRPutMenu(owner(), cellTag(), title, "", val, NRNoAction);
}

function addTemplateValue(parentId, label, array){
	// テンプレート規定値を追加
    var title = window.prompt("この入力値セットのタイトルをつけてください", "");
    if (!title) return;
    
    var obj = new Object();
    for (num in array){
        var rec = array[num];
        var field = document.getElementById(rec.id + ".value");
        
        if (field && field.value.length)
            obj[rec.label] = field.value;
    }
    
    // ## 頻度更新にもこれを使う
    // ## そうしないと public を元にしている場合 ohashi に val="" を書きこんでしまう
	var val = encodeSTRING(encodeObject(obj));
	NRPutMenuTemplate(owner(), cellLabel(), label, title, "", val, NRNoAction);
}

/// neuron.js による処理 /////////
////////////////////////////////


///////////////////////////////////////////
///// Z() //////////////////////////

function clickedComboBox(cellId){
	// ポップアップメニューで選択されたアイテムを入力欄へ転記
	var item = document.getElementById(cellId+".menu").value;
	if (isSame(item, "...その他")){
		var item = window.prompt("新規メニュー項目を入力してください", "");
		if (item.length == 0) return;
		
		// 選択されたポップアップメニューに対応するラベル名を得る
		var tr = document.getElementById(cellId);
		var td = tr.firstChild;
		var label = td.innerHTML;
		// 選択されたポップアップメニューの所属するテンプレートのタイトル名を得る
		var titleId = parentCellId(cellId) + ".name";
		var td = document.getElementById(titleId);
		var title = td.innerHTML;
		// 選択されたポップアップメニューのメニュー項目を得る
		var values = valueForItem(title);
		var items = itemsForLabel(values, label);
		// ポップアップメニューに新しいメニュー項目を追加
		var array = items.split("|");
		array[0] = item; // 選択値
		array[3] += ","+item; // メニューに item を追加
		items = array.join("|");
		showCellContents(tr, cellId, label, items); // フィールド表示内容を更新
		// 変更されたメニュー項目をサーバへ登録
		var array = items.split("|");
		array[0] = ""; // 選択値は空とする
		items = array.join("|");
		values = updateItemsForLabel(values, label, items);
		updateMenuItems(title, values);
	}
	document.getElementById(cellId+".value").value = item;
	checkValue(cellId); // 基準値に合致するかチェック
	
	function updateItemsForLabel(values, label, items){
		// "class(||I,II|I,II,III,IIIa,IIIb,IV,V)内膜(||-,I|-,+,I,II)メモ()" 中の
		// 例えば "class" に対するメニュー項目を items に置換
		var aLabel = "";
		var buff = "";
		for (var i=valueBegin=0,len=values.length; i < len; i++){
			var ch = values.charAt(i);
			if (ch == "("){ // label を取り出す
				aLabel = trim(values.substring(valueBegin, i));
				valueBegin = i+1;
			} else if (ch == ")"){ // label に対する value を特定した
				var value = values.substring(valueBegin, i);
				if (isSame(label, aLabel))
					buff += aLabel + "(" + items + ")";
				else
					buff += aLabel + "(" + value + ")";
				valueBegin = i+1;
			}
		}
		return buff;
	}
	
	function itemsForLabel(values, label){
		// "class(||I,II|I,II,III,IIIa,IIIb,IV,V)内膜(||-,I|-,+,I,II)メモ()" から
		// 例えば label:"class" に対するメニュー項目
		// "||I,II|I,II,III,IIIa,IIIb,IV,V" を取り出し返す
		var aLabel = "";
		for (var i=valueBegin=0,len=values.length; i < len; i++){
			var ch = values.charAt(i);
			if (ch == "("){ // label を取り出す
				aLabel = trim(values.substring(valueBegin, i));
				valueBegin = i+1;
			} else if (ch == ")"){ // label に対する value を特定した
				var value = values.substring(valueBegin, i);
				if (isSame(label, aLabel)) return value;
				valueBegin = i+1;
			}
		}
		return "";
	}
	
	function parentCellId(cellId){
		// cellId:"0.2.2" に対する parentCellId:"0.2" を返す
		var array = cellId.split(".");
		array = array.slice(0, array.length - 1);
		return array.join(".");
	}
}

function showPopUp(cellId, menu, item){
	// menu 用のポッパアップメニューを生成し item を選択
	var tr = document.getElementById(cellId);
	var td = tr.childNodes[1]; // right side FORM
	var array = menu.split(",");
	array.splice(0,0,"");
	array.push("...その他");
	var pp = makePopupMenu(td, cellId+".menu", array, item);
	var action = "clickedComboBox('"+cellId+"')";
	pp.setAttribute("onchange", action);
}

function BMI_with(height, weight){
	// ### BMI 計算のための特殊埋め込み関数 ###
	// height, weight ラベルの値から BMI を計算して返す
	// cell.value はリアルタイムな値ではないので、リアルな値を取る
	var cell = cellForLabel(structure(), height);
	if (!cell) return height;
	
	var val = document.getElementById(cell.id+".value").value; // フィールド値
	var ht = valueOfRecord(val) / 100;
	
	cell = cellForLabel(structure(), weight);
	if (!cell) return "";
	
	var val = document.getElementById(cell.id+".value").value; // フィールド値
	var wt = valueOfRecord(val) * 1;
	if (ht * wt == 0) return "";
	
	var bmi = wt / (ht * ht);
	bmi = Math.round(bmi * 10);
	bmi = Math.floor(bmi) / 10;
	return bmi;
}
function EFW_with(bpdF, aptdF, ttdF, flF){
	// ### EFW:胎児推定体重 計算のための特殊埋め込み関数 ###
    var bpd = 0;
    var aptd = 0;
    var ttd = 0;
    var fl = 0;
    
	var cell = cellForLabel(structure(), bpdF);
	if (cell)
        bpd = document.getElementById(cell.id+".value").value; // フィールド値
	var cell = cellForLabel(structure(), aptdF);
	if (cell)
        aptd = document.getElementById(cell.id+".value").value; // フィールド値
	var cell = cellForLabel(structure(), ttdF);
	if (cell)
        ttd = document.getElementById(cell.id+".value").value; // フィールド値
	var cell = cellForLabel(structure(), flF);
	if (cell)
        fl = document.getElementById(cell.id+".value").value; // フィールド値
    
	var efw = Math.floor((1.07 * bpd*bpd*bpd + 3.42 * aptd * ttd * fl)/1000);
    if (bpd * aptd * ttd * fl == 0) efw = 0;
    
    if (efw > 0){
        //window.open("./weight.png","EFW","width=450,height=610,left=10,top=30");
        return efw;
    } else {
        return "";
    }
}

function checkValue(cellId){
	// 入力された値のチェックを行う
	var textField = document.getElementById(cellId+".value"); // dynamically
    if (label(cellId) == "BMI"){
		// ### BMI 計算のための特殊埋め込み関数 ###
		var val = BMI_with("身長", "体重");
		document.getElementById(cellId+".value").value = val;
	} else if (label(cellId) == "EFW"){
		// ### EFW:胎児推定体重 計算のための特殊埋め込み関数 ###
		var val = EFW_with("BPD", "APTD", "TTD", "FL");
		document.getElementById(cellId+".value").value = val;
    }
	var value = textField.value; // dynamically
	var range = document.getElementById(cellId+".range").value; // dynamically
	var elm = document.getElementById(cellId).childNodes[0];
	switch (checkRangeOfRecord(value, range)){
		case -1:
			textField.style.color = "#000";
			textField.style.backgroundColor = "#9cf";
			break;
		case 1:
			textField.style.color = "#000";
			textField.style.backgroundColor = "#fcc";
			break;
		case 0:
			textField.style.color = "#000";
			textField.style.backgroundColor = "#fff";
			break;
	}
	
	function label(cellId){
		// cellId に相当するラベル名を返す
		var tr = document.getElementById(cellId);
		var td = tr.childNodes[0]; // left side FORM
		return td.innerHTML;
	}
	
	function checkRangeOfRecord(value, range){
		// レコード "50|mg|10-20" の中の 50 が 範囲におさまるかどうかチェック
		if (value.length == 0) return 0;
		if (range.length > 0){
			// value が range におさまらなければ over range status を返す
			var ary1 = range.split("..");
			if (ary1.length == 1){
				// "item1,item2,,," 形式の場合
				var st = ary1[0];
				var ary2 = st.split(",");
				var i, ct = ary2.length;
				for (i=0; i < ct; i++){
					var standard = ary2[i];
					if (isSame(value, standard)) return 0; // 正常値があった
				}
				return 1; // 正常値が一つもなかった
			} else if (ary1.length > 1){
				var min = ary1[0] * 1;
				var max = ary1[1] * 1;
				var val = value * 1;
				if (val < min) return -1;
				else if (max < val) return 1;
			}
		} else { // 検査センターからのデータをロードした場合
			if (value.indexOf("]#H") > 0)
				return 1;
			else if (value.indexOf("]#L") > 0)
				return -1;
		}
		return 0;
	}
}

function removeFormCell(cellId){
	// cellId のテンプレート１枚分を削除
	var label = document.getElementById(cellId+".name").innerHTML;
	
	// cellId のセルを削除して再表示
	var parentObj = removeFormCellForId(structure(), cellId);
	setFormStructure(parentObj); // 構造を記憶

	var elm = document.getElementById("editorArea");
	elm.innerHTML = "";
	showFormStructure(elm, parentObj); // 構造化したものを表示
	
	function removeFormCellForId(parentCell, cellId){
		// parentCell から cellId のセルを削除して返す
		var newCell = new Object();
		newCell.id = parentCell.id;
		newCell.label = parentCell.label;
		newCell.hasChild = parentCell.hasChild;
		newCell.children = new Array();
		newCell.hasChild = (parentCell.hasChild) ? parentCell.hasChild : 0;
		var i, num, count = parentCell.children.length;
		for (i=num=0; i < count; i++){
			var cell = parentCell.children[i];
			if (isSame(cell.id, cellId)) continue; // item removed
			cell.id = parentCell.id + "." + num; // 削除したため id を付け直す
			if ((cell.hasChild != null) && (cell.hasChild > 0))
				newCell.children[num++] = removeFormCellForId(cell, cellId);
			else
				newCell.children[num++] = cell;
		}
		return newCell;
	}
}

function showCellContents(tr, cellId, label, val){
	// テンプレートの CELL 一個を表示
	tr.innerHTML = "";
	var td = newTD(tr, "formRecordLeft", label); // 名称
	var td = newTD(tr, "formRecordRight", ""); // 単位
	var unit = unitOfRecord(val);
	var size = (unit.length > 0) ? 10 : 20;
	
	// ポップアップメニューがあれば表示
	var menu = menuOfRecord(val);
	if ((menu != null) && (menu.length > 0)){
		showPopUp(cellId, menu, valueOfRecord(val));
		size = 10;
	}
	
	// 入力欄を表示
	var hd = newHIDDEN(td, cellId+".range", rangeOfRecord(val));
	var fd = newFIELD(td, cellId+".value", "", size, valueOfRecord(val));
	var action = "checkValue('"+cellId+"')";
	fd.setAttribute("onchange", action);
	
	// 単位表示
	var sp = newSPAN(td, cellId+".unit");
	sp.innerHTML = unit;
	//var tx = newTEXT(sp, " ");
	
	// 入力された値のチェックを行う
	checkValue(cellId);
}

function childrenForId(parentObj, targetId){
    // targetId に相当するオブジェクトの children を返す
    if (parentObj.id && (parentObj.id == targetId)){
        return parentObj.children;
    }

    for (key in parentObj){
        // parentObj の子供オブジェクトを検索
        var obj = parentObj[key];
        
        if (typeof obj == "object"){
            var array = childrenForId(obj, targetId);
            if (array) return array;
        }
    }
    return null;
}

function selectTemplate(button, parentId, label){
    // テンプレート・ポップアップが選択された
    var array = childrenForId(structure(), parentId);
    if (array == null){
        alert("selectTemplate *** no children");
        return;
    }
    
    var title = button.innerHTML;
    if (title == "空欄") {
        // すべてのフィールドを空欄にする
        for (num in array){
            var rec = array[num];
            var field = document.getElementById(rec.id + ".value");
            
            if (field) field.value = "";
        }
    } else if (title == "...その他"){
        addTemplateValue(parentId, label, array);
    } else {
        // 選択されたテンプレートで各フィールドを上書きする
        var val = templateFor(label, title).value; // "心拍(+)尿蛋白(-).." 形式
        var templateObj = decodeObject(val);

        // すべてのフィールドを上書きする
        for (num in array){
            var rec = array[num];
            var field = document.getElementById(rec.id + ".value");
            if (!field) continue;
            
            var val = templateObj[rec.label];
            field.value = (val) ? val : "";
        }
    }
    closeFloatPanel();
}
function openCast(button, parentId, label){
    // 鋳型テンプレートを開く
    var pos = getPosition(button);
    var w = 80;
	var x = pos.x - w + 10; // 表示するx座標
	var y = pos.y; // 表示するy座標
    var elm = openSeeThroughPanel("floatPanel", x, y, w);

    var templates = templateNamesForItem(label);
    templates.splice(0, 0, "空欄");
    templates.push("...その他");
    var action = "selectTemplate(this,'"+parentId+"','"+label+"')";
    for (num in templates){
        var menu = templates[num];
        var div = newDIV(elm, "");
        var bt = newDIV(div, "/blueButton");
        bt.innerHTML = menu;
        bt.setAttribute("onclick", action);
    }
}

function showFormStructure(elm, parentObj){
	// parentObj の構造に従い FORM を表示
	// ## tbl は "formTable" から取得可能だが showFormStructure() を呼ぶ前の
	// ## tbl の処理が場合により異なるので showFormStructure() 外部から呼ぶこと
	if (parentObj == null) return;
    if (parentObj.hasChild == 0) return;
    
	if (isSame(parentObj.id, "0") == 0){
        // 伝票タイトルを生成
        var div = newDIV(elm, "tool-header");
        div.style.height = "25px";
        // --- LEFT SIDE ---
        var dv = newDIV(div, "left-side");
		var im = newIMAGE(dv, "icon", "./close.png", "X");
		var action = "removeFormCell('"+parentObj.id+"')";
		im.setAttribute("onclick", action);
        var dv = newDIV(div, parentObj.id+".name/titleLabel");
        dv.innerHTML = parentObj.label;
        // --- RIGHT SIDE ---
        var dv = newDIV(div, "right-side");
        var bt = newDIV(dv, "/closeButton");
        bt.innerHTML = "+";
        bt.style.color = "#555";
        bt.style.position = "relative";
        bt.style.top = "4px";
        var action = "openCast(this,'"+parentObj.id+"','"+parentObj.label+"')";
        bt.setAttribute("onclick", action); // iPad 用

        // 伝票タイトルの下に表示する伝票本体のテーブルを生成
        var div = newDIV(elm, "");
        var tbl = newTABLE(div, "formTable");
	}

	// 子供 cell を生成
	for (i in parentObj.children){
		var obj = parentObj.children[i];
		
		if (obj.hasChild == 0){
			// 子供が文字列(value)を持ち、孫(children)を持たない場合
			obj.id = parentObj.id + "." + i; // obj.id を付けなおす
			
			// テンプレート一行分の内容を表示
			if (i > 0){ // タイトル行「名称、基準値の表示」はスキップ
				var tr = newTR(tbl, obj.id, "");
				var label = trim(obj.label);
				showCellContents(tr, obj.id, label, obj.value);
			}
		} else {
			// 子供が孫(children)を持ち、文字列(value)を持たない場合
            var div = newDIV(elm, "");
			showFormStructure(div, obj);
		}
	}
	
	document.getElementById("message").innerHTML = "";
}

function showFORM(value){
	// カルテのデータ value を FORM に展開
	// ### ここが FORM のキモの部分 ###
	//alert("showFORM ==\n"+value); //##
	// 1) key(val) 構造のカルテ・データ value から カルテ・オブジェクト chartObj を生成
	// 2) その各トップラベル名を元にサーバからテンプレート取得し FORM 表示を追加
	// 3) その FORM へ label に対応したカルテデータを埋め込む
	
	// FORM を表示
	// 1) key(val) 構造のカルテ・データ value から カルテ・オブジェクト chartObj を生成
	var chartObj = buff2cell("0", "伝票構造", value); // メニューのバリューを構造化
	
	// 2) chartObj のトップラベル名を元にサーバからテンプレート取得し rootObj 作成
	// value に "\n   " が含まれれば formatMode と判定
	var mode = false;
	if (value.length){
		var array = value.split(formSeparator()); // "\n   "
		if (array.length > 1) mode = true;
	}
	initFormatMode(mode);
	
	var rootObj = new Object();
	rootObj.id = "0";
	rootObj.label = "";
	rootObj.value = null;
	rootObj.hasChild = 1;
	rootObj.children = new Array();
	rootObj.children[0] = titleCell(rootObj.id); // 子供として追加
	var i, count = chartObj.children.length;
	for (i=1; i < count; i++){
		// ０番目のタイトル行はスキップ
		var obj = chartObj.children[i];
		var cellId = "0." + (rootObj.children.length - 1);
		var label = obj.label;
		var val =  valueForItem(label);
		// label 相当のオブジェクトが rootObj にあればそれを、なければ chartObj のそれを
		var templateObj = (val) ? buff2cell(cellId, label, val) : obj;
		rootObj = addGroupForId(rootObj, cellId, label, templateObj);
	}
	
	// 3) rootObj へ chartObj からの label に対応したカルテデータを埋め込む
	rootObj = copyValue(rootObj, chartObj); // chartObj の valueを rootObj へ埋込む
	setFormStructure(rootObj); // 構造を記憶

	var elm = document.getElementById("editorArea");
	elm.innerHTML = ""; 
	showFormStructure(elm, rootObj); // 構造化したものを表示
	document.getElementById("message").innerHTML = "";
	
	// NOA ページと異なる日付の伝票の場合アラートを表示
	checkFormDate();
	
	function copyValue(rootObj, chartObj){
		// chartObj の中の value を rootObj の該当 Cell へ埋め込む
		var i, count = chartObj.children.length;
		for (i=0; i < count; i++){
			var obj = chartObj.children[i];
			if ((obj.hasChild != null) && (obj.hasChild > 0)){
				// chartObj をリカーシブルにたどりながら作業を進める
				rootObj.children[i] = copyValue(rootObj.children[i], obj);
			} else {
				// label に一致する obj を rootObj から得る
				var matched = false;
				var label = obj.label;
                for (n in rootObj.children){
					var robj = rootObj.children[n];
					// rootObj に label に一致するものがあれば obj.value を埋め込む
					if (isSame(label, robj.label)){
						// robj.value: "value|unit|range" に obj.value を挿入し
						// "obj.value|unit|range" にする
						var val = robj.value;
						if (val){			// rootObj が値を持っていた
							if (obj.value.indexOf("|") >= 0){
								// chartObj 内容がオプション属性の場合はそっくり置換
								robj.value = obj.value;
							} else {
								// rootObj の val を chartObj の値に置換
								// 属性 = "val | unit | range | menu"
								var ary = val.split("|");
								ary.splice(0, 1, obj.value);
								robj.value = ary.join("|");
							}
						} else {			// rootObj が値を持っていなかった
							if (obj.value){	// chartObj が値を持っていた
								if (obj.value.indexOf("|") >= 0){
									// chartObj がオプション属性の場合はそっくり置換
									robj.value = obj.value;
								} else {
									// chartObj の値を rootObj の val に入れる
									robj.value = obj.value + "||";
								}
							} else {		// chartObj が値を持っていなかった
								// ユーザがテキストで作成した "label()"形式の場合は
								// val が nil になるので、空データをあてがっておかな
								// いとエラーになる
								robj.value = "";
							}
						}
						matched = true;
						break;
					}
				}
				
				if (!matched){
					// rootObj(テンプレート)に、一致するラベルがなかった
					// newObj にカルテからの新規属性をセットして rootObj へ追加
					var newObj = new Object();
					var num = rootObj.children.length;
					newObj.id = rootObj.id + "." + num;
					newObj.label = label;
					newObj.value = obj.value;
					newObj.children = new Array();
					newObj.hasChild = 0;
					rootObj.children.push(newObj);
				}
			}
		}
		return rootObj;
	}
}

function closeForm(){
	// FORM 全体を閉じる
	document.getElementById("base").innerHTML = "";
}

function saved(answer){
	//	= "データは保存されました";
	//alert("saved -> "+answer); //##
	var elm = document.getElementById("_confirm");
	elm.innerHTML = "";
	var dv = newDIV(elm, "");
	dv.style.padding = "15px 20px";
	var tx = newTEXT(dv, "データは保存されました");
	
	// 最上部に開いた infoTip が見えないことがあるので最上部へスクロールしておく
	window.scroll(0, 0);
	showInfoTip(30, 50, dv, 1000); // 1000 ミリ秒でフェードアウト
}
function ok(){
	// 確定ボタンが押された
	var value = form2buff(structure(), true, formatMode());
    
    if (currentDate() == noa().currentDate()){
        // 本日のページから開かれた場合：DB へ直書きせず NOA の field へ書き戻す
        var status = document.getElementById("touchAndGoCheck").checked;
		noa().gotValueFromTool(value, status);
        
        // FORM パネルを閉じる
        if (! isPinUp())
            closeForm();
    } else {
        // 伝票入力などで他の日から開かれた場合：サーバのデータのみ更新
        var array = new Array();
        var tag = cellTag(); // "ProgressSection.examination" など
        array[tag] = encodeSTRING(value);
        NRPutPage(owner(),patientId(),currentDate(),"",array,saved);
    }
}

///// showFORM() //////////////////////////
///////////////////////////////////////////

function checkFormDate(){
	// 伝票をツールエリアに表示した場合に必要
	// NOA ページと異なる日付の伝票の場合アラートを表示
	if (window.top.noa.name == "noa"){
		var noaDate = window.top.noa.currentDate();
		var thisDate = currentDate();
		if (! isSameDate(noaDate, thisDate)){
			// alert(noaDate+"->"+thisDate); //##
			var elm = document.getElementById("_confirm");
			elm.innerHTML = "";
			var dv = newDIV(elm, "");
			dv.style.padding = "15px 20px";
			dv.innerHTML = "これは現在開いているカルテ<br/>とは別の日付の伝票です";
			showInfoTip(30, 100, dv, 1000); // ミリ秒でフェードアウト
		}
	}
}

function initForm(){
	var base = document.getElementById("base");

    // ===== FORM 表示エリア ==========================
    var elm = newDIV(base, "formBase");
    // === HEADER =======================
    var div = newDIV(elm, "tool-header");
    // --- LEFT SIDE ---
    var dv = newDIV(div, "/left-side");
    dv.style.width = "40%";
	var img = newIMAGE(dv, "icon", "./close.png", "close");
	img.setAttribute("onclick","closeForm()");
    img.style.position = "relative";
    img.style.bottom = "3px";
    var sp = newSPAN(dv, "");
    sp.style.marginLeft = "5px";
    sp.innerHTML = "伝票";
    // --- RIGHT SIDE ---
    var dv = newDIV(div, "/right-side");
    dv.style.marginRight = "5px";
    dv.style.width = "30%";
    // PIN UP
    var sp = newSPAN(dv, "pinUpArea");
    sp.style.paddingRight = "8px";
    sp.setAttribute("onclick", "setPinUp()");
    loadPinUp();
    // HELP ICON
	var im = newIMAGE(dv, "", "./Help.png", "?");
	im.setAttribute("onclick", "formHelp()");
	im.style.height = "18px";

	// popUpMenu
    var div = newDIV(elm, "popUpArea");
	
	// ===== 編集エリア ==================================
    var div = newDIV(elm, "editorArea");

    // === FOOTER =======================
    var div = newDIV(elm, "tool-footer");
    // --- LEFT SIDE ---
    var dv = newDIV(div, "/left-side");
    dv.style.marginLeft = "10px";
    dv.style.width = "80px";
    dv.innerHTML = fm_version();
    dv.style.position = "relative";
    dv.style.top = "3px";
    // --- RIGHT SIDE ---
    var dv = newDIV(div, "/right-side");
    dv.style.width = "200px";
    dv.style.paddingRight = "10px";
    dv.style.position = "relative";
    dv.style.top = "1px";
    var sp = newSPAN(dv, "formatModeArea");
    // HELP ICON
    var cb = newCHECKBOX(dv, "touchAndGoCheck", " 確定保存", isFormTouchAndGo());
    cb.setAttribute("onchange", "setFormTouchAndGo(this)");
    var bt = newDIV(dv, "/whiteButton");
    bt.innerHTML = "確定";
    bt.style.marginLeft = "10px";
    bt.setAttribute("onclick", "ok()");
    
	// === テンプレート編集エリア ================================
    var div = newDIV(base, "editorBase");
    
    // === floatPanel 用エレメント =============================
    var sp = newSPAN(base, "floatPanel");
    sp.style.visibility = "hidden";
    sp.style.position = "absolute";
    
    // ### message や _debug などのエレメントは form.php に書かないと
    // ### base が消えるとこれらも消えてエラーの元になる
    
	// ポップアップメニューを読み込み、カルテデータをセット
	getItems();
}

function fm_version(){
	return "Ver.121124";
}
