
var _attributes = ["fixed","unit","range","menu","type","value","dateFormat"];

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

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

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

function patientId(){
	return parent().patientId();
}

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

function currentTag(){
	return parent().currentTag();
}

function cellLabel(){
    var cell = parent().cellForTag(parent().currentTag());
    return cell.label;
}

function cellValue(){
    var obj = parent().valueForTag(currentTag(), currentDate());
    var val = (obj && obj.value) ? obj.value : "";

    return val;
}

function gotValueFromTool(value, status){
    // 周辺ツールから値 val を受け取るための API
    // NOA の CELL へ値を書き戻すために使う
    parent().gotValueFromTool(value, status);
}

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

///////////////////////////////////////////////////////////
///// 各伝票の構造とデータを記憶するオブジェクト
///// 伝票ツールの最初に起動される getItems() で読み込まれる
///// _menuObj には 「NOA の記憶する全ての伝票の構造」 が読み込まれる
///// _currentSlips には 「現在表示されている伝票の構造」が保持される

var _menuObj; // 各伝票の構造とデータを記憶するオブジェクト
function initItemRecords(){
	_menuObj = new Object();
}
function menuObj(){
    // 各伝票の構造とデータを記憶したオブジェクトを返す
    return _menuObj;
}
function addItemRecord(slipName, rec){
    // slipName は伝票名：(ex.特定健診 など)
	// rec = {slipName:{owner,tag,value,public,freq,menu,template},,} 形式
    // value = "fixed|unit|range|menu|type|value|dateFormat"; 形式
	// 他人が owner のものも記憶
    if (!rec.template){
        _menuObj[slipName] = rec;
    }
}
function menuObjFor(slipName){
    // 伝票名 slipName のオブジェクトを返す
    return _menuObj[slipName];
}
function formForSlipName(slipName){
    // 伝票名に対応する伝票構造オブジェクトを返す
    // "fixed|unit|range|menu|type|value|dateFormat"; 形式を返す
    //_debug("== formForSlipName->"+slipName); //##
    
	var rec = _menuObj[slipName];
    //_debug("rec->"+encodeObject(rec)); //##
    //alert("formForSlipName->"+encodeObject(rec)); //##
    
    if (rec && rec.value){
        //_debug("<p>"+slipName+" rec.value->"+rec.value+"</p>"); //##
        
        // "label(|||),," 型式を "label(fixed()unit(),,),," 型式に変換して返す
        var recs = decodeObject(rec.value);
        return slitToObj(recs);
    }
    return null;
}
function valueForItem(slipName){
    // 伝票名に対応するレコード文字列を返す：decodeObject() するとレコードオブジェクトになる
	var rec = _menuObj[slipName];
	return (rec) ? rec.value : "";
}
function addNewLabelTo(slipName, newLabel){
    // slipName 伝票に新規ラベル newLabel を挿入
	var rec = _menuObj[slipName];
	if (rec && rec.value && rec.value.length){
        var obj = decodeObject(rec.value);
        obj[newLabel] = "||||||"; // 新規ラベルを挿入
    } else {
        if (! _menuObj[slipName]) _menuObj[slipName] = new Object();
        if (! _menuObj[slipName].value) _menuObj[slipName].value = new Object();
        var obj = new Object();
        obj[newLabel] = "||||||"; // 新規ラベルを挿入
    }
    _menuObj[slipName].value = encodeObject(obj); // _menuObj へ書き戻す
}

function slitToObj(slipObj){
    // "label(|||),," 型式を "label(fixed()unit(),,),," 型式に変換
    //_debug("== slitToObj->"+encodeObject(slipObj)); //##
    
    var resultObj = new Object();
    for (label in slipObj){
        var val = slipObj[label];
        var array = val.split('|');

        var obj = new Object();
        obj.fixed = "";
        obj.unit = "";
        obj.range = ""; // 旧バージョンとの互換性のため dummy を入れておく
        obj.menu = "";
        obj.type = "";
        obj.value = "";
        obj.dateFormat = "";

        if (array.length == 1){
            // 文字列に '|' が含まれない場合は value と判断
            obj.value = val;
        } else {
            if (array.length > 0) obj.fixed = array[0]; // 必要
            if (array.length > 1) obj.unit = array[1];
            // 4: range はスキップ
            if (array.length > 3) obj.menu = array[3];
            if (array.length > 4) obj.type = array[4];
            if (array.length > 5) obj.value = array[5];
            if (array.length > 6) obj.dateFormat = array[6];
        }

        resultObj[label] = obj;
    }
    return resultObj;
}

var _isAnotherData;
function setIsAnotherData(status){
    _isAnotherData = status;
}
function isAnotherData(){
    // 表示されている伝票が表示されているカルテののでなければ true を返す
    return _isAnotherData;
}

// _currentSlips には 「現在表示されている伝票の構造」が保持される
var _currentSlips;
function initCurrentSlips(){
    _currentSlips = new Object();
}
function currentSlips(){
    // 伝票のオブジェクト群を入れたオブジェクト
    return _currentSlips;
}
function currentSlip(slipName){
    // 対象となっている伝票のオブジェクト
    return _currentSlips[slipName];
}
function addCurrentSlips(slipName, obj){
    // 表示された各伝票を記憶：その後変更されたデータは反映されていない
    if (!_currentSlips) _currentSlips = new Object();
    
    //alert("addCurrentSlips->"+encodeObject(obj)); //##
    
    _currentSlips[slipName] = obj;
}
function removeCurrentSlips(slipName){
    // 表示された各伝票リストから slipName の伝票を削除
    
    delete _currentSlips[slipName];
}

var _isNewForm; // 新規伝票なら true
function setIsNewForm(status){
    _isNewForm = status;
}
function isNewForm(){
    return _isNewForm;
}

///// 各伝票の構造とデータを記憶するオブジェクト ///
///////////////////////////////////////////////////////////


