
var samples = ["MenuTable:./MENU.txt","FieldTable:./FIELD.txt","PriceList:./PRICE.txt","ProgressSection:./GROUP.txt"];
var _indispensables = ["施設名","施設","自費係数","まるめ係数","訂正可能時間"]; // 必須項目

var _hospitalId;
function setHospitalId(hid){
	_hospitalId = hid;
}
function hospitalId(){
	// 新規作成されつつある HospitalId
	return _hospitalId;
}

var _hospitalIdTable;
var _hospitalIdTableInDB;
function setHospitalIdTable(array){
	_hospitalIdTable = array;
	
	// _hospitalIdTableInDB = array では _hospitalIdTable が変化すると
	// _hospitalIdTableInDB も変化してしまうので、値をコピーして作成
	_hospitalIdTableInDB = new Array();
    for (num in array){
		_hospitalIdTableInDB.push(array[num]);
	}
}
function hospitalIdTable(){
	return _hospitalIdTable;
}
function hospitalIdTableInDB(){
	// DB に保存された 施設ID の配列を返す
	return _hospitalIdTableInDB;
}

var _records;
function setRecords(obj){
    _records = (obj) ? obj : new Array();
}
function records(){
	return _records;
}
function owner(){
    // hospitalId() の一致したレコードの owner を返す
    for (num in _records){
        var rec = _records[num];
        if (rec.hospitalId != hospitalId()) continue;
        
        if (rec.owner) return rec.owner;
    }
	return null;
}
function recordForKey(key){
    // hospitalInfo から hospitalId(), key に一致するレコードを返す
    for (num in _records){
        var rec = _records[num];
        if (rec.key != key) continue;
        if (rec.hospitalId != hospitalId()) continue;
        
        return rec;
    }
	return null;
}
function setValueForKey(value, key){
    // hospitalId(), key に一致するレコードの値に value を与える
    if (_records.length){
        for (num in _records){
            var rec = _records[num];
            if (rec.hospitalId != hospitalId()) continue;
            if (rec.key != key) continue;
            
            _records[num].value = value;
            _records[num].changed = true;
            return;
        }
    } else {
        var num = 0;
    }

    // _records は DB の HospitalInfo から収集するので、あらかじめ DB に登録されていない
    // 空データの項目は _record に現れない。従って存在しない key は新規レコードを生成し追加
	_records[num + 1] = new Object();
	_records[num + 1].key = key;
	_records[num + 1].value = value;
	_records[num + 1].changed = true;
    
    _debug("setValueForKey _records->"+encodeObject(_records)); //##
}

function encodeSCRIPT(buff){
    // "script": を検出し内容を JSON で解析できないよう encode
    // "script":"{"key":"value","key":"value",,}" を
    // "script":"@{@|@'key@|@':@|@'value@|@',,}@" のように encode
    var key1 = '"script":"{';
    var array = buff.split(key1);
    if (array.length > 1){
        var left = array[0]; // script より左側の文字列
        array.shift(); // array の最初の要素を削除
        var ln = array.join(key1); // key1 より右側の文字列
        var key2 = '}"';
        var array2 = ln.split(key2);
        if (array2.length > 1){
            var script = array2[0];
            array2.shift(); // array の最初の要素を削除
            var right = array2.join(key2); // script より右側の文字列
            // script 中の '\\' を '' にする
            var array3 = script.split('\\');
            if (array3.length > 1) script = array3.join('');
            
            // script 中の " を @|@' に encode
            script = convertSTRING(script, '"', '@|@');
            script = '"script":"@{' + script + '}@"';
            
            // key1 がみつかるうちはリカーシブルに処理を続ける
            var result = encodeSCRIPT(right);
            if (result)
                return left + script + result;
            else
                return left + script + right;
        }
    }
    return null;
}
function decodeScriptIn(array){
    // array 中の encode された script を decode する
    for (num in array){
        var obj = array[num];
        if (!obj) continue;
        
        var script = obj.script;
        if (script){
            // "script":"@{@|@key@|@:@|@value@|@,,}@" を
            // {"key":"value",,} に decode
            script = convertSTRING(script, '@|@', '"');
            script = convertSTRING(script, '@{', '{');
            script = convertSTRING(script, '}@', '}');
            //   script = '{' + script + '}';
            obj.script = script;
        }
    }
    return array;
}

function mergeTable(table, obj){
    // テーブルの内容をテンプレートとマージ
    _debug("mergeTable->"+table); //##
    
    if (table == "MenuTable"){
        // obj: [{"owner":"ohashi","tag":"..","menu":"あり",,}{,,}]
        _source = obj;
        mergeMenuTable();
    } else if (table == "FieldTable"){
        // obj:[{"owner":"ohashi","tag":"..",,},{,,},,]
        _source = obj;
        mergeFieldTable();
    } else if (table == "PriceList"){
        // obj: [{"code":"","alias":"",},{"code":"",},]
        _source = obj;
        mergePriceList();
    } else { // GROUP データをサーバへ送るループに入る
        _source = obj;
        mergeGroup();
    }
}


