
/////////////////////////////////////////////
///// 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 変数
function initItemRecords(){
	_menuObj = new Object();
}
function addItemRecord(item, rec){
	// array = [owner,value,public,freq,menu] 形式
	// 他人が owner のものも記憶
	_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;
}

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";
    }
}
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";
        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;
	
	// value を元にしたテンプレートを画面に追加
	var tbl = document.getElementById("formTable");
	tbl.innerHTML = "";
	
	// rootObj に obj group を追加
	var rootObj = structure();
	//alert("rootObj:"+rootObj);//##
	var cellId = "0." + (rootObj.children.length - 1);
	var obj = buff2cell(cellId, item, value); // item に対応する value を構造化
	rootObj = addGroupForId(rootObj, cellId, item, obj);
	setFormStructure(rootObj); // 更新された構造を記憶
	
	// 構造化したものを表示
	showFormStructure(tbl, 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];
        
		menuItems.push(rec.menu);
		addItemRecord(rec.menu, rec);
	}
	var items = myMenuItems(menuItems);
	items.push('...その他');
	
	// テンプレート選択用ポップアップを更新
	var elm = document.getElementById("popUpArea");
	elm.innerHTML = "";
	
	var pu = makePopupMenu(elm, "itemPopUp", items, "");
	pu.setAttribute("onchange", "popUpClicked()");
	
	var js = newSPAN(elm, "_addTemplateArea");
	var bt = newBUTTON(js, "", "追加");
	bt.setAttribute("onclick", "addTemplate()");
	
	var im = newIMAGE(elm, "icon", "./hammer.png", "X");
	im.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() ###
	NRGetMenu(owner(), cellLabel(), showItemPopUp);
}

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

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


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

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;
	var tbl = document.getElementById("formTable");
	tbl.innerHTML = "";
	
	// cellId のセルを削除して再表示
	var parentObj = removeFormCellForId(structure(), cellId);
	setFormStructure(parentObj); // 構造を記憶
	showFormStructure(tbl, 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 showFormStructure(tbl, parentObj){
	// parentObj の構造に従い FORM を表示
	// ## tbl は "formTable" から取得可能だが showFormStructure() を呼ぶ前の
	// ## tbl の処理が場合により異なるので showFormStructure() 外部から呼ぶこと
	if (parentObj == null) return;
	
	// cell header を生成
	var tr = newTR(tbl, "formHeader", "");
	var td = newTD(tr, "", "");
	if (isSame(parentObj.id, "0") == 0){
		var im = newIMAGE(td, "icon", "./close.png", "X");
		var action = "removeFormCell('"+parentObj.id+"')";
		im.setAttribute("onclick", action);
        
		// public のテンプレート場合はそれをタイトルに表示
		var _owner = ownerForItem(parentObj.label);
		if (_owner != owner()){
			var tx = newTEXT(td, " " + _owner);
		}
	}
	var td = newTD(tr, parentObj.id+".name", parentObj.label);
	
	// 子供 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)を持たない場合
			showFormStructure(tbl, 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 = ""; // closeEditor() 使わない
	// formTable は既存のものを使うのではなく作成しなおさないと
	// ポップアップメニューなどが編集内容と置き換わらない
	var tbl = newTABLE(elm, "formTable");
	showFormStructure(tbl, 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 elm = document.getElementById("base");
	var tbl = newTABLE(elm, "bodyTable"); // 固有名称につき base-table を使わない
	
	// header
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "", "");
	var tbl2 = newTABLE(td, "base-table");
	var tr2 = newTR(tbl2, "title-bar", "");
    // left side
	var td2 = newTD(tr2, "left-side", "");
	var img = newIMAGE(td2, "icon", "./close.png", "close");
	img.setAttribute("onclick","closeForm()");
	var array = currentDate().split(" ");
	var tx = newTEXT(td2, " 伝票" + " " + array[0] + "　");
    // right side: pinUp
	var td2 = newTD(tr2, "pinUpArea", "");
    td2.style.textAlign = "right";
    td2.style.width = "20px";
    td.setAttribute("onclick", "setPinUp()");
    loadPinUp();
    // right side: Help
	var td2 = newTD(tr2, "", "");
    td2.style.textAlign = "right";
    td2.style.width = "20px";
	var im = newIMAGE(td2, "", "./Help.png", "?");
	im.setAttribute("onclick", "formHelp()");
	im.style.height = "18px";
	
	// popUpMenu
	var tr = newTR(tbl, "controls", "");
	tr.style.backgroundColor = "#fff";
	var td = newTD(tr, "popUpArea", "");
	
	// 編集エリア
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "editorArea", "");
	var tab = newTABLE(td, "formTable");
	
	// 注意事項
	var tr = newTR(tbl, "_helpArea", "");
	
	// footer
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "", "");
	var tbl2 = newTABLE(td, "base-table");
	var tr2 = newTR(tbl2, "title-bar", "");
	var td2 = newTD(tr2, "left-side", fm_version());
    td2.style.paddingLeft = "5px";
	var td2 = newTD(tr2, "right-side", "");
	var js = newSPAN(td2, "formatModeArea");
    var status = isFormTouchAndGo();
    var cb = newCHECKBOX(td2, "touchAndGoCheck", " 確定保存", status);
    cb.setAttribute("onchange", "setFormTouchAndGo(this)");
	var bt = newBUTTON(td2, "", "確定");
	bt.setAttribute("onclick", "ok()");
    
	// 編集用テーブル
	var tbl = newTABLE(elm, "editorTable");
    
    // ### message や _debug などのエレメントは form.php に書かないと
    // ### base が消えるとこれらも消えてエラーの元になる
    
	// ポップアップメニューを読み込み、カルテデータをセット
	getItems();
}

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