function formSeparator(){
	return "<br>　"; // スペースは２バイト文字のスペース
}

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" を返す
    if (rec && (rec.length > 0)){
        var array = rec.split("|");
        
        var value = array[0];
        var ary = value.split(" ");
        if (ary.length > 1)
            var value = ary[0];
        return value;
    } else {
        return "";
    }
}
function unitOfRecord(rec){
	// レコード "50|mg|10..20" の中の値 "mg" だけを返す
	// レコード "50 MG|mg|10..20" の場合は "MG" を返す
    if (rec && (rec.length > 0)){
        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;
    } else {
        return "";
    }
}
function rangeOfRecord(rec){
	// レコード "50|mg|10..20" の中の値 "10..20" だけを返す
    /*
    if (rec && (rec.length > 0)){
        var array = rec.split("|");
        var range = (array.length > 2) ? array[2] : "";
        return range;
    } else {
        return "";
    }
     */
    return ""; // 旧バージョンとの互換のため
}
function menuOfRecord(rec){
	// レコード "50|mg|10..20|1,2,3" の中の値 "1,2,3" だけを返す
    if (rec && (rec.length > 0)){
        var array = rec.split("|");
        var menu = (array.length > 3) ? array[3] : null;
        return menu; // ### menu ない場合は "" ではなく null を返す
    } else {
        return null;
    }
}
function typeOfRecord(rec){
	// レコード "50|mg|10..20||dateType" の中の値 "dateType" だけを返す
    if (rec && (rec.length > 0)){
        var array = rec.split("|");
        var type = (array.length > 4) ? array[4] : null;
        return type; // ### menu ない場合は "" ではなく null を返す
    } else {
        return "";
    }
}

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 selectedItem(){
	return document.getElementById("itemPopUp").value;
}

function popUpClicked(elm){
    // 伝票名ポップアップ・メニューがクリックされた
    var item = elm.value;
    
    //_initDebug(false); //##
    _debug("popUpClicked->"+currentTag()+"->"+item); //##

	// 選択されたメニュー・アイテムが　"...その他" なら新規登録
	if (item == "...その他"){
        var slipName = prompt("新規伝票名");
        if (slipName.length > 0){
            addNewOrderSlip(slipName); // _menuObj[slipName] を生成
            openSlipEditor(slipName);
            return;
        }
	}
    var cell = parent().cellForTag(currentTag());
    _debug("cell->"+encodeObject(cell)); //##
    _debug("study->"+cell.study); //##
    
    if (cell.study * 1 > 0){ // 頻度学習が on なら頻度学習を行う
        // freq = "" なら、使用されたメニュー項目の頻度を increment
        // ### doNothing の代わりに null や "" を指定すると正常終了しない
        put_group_menu(owner(), item, "", [], doNothing);
    }
}

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 changedMenu(elm, fid){
    // 伝票フィールドのメニューが選択された
    var menuItem = elm.value;
	var fd = document.getElementById(fid);
    if (fd){
        fd.value = menuItem;
        checkValue(fid);
    } else {
        alert(fid + " に相当する入力欄がありません");
    }
}

function removeOrderSlip(slipName){
    // slipName の伝票を画面から削除
    
    // 伝票リストから削除しておく
    removeCurrentSlips(slipName);
    
    // 伝票を再表示
	document.getElementById("editorArea").innerHTML = "";
    var slips = currentSlips(); // 表示されている伝票を入れたオブジェクト
    for (slipName in slips){
        var slip = slips[slipName]; // 最初に表示時点での伝票構造とデータのオブジェクト
        showOrderSlip(slipName, slip);
    }
}

function slipWithString(value){
    // value 文字列をオブジェクトにして返す
    /* value は以下のような文字列 -------------
     class(||I|I,II,IIIa,IIIb,IV,V)内膜(|||-,+,判定不能)採取器具(綿棒|||スクレーパ,綿棒,頚管ブラシ)メモ(|||炎症性変化,sq.metaplastic cell,軽度核腫大細胞,follow up,atrophic change,扁平上皮化生,酵母様真菌,mild dysplasia,moderate dysplasia,内膜細胞みとめず判定不能,トリコモナス,出血あり内膜も採取,細菌,ホルモン活性の強い細胞診)
     */
    var objects = new Object();
    var records = decodeObject(value);
    for (label in records){
        var ln = records[label];
        var obj = new Object();
        if (ln.length > 0){
            var array = ln.split('|');
            for (num in array){
                // VALUE (and UNIT) ---------------
                var st = array[0];
                var ary = st.split(' ');
                // "50 MG|mg|10..20" なら "50" を obj.fixed に入れる
                obj.fixed = ary[0]; // default 値
                if (ary.length > 1){
                    // "50 MG|mg|10..20" なら "MG" を obj.unit に入れる
                    obj.unit = ary[1];
                }
                // UNIT ---------------------------
                // "50|mg|10..20" なら "mg" を obj.unit に入れる
                // "50 MG|mg|10..20" なら "MG" を obj.unit に入れる
                if (!obj.unit && (array.length > 1)) obj.unit = array[1];
                // RANGE --------------------------
                // "50|mg|10..20" なら "10..20" を obj.range に入れる
                //obj.range = (array.length > 2) ? array[2] : null;
                // MENU ---------------------------
                // "50|mg|10..20|1,2,3" なら "1,2,3" を obj.menu に入れる
                obj.menu = (array.length > 3) ? array[3] : null;
                // TYPE ---------------------------
                // "||||dateType" なら "dateType" を obj.type に入れる
                obj.type = (array.length > 4) ? array[4] : null;
                // DATE FORMAT -------------------
                // "|||||dateFormat" なら "dateFormat" を obj.dateFormat に入れる
                obj.dateFormat = (array.length > 6) ? array[6] : null;
            }
        }
        objects[label] = obj;
    }
    return objects;
}

function addNewOrderSlip(slipName){
    // 伝票名：slipName の伝票オブジェクトを追加
    // 伝票リストに追加しておく
    addCurrentSlips(slipName, menuObjFor(slipName));
}

function moveOrderSlip(label1, label2){
    // label1 を label2 の位置へ移動：その他のレコードは順送りになる
    //_initDebug(true); //##
    _debug("== moveOrderSlip "+label1+"->"+label2); //##
    
    var obj = menuObjFor(_slipName); // 既存の伝票オブジェクト
    //_debug("obj-> "+encodeObject(obj)); //##
    
    var st = obj.value; // "日付(||||)身長(||||)体重(||||)" 形式
    var recs = decodeObject(st); // 既存の伝票オブジェクト
    
    // label1 のフィールドを移動
    var targetRec = recs[label1]; // 移動させるフィールド
    _debug("----- targetRec->"+targetRec); //##
    var newRecs = new Object(); // 並べ替えた伝票オブジェクト
    for (name in recs){
        var rec = recs[name];
        //_debug(name+"->"+rec); //##

        if (name == label1){
            continue;
        } else if (name == label2){
            //_debug("-- put 1->"+label1+"->"+targetRec); //##
            newRecs[label1] = targetRec;
            //_debug("-- put 2->"+name+"->"+rec); //##
            newRecs[name] = rec;
        } else {
            //_debug("-- put->"+name+"->"+rec); //##
            newRecs[name] = rec;
        }
    }
    _debug("moved->"+encodeObject(newRecs)); //##
    
    // 並べ替えの済んだ伝票オブジェクトを記憶
    obj.value = encodeObject(newRecs);

    _debug("obj.value->"+obj.value); //##
    _debug("=========="); //##

    // 伝票エディターを再表示
    openSlipEditor(_slipName);
}