////////////////////////////////////////////////////
///// Ajax /////////////////////////////////////////

var _sampleNum;

function sampleTableName(){
    // 現在選択されているサンプルのテーブル名を返す
    var st = samples[_sampleNum]; // "MenuTable:./MENU.txt"
    var ary = st.split(":");
    return ary[0]; // "MenuTable"
}

function loadedSampleData(){
	// サンプルデータを DB に読み込んだ結果を返す
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert("loadedSampleData-> "+value); //##
		_debug("<p>loadedSampleData-> "+value + "</p>"); //##
		var array = value.split("<SEPARATOR>");
		if (array.length > 1){
			if (array[1].length > 0){
				// ### JSON に含まれる改行を encode しておく
				var val = transferCR(array[1]);
                // ### "script":"***" の中の JSON を encode しておかないと "script"
                // ### の中を、ここでは文字列として扱いたいのに JSON 解析されてしまう
                var st = encodeSCRIPT(val);
                if (st) val = st;
                
                // JSON が解析できるようになったのでオブジェクトへ変換
				var obj = eval('(' + val + ')');
				
                //_debug("loadedSampleData->"+encodeObject(obj)); //##
                
				// ### object 中の encode された改行を decode する
				obj = decodeEncodedCR(obj);
                // ### encode されていた JSON を元の JSON 文字列に decode する
				obj = decodeScriptIn(obj);
                
				_num = 0;
                mergeTable(sampleTableName(), obj);
			} else
				alert("ERROR *** メニュー・ソースがありません\n\n"+ value);
		}
	}
	
	function decodeEncodedCR(array){
		// obj 中の encode された改行を decode する
		for (var i=0,ct=array.length; i < ct; i++){
			var newObj = new Object();
			var obj = array[i];
			for (key in obj){
				var val = obj[key];
				newObj[key] = transferToCR(val);
			}
			array[i] = newObj;
		}
		return array;
	}
}
function loadSampleData(){
	// サンプルデータを DB に読み込む
    if (_sampleNum >= samples.length){
        // サンプルデータの読み込みが終了
        hideMessage("_message");
        alert("サンプルデータの読込が終了しました。左メニュー「施設・ユーザ登録」を再度クリックしてください。"); 
        
        // debug メッセージを残すため initRegister() や showHospitalInfo() へ進まない
    } else {
        xmlHttpObject = createXMLHttpRequest(loadedSampleData);
        if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
            array = new Array();
            var st = samples[_sampleNum]; // "MenuTable:./MENU.txt"
            var ary = st.split(":");
            array['tableType'] = ary[0]; // "MenuTable"
            array['filename'] = ary[1]; // "./MENU.txt"
            
            var val = encodeObject(array);
            var st = "sysServer.php?command=GET_ARCHICE"
            + "&value=" + encodeSTRING(val);
            
            //_debug("<p>loadSampleData-> "+st+"</p>"); //##
            
            xmlHttpObject.open("GET", encodeURI(st), true);
            xmlHttpObject.send(null);
        }
    }
}

var _source;
var _num;
function mergedMenuTable(){
	// MenuTable がマージされた
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert(value); //##
		showMessage("_message", value);
		mergeMenuTable();
	}
}
function mergeMenuTable(){
	// メニュー・ソースを DB とマージ
	if (_num < _source.length){
		xmlHttpObject = createXMLHttpRequest(mergedMenuTable);
		if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
			var obj = _source[_num++];
			// MenuTable は public 権限で DB に書込む
			var st = "./sysServer.php?command=MERGE_MENU"
			+ "&owner=public"
			+ "&value=" + encodeSTRING(encodeObject(obj));
			//alert(st); //return;//##
			xmlHttpObject.open("GET", encodeURI(st), true);
			xmlHttpObject.send(null);
		}
	} else {
		// 振り出しへ戻る
        _sampleNum++;
        loadSampleData();
	}
}

function mergedFieldTable(){
	// MenuTable がマージされた
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert(value); //##
		showMessage("_message", value);
        //_debug(value); //##
        
		mergeFieldTable();
	}
}
function mergeFieldTable(){
	// メニュー・ソースを DB とマージ
	if (_num < _source.length){
		xmlHttpObject = createXMLHttpRequest(mergedFieldTable);
		if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
			var obj = _source[_num++];
			// FieldTable は public 権限で DB に書込む
			var st = "./sysServer.php?command=MERGE_FIELD"
			+ "&owner=public"
			+ "&value=" + encodeSTRING(encodeObject(obj));
			//alert(st); //return;//##
            
			xmlHttpObject.open("GET", encodeURI(st), true);
			xmlHttpObject.send(null);
		}
	} else {
		// 振り出しへ戻る
        _sampleNum++;
        loadSampleData();
	}
}