function changeValue(slipName, label, attribute, value){
    // 属性の設定値が変更された
    //_debug("== changeValue->"+slipName+"->"+label+"->"+attribute+"->"+encodeObject(_menuObj[slipName])); //##

    // _menuObj[slipName]['value'] に入っている文字列をオブジェクトに解凍
    var st = _menuObj[slipName]['value'];
    if (st && st.length){
        var rec = decodeObject(st);
        var val = rec[label];
        var array = val.split('|');
    } else {
        var rec = new Object();
        rec[label] = new Object();
        var array = ["","","","","","",""];
    }
    
    // オブジェクト中の該当属性の値をセット
    if (attribute == 'fixed')
        array[0] = value;
    else if (attribute == 'unit')
        array[1] = value;
    //else if (attribute == 'range')
    //    array[2] = value;
    else if (attribute == 'menu')
        array[3] = value;
    else if (attribute == 'type')
        array[4] = value;
    else if (attribute == 'value')
        array[5] = value;
    else if (attribute == 'dateFormat')
        array[6] = value;
    
    // 属性列を | で区切った文字列にエンコードしオブジェクトに格納
    rec[label] = array.join('|');
    
    //_debug("-- rec[label]==>"+rec[label]); //##
    
    // 属性値を更新したオブジェクトをエンコードし再び _menuObj[slipName]['value'] に収納
    _menuObj[slipName]['value'] = encodeObject(rec);
    
    //_debug("=== _menuObj[slipName]->"+encodeObject(_menuObj[slipName])); //##
}

function changeLabel(elm, slipName, label){
    // ラベル（フィールド名）が変更された
    //var newLabel = inner_text(elmFor(label+".label"));
    var newLabel = document.getElementById(label+".label").innerText;
    //_initDebug(true); //##
    _debug("=== changeLabel->"+label+"->"+newLabel); //##
    
    var st = _menuObj[slipName]['value'];
    if (st && st.length){
        var rec = decodeObject(st);
        var val = rec[label];
        
        // 新規フィールドを挿入
        rec[newLabel] = val;
        
        // 変更されたフィールドを削除
        delete rec[label];
        
        // 属性値を更新したオブジェクトをエンコードし再び _menuObj[slipName]['value'] に収納
        _menuObj[slipName]['value'] = encodeObject(rec);
        
        _debug("=== changeLabel->"+encodeObject(_menuObj[slipName])); //##
    }
}
function changeFixed(elm, slipName, label){
    // 規定値が変更された
    changeValue(slipName, label, 'fixed', elm.value);
}
function changeUnit(elm, slipName, label){
    // 単位が変更された
    changeValue(slipName, label, 'unit', elm.value);
}
function changeMenu(elm, slipName, label){
    // メニューが変更された
    var ary = elm.value.split('\n');
    var value = ary.join(',');

    changeValue(slipName, label, 'menu', value);
}
function changeType(slipName, label, val){
    // タイプが変更された
    changeValue(slipName, label, 'type', val);
}
function changeDateType(elm, slipName, label){
    // 日付の型式が変更された ### 日付の表示形式は dateFormat として記憶 ###
    // _menuObj[slipName]['value'] に入っている文字列をオブジェクトに解凍
    var st = _menuObj[slipName]['value'];
    if (st && st.length){
        var rec = decodeObject(st);
        var val = rec[label];
        var array = val.split('|');
    } else {
        var rec = new Object();
        rec[label] = new Object();
        var array = ["","","","","","",""];
    }
    
    // オブジェクト中の日付属性の値をセット
    array[6] = elm.value; // dateFormat

    // 属性列を | で区切った文字列にエンコードしオブジェクトに格納
    rec[label] = array.join('|');
    
    // 属性値を更新したオブジェクトをエンコードし再び _menuObj[slipName]['value'] に収納
    _menuObj[slipName]['value'] = encodeObject(rec);
}

function fieldId(slipName, label){
    // 入力欄の ID を生成して返す
    return slipName + "^" + label; 
}

function setNow(fid){
    // fid の年月日ポップアップに本日の年月日を設定
    var array = fid.split("^"); // fid = slipName + "^" + label
    var slipName = array[0];
    var label = array[1];
    var formObj = formForSlipName(slipName); // 伝票構造フォーマット
    var fObj = formObj[label];

    var dv = document.getElementById(fid+".dateArea");
    dv.innerHTML = "";
    
    // 表示形式に従って日付ポップアップを表示
    var dateArray = arrayWithDateTime(todayAndTime());
    showDatePopup(dv, fid, fObj.dateFormat, dateArray);
}

function showDatePopup(elm, fid, type, dateArray){
    // 表示形式に従って日付ポップアップを表示
    var sp = newSPAN(elm, "");
    sp.innerHTML = "";
    sp.style.paddingRight = "5px";
    var img = newIMAGE(sp, "", "./timer-set.png", "time");
    img.style.height = "14px";
    img.setAttribute("onclick", "setNow('" + fid +"')");
    img.style.position = "relative";
    img.style.top = "5px";
    img.setAttribute("class", "expandIcon");
    var dv = newSPAN(elm, fid+".dateArea");

    var yy = dateArray[0];
    var mm = dateArray[1];
    var dd = dateArray[2];
    // type は rec.menu として記憶されている
    if (type == "年月"){
        var dp = newDatePopUp(dv, fid, "平成", yy, mm, dd, true, NRNoAction);
    } else if (type == "年月日時分"){
        // ## 時分を表示できるポップアップ・メニューを設定
        var h = dateArray[3];
        var m = dateArray[4];
        var s = dateArray[5];
        var dp = newDatePopUp(dv, fid, "平成", yy, mm, dd, false, NRNoAction);
        newBR(dv);
        // 時
        var sp = newSPAN(dv, "");
        sp.style.paddingLeft = "20px";
        var pp = newPopupMenu(sp, fid+".hour", hours(), h);
        var sp = newSPAN(dv, "");
        sp.innerHTML = "時";
        // 分
        var pp = newPopupMenu(dv, fid+".min", minitues(), m);
        var sp = newSPAN(dv, "");
        sp.innerHTML = "分";
    } else { // 年月日タイプ
        var dp = newDatePopUp(dv, fid, "平成", yy, mm, dd, false, NRNoAction);
    }
    
    function hours(){
        var array = [""];
        for (i=0; i < 24; i++) array.push(i);
        return array;
    }
    function minitues(){
        var array = [""];
        for (i=0; i < 60; i++) array.push(i);
        return array;
    }
}

function showFormPanel(){
    // FORM を別ウインドウで開く
    window.open("./form.php","FORM"
                ,"width=500,height=1000,scrollbars=yes,dependent=yes");
}

function showOrderSlip(slipName, records){
    // 伝票を開く
    //console.log("== showOrderSlip", slipName, encodeObject(records)); //##
    
    addCurrentSlips(slipName, records); // 表示された各伝票を記憶

    var elm = document.getElementById("editorArea");
    
    // HEADER ============================================
    if (isAnotherData()){
        var div = newDIV(elm, "/gray-header");
    } else {
        var div = newDIV(elm, "/tool-header");
    }
    // LEFT SIDE ---------------------------------
    var dv = newDIV(div, "/left-side");
    dv.style.width = "60%";
    // クローズ・アイコン
    var im = newIMAGE(dv, "icon", "./close.png", "X");
    im.setAttribute("onclick", "removeOrderSlip('"+slipName+"')");
    im.setAttribute("class", "expandIcon");
    // 伝票名
    var sp = newSPAN(dv, "");
    sp.innerHTML = slipName;
    sp.style.paddingLeft = "10px";
    // RIGHT SIDE ---------------------------------
    var dv = newDIV(div, "/right-side");
    dv.style.position = "relative";
    dv.style.top = "4px";
    // テンプレート・アイコン
    var sp = newSPAN(dv, slipName + ".templateArea");
    sp.style.marginRight = "5px";
    var img = newIMAGE(sp, "icon", "./menu.png", "+");
    var action = "getTemplateMenu('"+slipName+"')";
    img.setAttribute("onclick", action);
    img.style.height = "11px";
    img.setAttribute("class", "expandIcon");
    img.style.position = "relative";
    img.style.bottom = "8px";
    // ハンマー・アイコン
    var sp = newSPAN(dv, "");
    var img = newIMAGE(sp, "icon", "./hammer.png", "X");
    img.setAttribute("onclick", "openSlipEditor('" + slipName + "')");
    img.setAttribute("class", "expandIcon");
    img.style.position = "relative";
    img.style.bottom = "8px";
    
    // CONTENTS ============================================
    var pane = newDIV(elm, "/tool-body");
    pane.style.padding = "5px";
    if (isAnotherData()) pane.style.backgroundColor = "#eee";
    var tbl = newTABLE(pane, "/base-table");
    tbl.style.fontSize = "10pt";
    
    var formObj = formForSlipName(slipName); // 伝票構造フォーマット
    for (label in records){
        var rec = records[label];
        var fid = fieldId(slipName, label);
        
        var tr = newTR(tbl, "", "");
        // LABEL
        var td = newTD(tr, "", "");
        td.style.width = "70px";
        td.style.verticalAlign = "top";
        var sp = newSPAN(td, "");
        sp.innerHTML = label;

        // POPUP & VALUE
        var td = newTD(tr, "", "");
        td.style.borderBottom = "thin solid #ccc";
        td.style.paddingLeft = "5px";
        //  VALUE OR DATE POPUP
        if (formObj){
            var fObj = formObj[label];
        }
        if (fObj && (fObj.type == "dateType")){
            var dv = newDIV(td, fid+".dateArea");
            dv.style.padding= "3px 0";
            var dateArray = ["","","","","",""];
            if (rec.value) // メモリーに記憶されていた場合
                dateArray = arrayWithDateTime(rec.value);
            
            // 日付の表示形式で年月日ポップアップを表示：表示形式は dateFormat として記憶
            showDatePopup(dv, fid, fObj.dateFormat, dateArray);
        } else {
            //console.log("value("+rec.value+")", "fixed("+rec.fixed+")"); //##

            var val = ""; // NOA データがなければ valueOfRecord(rec)
            if (isNewForm()){
                // 新規伝票では初期設定値のみを表示
                if (rec.fixed && (rec.fixed.length > 0))
                    val = rec.fixed; // 新規伝票かつ default 値があった場合
            } else if (rec.value && (rec.value.length > 0)){
                // 検査欄から読込んだ伝票では検査欄から読込んだ値のみを表示
                val = rec.value; // メモリーに記憶されていた場合
            }
            
            //  POPUP MENU
            if (rec.menu && (rec.menu.length > 0)){
                var array = rec.menu.split(',');
                array.splice(0,0,"");
                var pp = newPopupMenu(td, label+".menu", array, val);
                pp.setAttribute("onchange", "changedMenu(this,'"+fid+"')");
            }
            // VALUE
            var fd = newFIELD(td, fid, "", 20, val);
            // onkeydownn だと iOS の場合 checkValue() 値に入力文字が追加されてしまう
            fd.setAttribute("onkeyup", "checkValue('" + fid + "')");
            checkValue(fid);
            
            // UNIT
            if (rec.unit){
                var sp = newSPAN(td, "");
                sp.innerHTML = rec.unit;
                sp.style.paddingLft = "5px";
            }
        }
    }
}

function addTemplate(){
	// 選択ポップアップ名：item を元にテンプレート取得し伝票ツール画面に追加
	var slipName = selectedItem(); // 伝票名
	var obj = formForSlipName(slipName);
	if (obj){
        setIsNewForm(true); // 新規伝票であることを記憶
        addCurrentSlips(slipName, obj); // 伝票を画面に追加
        showOrderSlip(slipName, obj); // 追加された伝票を表示

        // 新規伝票が追加された場合はテンプレート・メニューを開く
        // この後、サーバで slipName の頻度が更新される
        getTemplateMenu(slipName);
    }
}

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


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