function mergedGroup(){
	// GROUP がマージされた
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert(value); //##
		showMessage("_message", value);
		mergeGroup();
	}
}
function mergeGroup(){
	// GROUP を DB とマージ
	if (_num < _source.length){
		xmlHttpObject = createXMLHttpRequest(mergedGroup);
		if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
			var obj = _source[_num++];
            //alert("mergeGroup->"+encodeObject(obj)); //return; //##
            var args = new Array();
            args['patientId'] = "GroupMenu";
            args['pageHeader'] = obj.pageHeader;
            args['subject'] = obj.subject;
            args['object'] = obj.object;
            args['examination'] = obj.examination;
            args['prescription'] = obj.prescription;
            args['disease'] = obj.disease;
            args['treatment'] = obj.treatment;
            args['plan'] = obj.plan;
            args['freq'] = 0;
            args['owner'] = "public";
            
			// MenuTable は public 権限で DB に書込む
			var st = "./sysServer.php?command=MERGE_GROUP"
			+ "&value=" + encodeSTRING(encodeObject(args));
			//alert(st); return;//##
			xmlHttpObject.open("GET", encodeURI(st), true);
			xmlHttpObject.send(null);
		}
	} else {
		// 振り出しへ戻る
        _sampleNum++;
        loadSampleData();
	}
}

function mergedPriceList(){
	// priceList がマージされた
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert(value); //##
		showMessage("_message", value);
        //_debug(value); //##
        
		mergePriceList();
	}
}
function mergePriceList(){
	// メニュー・ソースを DB とマージ
	if (_num < _source.length){
		xmlHttpObject = createXMLHttpRequest(mergedPriceList);
		if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
			var obj = _source[_num++];
			var st = "./sysServer.php?command=MERGE_PRICE"
			+ "&owner=" + owner()
			+ "&value=" + encodeSTRING(encodeObject(obj));
			//alert(st); //return;//##
			xmlHttpObject.open("GET", encodeURI(st), true);
			xmlHttpObject.send(null);
		}
	} else {
		// 振り出しへ戻る
        _sampleNum++;
        loadSampleData();
	}
}

function removedNoaDB(){
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		alert(value);
        
        // 振り出しへ戻る
        initRegister();
	}
}
function removeNoaDB(){
    // NOA データベースを全て削除
    if (! confirm("NOA のデータベースを一旦すべて削除します")) return;
    
    xmlHttpObject = createXMLHttpRequest(removedNoaDB);
    if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
        var st = "./sysServer.php?command=RREMOVE_NOA";
        //alert(st); //return;//##
        xmlHttpObject.open("GET", encodeURI(st), true);
        xmlHttpObject.send(null);
    }
}

function createdTablesIfNeeded(){
	// 各テーブルの存在がチェックされすべて生成された
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert("createdTablesIfNeeded->"+value);//###
		var array = value.split("<SEPARATOR>");
		if (array.length > 1){
			var st = array[1];
			if (st.length){
				// テーブルの新規生成メッセージがあった場合、表示
                _debug("createdTablesIfNeeded->"+st); //##
                
                // テーブルが生成されたのでデータ読込み
                _initDebug(false); //##

                _sampleNum = 0;
                loadSampleData();
            } else {
                _debug("createdTablesIfNeeded-> okay"); //##
                // テーブルは既に存在したのでデータ読込みせず、次のステップへ
                showHospitalInfo();
            }
		} 
        hideMessage("_message");
	} else
		showMessage("_message", "create TABLES if needed ...");
}
function createTablesIfNeeded(){
	// DB に table が存在しなければ新たに生成
	xmlHttpObject = createXMLHttpRequest(createdTablesIfNeeded);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var st = "./sysServer.php?command=CREATE_TABLE_IF_NEEDED";
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function closeReadRetry(){
    var elm = document.getElementById("readRetryArea");
    elm.innerHTML = "";
}
function readRetry(){
    // 読込がうまくいかない場合 NOA DB を削除してやり直しをうながす
    var elm = document.getElementById("readRetryArea");
    elm.innerHTML = "";
    elm.style.padding = "5px 5px";

    var bt = newBUTTON(elm, "", "NOA データベースを削除");
    bt.setAttribute("onclick", "removeNoaDB()");
    
    var sp = newSPAN(elm, "");
    sp.style.paddingLeft = "10px";
    sp.innerHTML = " した後、左メニューから「施設・ユーザ登録」をもう一度選択してください";
}

function checkedDataBase(){
	// NOA DB のテーブル類がそろっているかどうかサーバから返答
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert("checkedDataBase ---\n"+value);//###
        _debug("..checkedDataBase-><p>"+value+"</p>"); //##
		var array = value.split("<SEPARATOR>");
		if (array.length > 1){
            if (array[1].length){
                // NOA DB の生成に失敗した
                _debug("ERROR *** "+array[1]); // Error message
                
                var elm = document.getElementById("message");
                var a = newA(elm, "読み込みがうまくいなかい場合", "#", "");
                a.setAttribute("onclick", "readRetry()");
                var div = newDIV(elm, "readRetryArea");
            } else {
                // NOA DB は存在したか生成された
                _debug("checkDB okay"); // Error message
                
                // NOA TABLE が存在しなければ生成
                createTablesIfNeeded();
            }
        }
		hideMessage("_message");
	} else
		showMessage("_message", "check up TABLES ...");
}
function checkDataBase(){
	// NOA DB が存在するかチェック
    _initDebug(false); //##
    _debug("start checkDataBase.."); //##
    
	xmlHttpObject = createXMLHttpRequest(checkedDataBase);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var st = "./sysServer.php?command=CHECK_DB";
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function gotHospitalTable(){
	// サーバから返された hospitalTable のレコード群から hospitalId ポップアップ生成
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		// alert("gotHospitalTable ===\n"+value);//###
		var array = value.split("<SEPARATOR>");
		if (array.length > 1){
			var buff = trim(array[1]);
			var items = new Array();
			if (buff.length > 0){
				var records = JSON.parse(buff);
                //alert("records->"+encodeObject(records)); //##
                
				var old_hid = "";
                for (no in records){
					// hospitalInfo record から hospitalId の配列を作成
					var record = records[no];
					var hid = record.hospitalId;
					if (!isSame(hid, old_hid)) items.push(hid);
					old_hid = hid;
				}
			}
			setHospitalIdTable(items);
			items.splice(0,0,"");
			items.push("...その他");
			var elm = document.getElementById("popUpArea");
			elm.innerHTML = "";
			var pu = makePopupMenu(elm, "hospitalId", items, "");
			pu.setAttribute("onchange", "clickedHospitalId(this)");
			hideMessage("_message");
		} else
			showMessage("_message", value);
	}
	else
		showMessage("_message", "getHospitalTable ...");
}
function getHospitalTable(){
	// 保険者番号に一致する保険者名・電話番号を検索し表示
	xmlHttpObject = createXMLHttpRequest(gotHospitalTable);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var st = "./sysServer.php?command=GET_HOSPITAL_TABLE"
        + "&target=";
		//alert("getHosptailTable:"+st); //##
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function gotHospitalInfo(){
	// サーバから返された hospitalTable のレコード群から hospitalId 編集テーブル表示
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert("gotHospitalInfo ===\n"+value);//###
		var array = value.split("<SEPARATOR>");
		if (array.length > 1){
			var buff = array[1];
			var items = new Array();
            var records = JSON.parse(buff);
			//alert("gotHospitalInfo ==\n"+encodeObject(records));//##

            setRecords(records);
			showHospitalTable();
            
			hideMessage("_message");
		} else
			showMessage("_message", value);
	}
	else
		showMessage("_message", "getHospitalInfo ...");
}
function getHospitalInfo(hospitalId){
	// 施設 ID に一致する施設属性を検索し表示
    if (hospitalId.length == 0){
        alert("施設ID が空です");
        return;
    }
    
	xmlHttpObject = createXMLHttpRequest(gotHospitalInfo);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
        setHospitalId(hospitalId);
        
		var st = "./sysServer.php?command=GET_HOSPITAL_TABLE"
		+ "&target=" + hospitalId;
		//alert(st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function saved(){
	// サーバから返された hospitalTable のレコード群から hospitalId 編集テーブル表示
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert("saved ===\n"+value);//###
		var array = value.split("<SEPARATOR>");
		if (array.length > 1){
            // デバッグ用ログが返ってくる
            //alert("saved->"+array[1]); //##
            
			hideMessage("_message");
            
            // 職員リストを閉じる
            closeStaffInfo();
            
            // 初期画面へ戻る
            getHospitalInfo(hospitalId());
            showHospitalInfo();
            document.getElementById("hospitalEditorArea").innerHTML = "";
        }
	} else {
		showMessage("_message", "save hospitalInfo ...");
    }
}
function save(){
    // 施設情報をサーバへ保存
	if (incompleteHospitalInfo()) return;
	
	xmlHttpObject = createXMLHttpRequest(saved);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
        _initDebug(false); //##

		var st = "./sysServer.php?command=PUT_HOSPITAL_TABLE"
		+ "&value=" + encodeObject(changedRecords());
        
		_debug("save ---<br>"+st); //return; //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
    
	function changedRecords(){
		var results = new Object();
        for (i in records()){
			var rec = records()[i];
			if (rec.changed)
                results[rec.key] = encodeSTRING(rec.value);
		}
        
        // 転送オブジェクトが２階層になると処理が面倒なので中に組み込んでしまう
        results['owner'] = owner();
        results['hospitalId'] = hospitalId();
        
		return results;
	}
	
	function incompleteHospitalInfo(){
		// 施設情報の入力内容が不十分なら true を返す
		var array = records();
        for (k in _indispensables){
			var key = _indispensables[k];
			var found = false;
            for (i in array){
				var rec = array[i];
				if (key == rec.key){
					found = true;
					if (!rec.value || (rec.value.length == 0)){
                        alert("「" + key + "」が空欄で保存できません");
						return true;
					}
				}
			}

			if (found == false){
                alert("「" + key + "」が空欄で保存できません");
				return true;
			}
		}
		return false;
	}
}