function _showFormFor(value){
    // カルテから送られた内容を表示 
    // ### value には HTML コントロール文字が入っているが、このままでよい ###
    // HTML コントロール文字を削除すると [a<=b] のような文字列が壊れてしまう
    //console.log("----- value("+value+")"); //##
    elmFor("editorArea").innerHTML = ""; // 画面をクリアー
    initCurrentSlips();
    
    if (trim(value).length > 0){
        // 伝票の元となる CELL 記述内容があった
        var obj = decodeObject(value);
        //console.log("----- obj("+encodeObject(obj)+")"); //##
        
        // CELL に記述された伝票文字列を解析
        for (slipName in obj){
            var rec = obj[slipName]; // CELL 記述の伝票オブジェクト
            var cellObj = slitToObj(rec);
            
            // slipName のテンプレート・オブジェクトを取り出す
            var tempObj = formForSlipName(slipName);
            
            // _menuObj に CELL からの rec を merge する
            for (label in cellObj){
                // フィールド・ラベル毎に CELL 内容をテンプレート構造へマージ
                var labelObj = cellObj[label]; // ラベル毎のフィールド・オブジェクト
                var tLabelObj = (tempObj) ? tempObj[label] : null; // テンプレートのフィールド
                if (tLabelObj){
                    // テンプレート属性へ CELL 属性をマージ
                    for (name in tLabelObj){
                        var attribute = tLabelObj[name]; // テンプレートの属性データ
                        var cellAtr = labelObj[name]; // CELL 記述から抽出した属性データ
                        if (cellAtr){
                            // unit が指定されているなら value データから単位名を削除
                            if (name == 'value'){
                                var unit = tLabelObj['unit'];
                                var pos = cellAtr.indexOf(unit);
                                // 単位名の前の空白を含めて削除
                                if (pos > 0) cellAtr = cellAtr.substr(0, pos - 1);
                            }
                            // cellAtr を _menuObj へ上書きする
                            changeValue(slipName, label, name, cellAtr);
                        }
                    }
                } else { // label はテンプレートに存在しない属性だった
                    // _menuObj へ label を追加し tempObj を再読込
                    addNewLabelTo(slipName, label);
                    
                    for (num in _attributes){ // fixed など全ての属性をスキャン
                        var name = _attributes[num]; // テンプレートの属性名
                        var cellAtr = labelObj[name]; // CELL 記述から抽出した属性データ
                        if (cellAtr){
                            // cellAtr を _menuObj へ上書きする
                            changeValue(slipName, label, name, cellAtr);
                        }
                    }
                }
            }
            // changeValue() で　_menuObj が更新されたので tempObj を再度読み出す
            var tempObj = formForSlipName(slipName);
            //console.log("-- tempObj", encodeObject(tempObj)); //##
            
            // 伝票リスト（現在表示するもののみ）に追加しておく
            addCurrentSlips(slipName, tempObj); // <==### tempObj フォーマットが違う？
            //console.log("-- addCurrentSlips", encodeObject(tempObj)); //##
            
            // 追加された伝票を表示
            showOrderSlip(slipName, tempObj);
        }
    }
}
function showItemPopUp(answer){
	// 検査フォーム名のリストをサーバから読込み
	// ### formEditor.js からも使われる
	var array = JSON.parse(answer);
	//console.log("== showItemPopUp", encodeObject(array)); //##
    
	initItemRecords();
	var menuItems = new Array();
	for (num in array){
		// rec = "owner(ohashi)tag(検査)value(class^[^||I|I,II,IIIa,IIIb,IV,V^]^内膜^[^|||-,+,判定不能^]^採取器具^[^綿棒|||スクレーパ,綿棒,頚管ブラシ^]^メモ^[^|||炎症性変化,sq.metaplastic cell,軽度核腫大細胞,follow up,atrophic change,扁平上皮化生,酵母様真菌,mild dysplasia,moderate dysplasia,内膜細胞みとめず判定不能,トリコモナス,出血あり内膜も採取,細菌^]^)public(0)freq(711)menu(smear)template()" 形式
		var rec = array[num];
        //console.log("rec->", encodeObject(rec)); //##
        
        // template 値を持つものはテンプレート・メニュー用なのでスキップ
        if (rec.template && rec.template.length) continue;
        
        // value（伝票構造）を持たないものはスキップ：過去のバグ・データ除去のため
        if (!rec.value || (rec.value.length == 0)) continue;
        
        addItemRecord(rec.menu, rec);
        
		if (rec.template) continue; // テンプレート用はメニュー・アイテムに入れない
        
        menuItems.push(rec.menu);
	}
    menuItems.push("...その他");
    //alert("=== showItemPopUp ->"+encodeObject(_menuObj)); //##
	
	// テンプレート選択用ポップアップを更新
	var elm = document.getElementById("popUpArea");
	elm.innerHTML = "";
    
    var dv = newDIV(elm, "/left-side");
	dv.style.width = "80%";
	var pu = newPopupMenu(dv, "itemPopUp", menuItems, "");
	pu.setAttribute("onchange", "popUpClicked(this)");
    var bt = newDIV(dv, "/flatButton");
    bt.innerHTML = "追加";
	bt.setAttribute("onclick", "addTemplate()");
    bt.style.position = "relative";
    bt.style.top = "1px";
    bt.style.marginLeft = "3px";
    
    var dv = newDIV(elm, "hammerArea/right-side");
    dv.style.padding = "5px 20px 5px 0";
    dv.style.width = "25px";
    
    
    // =====================================================
	// === カルテから送られた内容を表示 =========================
    // =====================================================
    
    // ### value には HTML コントロール文字が入っているが、このままでよい ###
    // HTML コントロール文字を削除すると [a<=b] のような文字列が壊れてしまう
    var value = cellValue();
    _showFormFor(value);
}
function getItems(){
	// サーバから 検査伝票フォーム のリストを取り寄せ _menuObj として保存
    // ### FORM 用メニューは第２因子が tag ではなく cell.label ###
    // cell.label は "検査" -- MenuTalbe から tag=="検査" を取り出す
    // ちなみに CELL MENU では第２引数が tag
    /* --- MenuTable の内容 ---
     tag: 検査 --- 検査欄であることを示す（ここを tag にすると検査欄メニューになる）
     menu: 尿一般 --- 伝票名
     template: null --- テンプレート・メニュー用では「初期値」など
     value: 伝票構造が入っている
     */
	get_menu(owner(), cellLabel(), showItemPopUp);
}

function updateMenuFreq(slipName){
	// サーバのメニュー項目を更新
    
    // 伝票では第２引数が cell.tag テンプレートでは第２引数が cell.label
    // var value = valueForItem(slipName);
    // ### value があると予期せぬ値がテンプレートに書き込まれるバグを発生することあり
	put_menu(owner(), cellLabel(), slipName, "", "", NRNoAction);
}

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


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