function removedHospital(){
	// 施設が削除された
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert("removedHospital ===\n"+value);//###
        
		hideMessage("_message");
        
        // 職員リストを閉じる
        closeStaffInfo();

        // 初期画面へ戻る
        getHospitalInfo(hospitalId());
        showHospitalInfo();
        document.getElementById("hospitalEditorArea").innerHTML = "";
	}
	else
		showMessage("_message", "remove hospital ...");
}
function removeHospital(){
	// 施設ID ならびにその施設情報すべてを削除
	if (confirm(hospitalId() + " の施設を（所属スタッフを含め）削除していいですか")){
		xmlHttpObject = createXMLHttpRequest(removedHospital);
		if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
			var array = new Array();
            array['hospitalId'] = hospitalId();
			
			var st = "./sysServer.php?command=REMOVE_HOSPITAL"
			+ "&value=" + encodeObject(array);
			//alert(st); return; //##
            
			xmlHttpObject.open("GET", encodeURI(st), true);
			xmlHttpObject.send(null);
		}
	}
}

///// Ajax /////////////////////////////////////////
////////////////////////////////////////////////////


////////////////////////////////////////////////////////
///// FACILITY EDITOR //////////////////////////////////

function showHospitalTable(){
	// records を元に HospitalTable 内容を表示
	var elm = document.getElementById("hospitalEditorArea");
	elm.innerHTML = "";
	var tbl = newTABLE(elm, "base-table");
	tbl.style.backgroundColor = "#ffc";
	tbl.style.fontSize = "10pt";
    
	//alert("showHospitalTable ==\n"+encodeObject(records()));//##
    
	// title
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "label-left", "属性");
	var td = newTD(tr, "label-left", "設定値");
	var td = newTD(tr, "label-left", "更新年月日");
	var td = newTD(tr, "label-left", "オーナー");
	
	// 決め打ちの contents
	var tr = newTR(tbl, "", "");
    
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "label-left", "施設ID");
	var td = newTD(tr, "label-left", hospitalId()); // 新規施設登録で必要

	makeFieldRow(tbl, "施設名");
	makeFieldRow(tbl, "住所");
	makeFieldRow(tbl, "電話番号");
	makeFieldRow(tbl, "FAX");
	makeFieldRow(tbl, "都道府県番号");
	makeFieldRow(tbl, "点数表番号");
	makeFieldRow(tbl, "保険医療機関コード");
	makeCheckBoxRow(tbl, "明細書発行体制等加算");
	var items = new Array("日","月","火","水","木","金","土");
	makeCheckBoxesRow(tbl, "診療曜日", items);
	timeRangeRow(tbl, "診療時間");
	makeComboBoxRow(tbl, "施設", ["","病院","診療所"], "");
	var comment = " x 保険点数 = 自費料金";
	makeComboBoxRow(tbl, "自費係数", ["","10","20"], comment);
	var items = ["","0","1","2","3","4","5","6","7","8","9"];
	var comment = " 1:八捨九入 5:四捨五入 9:零捨一入";
	makeComboBoxRow(tbl, "まるめ係数", items, comment);
	var times = ["","1","3","6","12","24"];
	makeComboBoxRow(tbl, "訂正可能時間", times, " この時間内ならカルテ修正可能");
	
	// controls
	var tr = newTR(tbl, "yellow-bar", "");
	var td = newTD(tr, "right-side", "");
	td.setAttribute("colspan","4");
	var bt = newBUTTON(td, "", "この施設を削除");
	bt.setAttribute("onclick", "removeHospital()");
	var sp = newSPAN(td, "saveArea");

    // timeRangeRow() の内容をサーバへリクエスト： Ajax にアクセス
    // この Ajax の後に getStaffList() の Ajax を発出
    openConsultationHours("診療時間");
}

function changeValue(key){
	// _records オブジェクト中の key に該当するレコードを更新
    _initDebug(false); //##
    
	var obj = moduleForId(key);
    //_debug("moduleForId( "+key+" )->"+obj); //##
	if (obj){
		//_debug("changeValue:"+key+"("+obj.value+") type( "+obj.type+" )"); //##
		if (obj.type == "checkBoxes"){
			var array = obj.value.split(",");
			if (isEmptyArray(array))
				setValueForKey("", key);
			else
				setValueForKey(obj.value, key);
		} else if (obj.type == "checkbox"){ // dom.js で指定
			setValueForKey(obj.value, key);
		} else if (obj.type == "timeRange"){
            setValueForKey(obj.value, key);
		} else {
            var val = document.getElementById(key).value;
            //_debug("key("+key+") val( "+val+" )"); //##
            setValueForKey(val, key);
        }
	} else {
		var elm = document.getElementById(key);
		var val = elm.value;
		//_debug("changeValue: "+key+"("+elm.value+") "); //##
		setValueForKey(val, key);
	}
    
	// 保存ボタンを表示
	var elm = document.getElementById("saveArea");
	elm.innerHTML = "";

	var bt = newBUTTON(elm, "", "保存");
	bt.setAttribute("onclick", "save()");
	
	function twoColumns(num){
		// 2桁表示にして返す
		num = num * 1; // 数値にする
		if (num < 10)
			return "0" + num;
		else
			return "" + num;
	}
	
	function isEmptyArray(array){
		// array 内のオブジェクトの長さがすべてゼロなら その配列は空と判定する
		for (var i=0,ct=array.length; i < ct; i++){
			if (array[i].length > 0) return false;
		}
		return true;
	}
}

function isNeeded(label){
    // 必須項目なら赤で表示
    for (num in _indispensables){
        if (label == _indispensables[num]) return true;
    }
    return false;
}

function makeFieldRow(tbl, key){
	// 入力フィールドを生成
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "label-left", key);
    if (isNeeded(key)) td.style.color = "#f30";
    
	var record = recordForKey(key);
	if (record){ // DB に存在するレコード
		var td = newTD(tr, "label-left", "");
		var fd = newFIELD(td, key, "", 50, record.value);
		fd.setAttribute("onchange", "changeValue('" + key +"')");
		var td = newTD(tr, "label-left", record.updateTime);
        td.style.fontSize = "9pt";
		var td = newTD(tr, "label-left", record.owner);
	} else { // 新規追加されまだ DB に保存されないレコード
		var td = newTD(tr, "label-left", "");
		var fd = newFIELD(td, key, "", 50, "");
		fd.setAttribute("onchange", "changeValue('" + key +"')");
		var td = newTD(tr, "", "");
		var td = newTD(tr, "", "");
	}
	setModuleForId(fd, key); // dom.js
	return tr;
}

function _cb_clicked(key){
	// チェックボックスがチェックされる毎に this.value を更新
	var obj = moduleForId(key);
	var elm = document.getElementById(key);
	obj.value = (elm.checked) ? "yes" : "no";
	changeValue(key);
}
function makeCheckBoxRow(tbl, key){
	// チェックボックスの入力フィールドを生成
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "label-left", key);
    if (isNeeded(key)) td.style.color = "#f30";
	var td = newTD(tr, "label-left", "");
	var record = recordForKey(key);
	if (record){
		var status = (record.value && (record.value == "yes")) ? 1 : 0;
		var cb = newCHECKBOX(td, key, "", status);
		cb.setAttribute("onchange", "_cb_clicked('"+key+"')");
	} else {
		var cb = newCHECKBOX(td, key, "", 0);
		cb.setAttribute("onchange", "_cb_clicked('"+key+"')");
	}
	setModuleForId(cb, key); // dom.js
}