function BMI_with(slipName, height, weight){
	// ### BMI 計算のための特殊埋め込み関数 ###
	// height, weight ラベルの値から BMI を計算して返す
	// cell.value はリアルタイムな値ではないので、リアルな値を取る
    var fid = fieldId(slipName, height);
	var elm = document.getElementById(fid);
	if (!elm) return "";
	
	var ht = trim(elm.value) / 100;
	
    var fid = fieldId(slipName, weight);
	var elm = document.getElementById(fid);
	if (!elm) return "";
	
	var wt = trim(elm.value) * 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(slipName, bpdF, aptdF, ttdF, flF){
	// ### EFW:胎児推定体重 計算のための特殊埋め込み関数 ###
    var bpd = 0;
    var aptd = 0;
    var ttd = 0;
    var fl = 0;
    
    var fid = fieldId(slipName, bpdF);
	var elm = document.getElementById(fid);
	if (elm) bpd = trim(elm.value); // フィールド値
    var fid = fieldId(slipName, aptdF);
	var elm = document.getElementById(fid);
	if (elm) aptd = trim(elm.value); // フィールド値
    var fid = fieldId(slipName, ttdF);
	var elm = document.getElementById(fid);
	if (elm) ttd = trim(elm.value); // フィールド値
    var fid = fieldId(slipName, flF);
	var elm = document.getElementById(fid);
	if (elm) fl = trim(elm.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){
        return efw;
    } else {
        return "";
    }
}
function TSAT_with(slipName, ironF, tibcF){
    // ### TSAT 計算のための特殊埋め込み関数 ### by Dr.K.YAMASAKI
    // iron, tibc ラベルの値から TSAT を計算して返す
    // cell.value はリアルタイムな値ではないので、リアルな値を取る
    var fid = fieldId(slipName, ironF);
	var elm = document.getElementById(fid);
	if (elm) iron = trim(elm.value); // フィールド値
    
    var fid = fieldId(slipName, tibcF);
	var elm = document.getElementById(fid);
	if (elm) tibc = trim(elm.value); // フィールド値
    if (iron * tibc == 0) return "";
    
    var tsat = iron / tibc *100;
    tsat = Math.round(tsat * 10);
    tsat = Math.floor(tsat) / 10;
    return tsat;
}
function MCV_with(slipName, hematoF, rbcF){
    // ### MCV 計算のための特殊埋め込み関数 ### by Dr.K.YAMASAKI
    // hemato, rbc ラベルの値から MCV を計算して返す
    // BMIの関数を参考にして作成
    var fid = fieldId(slipName, hematoF);
	var elm = document.getElementById(fid);
	if (!elm) return ""
        
        var hemato = trim(elm.value)
        
        var fid = fieldId(slipName, rbcF);
	var elm = document.getElementById(fid);
	if (!elm) return ""
        
        var rbc = trim(elm.value)
        if (hemato * rbc == 0) return "";
    
    var mcv = hemato / rbc *1000;
    mcv = Math.round(mcv * 10);
    mcv = Math.floor(mcv) / 10;
    return mcv;
}
function MCH_with(slipName, hgbF, rbcF){
    // ### MCH 計算のための特殊埋め込み関数 ### by Dr.K.YAMASAKI
    // hgb, rbc ラベルの値から MCH を計算して返す
    // BMIの関数を参考にして作成
    var fid = fieldId(slipName, hgbF);
	var elm = document.getElementById(fid);
	if (!elm) return ""
        
        var hgb = trim(elm.value)
        
        var fid = fieldId(slipName, rbcF);
	var elm = document.getElementById(fid);
	if (!elm) return ""
        
        var rbc = trim(elm.value)
        if (hgb * rbc == 0) return "";
    
    var mch = hgb / rbc *1000;
    mch = Math.round(mch * 10);
    mch = Math.floor(mch) / 10;
    return mch;
}
function MCHC_with(slipName, hematoF, hgbF){
    // ### MCHC 計算のための特殊埋め込み関数 ### by Dr.K.YAMASAKI
    // hemato, hgb ラベルの値から MCHC を計算して返す
    // BMIの関数を参考にして作成
    var fid = fieldId(slipName, hematoF);
	var elm = document.getElementById(fid);
	if (!elm) return ""
        
        var hemato = trim(elm.value)
        
        var fid = fieldId(slipName, hgbF);
	var elm = document.getElementById(fid);
	if (!elm) return ""
        
        var hgb = trim(elm.value)
        if (hemato * hgb == 0) return "";
    
    var mchc = hgb / hemato *100;
    mchc = Math.round(mchc * 10);
    mchc = Math.floor(mchc) / 10;
    return mchc;
}

function checkValue(fid){
	// 入力された値のチェックを行う
    //_initDebug(true); //##
    //_debug("== checkValue->"+ fid); //##

	var textField = document.getElementById(fid); // dynamically
    
    var ary = fid.split("^"); // fid は "slipName^label" 型式
    var slipName = ary[0]; // 伝票名
    var label = ary[1]; // フィールド・ラベル

    if (label == "BMI"){
		// ### BMI 計算のための特殊埋め込み関数 ###
		var val = BMI_with(slipName, "身長", "体重");
        setBuiltinFrame(textField, val);
	} else if (label == "EFW"){
		// ### EFW:胎児推定体重 計算のための特殊埋め込み関数 ###
		var val = EFW_with(slipName, "BPD", "APTD", "TTD", "FL");
        setBuiltinFrame(textField, val);
    } else if (label == "TSAT"){
        // ### TSAT:トランスフェリン飽和度 計算のための特殊埋め込み関数 ### by Dr.K.YAMASAKI
        var val = TSAT_with(slipName, "血清鉄", "TIBC");
        setBuiltinFrame(textField, val);
    } else if (label == "MCV"){
        // ### MCV:平均赤血球容積のための特殊埋め込み関数 ### by Dr.K.YAMASAKI
        var val = MCV_with(slipName, "ヘマトクリット", "赤血球数");
        setBuiltinFrame(textField, val);
    } else if (label == "MCH"){
        // ### MCH:平均赤血球容積のための特殊埋め込み関数 ### by Dr.K.YAMASAKI
        var val = MCH_with(slipName, "ヘモグロビン", "赤血球数");
        setBuiltinFrame(textField, val);
    } else if (label == "MCHC"){
        // ### MCHC:平均赤血球血色素濃度のための特殊埋め込み関数 ### by Dr.K.YAMASAKI
        var val = MCHC_with(slipName, "ヘマトクリット", "ヘモグロビン");
        setBuiltinFrame(textField, val);
    }
	var value = textField.value; // dynamically
    if (!value || value.length == 0) return;

    // 指定範囲を取り出す
    var slipObj = currentSlip(slipName); // 表示されている伝票を入れたオブジェクト
    
    if (hasStandard(textField) == false){ // 文字列埋込の基準値で判定し警告色
        // parent() に基準値が記憶されており、基準値からはずれるなら警告色
        if (slipObj[label]) parent().checkStandard(textField, label, value);
    }
    
    
    function setBuiltinFrame(elm, value){
        // 埋め込み関数の設定された入力フィールドに value を表示し、枠の色を薄くする
        elm.value = value;
        elm.style.border = "1px solid #eee";
    }
	
	function label(cellId){
		// cellId に相当するラベル名を返す
		var tr = document.getElementById(cellId);
		var td = tr.childNodes[0]; // left side FORM
		return td.innerHTML;
	}
    
    function hasStandard(textField){
        // textField の値が textField 埋込基準値にはずれていれば警告色
        // HL7 型式のデータの場合にこの型式がとられる
        
        // textField 文字列の [ と ] で挟まれた部分を抽出
        var results = extractSTRING(textField.value, '[', ']');
        if (!results){
            // textField 値に基準値が埋め込まれていなかった
            return false;
        }
        //console.log("results", results); //##
        
        var val = results[0]; // [ より左の文字列：検査値
        var ary = val.split(' ');
        val = ary[0]; // '20 mg' 文字列を '20' にする
        
        var standard = results[1]; // [ と ] で挟まれた文字列：基準値
        var right = results[2]; // ] より右の文字列：通常は文字列なし
        
        if ((standard.length > 1) && (standard.indexOf('-') >= 0)){ // [min-max] 型式
            var ary = standard.split("-");
            var min = ary[0] * 1; // 最小基準値
            var max = ary[1] * 1; // 最大基準値
            val = val * 1; // "val" 文字列：検査値
            //console.log("min-max", val, min, max); //##
            
            if (val < min)
                textField.style.backgroundColor = "#ddf";                                
            else if (val > max)
                textField.style.backgroundColor = "#fee";                                
        } else if (standard.indexOf('<') >= 0) {
            // 血清： [<=30] [<1.0] [陰性<8] 形式
            //console.log(" hasStandard <", val, ln); //##
            var ary = standard.split("<=");
            if (ary.length > 1){
                var max = ary[1] * 1; // 最大基準値
                if (val * 1 > max)
                    textField.style.backgroundColor = "#fee"; 
            } else {
                var ary = standard.split("<");
                if (ary.length > 1){
                    var max = ary[1] * 1; // 最大基準値
                    if (val * 1 >= max)
                        textField.style.backgroundColor = "#fee"; 
                }
            }
        } else if (standard.indexOf('>') >= 0) {
            // 血清： [<=30] [<1.0] [陰性<8] 形式
            var ary = standard.split(">=");
            if (ary.length > 1){
                var min = ary[1] * 1; // 最大基準値
                if (val * 1 < min)
                    textField.style.backgroundColor = "#ddf"; 
            } else {
                var ary = standard.split(">");
                if (ary.length > 1){
                    var min = ary[1] * 1; // 最大基準値
                    if (val * 1 <= min)
                        textField.style.backgroundColor = "#ddf"; 
                }
            }
        } else {
            // 部分尿： [+-] [-] 形式
            // 血清： [陰性] 形式
            // 部分尿の場合 "（-）" 形式の場合があるので両カッコを削除
            var array = extractSTRING(val, '（', '）');
            if (array) val = array[1];
            //console.log(" [stardard]", val, standard); //##
            
            if (val != standard) textField.style.backgroundColor = "#fee";                                
        }
        
        return true;
    }
}

function closeForm(){
	// FORM 全体を閉じる
    if (window.name == "tools")
        document.getElementById("base").innerHTML = "";
    else
        window.close();
}

function savedOrder(answer){
    // 過去データを上書きした場合は画面を再表示
    window.top.location.reload();
}
function saveOrder(){
	// 確定ボタンが押された：伝票のデータを NOA 本体へ転送
    /* if (isAnotherData()){
        if (confirm("過去の伝票ですが変更していいですか") == false) return;
    } */
    var withUnit = valueWithUnit(); // データに単位を添えて書き戻すかのステータス
    var slipArray = new Array(); // 伝票群の構造・データを記憶する配列
    var slips = currentSlips(); // 表示されている伝票を入れたオブジェクト
    for (slipName in slips){
        var slip = slips[slipName]; // 最初に表示時点での伝票構造とデータのオブジェクト

        var slipObj = new Object(); // 伝票の各フィールドを記憶するオブジェクト
        for (label in slip){
            var labelObj = slip[label];
            // 通常の値は fid から取得できる
            var fid = fieldId(slipName, label);
            var val = document.getElementById(fid).value;
            
            // 空データの項目は省略
            if ((val.length == 0) && (ignoreBlankForm())) continue;
            
            // 単位表示チェックが入っていれば単位を添えて書き戻す
            if (withUnit && (labelObj.unit.length))
                val += " " + labelObj.unit;

            slipObj[label] = val;

            // 時分のある場合は時分を取得
            var helm = document.getElementById(fid+".hour");
            if (helm){
                var dateTime = val; // "2013-09-19" のような型式：時刻はない場合あり
                var times = arrayWithDateTime(dateTime); // 日時の配列：時分秒も
                
                // 配列の時の部分を置換
                times[3] = (helm.value.length > 0) ? helm.value : "00"; 
                
                var melm = document.getElementById(fid+".min");
                if (melm) 
                    times[4] = (melm.value.length > 0) ? melm.value : "00"; // 配列の分の部分を置換
                
                var st = dateTimeWithArray(times);
                if (times[0] * times[1] * times[2] == 0)
                    slipObj[label] = " ";
                else
                    slipObj[label] = st;
            }
            
            // 整形モードの場合、各項目の末尾に改行を入れる
            //if (formatMode()) slipObj[label] += "#<br>";
        }
        var recObj = new Object(); // 一伝票の構造・データを含むオブジェクト
        recObj[slipName] = slipObj;
        var rec = encodeObject(recObj); // １伝票の構造・データを含む文字列

        slipArray.push(rec); // １伝票の文字列を配列に入れる
    }
    
    if (isAnotherData()){
        var value = slipArray.join(""); // 伝票文字列の区切りには既に改行が入っているはず
        // 本日以外のページから開かれた場合 DB へ直書き
        var dateTime = elmFor("historyPop").value; // 伝票の日付
        var limit = parent().timeLimit();
        var container = new Object();
        var tag = parent().currentTag();
        container[tag] = value;
        
        put_page(owner(),patientId(),dateTime,limit,container,savedOrder);
    } else {
        var value = slipArray.join("<br>"); // 伝票文字列の区切りに改行を入れる
        // 本日のページから開かれた場合：DB へ直書きせず NOA の field へ書き戻す
        var status = document.getElementById("touchAndGoCheck").checked;
        gotValueFromTool(value, status);
        _showExamDate(); // 検査日を表示
    }
    
    // FORM パネルを閉じる
    if (status) closeForm();
}

function selectForm(elm){
    // 受診日ポップアップから選択された伝票を表示
    var dateTime = elm.value;
    var tag = parent().currentTag();
    var obj = parent().valueForTag(tag, dateTime);
    
    // 表示されているカルテと同じ年月日の伝票かどうかを検証
    var status = (dateTime == parent().currentDate()) ? false : true;
    setIsAnotherData(status);
    
    // CELL 内容 obj.value を伝票形式で表示
    _showFormFor(obj.value);
    
    // カルテと同じ年月日の伝票ならポップアップを消し年月日を表示
    if (dateTime == parent().currentDate()) _showExamDate();
}

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

function _showDateOrNot(elm){
    // mouse out 時、ポップアップ内容が選択変更されていればポップアップを文字列に戻さない
    var dateTime = elm.value;
    if (dateTime == parent().currentDate())
        _showExamDate();
}

function _showExamHistory(){
    // 検査を行った受診日のポップアップ・メニューを表示
    var elm = elmFor("examHistoryArea");
    
    var array = examHistory();
    if (array){
        // CELL が編集モードでなければ currentTag() が取得できない
        elm.innerHTML = "";
        var pp = newPopupMenu(elm, "historyPop", array, "");
        pp.setAttribute("onchange", "selectForm(this)");
        pp.setAttribute("onmouseout", "_showDateOrNot(this)");
    }
    
    function examHistory(){
        // 検査の行われた受診日の配列を返す
        var currentDate = parent().currentDate();
        var tag = parent().currentTag();
        if (!tag)
            return null;

        var array = new Array();
        var history = parent().history();
        for (num in history){
            var dateTime = history[num];
            
            if (dateTime == currentDate){
                array.push(dateTime);
            } else {
                var obj = parent().valueForTag(tag, dateTime);
                var buff = (obj.value) ? trim(obj.value) : "";
                if (buff.length && ((buff.indexOf("(") > 0) && (buff.indexOf(")") > 0)))
                    array.push(dateTime);
            }
        }
        return array;
    }
}
function _showExamDate(){
    // 検査日を表示
    var elm = elmFor("examHistoryArea");
    elm.innerHTML = "";
    var sp = newSPAN(elm, "");
    sp.innerHTML = parent().currentDate();
    sp.style.paddingLeft = "8px";
    sp.style.fontSize = "10pt";
    sp.setAttribute("onmouseover", "_showExamHistory()");
}

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

    // ===== FORM 表示エリア ==========================
    var elm = newDIV(base, "formBase");
    // === HEADER =======================
    var div = newDIV(elm, "/tool-header");
    // --- LEFT SIDE ---
    var dv = newDIV(div, "/left-side");
    dv.style.width = "250px";
    // ラベル
    var sp = newSPAN(dv, "");
    sp.style.marginLeft = "5px";
    sp.innerHTML = "伝票";
    // 検査歴
    var sp = newSPAN(dv, "");
    sp.innerHTML = "検査日";
    sp.style.marginLeft = "10px";
    sp.style.fontSize = "9pt";
    var sp = newSPAN(dv, "examHistoryArea");
    var sp = newSPAN(sp, "");
    _showExamDate(); // 検査日を表示
    // --- RIGHT SIDE ---
    var dv = newDIV(div, "/right-side");
    // 外部ウインドー・アイコン -------
    if (window.name == "tools"){
        var sp = newSPAN(dv, "outWindow/outArrowArea");
        sp.setAttribute("onclick", "showFormPanel()");
        sp.style.marginRight = "10px";
        setInfoTip("outWindow", "別ウインドーで開く"); // HELP
        var img = newIMAGE(sp, "", "./outArrow.png", "?");
        img.style.height = "12px";
        img.style.position = "relative";
        img.style.top = "3px";
        img.setAttribute("class", "expandIcon");
    }
    // HELP ICON
	var im = newIMAGE(dv, "", "./help.png", "?");
	im.setAttribute("onclick", "openHelp('formHelp.html')");
    im.style.height = "18px";
    im.style.position = "relative";
	im.style.bottom = "3px";
    im.setAttribute("class", "expandIcon");

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

    // === FOOTER =======================
    var div = newDIV(elm, "/tool-footer");
    // --- LEFT SIDE ---
    var dv = newDIV(div, "/right-side");
    dv.style.paddingRight = "0px";
    // 単位表示
    var sp = newSPAN(dv, "");
    sp.style.paddingRight = "5px";
    var cb = newCHECKBOX(sp, "withUnitCheck", "単位表示", valueWithUnit());
    cb.setAttribute("onchange", "setValueWithUnit(this)");
    // 「空欄を書き戻さない」チェックボックスを表示
    var sp = newSPAN(dv, "");
    sp.style.paddingRight = "5px";
	var cb = newCHECKBOX(sp, "", "空欄無視", ignoreBlankForm());
	cb.setAttribute("onclick", "setIgnoreBlankForm(this)"); // localStorage.js
    /* // 「整形」チェックボックスを表示
     var sp = newSPAN(elm, "");
     sp.style.paddingRight = "5px";
     var cb = newCHECKBOX(sp, "", "整形", formatMode());
     cb.setAttribute("onclick", "setFormatMode(this)"); // localStorage.js
     */
    // 確定保存チェックボックス
    var cb = newCHECKBOX(dv, "touchAndGoCheck", "確定保存", isFormTouchAndGo());
    cb.setAttribute("onchange", "setFormTouchAndGo(this)");
    // 確定ボタン
    var bt = newDIV(dv, "/fixButton");
    bt.innerHTML = "確定";
    bt.style.margin = "0 10px";
    bt.setAttribute("onclick", "saveOrder()");
    
    // VERSION
    var div = newDIV(base, "");
    div.innerHTML = fm_version();
    div.style.padding = "3px 0 0 10px";
    div.style.fontSize = "9pt";
    div.style.color = "#aaa";
    
    setIsNewForm(false); // 新規伝票ではないことを記憶
    
	// ポップアップメニューを読み込み、カルテデータをセット
	getItems();
}

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