function _cbx_clicked(id){
	// チェックボックスがチェックされる毎に this.value を更新
	// obj の各チェックボックスの状態を obj.value へ以下のような文字列として吐き出す
	// ",,火,水,,金," -- "on" は空白以外なら何の文字でも構わない
	var array = new Array();
	var obj = moduleForId(id);
	var items = obj.items;
	var id = obj.id;
	for (var i=0,ct=items.length; i < ct; i++){
		var stat = document.getElementById(id+"_cbx_"+items[i]).checked;
		array[i] = (stat) ? items[i] : "";
	}
	// this.value を更新
	obj.value = array.join(",");
	//alert("cbx_makeValue:"+id+"->"+obj.value); //##
	changeValue(id);
}
function makeCHECKBOXES(elm, id, items, statuses){
	// 複数のチェックボックスを表示
	// コンストラクタ：
	//   var items = new Array("foo","bar");
	//   var statuses = new Array("","on"); // on は空白以外なら何でも可
	//   var obj = new newCHECKBOXES(elm, id, items, statuses) で生成
	// チェック状態を外部から取得：
	//   var st = obj.value; で取得できる
	//   チェックされた item を",月,,水,,," のように","で区切った文字列として取得
	var array = new Array();
	var boxes = new Array();
	for (var i=0,ct=items.length; i < ct; i++){
		var status = (statuses && (statuses.length >= i))
		? statuses[i].length : 0;
		var cb = newCHECKBOX(elm, id+"_cbx_"+items[i], items[i], status);
		cb.setAttribute("onchange", "_cbx_clicked('"+id+"')");
		array[i] = (statuses && (statuses[i].length)) ? items[i] : "";
		boxes[i] = cb;
	}
	this.value = array.join(",");
	this.checkboxes = boxes;
	this.id = id;
	this.items = items;
	this.type = "checkBoxes";
	setModuleForId(this, id);
	
	return this;
}
function makeCheckBoxesRow(tbl, key, items, comment){
	// チェックボックスの並んだ入力フィールドを生成
    _initDebug(false); //##
    
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "label-left", key);
    if (isNeeded(key)) td.style.color = "#f30";
	var record = recordForKey(key);
	if (record){ // DB に存在するレコード
		var td = newTD(tr, "label-left", "");
		var statuses = itemsOfRecord(record);
		td.style.color = "#a63"; //brown
		makeCHECKBOXES(td, key, items, statuses);
		if (comment) var tx = newTEXT(td, comment);
		var td = newTD(tr, "label-left", record.updateTime);
        td.style.fontSize = "9pt";
		var td = newTD(tr, "label-left", record.owner);
	} else { // 新規追加されまだ DB に保存されないレコード
		var td = newTD(tr, "label-left", "");
		td.style.color = "#a63"; //brown
		makeCHECKBOXES(td, key, items);
		if (comment) var tx = newTEXT(td, comment);
		var td = newTD(tr, "", "");
		var td = newTD(tr, "", "");
	}
	return tr;
	
	function itemsOfRecord(record){
		if (record)
			return record.value.split(",");
		else
			return new Array();
	}
}

function timeRangeRow(tbl, key){
	// "09:00..12:00,15:00..17:00" のように診療時間を入力するモジュール
    // １行目：診療時間帯ごとのレコードを表示
	var tr = newTR(tbl, "timeRangeArea", "");
	var td = newTD(tr, "label-left", key);
    td.style.verticalAlign = "top";

	var td = newTD(tr, "label-left", "");
    td.setAttribute("colspan", "3");
    var dv = newDIV(td, "timeEditArea");

    // ２行目：診療時間情報を CSV で表示
	var tr = newTR(tbl, "timeRangeArea", "");
    var td = newTD(tr, "label-left", ""); // 空ラベル
    var td = newTD(tr, "consultResultArea", ""); // 診療時間：設定値
    td.setAttribute("colspan", "3");
    td.style.paddingLeft = "9px";
    td.style.width = "150px";
    
	// timeRangeRow 用のオブジェクトを生成し登録
	var obj = new Object();
	obj.type = "timeRange";
	setModuleForId(obj, key);
}

function clickedComboPopup(elm, key){
	// comboBox のポップアップメニューがクリックされた
	document.getElementById(key).value = elm.value;
	changeValue(key);
}
function makeComboBoxRow(tbl, key, items, comment){
	// comboBox 入力フィールドを生成
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "label-left", key);
    if (isNeeded(key)) td.style.color = "#f30";
	var record = recordForKey(key);
	if (record){ // DB に存在するレコード
		var td = newTD(tr, "label-left", "");
		td.style.color = "#a63"; //brown
		comboBox(td, key, items, record.value);
		var tx = newTEXT(td, comment);
		var td = newTD(tr, "label-left", record.updateTime);
        td.style.fontSize = "9pt";
		var td = newTD(tr, "label-left", record.owner);
	} else { // 新規追加されまだ DB に保存されないレコード
		var td = newTD(tr, "label-left", "");
		td.style.color = "#a63"; //brown
		comboBox(td, key, items, "");
		var tx = newTEXT(td, comment);
		var td = newTD(tr, "", "");
		var td = newTD(tr, "", "");
	}
	return tr;
	
	function comboBox(elm, key, items, val){
		var pu = makePopupMenu(elm, "", items, val);
		pu.setAttribute("onchange", "clickedComboPopup(this,'"+key+"')");
		var fd = newFIELD(td, key, "", 10, val);
		fd.setAttribute("onchange", "changeValue('" + key +"')");
	}
}

function clickedHospitalId(elm){
	// hospitalId ポップアップが選択された
	var hid = elm.value;
	//alert("clickedHospitalId: " + hid); //## debug
	setHospitalId(hid);
	if (hid.length == 0){
		// 空の hospitalId が選択された
        // 施設情報エリアを削除
        document.getElementById("hospitalEditorArea").innerHTML = "";
        // 職員情報エリアを閉じる
		closeStaffInfo(); // staff.js
		return;
	} else if (isSame(hid, "...その他")){
		hid = window.prompt("新規施設ID（数字）を入力してください","");
		if (hid.length == 0) return;
        setHospitalId(hid);
	}
	getHospitalInfo(hid);
}

function closeIdHelp(){
    document.getElementById("hospitalInfoHelpArea").innerHTML = "";
}
function showIdIHelp(){
	var elm = document.getElementById("hospitalInfoHelpArea");
    if (elm.innerHTML.length){
        closeIdHelp();
    } else {
        var div = newDIV(elm, "");
        div.style.padding = "10px 10px";
        var st = "施設ID は医療機関を特定するためのものです。ポップアップ・メニューから施設IDを選択しますが、施設IDが未登録なら「...その他」の選択で施設情報を新規登録できます。「保険医療機関コード」など一意のIDを使うのがよいでしょう。他医療機関との連携予定がなければ 施設IDに何を設定しても問題ありません。";
        var sp = newSPAN(div, "");
        sp.style.color = "#a63"; //brown
        sp.innerHTML = st;
        var a = newA(div, "閉じる", "#", "");
        a.setAttribute("onclick", "closeIdHelp()");
    }
}
function showRedHelp(){
	var elm = document.getElementById("hospitalInfoHelpArea");
    if (elm.innerHTML.length){
        closeIdHelp();
    } else {
        var div = newDIV(elm, "");
        div.style.padding = "10px 10px";
        var st = "とりあえず使って見るには赤文字の必須項目入力のみでも構いません。<br>黒文字の項目は 紹介状、処方箋、診療費計算、診療予約などに必要です。";
        var sp = newSPAN(div, "");
        sp.style.color = "#a63"; //brown
        sp.innerHTML = st;
        var a = newA(div, "閉じる", "#", "");
        a.setAttribute("onclick", "closeIdHelp()");
    }
}

function toggleHospitalInfo(){
    // 施設情報ペーンを開閉
	var elm = document.getElementById("hospitalEditorArea");
    if (elm.innerHTML.length){
        elm.innerHTML = "";
    } else {
        getHospitalInfo(hospitalId());
    }
}
function showHospitalInfo(){
    // 施設情報を表示
	// 施設情報の入力画面を表示
	var elm = document.getElementById("hospitalInfoArea");
	elm.innerHTML = "";
    
    // 施設ID選択バー
    var div  = newDIV(elm, "yellow-bar");
    // ラベル
    var sp = newSPAN(div, "");
    sp.style.paddingRight = "5px";
    sp.innerHTML = "施設 ID";
    sp.setAttribute("onclick", "toggleHospitalInfo()");
    setChangeColor(sp, '#000', '#fc3');
    // 施設ポップアップ
    var sp = newSPAN(div, "popUpArea");
    sp.style.paddingRight = "5px";
    // ヘルプ・アンカー
    var sp = newSPAN(div, "");
    sp.style.fontSize = "9pt";
    var a = newA(sp, "施設IDとは", "#", "");
    a.setAttribute("onclick", "showIdIHelp()");
    var sp = newSPAN(div, "");
    sp.style.fontSize = "9pt";
    sp.style.marginLeft = "10px";
    var a = newA(sp, "赤文字の項目について", "#", "");
    a.setAttribute("onclick", "showRedHelp()");
    
    // 施設ヘルプ・エリア
    var div  = newDIV(elm, "hospitalInfoHelpArea");
    
    // 施設情報編集エリア
    var div = newDIV(elm, "hospitalEditorArea");
	
    getHospitalTable();
}

///// FACILITY EDITOR //////////////////////////////////
////////////////////////////////////////////////////////

function closeMessage(){
    // メッセージを削除
    document.getElementById("topMessage").innerHTML = "";
}

function initRegister(){
    var elm = document.getElementById("base");
    elm.style.padding = "5px 5px";
    elm.style.fontSize = "10pt";
    elm.style.backgroundColor = "#ffc";
    
    var dv = newDIV(elm, "");
    dv.style.color = "#a63"; //brown
    dv.innerHTML = "NOA を使うには、必ず施設とユーザの登録を行ってください。";
    
	// 施設情報ポップアップ・エリア
    var div = newDIV(elm, "hospitalInfoArea");
    
    // 職員情報ポップアップ・エリア
    var div = newDIV(elm, "staffInfoArea");

	// HospitalTable, UserTable が存在しなければ作成
	checkDataBase();
}