
// neuron.js は NOAシステム ３層構造の中間であるロジック層を形成
// 基本的にすべての依頼は neuron.js を通じて行われる
// 他から呼ばれ neuron.js で処理されるメソッドは他と区別するため頭に NR がつく

var _isPrivate = false;

////////////////////////////////////////////////////////////////
///// LOGIN から引き継いだパラメータ //////////////////////////////

var _hospitalObject;
var _facility;
function setHospitalContainer(){
    // login.js から hospitalObject を localStorage 渡しで受け取り記憶
    _hospitalObject = hospitalObject(); // localStorage.js
    
    //alert("setHospitalContainer->"+encodeObject(_hospitalObject)); //##
}
function userCode(){
    // ユーザ権限コード：none, read, write, delete, all
    return _hospitalObject['userCode'];
}
function sectionCode(){
    // 診療科コード (MML0028)
    return _hospitalObject['sectionCode'];
}
function groupCode(){
    // 職種コード：番号ではなく 'doctor' のような形式 (MML0026)
    return _hospitalObject['groupCode'];
}
function owner(){
    // login name
    return _hospitalObject['loginName'];
}
function userName(){
    // login 者の漢字氏名
    return _hospitalObject['kanjiName'];
}
function hospitalId(){
    // 施設 ID
    return _hospitalObject['hospitalId'];
}
function hospitalName(){
    // 漢字施設名
    return _hospitalObject['hospitalName'];
}

///// LOGIN から引き継いだパラメータ //////////////////////////////
////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////
///// CELL STRUCTURE //////////////////////////////////////////

function cellTemplate(){
    // CELL 構造のテンプレート：サーバにデータがない場合使われる default 値
    var obj = new Object();
    
    var num = 0;
    makeCell(obj, num++, _progress, "ProgressSection.subject", "主訴", 1, 3, "");
    makeCell(obj, num++, _progress, "ProgressSection.object", "所見", 1);
    makeCell(obj, num++, _progress, "ProgressSection.assessment", "考察", 1);
    makeCell(obj, num++, _progress, "ProgressSection.plan", "計画", 1);
    makeCell(obj, num++, _progress, "FrontTable.plan", "予定", 1);
    makeCell(obj, num++, _progress, "ProgressSection.disease", "病名", 1);
    makeCell(obj, num++, _progress, "ProgressSection.examination", "検査", 1, 6, "openForm");
    makeCell(obj, num++, _progress, "ProgressSection.prescription", "処方", 1, 6, "openPrescriptionEditor");
    makeCell(obj, num++, _progress, "ProgressSection.treatment", "診療", 1, 6, "openVinEditor");
    
    var num = 0;
    makeCell(obj, num++, _basic, "NameSection.patientKanjiName", "氏名", 0, 6);
    makeCell(obj, num++, _basic, "NameSection.patientKanaName", "ふりがな", 0, 6);
    makeCell(obj, num++, _basic, "NameSection.patientRomajiName", "ローマ字", 0, 6);
    makeCell(obj, num++, _basic, "PatientTable.anotherId", "anotherId", 0, 6);
    makeCell(obj, num++, _basic, "PatientTable.receiptId", "receiptId", 0, 6);
    makeCell(obj, num++, _basic, "PatientTable.birthDate", "生年月日", 0, 5);
    makeCell(obj, num++, _basic, "PatientTable.sex", "性別", 0, 4);
    makeCell(obj, num++, _basic, "UniversalSection.introduction", "紹介", 0);
    makeCell(obj, num++, _basic, "AddressSection.email", "E-mail", 0, 6);
    makeCell(obj, num++, _basic, "AddressSection.zip", "郵便番号", 0, 6);
    makeCell(obj, num++, _basic, "AddressSection.address", "住所", 0, 1);
    makeCell(obj, num++, _basic, "AddressSection.phone", "電話", 0, 6);
    makeCell(obj, num++, _basic, "BasicSection.job", "本人職業", 0);
    makeCell(obj, num++, _basic, "MalitalSection.type", "婚姻", 0, 4);
    makeCell(obj, num++, _basic, "MalitalSection.startDate", "結婚日", 0, 5);
    makeCell(obj, num++, _basic, "MalitalSection.partner", "配偶者", 0, 6);
    makeCell(obj, num++, _basic, "MalitalSection.partnersJob", "配偶職業", 0);
    makeCell(obj, num++, _basic, "MalitalSection.partnersOffice", "勤務先", 0);
    makeCell(obj, num++, _basic, "BasicSection.allergy", "アレルギー", 1, 4);
    
    if (_isPrivate){
        makeCell(obj, num++, _basic, "UniversalSection.menstrualCycle", "月経周期", 0); // local
        makeCell(obj, num++, _basic, "UniversalSection.menstruationBlood", "月経血", 0, 4); // local
        makeCell(obj, num++, _basic, "UniversalSection.periodPains", "月経痛", 0, 4); // local
        makeCell(obj, num++, _basic, "UniversalSection.firstMenstrualPeriod", "初潮", 0, 4); // local
        makeCell(obj, num++, _basic, "UniversalSection.KA", "KA", 0, 4); // local
        makeCell(obj, num++, _basic, "UniversalSection.SA", "SA", 0, 4); // local
        makeCell(obj, num++, _basic, "UniversalSection.FG", "FG", 0, 4); // local
        makeCell(obj, num++, _basic, "UniversalSection.NG", "NG", 0, 4); // local
        makeCell(obj, num++, _basic, "UniversalSection.pregnancyRecord", "妊娠履歴", 0); // local
        makeCell(obj, num++, _basic, "UniversalSection.menopause", "閉経", 0, 6); // local
    }
    
    makeCell(obj, num++, _basic, "BasicSection.bloodtype", "血液型", 0, 4);
    makeCell(obj, num++, _basic, "BasicSection.drinking", "飲酒", 0);
    makeCell(obj, num++, _basic, "BasicSection.smoking", "喫煙", 0);
    makeCell(obj, num++, _basic, "BasicSection.history", "既往歴", 0);
    makeCell(obj, num++, _basic, "AddressSection.memo", "メモ", 0);
             
    var num = 0;
    makeCell(obj, num++, _insurance, "HealthInsurance.shubetsu", "種別", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.kubun", "区分", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.paymentRatio", "負担割", 0);
    makeCell(obj, num++, _insurance,
             "HealthInsurance.kigou", "記号", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.bangou", "番号", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.ownerNumber", "保険番号", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.ownerName", "保険者名", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.ownerPhone", "電話", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.continuedDiseases", "継続療養", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.discountRatio", "割引％", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.startDate", "資格取得", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.expiredDate", "有効期限", 0);
    makeCell(obj, num++, _insurance, "HealthInsurance.confirmation", "証書確認", 0);
    makeCell(obj, num++, _insurance, "PublicInsurance.shubetsu", "公費種別", 0);
    makeCell(obj, num++, _insurance, "PublicInsurance.ownerName", "公費名称", 0);
    makeCell(obj, num++, _insurance, "PublicInsurance.ownerNumber", "負担番号", 0);
    makeCell(obj, num++, _insurance, "PublicInsurance.recipientNumber", "受給番号", 0);
    makeCell(obj, num++, _insurance, "PublicInsurance.paymentRatio", "負担率", 0);
    makeCell(obj, num++, _insurance, "PublicInsurance.payment", "負担額", 0);
    makeCell(obj, num++, _insurance, "PublicInsurance.startDate", "交付日", 0);
    makeCell(obj, num++, _insurance, "PublicInsurance.expiredDate", "有効期限", 0);
    
    return obj;

    function makeCell(obj, num, mode, tag, label, fieldType, menuType, editor){
        // CELL 属性を生成
        var cell = new Object();
        // owner
        cell.tag = tag;
        cell.buttonType = 0; // 0:メニュー複数選択 1:単一選択
        // menuType 0:rotary 1:address 2:calendar 3:group 4:panel 5:date 6:none
        cell.menuType = (menuType) ? menuType : 0;
        cell.menuAction = 1; //  0:文末へ追加 1:最終行へ追加 2:置換
        cell.hitAndRun = ""; // 0:表示 1:非表示
        cell.fieldType = fieldType; // 0:field 1:text
        cell.direction = "CELL"; // old NOA 型式との識別用
        cell.disabled = (tag == "PatientTable.birthDate") ? 1 : 0;
        cell.editor = (editor) ? editor : "";
        cell.id = mode;
        cell.script = "";
        cell.bgcolor = "";
        cell.label = label;
        cell.numbering = num; // groupMenu の場合、プロブレム番号自動付加を示す
        cell.study = 0;
        cell.fontSize = "";
        cell.fontFamily = "";
        cell.color = "";
        
        obj[tag] = cell;
    }
}

///// CELL STRUCTURE //////////////////////////////////////////
///////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////
///// MENU STRUCTURE //////////////////////////////////

// menuType
var _main = 0;
var _page = 1;
var _tool = 2;

function menuTemplate(){
    // メニュー構造のテンプレート
    var array = new Array();
    // main menu
    array.push({"menuType":_main,"label":"検索","url":"search()","editor":"カルテ内容を検索","fix":"1"});
    
    if (_isPrivate)
        array.push({"menuType":_main,"label":"周産期管理","url":"openPrenatal()","editor":"周産期管理","icon":"human.png","window":"1"}); // ### PRIVATE
    
    array.push({"menuType":_main,"label":"ProblemList","url":"openProblemList()","editor":"ProblemList","icon":"checkGreen.png"});
    
    // page menu
    array.push({"menuType":_page,"label":"文書作成","url":"openDocMaker()","editor":"文書作成","window":"1","icon":"docSmall.png"});
    array.push({"menuType":_page,"label":"付箋","url":"showPostItForce()","editor":"付箋","fix":"1","icon":"flag.png"});
    array.push({"menuType":_page,"label":"印刷","url":"printPDF()","editor":"印刷", "fix":"1","icon":"printer.png"});
    
    // tool menu
    array.push({"menuType":_tool,"label":"検索","subTitle":"1"});
    array.push({"menuType":_tool,"label":"条件検索","url":"chartFinder.php"});
    array.push({"menuType":_tool,"label":"受診日検索","url":"lvdSearch.php"});
    
    if (_isPrivate){
        array.push({"menuType":_tool,"label":"薬剤検索","url":"/Medicine"});
        array.push({"menuType":_tool,"label":"SimpleNote","url":"https://simple-note.appspot.com/"}); // ### PRIVATE
    }
    
    array.push({"menuType":_tool,"label":"頁","subTitle":"1"});
    array.push({"menuType":_tool,"label":"日時指定ページ追加","url":"addAnyPage()"});
    
    array.push({"menuType":_tool,"label":"印刷","subTitle":"1"});
    array.push({"menuType":_tool,"label":"カルテの全ページ","url":"printAllPages()"});
    array.push({"menuType":_tool,"label":"本日受診の全カルテ","url":"printAllPDF()"});
    
    array.push({"menuType":_tool,"label":"道具","subTitle":"1"});
    array.push({"menuType":_tool,"label":"Pickup","url":"/PickUp"});
    array.push({"menuType":_tool,"label":"画像読込","url":"/Picture"});
    array.push({"menuType":_tool,"label":"Draw","url":"/Draw","window":"1"});
    
    if (_isPrivate){
        array.push({"menuType":_tool,"label":"HL7","url":"/HL7","window":"1"}); // ### PRIVATE
        array.push({"menuType":_tool,"label":"メッセンジャー","url":"/Messenger"});
    }
    
    array.push({"menuType":_tool,"label":"リマインダー","url":"/Reminder"});
    array.push({"menuType":_tool,"label":"年齢計算","url":"/AGE"});
    array.push({"menuType":_tool,"label":"診療統計","url":"/Statistics","window":"1"});
    
    array.push({"menuType":_tool,"label":"受付","subTitle":"1"});
    array.push({"menuType":_tool,"label":"FRONT","url":"openFRONT()","window":"1"});
    array.push({"menuType":_tool,"label":"FRONTへ伝達","url":"openMessenger()"});
    
    array.push({"menuType":_tool,"label":"交信","subTitle":"1"});
    array.push({"menuType":_tool,"label":"ORCA接続","url":""});
    
    array.push({"menuType":_tool,"label":"管理","subTitle":"1"});
    array.push({"menuType":_tool,"label":"バックアップ","url":"archiver.php", "fix":"1"});
    array.push({"menuType":_tool,"label":"PriceList","url":"/NOAManager/priceList.php"});
    array.push({"menuType":_tool,"label":"新患登録","url":"patientRegister.php"});
    array.push({"menuType":_tool,"label":"保険証画像","url":"../InsViewer","window":"1"});
    array.push({"menuType":_tool,"label":"設定","subTitle":"1"});
    array.push({"menuType":_tool,"label":"初期設定","url":"preference.php", "fix":"1"});
    array.push({"menuType":_tool,"label":"レイアウト設定","url":"layout.php", "fix":"1"});
    array.push({"menuType":_tool,"label":"診療予約","url":"/Booking","window":"1"});
    
    array.push({"menuType":_tool,"label":"HELP","subTitle":"1"});
    array.push({"menuType":_tool,"label":"NOA HELP","url":"noaHelp()"});
    array.push({"menuType":_tool,"label":"InfoBoard","url":"/InfoBoard", "fix":"1"});
    
    if (_isPrivate)
        array.push({"menuType":_tool,"label":"TEST","url":"test()"}); // ### PRIVATE
    
    return array;
}

var _menuStructure;
function setMenuStructure(obj){
    if (obj.length){
        _menuStructure = obj;
    } else {
        _menuStructure = null;
    }
}
function menuStructure(){
    // [{"id":"1","label":"検索",,,},,,] 形式のメニュー構造を保持
    if (!_menuStructure){
        _menuStructure = menuTemplate();
        
        for (num in _menuStructure){
            var cell = _menuStructure[num];
            
            // menuTemplate() には id がないので num を id として cell に記憶
            // 新たに menuCell が追加される場合は最大 id が振られる
            cell.id = num; 
        }
    }

    return _menuStructure;
}

function kickMenuCell(url, inWindow){
    // menuCell のアクションを起動
    if (url && (url.indexOf("()") >= 0)){
        // 組込み関数を実行
        eval(url);
    } else {
        // URL を実行
        var target = (inWindow * 1) ? "_blank" : "tools";
        var win = window.open(url, target);
        win.focus();
    }
}

///// MENU STRUCTURE //////////////////////////////////
///////////////////////////////////////////////////////


///////////////////////////////////////////////////////
///// LAYOUT STRUCTURE ////////////////////////////////

// 以下は cell.id へ設定されるが、第７世代 NOA の cell.id とカブらないよう数値以外とする
var _progress = 'P';
var _basic = 'B';
var _insurance = 'I';

function modeForTag(tag){
    // tag から mode を判定して返す
    var array = tag.split(".");
    var table = array[0];
    if (table == "ProgressSection"){
        return _progress;
    } else if (tag == "FrontTable.plan"){
        return _progress;
    } else if (table.indexOf("Insurance") >= 0){
        return _insurance;
    } else {
        return _basic;
    }
}

var _layoutArray;
function setLayoutArray(tagList, useTemplate){
    // tagList = {tag:cell, tag:cell ,,,} 型式から
    // layoutArray = [cell, cell ,,,] 型式を生成
    // ### tagList は DB から取得時に numbering 順にソートされている
    _initDebug(true); //##
    _debug("== setLayoutArray: useTemplate->"+useTemplate); //##
    
    // DB から読み込んだ tagList を obj にコピー
    var obj = new Object();
    for (tag in tagList){
        obj[tag] = tagList[tag];
        
        _debug(tag+"->"+obj[tag].label+"->"+obj[tag].numbering); //##
    }
    
    _debug("<br>== read template ==="); //##
    // obj に欠損あればテンプレートで補完：全面的にテンプレートを使った場合ここは機能しない
    // ## テンプレートを tagList で上書きする方が簡潔だが
    // ## CELL 順序を指定する numbering がテンプレート固定になってしまう
    var tmpObj = cellTemplate();
    for (tag in tmpObj){
        if (!obj[tag]){
            obj[tag] = tmpObj[tag];
            
            _debug(tag+"=>"+obj[tag].label+"->"+obj[tag].numbering); //##
        }
    }
    
    _debug("<br>== _layoutArray ==="); //##
    
    // obj = {tag:cell,tag:cell,,} 型式から layoutArray = [cell,cell,,] 型式を生成
    _layoutArray = new Array();
    for (tag in obj){
        var cell = obj[tag];
        _layoutArray.push(cell);
        
        _debug(tag+"->"+encodeObject(cell)); //##
    }
    
    if (useTemplate){
        // レイアウトに全面的にテンプレートを使った場合、そのレイアウトを DB へコピー
        // _layoutArray 中の cell の自動 numbering はサーバ側で実施
        NRPostLayout(owner(), encodeObject(_layoutArray), NRNoAction);
    }
}
function swapLayoutArray(array){
    // アーカイブからの復元に使う：layout.js
    _layoutArray = array;
}

function layoutArray(mode){
    // [{"tag":"","label":"","disabled":""},,,] 形式
    
    _initDebug(false); //##
    _debug("=== layoutArray: mode->"+mode); //##
    _debug("_layoutArray->"+encodeObject(_layoutArray)); //##
    
    // _layoutArray は numbering 属性でソートした配列
    var layoutArray = new Array();
    for (num in _layoutArray){
        var cell = _layoutArray[num];
        if (mode == null)
            layoutArray.push(cell);
        else if (cell.id == mode)
            layoutArray.push(cell);
    }
    
    _debug("<br>--- layoutArray->"+encodeObject(layoutArray)); //##
    
    return layoutArray;
}

function fieldForTag(tag){
    // tag に相当する cell を返す：cell にはレイアウト属性を記憶
    var mode = modeForTag(tag);
    var layouts = layoutArray(); // 一部のテーブルが未読込でも cellTemplate() で補完
    var numbering = 0;
    for (num in layouts){
        var cell = layouts[num];
        if (cell.id != mode) continue;
        
        if (cell.tag == tag){
            // numbering 属性は layoutArray() に含まれていないのでここで追加
            cell.numbering = numbering;
            return cell;
        }
        numbering++;
    }
    return cell;
}
function _fieldForTag(tag){
    // tag に該当する field オブジェクトを返す
    var layouts = layoutArray(); // 一部のテーブルが未読込でも cellTemplate() で補完
    //alert("fieldForTag->"+tag+"->"+encodeObject(layouts)); //##
    
    for (num in layouts){
        var cell = layouts[num];
        if (cell.tag == tag) return cell;
    }
    
    return null;
}

var _tagArray;
function tagArray(){
    // tag 名の配列
    if (!_tagArray){
        _tagArray = new Array();
        var array = layoutArray(_basic);
        for (num in array){
            var obj = array[num];
            _tagArray.push(obj.tag);
        }
        var array = layoutArray(_insurance);
        for (num in array){
            var obj = array[num];
            _tagArray.push(obj.tag);
        }
        var array = layoutArray(_progress);
        for (num in array){
            var obj = array[num];
            _tagArray.push(obj.tag);
        }
    }
    
    return _tagArray;
    
    /*
    var layouts = layoutArray(); // 一部のテーブルが未読込でも cellTemplate() で補完
    var array = new Array();
    for (num in layouts){
        var cell = layouts[num];
        array.push(cell.tag);
    }
    
    return array;
     */
}

var _progressArray;
function progressTagArray(){
    // ProgressSection のタグ名のみの配列を返す
    if (!_progressArray){
        _progressArray = new Array();
        var array = layoutArray(_progress);
        for (num in array){
            var rec = array[num];
            _progressArray.push(rec.tag);
        }
    }
    return _progressArray;
}

function nextTagFor(tag, mode){
    // tag の次の tag を返す
    // ### panelEditor から使う場合は panelEditor.js に noa().layoutArray() が必要
    var touched = false; // まず目標の tag をみつけた：この後、次の tag を探す
    var array = layoutArray(mode);
    for (num in array){
        var rec = array[num];
        if (rec.disabled * 1 > 0) continue; // 編集不可はスキップ
        if (rec.hitAndRun * 1 > 0) continue; // 非表示はスキップ

        // すでに目標 tag を見つけた後なら、次のこの tag が nextTag
        if (touched)
            return rec.tag;

        // rec.tag が目標 tag と合致した
        if (tag == rec.tag)
            touched = true;
    }
    return null;
}

///// LAYOUT STRUCTURE ////////////////////////////////
///////////////////////////////////////////////////////


///////////////////////////////////////////////////////
///// 周辺ツールから外部参照されるオブジェクト //////////////

var _currentDate;
function setCurrentDate(date){
    // 対象となるページ（現在開いているページ）の日付を設定
   
    if (_currentDate && (_currentDate != date)){
        // 過去に開いていたページ・ヘッダーがあれば閉じる
        var elm = document.getElementById(_currentDate + ".basic");
        if (elm) {
            elm.style.backgroundColor = "#fff";
            elm.innerHTML = "";
        }
    }

    _currentDate = date;
}
function currentDate(){
    // 編集中の CELL の受診日：cellEditor.js で使われるが、外部参照もされる
    return _currentDate;
}

var _currentTag;
function setCurrentTag(tag){
    _currentTag = tag;
}
function currentTag(){
    // 編集中の CELL のタグ
    return _currentTag;
}

var _patientId;
function setPatientId(id){
    _patientId = id;
}
function patient_id(){
    return _patientId;
}

var _patientKanjiName;
function setPatientKanjiName(name){
    _patientKanjiName = name;
}
function patientKanjiName(){
    return _patientKanjiName;
}

var _userList;
function setUserList(obj){
	_userList = obj;
}
function userList(){
    // { "someone":"誰か", "ohashi":"大橋 克洋"} 型式
    return _userList;
}
function userNames(){
    // ["ohashi","tanaka"] を返す
    var array = new Array();
    for (logname in _userList){
        array.push(logname);
    }
    return array;
}
function userKanjiNames(){
    // ["大橋","田中"] を返す
    var array = new Array();
    for (logname in _userList){
        var kanji = _userList[logname];
        array.push(kanji);
    }
    return array;
}
function loginNameForkanjiName(kanjiname){
    for (logname in _userList){
        var kanji = _userList[logname];
        if (kanji == kanjiname) return logname;
    }
	return "??";
}
function userKanjiName(loginName){
    for (logname in _userList){
        var kanji = _userList[logname];
        if (logname == loginName) return kanji;
    }
	return "??";
}

var _user;
function setUserInfo(obj){
    // {"userCode":"all","sectionCode":"23","loginName":"ohashi",,,}
    //alert("setUserInfo->"+encodeObject(obj)); //##
    
	_user = obj;
}
function userInfo(){
    return _user;
}
function userInfoForKey(key){
	return (_user) ? _user[key] : "??";
}
function isSuperUser(){
    return (_user.userCode == "all") ? true : false;
}

var _hospital;
function setHospitalInfo(obj){
	if (obj && obj['訂正可能時間'])
        setTimeLimit(obj['訂正可能時間']);
    else
        setTimeLimit("24");
	_hospital = obj;
}
function hospitalInfoForKey(key){
	// _hospital は obj["施設名"] = "大橋医院" 形式
	return _hospital[key];
}

var _timeLimit;
function setTimeLimit(val){
	// 編集可能時間を記憶: "3" or ("3:00" or "3:00:00") 形式
	var array = val.split(":");
	switch (array.length){
		case 1: var sec = array[0] * 3600; break;
		case 2: var sec = array[0] * 3600 + array[1] * 60; break;
		default: var sec = array[0] * 3600 + array[1] * 60 + array[2] * 1; break;
	}
	_timeLimit = "" + sec;
}
function timeLimit(){
	return _timeLimit;
}

function putValueForTag(val, tag){
    // currentDate(), tag の CELL のエディターを開いて val を書き込む
    // DocMaker から使われる
    openEditor(currentDate(), tag, val);
}
function valueForTag(tag){
	// tag:"NameSection.patientKanjiName" に相当する値を返す
    // 事前にその受診日の BasicInfo が読込まれている必要がある
	var cell = cellFor(currentDate(), tag);
	return (cell) ? cell.trimValue : "";
}

function labelForTag(tag){
    // 事前にその受診日の BasicInfo が読込まれている必要がある
	var cell = cellFor(currentDate(), tag);
	return (cell) ? cell.label : "";
}

function editingCellValue(){
    // 編集中の CELL の pureValue
	var cell = cellFor(currentDate(), currentTag());
    return cell.trimValue;
}

var _isReadOnly;
var _readOnlyDate;
function setIsReadOnly(status, date){
    // 書込不可の status を条件により設定
    var pageChanged = (isSameDate(date, _readOnlyDate) == 0) ? true : false;
    if (date){
        // 日付が添えてあれば、日付を基に _isReadOnly を設定
        if (isSameDate(today(), date)){
            // date が本日なら無条件に readOnly を否定
            _isReadOnly = false;
        } else if (pageChanged){
            // 今まで開いていたエディターと異なる日付なら
            // 初心に戻り本日以外の日付はすべて readOnly とする
            _isReadOnly =  (isSameDate(date, today())) ? false : true;
        } else {
            // すでに開いていたエディターと同じ日付なので readOnly の設定変更せず
            if (!_isReadOnly) _isReadOnly = status;
        }
        _readOnlyDate = date;
    } else {
        // 日付が添えてなければ status を基に _isReadOnly　を設定
        _isReadOnly = status;
    }
}
function isReadOnly(){
    // 編集可能かどうかを返す
    return _isReadOnly;
}

///// 周辺ツールから外部参照されるオブジェクト //////////////
///////////////////////////////////////////////////////

function isToday(){
    return (isSameDate(currentDate(), today()) > 0) ? true : false;
}

function removeCheck(){
    // 無条件に編集不可のチェックをはずす
    setIsReadOnly(false);
    
    var elm = document.getElementById("readOnlyCheck").parentNode;
    elm.innerHTML = "";
    var cb = newCHECKBOX(elm, "readOnlyCheck", "編集不可", 0);
    cb.setAttribute("onchange", "clickedReadOnly(this)");
}

function closeWarm(){
    // 警告パネルを閉じる
    var el = document.getElementById("_alerm");
    el.innerHTML = "";
    el.style.visibility = "hidden";
}
function openWarm(x, y, h, w, action){
    // 警告パネルを表示
    // このデータが過去のものであれば、警告パネルを出す
    var el = document.getElementById("_alerm");
    el.innerHTML = "";
    if (el.style.visibility == "visible"){
        // 警告パネルを toggle 式に開閉
        closeWarm();
        return;
    }
    el.style.left = x; // 表示するx座標
    el.style.top = y; // 表示するy座標
    el.style.height = h;
    el.style.width = w;
    el.style.visibility = "visible";
    el.style.border = "thin solid #aaa";
    el.style.fontSize = "11pt";
    el.style.fontFamily = "arial, Helvetica";
    el.style.padding = "10px 10px";
    el.setAttribute("onclick", action);
    
    el.style.backgroundColor = "#669";
    el.style.color = "#fff";
	setOpacity(el, 0.85);
    
    var array = new Array();
    array.push("過去ページなので変更できません");
    array.push("　１）強制的に修正するなら この警告をクリック");
    array.push("　２）キャンセルするなら 左のラベルをクリック");
    
    var dv = newDIV(el, "");
    dv.innerHTML = array.join("<br/>");
}

function openImage(url){
    // 本文中の Image をクリックした時に呼ばれる
	var win = window.open("./imageViewer.php?value=" + url, "ImageViewer"
				,"width=1500,height=1100,scrollbars=yes,resizable=yes");
	win.focus();
}

function modifyItem(tag, item){
	// フィールドの種類により menuItem をモディファイ
	// tag は "ProgressSection.disease" や "gm-disease" など
	if (tag.indexOf("disease") >= 0){
		// 挿入アイテムの行頭に「タイムスタンプ」をつける
		var yy = currentDate().substr(2, 2);
		var mm = currentDate().substr(5, 2);
		var dd = currentDate().substr(8, 2);
		
		// item が複数行になっていても、各行頭に dateStamp を付加
		var array = item.split("\n");
		var ary = new Array();
        for (num in array){
			if (array[num].length) ary.push(yy+mm+dd+" "+array[num]);
		}
		return ary.join("\n");
	}
	else
		return item;
}

var _receiver;

function NRSendBack(){
	// サーバから返された処理を実行
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		//alert("NRSendBack ===\n"+value);//##
		var array = value.split("<SEPARATOR>");
		if (array.length > 1){
            // ##### _receiver の処理でコケると _message が消えない #####
			_receiver(array[1]); // JSON
		}
		hideMessage("_message");
	} else 
		showMessage("_message", "サーバで処理中です ... ");
}

function NRNoAction(answer){
	// receiver として何も返す必要がないときに使う
}

function NR_debug(){
	// サーバから返された処理を実行
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		alert("=== NR_debug ===\n"+value); //## 返されたメッセージを debug 用に表示
		var array = value.split("<SEPARATOR>");
		if (array.length > 1){
			_receiver(array[1]); // JSON
		}
		hideMessage("_message");
	} else 
		showMessage("_message", "サーバで処理中です ...");
}

////////////////////////////////////////////
///// TAG をキーとした CELL 属性 /////////////

function NRGetCellUserHospitalInfo(owner, receiver){
    // 全てのCELL属性・ユーザ情報・ホスピタル情報 をサーバから取得
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		
		_receiver = receiver; 
		var st = "./server.php?command=GET_ALL_CELL_ATTRIBUTES"
		+ "&value=" + encodeObject(array);
		
        //alert("NRGetCellUserHospitalInfo ====\n"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetLayout(owner, receiver){
    // NOA のレイアウトをサーバから取得
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=GET_LAYOUT"
		+ "&value=" + encodeObject(array);
		
        //alert("NRGetLayout ====\n"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetMenu(owner, tag, receiver){
	// ### groupMenu type の場合はサーバで判断し専用メニューを読み込み
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
    xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["tag"] = tag;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
        // PickUp などからも呼ばれるので絶対パス
		var st = "/XNOA/server.php?command=GET_MENU"
		+ "&value=" + encodeObject(array);
		
        //alert("NRGetMenu->"+st);//===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPutMenu(owner, tag, item, freq, value, receiver){
	if (!owner || owner.length == 0)
		alert("NRPutMenu: owner *** is null"); 
	
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		// すでに同じメニューアイテムが存在すれば頻度をインクリメント
		var array = new Array();
		array["owner"] = owner;
		array["tag"] = tag;
		array["menuItem"] = encodeSTRING(item);
		array["freq"] = freq;
		array["val"] = encodeSTRING(value);
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
        // PickUp などからも呼ばれるので絶対パス
		var st = "/XNOA/server.php?command=PUT_MENU"
		+ "&value=" + encodeObject(array);
        
		//alert("NRPutMenu ==\n"+st); //return;//===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRRemoveMenu(owner, tag, menuItem, receiver){
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["tag"] = tag;
		array["menuItem"] = encodeSTRING(menuItem);
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=REMOVE_MENU"
		+ "&value=" + encodeObject(array);
		
        //alert("NRRemoveMenu ==\n"+st); return;//===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPutGroupMenu(owner, item, freq, subItems, receiver){
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		// すでに同じメニューアイテムが存在すれば頻度をインクリメント
		var array = new Array();
		array["owner"] = owner;
		array["menuItem"] = encodeSTRING(item);
		array["freq"] = freq;
        
        if (subItems){
            // subItems をフラットにする
            for (tag in subItems){
                array[tag] = encodeSTRING(subItems[tag]);
            }
        }
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=PUT_GROUP_MENU"
		+ "&value=" + encodeObject(array);
        
		//alert("NRPutGroupMenu ==\n"+st); //return;//===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

///// TAG をキーとした CELL 属性 /////////////
////////////////////////////////////////////


//////////////////////////////////////////////////////////
///// CELL ///////////////////////////////////////////////

var _structure;

function cellId(entryDate, tag){
    // entryDate, tag から cell の id を生成して返す
    return entryDate + "_" + tag;
}

function cellFor(entryDate, tag){
    // entryDate, tag に対応する CELL を返す
    return _structure[entryDate][tag];
}
function cellForId(cid){
    // entryDate, tag に対応する CELL を返す
    var array = cid.split("_");
    return _structure[array[0]][array[1]];
}
function setCell(entryDate, tag, val){
    // CELL オブジェクトを生成
    var cell = new Object();
    
    //_debug("== setCell: ->"+entryDate+"->"+tag+"->"+val); //##
    //_debug("cell.id->"+cellId(entryDate, tag)); //##

    cell.id = cellId(entryDate, tag);
    cell.entryDate = entryDate;
    cell.tag = tag;
    var obj = fieldForTag(tag);

    cell.label = (obj) ? obj.label : tag; //###
    cell.value = val;
    
    cell.trimValue = pureValue(val);
    cell.htmlValue = (val) ? htmlForValue(val) : "";
    cell.isPast = (val && (val.indexOf("<PAST>") >= 0)) ? true : false;
    
    return cell;
}

function setCellToStructure(date, tag, cell){
    _structure[date][tag] = cell;
}

function setStructure(obj){
    // obj は {entryDate:{subject:"",object:"",,kanjiName:"",kanaName:""} 形式
    _initDebug(false); //##
    _debug("== setStructure: ->"+encodeObject(obj)); //##

    var history = new Array();
    for (entryDate in obj){
        history.splice(0, 0, entryDate);
    }
    
    // 前回と同じ所見は null になっているので、受診日順にスキャンし、これを補完する
    var subject="";
    var object="";
    var examination="";
    var prescription="";
    var disease="";
    var treatment="";
    var assessment="";
    var plan="";
    var kanjiName="";
    var kanaName="";
    var romajiName="";
    var recs = new Object();
    _structure = new Object();
    
    for (num in history){
        var entryDate = history[num];
        var rec = obj[entryDate];
        
        // {tag:cell,,,} 形式の newRec オブジェクトを生成
        // サーバからの転送データを少なくするため省略されたタグ名を補完
        var newRec = new Object();
        subject = complement(rec, newRec,"ProgressSection.subject","subject", subject);

        object = complement(rec, newRec,"ProgressSection.object","object", object);
        examination = complement(rec, newRec,"ProgressSection.examination","examination", examination);
        prescription = complement(rec, newRec,"ProgressSection.prescription","prescription", prescription);
        disease = complement(rec, newRec,"ProgressSection.disease","disease", disease);
        assessment = complement(rec, newRec,"ProgressSection.assessment","assessment", assessment);
        treatment = complement(rec, newRec,"ProgressSection.treatment","treatment", treatment);
        plan = complement(rec, newRec,"ProgressSection.plan","plan", plan);
        kanjiName = complement(rec, newRec,"NameSection.patientKanjiName","kanjiName", kanjiName);
        kanaName = complement(rec, newRec,"NameSection.patientKanaName","kanaName", kanaName);
        romajiName = complement(rec, newRec,"NameSection.patientRomajiName","romajiName", romajiName);

        recs[entryDate] = newRec;
    }
    
    //alert("history->"+encodeObject(history)); ////return; //##
    
    // 日付が昇順になっているので降順にする
    history = history.reverse();
    for (num in history){
        var entryDate = history[num];
        var rec = recs[entryDate];
        _structure[entryDate] = rec;
    }
    
    function complement(rec, newRec, tag, fieldName, value){
        // value が null なら過去データで補完
        if ((rec[fieldName] == null) || (rec[fieldName].length == 0)){
             // 本日のデータがなければ過去データを使う
            newRec[tag] = setCell(entryDate, tag, "<PAST>"+value+"</PAST>");
        } else {
            // 本日のデータがあるなら
            value = rec[fieldName];
            newRec[tag] = setCell(entryDate, tag, value);
        }
        
        return value;
    }
}
function structure(){
    // ProgressSection の全レコードを収納したオブジェクト
    // {entryDate:{tag:{label:"",tag:"",value:"",,,},,,},,,} 形式
    return _structure;
}

///// CELL ///////////////////////////////////////////////
//////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////
///// CELL EDITOR ////////////////////////////////////////

function NRPutCellAttributes(owner,
							 tag,
							 buttonType,
							 menuType, 
							 menuAction,
                             hitAndRun,
							 fieldType,
							 disabled,
							 editor,
                             id,
							 script,
							 bgcolor,
							 label,
                             numbering,
							 study,
							 fontSize, 
							 fontFamily,
							 color,
                             groupObjct,
							 receiver){
    // CELL 属性をサーバへ保存：menuItem がなければ生成
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["tag"] = tag;
		array["buttonType"] = buttonType;
		array["menuType"] = menuType;
		array["menuAction"] = menuAction;
		array["hitAndRun"] = hitAndRun;
		array["fieldType"] = fieldType;
		array["disabled"] = disabled;
		array["editor"] = editor;
		array["id"] = id;
		array["script"] = script;
		array["bgcolor"] = bgcolor;
		array["label"] = label;
		array["numbering"] = numbering;
		array["study"] = study;
		array["fontSize"] = fontSize;
		array["fontFamily"] = fontFamily;
		array["color"] = color;
        
        // groupObject はフラットに展開
        if (groupObjct){
            for (tag in groupObjct){
                array[tag] = groupObjct[tag];
            }
        }
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var val = encodeObject(array);
		var st = "./server.php?command=SET_CELL_ATTRIBUTES"
		+ "&value=" + encodeSTRING(val);
		
        //alert("NRPutCellAttributes ===\n"+st); //return; //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

///// CELL EDITOR ////////////////////////////////////////
//////////////////////////////////////////////////////////

function NRPutPostIt(owner, patientId, entryDate, type, val, receiver){
	// PostIt に value を与える（ value=="" ならレコード削除）
    // xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["patientId"] = patientId;
		array["entryDate"] = entryDate;
		array["type"] = type;
		array["val"] = encodeSTRING(val);
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=PUT_POST_IT"
		+ "&value=" + encodeObject(array);
		
		//alert("NRPutPostIt =====\n" + st); //###
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

var _postItRecords;
function postItRecords(){
    // postIt を記憶する受診日タグのついたオブジェクト
    // {"2012-07..":{"entryDate":"","type":"","value":"memo","":""},,,} 形式
    return _postItRecords;
}
function setPostItRecordAtDate(datetime, obj){
    _postItRecords[datetime] = obj;
}
function postItFor(entryDate){
    // entryDate 以前の付箋データを返す
    for (datetime in _postItRecords){
        if (datetime <= entryDate) return _postItRecords[datetime];
    }
    return null;
}

var _anotherReceiver;
function gotBasic(answer){
    // ProgressSection 以外のテーブルデータを扱う
    //  ProgressSection は全履歴をメモリー上に保持するが
    //  それ以外のテーブル・データはページを開く都度読込まれる
    // obj={tag:value,,,} 形式
    //alert("->"+answer); //##

    var obj = JSON.parse(answer);
    
    _postItRecords = new Array();
    for (tag in obj){
        var val = obj[tag];
        
        if (tag == "UniversalSection.postIt"){
            // val = {"entryDate":"..","type":"0","value":"memo","updateTime":""}
            _postItRecords[val.entryDate] = val;
        } else if (typeof val == "object"){
            // val がオブジェクトだと setCell() でコケるので念のため排除
            alert("gotBasic: " + tag + "->" + encodeObject(val));
        } else {
            var cell = setCell(currentDate(), tag, val);
            
            // setCell() の中では _structure がまだ未生成のことあり追加できない
            setCellToStructure(currentDate(), tag, cell);
        }
    }

    if (_anotherReceiver)
        _anotherReceiver(); // noa.js
}
function NRGetBasic(entryDate, anotherReceiver){
    // patientId, entryDate に対応するページデータをサーバへリクエスト
    // getPage と異なるのはデータ取得だけでページを表示しないこと
    setCurrentDate(entryDate);

    _anotherReceiver = anotherReceiver;
    
    var st = tagArray().join(",");
    
    //alert("NRGetPage->"+currentDate()); //##
    
    NRGetPage(owner(), patient_id(), entryDate, "", st, gotBasic);
}

function NRGetPatients(searchKey, receiver){
	// serchKey に一致する患者リストを返す
	// 検索キーにマッチしたカルテのリストを表示
    // ### FRONT からも利用される
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
        var ch = searchKey.charAt(0);
        if (('0' <= ch) && (ch <='9'))
            var mode = "id";
        else if (('a' <= ch) && (ch <='z'))
            var mode = "kana";
        else if ('.' == ch){
            var mode = "anotherId";
            searchKey = searchKey.substr(1);
        } else
            var mode = "kanji";

		var array = new Array();
		array["key"] = mode;
		array["val"] = searchKey;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
        // InfoViewer FRONT などから呼ばれるので絶対パスが必要
		var st = "/XNOA/server.php?command=GET_PATIENTS"
		+"&value=" + encodeObject(array);
		
        //alert("NRGetPatients ====\n"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetProgressSection(owner, patientId, receiver){
    // owner, patientId の ProgressSection レコードを全て返す
    // 同時にアクセス・ログにも patientId を記憶
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["patientId"] = patientId;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=GET_PROGRESS_SECTION"
		+"&value=" + encodeObject(array);
		
        //alert("NRGetProgressSection ====\n"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetAccessLog(owner, receiver){
    // owner のアクセス・ログをサーバへリクエスト
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=GET_ACCESS_LOG"
		+"&value=" + encodeObject(array);
		
        //alert("NRGetAccessLog ====\n"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetPage(owner, patientId, entryDate, updateTime, tagArray, receiver){
    // owner, patientId, entryDate updateTime の tagArray に対応する value を返す
    // updateTime が "" なら最後の updateTime
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["patientId"] = patientId;
		array["entryDate"] = entryDate;
		array["updateTime"] = updateTime;
		array["tagArray"] = tagArray; // タグをカンマで区切った文字列
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶

        // FRONT からも呼ばれるので絶対パスが必要
		var st = "/XNOA/server.php?command=GET_PAGE"
		+ "&value=" + encodeObject(array);
		
        // alert("NRGetPage =====\n" + st); //###
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRAddPage(owner, patientId, dateTime, receiver){
	// owner, patientId, dateTime のページを追加
	// dateTime = "2009-01-09 17:48:33" 形式
	//　　同時に lastVisitDate (最終受診日) に当日のタイムスタンプを押す
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["patientId"] = patientId;
		array["entryDate"] = dateTime;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=ADD_PAGE"
		+ "&value=" + encodeObject(array);
		
		//alert("NRAddPage->"+st); //return; //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function IFPutPage(owner,patientId,currentDate,timeLimit,container,receiver){
    // 周辺ツールから使うためのインタフェース: PatientRegister
    // 周辺ツールから NRPutPatient() を直接呼ぶと searver の path が変わってしまうため
    NRPutPage(owner,patientId,currentDate,timeLimit,container,receiver);
}
function NRPutPage(owner,patientId,currentDate,timeLimit,container,receiver){
    // owner, patientId, entryDate の container をサーバへ保存
    // container = {"tag":"value",,,} 形式
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["patientId"] = patientId;
		array["entryDate"] = currentDate;
		array["timeLimit"] = timeLimit;
		
		for (tag in container){
			// '#' が入るので encodeSTRING() 処理が必要
			array[tag] = encodeSTRING(container[tag]);
		}
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=PUT_PAGE"
		+ "&value=" + encodeObject(array);
		
		//alert("NRPutPage ===\n"+st); //return; //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetInsrance(patientId, receiver){
    // patientId に相当する保険証画像イメージがあればその URLリスト を返す
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        var args = new Array();
        args['patientId'] = trim(patientId);
        
        // FRONT など外部から使うには絶対パスの必要あり
        var st = "/XNOA/server.php"
        + "?command=GET_INSURANCE"
        + "&value=" + encodeObject(args);
        
        //alert("NRGetInsrance --\n"+st); //return; //##
        
        xmlHttpObject.open("GET", encodeURI(st), true);
        xmlHttpObject.send(null);
	}
}

function NRRemovePage(owner, patientId, dateTime, timeLimit, receiver){
	// owner, patientId, dateTime のページを削除
    //	xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["patientId"] = patientId;
		array["entryDate"] = dateTime;
		array["timeLimit"] = timeLimit;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=REMOVE_PAGE"
		+ "&value=" + encodeObject(array);
		
		//alert("NRRemovePage =====\n" + st); //###
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetGroupMenuItems(owner, menuItem, receiver){
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["menuItem"] = menuItem;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=GET_GROUP_MENU_ITEMS"
		+ "&value=" + encodeObject(array);
		
        //alert("NRGetGroupMenuItems->"+st); //###
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetFrontPatients(entryDate, receiver){
    // FRONT の entryDate の受診者リストをサーバへリクエスト
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["entryDate"] = entryDate;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=GET_FRONT_PATIENTS"
		+ "&value=" + encodeObject(array);
		
        //alert("NRGetFrontPatients->"+st); //###
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetRecordsForKeys(pid, owner, keys, receiver){
	// 配列 keys に含まれるキーを含む全てのレコードを返す
	// ## Pickup ツールで使用する
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["patientId"] = pid;
		array["owner"] = owner;
		array["keys"] = keys; // 改行された文字列
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=GET_RECORDS_FOR_KEYS"
		+"&value=" + encodeObject(array);
		//alert("NRGetRecordsForKeys ====\n"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRFind(tag, pid, key, from, to, unique, receiver){
	// 検索条件により検索
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["tag"] = tag;
		array["patientId"] = pid;
		array["searchKey"] = key;
		array["from"] = from;
		array["to"] = to;
		array["unique"] = unique;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=FIND"
		+ "&value=" + encodeObject(array);
        
		//alert(st); //###
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPutArchive(owner, patientId, receiver){
    // xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["patientId"] = patientId;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=PUT_ARCHIVE"
		+ "&value=" + encodeObject(array);
		
        //alert(st); //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPutAllArchive(owner, currentDate, receiver){
	// 当日の全患者のデータをアーカイブし保存するようサーバへ依頼
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["entryDate"] = currentDate;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=PUT_ALL_ARCHIVE"
		+ "&value=" + encodeObject(array);
		//alert(st); //===
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetArchive(patientId, receiver){
    // xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["patientId"] = patientId;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=GET_ARCHIVE"
		+ "&value=" + encodeObject(array);
		//alert(st); //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetInsurance(ownerNumber, receiver){
	// 保険者番号から該当保険者レコードを検索
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["HealthInsurance.ownerNumber"] = ownerNumber;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=GET_HEALTHINSURANCE_WITH_KEY"
		+ "&value=" + encodeObject(array);
		//alert(st); return; //===
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRLogin(name, pwd, receiver){
	// login を支配
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		// サーバとの約束事
		var array = new Array();
		array["loginName"] = name;
		array["passwd"] = pwd;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶

        // FRONT など外部から使うには絶対パスの必要あり
		var st = "/XNOA/server.php?command=LOGIN"
		+ "&value=" + encodeObject(array);
		//alert("NRLogin->"+st);

		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPostLayout(owner, value, receiver){
    // レイアウトをサーバへ保存："GET" では大きすぎてコケるので "POST" を使用
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
        // encodeURI は '&' をエンコードしてくれないのでこちら側でエンコード
        // ### send() に与える文字列:st 全体をエンコードしては駄目 ###
        var st = "";
        st += "command=PUT_LAYOUT"
        st += "&owner=" + owner;
        st += "&value=" + encodeURI(encodeSTRING(value));
        
        //alert("NRPostLayout ====\n"+st); return; //##
        
        xmlHttpObject.open("POST", "postServer.php", true);
        xmlHttpObject.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');
        xmlHttpObject.send(st);
	}
}

function NRRemoveTagAndLabel(owner, receiver){
    // tag と label のレイアウトをサーバから削除
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		// サーバとの約束事
		var array = new Array();
		array["owner"] = owner;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
		var st = "./server.php?command=REMOVE_TAG_LABEL"
		+ "&value=" + encodeObject(array);
        
		//alert(st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPutToolMenu(owner, array, receiver){
    // TOOL_MENU のデータをサーバへ保存
    // array のデータ量が多いと転送エラーになるので POST 型式でサーバへ送る
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
        // encodeURI は '&' をエンコードしてくれないのでこちら側でエンコード
        // ### send() に与える文字列:st 全体をエンコードしては駄目 ###
        var st = "";
        st += "command=PUT_TOOL_MENU"
        st += "&owner=" + owner;
        var value = encodeObject(array);
        value = encodeSTRING(value);
        st += "&value=" + encodeURI(value);
        
        //alert("NRPutToolMenu ====\n"+st); //##
        
        xmlHttpObject.open("POST", "postServer.php", true);
        xmlHttpObject.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');
        xmlHttpObject.send(st);
	}
}

function NRGetToolMenu(owner, receiver){
    // TOOL MENU 構造をサーバへリクエスト
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		// サーバとの約束事
		var array = new Array();
		array["owner"] = owner;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		// FRONT など他のアプリからも使えるよう server.php はフルパス指定
		var st = "./server.php?command=GET_TOOL_MENU"
		+ "&value=" + encodeObject(array);
        
		//alert(st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRRemoveToolMenu(owner, label, receiver){
    // メニュー構造をサーバへリクエスト
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		// サーバとの約束事
		var array = new Array();
		array["owner"] = owner;
		array["label"] = label;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		// FRONT など他のアプリからも使えるよう server.php はフルパス指定
		var st = "./server.php?command=REMOVE_TOOL_MENU"
		+ "&value=" + encodeObject(array);
        
		//alert(st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRRemoveScraps(owner, folder, receiver){
    // owner/folder 中の '_' で始まるスクラップファイルを全て削除
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		// サーバとの約束事
		var array = new Array();
		array["owner"] = owner;
		array["folder"] = folder;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		// FRONT など他のアプリからも使えるよう server.php はフルパス指定
		var st = "./server.php?command=REMOVE_SCRAPS"
		+ "&value=" + encodeObject(array);
        
		//alert(st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRputRemind(pid, type, owner, dataString, receiver){
	// pid,type,owner,dataString を UniversalSection に格納
	// ## Reminder ツールで使用する
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["patientId"] = pid;
		array["owner"] = owner;
		array["type"] = type; // いずれ使うかも知れない
		array["dataString"] = dataString;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=PUT_REMINDER"
		+"&value=" + encodeObject(array);
		//alert("NRGetPatients ====\n"+st); //##
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}
function NRgetRemind(pid, type, owner, receiver){
	// pid,type,owner に一致する UniversalSection のレコードを返す
	// ## Reminder ツールで使用する
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["patientId"] = pid;
		array["owner"] = owner;
		array["type"] = type; // いずれ使うかも知れない
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=GET_REMINDER"
		+"&value=" + encodeObject(array);
		//alert("NRGetPatients ====\n"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPutArchiveFile(owner, folder, array, receiver){
    // array を POST 型式でサーバへ転送し JSON 型式で保存
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
        // encodeURI は '&' をエンコードしてくれないのでこちら側でエンコード
        // ### send() に与える文字列:st 全体をエンコードしては駄目 ###
        var st = "";
        st += "command=PUT_ARCHIVE_FILE"
        st += "&owner=" + owner;
        st += "&folder=" + folder;
        var value = encodeObject(array);
        value = encodeSTRING(value);
        st += "&value=" + encodeURI(value);
        
        //alert("NRPutArchiveFile ====\n"+st); //return; //##

        xmlHttpObject.open("POST", "postServer.php", true);
        xmlHttpObject.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');
        xmlHttpObject.send(st);
	}
}
    
function NRGetArchiveFile(owner, folder, filename, receiver){
    // ファイルをサーバへリクエスト
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
    xmlHttpObject = createXMLHttpRequest(NRSendBack);
    if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["folder"] = folder;
		array["filename"] = filename;
        
        _receiver = receiver; // 結果を受け付けるメソッドを記憶
        var st = "./server.php?command=GET_ARCHIVE_FILE"
        + "&value=" + encodeObject(array);
        
        //alert(st); //return; //##
        
        xmlHttpObject.open("GET", encodeURI(st), true);
        xmlHttpObject.send(null);
    }
}

function NRGetArchiveFiles(owner, folder, receiver){
    // TOOL MENU のバックアップファイル・リストをサーバへリクエスト
    xmlHttpObject = createXMLHttpRequest(NRSendBack);
    if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["folder"] = folder;
        
        _receiver = receiver; // 結果を受け付けるメソッドを記憶
        var st = "./server.php?command=GET_ARCHIVE_FILES"
        + "&value=" + encodeObject(array);
        
        //alert(st); //return; //##
        
        xmlHttpObject.open("GET", encodeURI(st), true);
        xmlHttpObject.send(null);
    }
}

function NRRemoveArchiveFile(owner, folder, filename, receiver){
    // TOOL MENU のバックアップファイルを削除
    xmlHttpObject = createXMLHttpRequest(NRSendBack);
    if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["folder"] = folder;
		array["filename"] = filename;
        
        _receiver = receiver; // 結果を受け付けるメソッドを記憶
        var st = "./server.php?command=REMOVE_ARCHIVE_FILE"
        + "&value=" + encodeObject(array);
        
        //alert(st); //return; //##
        
        xmlHttpObject.open("GET", encodeURI(st), true);
        xmlHttpObject.send(null);
    }
}

function NRPutPassword(name, pwd, receiver){
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		// サーバとの約束事
		var array = new Array();
		array["loginName"] = name;
		array["passwd"] = pwd;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=SET_PASSWD"
		+ "&value=" + encodeObject(array);
		
        //alert(st); return; //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPutPatient(own,pid,aid,rid,date,bdate,sex,kanji,kana,roma,receiver){
	// 新患登録
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack); // global 変数で宣言
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = own;
		array["patientId"] = pid;
		array["anotherId"] = aid;
		array["receiptId"] = rid;
		array["entryDate"] = date;
		array["birthDate"] = bdate;
		array["sex"] = sex;
		array["kanjiName"] = kanji;
		array["kanaName"] = kana;
		array["romajiName"] = roma;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
        // ### FRONT からも利用
		var st = "/XNOA/server.php?command=PUT_NEW_PATIENT"
		+ "&value=" + encodeObject(array);
        
		//alert("NRPutPatient->"+st); //return; //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRRemoveRecordsForTag(owner, tag, receiver){
    // UniversalSection から owner, tag の全レコードを削除
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack); // global 変数で宣言
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["tag"] = tag;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "./server.php?command=REMOVE_RECORDS_FOR_TAG"
		+ "&value=" + encodeObject(array);
        
		//alert("NRRemoveRecordsForTag->"+st); //return; //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRMergeArchive(owner, pid, tag, entryDate, updateTime, val, receiver){
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["owner"] = owner;
		array["patientId"] = pid;
		array["tag"] = tag;
		array["entryDate"] = entryDate;
		array["updateTime"] = updateTime;
		array["val"] = val;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=MERGE_ARCHIVE"
		+ "&value=" + encodeObject(array);
		//alert("NRMergeArchive->"+st); return; //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetBooking(patientId, dateTime, receiver){
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["patientId"] = patientId;
		array["dateTime"] = dateTime;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=GET_BOOKING"
		+ "&value=" + encodeObject(array);
		//alert("NRGetBooking->"+st); //return; //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}


///////////////////////////////////////////////
///// 組込み周辺ツール //////////////////////////

function openFRONT(){
    // FRONT を開く
	var array = new Array();
	array['owner'] = owner();
	array['hospitalId'] = hospitalId();
	array['hospitalName'] = hospitalName();
	var args = encodeObject(array);
	var href = "/FRONT/index.php?value="+encodeSTRING(args);
    
	var win = window.open(href, "FRONT", "_blank");
	win.focus();
}

function tagStrings(){
    // "tag:label,,," 型式のオブジェクトを返す
    var results = new Array();
    var array = layoutArray(_basic);
    for (num in array){
        var obj = array[num];
        results.push(obj.tag + ":" + obj.label);
    }
    var array = layoutArray(_insurance);
    for (num in array){
        var obj = array[num];
        results.push(obj.tag + ":" + obj.label);
    }
    var array = layoutArray(_progress);
    for (num in array){
        var obj = array[num];
        results.push(obj.tag + ":" + obj.label);
    }
    return results.join(",");
}

function archived(answer){
    // カルテデータがアーカイブされた返事を受け取る
    //alert("archived->"+answer); //##
    archiveMessage(patient_id()+" "+patientKanjiName()+" のカルテをバックアップしました");
    hideMessage("_message");
    
    var printImage = 0;
    if (hasImage()){
        if (confirm("添付されている画像も印刷しますか？ （ Alpha channel を持たない画像は印刷できません。その場合はキャンセルを押せば画像なしで印刷されます）。")){
            printImage = 1;
        }
    }

	var url = "./printLog.php?patientId="+patient_id()
	+ "&entryDate="+currentDate()
	+ "&owner="+owner()
	+ "&printImage="+printImage
	+ "&isSmallFont="+pagePrintFontSize()
	+ "&isHalfPage="+pagePrintWidth()
	+ "&tags="+tagStrings();
    
	var win = window.open(url, "NOA_PDF", "scrollbars=yes");
	win.document.title = "PRINT"; // window title に "PRINT" 表示
	win.focus();
    
    function hasImage(){
        // このページが image 貼付されているかどうかを返す
        var cell = cellFor(currentDate(), "ProgressSection.object");
        return (cell.value && (cell.value.indexOf("<IMG:") >= 0)) ? true : false;
    }
}
function printPDF(){
	// カルテを印刷する
	if (isSameDate(currentDate(), today()) == 0){
		if (!confirm(currentDate() + " は本日のページではありませんが印刷しますか"))
			return;
	}

    // このカルテの全データをアーカイブし保存するようサーバへ依頼
	NRPutArchive(owner(), patient_id(), archived);
}

function archivedAllItems(answer){
    showFadeoutInfo("_debug", answer, 1000);
}
function printAllPDF(){
	// 本日の全カルテを印刷する
	if (isSameDate(currentDate(), today()) == 0){
		if (!confirm(currentDate() + " は本日のページではありませんが印刷しますか"))
			return;
	}
	
	var url = "./printLog.php?patientId="
	+ "&entryDate="+currentDate()
	+ "&owner="+owner()
	+ "&isSmallFont="+pagePrintFontSize()
	+ "&isHalfPage="+pagePrintWidth()
	+ "&tags="+tagStrings();

	var win = window.open(url, "NOA_PDF", "scrollbars=yes");
	win.document.title = "PRINT"; // window title に "PRINT" 表示
	win.focus();
	
	// 当日の全患者のデータをアーカイブし保存するようサーバへ依頼
	showMessage("_message", "本日受診の全カルテをアーカイブします...[ 未完成 ]");
	NRPutAllArchive(owner(), currentDate(), archivedAllItems);
}

function printPages(){
    // 指定された複数ページを印刷
    // ### TOOL AREA から呼ばれるので NOA に対し呼びかけをする必要あり ###
	var win = window.top.tools;
    var fromDate = win.document.getElementById("fromDatePopup").value;
    var toDate = win.document.getElementById("toDatePopup").value;
    var noa = window.top.noa;

	var url = "./printAllPages.php?"
	+ "owner="+noa.owner()
    + "&patientId=" + noa.patient_id()
	+ "&patientKanjiName="+noa.valueForTag("NameSection.patientKanjiName")
    + "&fromDate=" + fromDate
    + "&toDate=" + toDate;
    //alert(url); return; //##
    
	var win = window.open(url, "PRINT ALL PAGES", "scrollbars=yes");
	win.document.title = "PRINT ALL PAGES"; // window title に "PRINT" 表示
	win.focus();
}
function printAllPages(){
	// このカルテの全ページを印刷する
	var win = window.top.tools;
	var elm = win.document.getElementById("base");
	elm.innerHTML = "";
    
    // === HEADER ===
    var div = newDIV(elm, "title-bar");
    div.innerHTML = "カルテの指定範囲を印刷";
    
    var div = newDIV(elm, "");
    div.style.fontSize = "10pt";
    div.style.padding = "5px 10px";
    var dv = newDIV(div, "");
	var items = history();
	var item = items[items.length - 1];
	var pu = makePopupMenu(dv, "fromDatePopup", items, item);
    var sp = newSPAN(dv, "");
    sp.style.paddingLeft = "3px";
    sp.innerHTML = "から";
    
    var dv = newDIV(div, "");
	var pu = makePopupMenu(dv, "toDatePopup", items, currentDate());
    var sp = newSPAN(dv, "");
    sp.style.padding = "0px 3px";
    sp.innerHTML = "までのページを";
	var bt = newBUTTON(dv, "", "印刷");
    bt.setAttribute("onclick", "printPages()");
    
    // === FOOTER ===
    var div = newDIV(elm, "title-bar");
    div.style.height = "20px";

    function history(){
        // 受診年月日の配列を返す
        var array = new Array();
        var obj = structure();
        for (entryDate in obj){
            array.push(entryDate);
        }
        return array;
    }
}

function NRGetTableRecords(patientId, receiver){
	// 各テーブルごと patientId のレコード数を返す
	// NOAManager で使う
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["patientId"] = patientId;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=GET_TABLE_RECORDS"
		+"&value=" + encodeObject(array);
		//alert(st); //return; //##
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRRemovePatient(table, patientId, receiver){
	// table から patientId のレコード全てを削除
	// NOAManager で使う
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["table"] = table;
		array["patientId"] = patientId;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=REMOVE_TABLE_RECORDS"
		+ "&value=" + encodeObject(array);
		//alert(st); //return; //##
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetImagFileBetween(from, to, receiver){
    // from to の期間にコピーした保険証画像を検索
	// NOAManager で使う
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["fromDate"] = from;
		array["toDate"] = to;
		
        //document.getElementById("dataArea").innerHTML = "検索中：しばらくお待ちください";
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=GET_CONDITIONAL_INS_FILES"
		+ "&value=" + encodeObject(array);
		
        //document.getElementById("_debug").innerHTML = st; //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRGetImageFile(filename, receiver){
    // filename のイメージファイルをリクエスト
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
		var array = new Array();
		array["filename"] = filename;
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=GET_INS_IMAGE"
		+ "&value=" + encodeObject(array);
		
        //document.getElementById("_debug").innerHTML = st; //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRRemoveFiles(files, receiver){
    // カンマで区切られたファイルをサーバから削除
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ 
		var array = new Array();
		array["files"] = encodeSTRING(files);
		
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
		var st = "/XNOA/server.php?command=REMOVE_INS_IMAGE"
		+ "&value=" + encodeObject(array);
        
        //alert("NRRemoveFiles->"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function addAnyPage(){
	// 指定した年月日のページを追加
	var userCode = userInfoForKey("userCode");
	if (userCode == "all"){
		var href = "./addAnyPage.php?owner="+owner();
		window.open(href, "tools");
	} else {
		alert("アクセス・コード: "+userCode+" なのでページ追加権限がありません");
    }
}

///// MESSENGER ///////////////////////
function NRRemoveMessage(docId){
    // docId の MESSAGE レコードをサーバから消去
    //xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
        var array = new Array();
		array['docId'] = docId;
		var val = encodeObject(array);
		
		_receiver = closeMessage; // 結果を受け付けるメソッドを記憶
        
		var st = "/XNOA/server.php?command=REMOVE_MESSAGE"
		+ "&value=" + val;
        
		//alert("NRRemoveMessage->"+st); //##
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function NRPutMessage(){
    // メッセージを送信
    var obj = new Object();
    var sender = owner();
    var senderApp = document.getElementById("receiverApp").innerHTML; // 返信で立場逆転
    obj["sender"] = sender + "@" + senderApp; // owner に格納
    var receiver = document.getElementById("userNamePopup").value;
    if (receiver.length == 0){
		alert("送付先が指定されていません"); return;
    }
    var receiverApp = document.getElementById("appNamePopup").value;
    obj["receiver"] = receiver + "@" + receiverApp; // mishuu に格納
    var msg = document.getElementById("messageText").value;
    if (trim(msg).length == 0){
		alert("メッセージ内容が空です"); return;
    }
    obj["message"] = msg; // plan に格納
    obj["docId"] = document.getElementById("docId").innerHTML; // rowid に相当
    
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
        //alert("NRPutMessage->"+encodeObject(obj)); //##
        
		_receiver = closeMessage; // 結果を受け付けるメソッドを記憶
        
        // FRONT からも呼ばれる
		var st = "/XNOA/server.php?command=PUT_MESSAGE"
		+ "&value=" + encodeSTRING(encodeObject(obj));
		//alert(st); //return; //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

function removeMessageMenu(){
    // MESSAGE MENU の選択項目を削除
    var item = document.getElementById("messagePopup").value;
    if (item.length == 0) return;
    if (item == "...その他") return;
    
    if (confirm("「" + item + "」をメニューから削除していいですか？")){
		NRRemoveMenu(owner(), "MESSAGE_MENU", item , gotMessageMenu);
    }
}

function clickedMessageMenu(elm){
    // MESSAGE MENU が選択された
    var item = elm.value;
    
    if (item == "...その他"){
		item = window.prompt("新規メニュー項目を入力してください", "");
		if (item.length == 0) return;
		// menuItem をサーバへ登録するために incrementFrequency() を使う
		NRPutMenu(owner(), "MESSAGE_MENU", item , "", "", gotMessageMenu);
    } else {
        var buff = document.getElementById("messageText").value;
        document.getElementById("messageText").value = buff + "\n" + item;
    }
}

function gotMessageMenu(answer){
    // メッセージ・メニューを受け取り表示
    //alert("gotMessageMenu->"+answer); //##
    var obj = JSON.parse(answer);
    
    // ===== メッセージ・ポップアップを生成 ======
    var menuItems = obj.messageMenu;
    var items = [""];
    for (item in menuItems){
        items.push(item);
    }
    items.push("...その他");
    
    var elm = document.getElementById("messagePopupArea");
    elm.innerHTML = "";
    
    // SHELTER
	var sp = newSPAN(elm, "");
    sp.style.paddingLeft = "10px";
	var a = newA(sp, "縮小", "#", "");
	a.setAttribute("onclick", "takeShelter()");
    
    // 空欄にする
	var sp = newSPAN(elm, "");
    sp.style.paddingLeft = "10px";
	var a = newA(sp, "空欄にする", "#", "");
	a.setAttribute("onclick", "clearMessage()");

    // MESSAGE MENU
    var pu = makePopupMenu(elm, "messagePopup", items, "");
    pu.setAttribute("onchange", "clickedMessageMenu(this)");
    // remove menu icon
    var sp = newSPAN(elm, "");
    sp.style.paddingLeft = "5px";
	var im = newIMAGE(sp, "", "./remove-field.png", "削除");
	im.style.height = "14px";
	im.style.verticalAlign = "middle";
	im.setAttribute("onclick", "removeMessageMenu()");
   
    // ===== ユーザ・ポップアップを生成 =====
    var userList = obj.userList;
    var userNames = new Array();
    for (logname in userList){
        userNames.push(logname);
    }
    //alert("userNames->"+encodeObject(userNames)); //##
    
    var elm = document.getElementById("userPopArea");
    var sender = elm.innerHTML;
    elm.innerHTML = "";
	var pu = makePopupMenu(elm, "userNamePopup", userNames, sender);
}
function NRGetMessageMenu(owner, receiver){
    // メッセージ・メニューをサーバへリクエスト
	//xmlHttpObject = createXMLHttpRequest(NR_debug);
	xmlHttpObject = createXMLHttpRequest(NRSendBack);
	if (xmlHttpObject){ // GETパラメータ付きでリクエスト送信
        var array = new Array();
		array['owner'] = owner;
        
		_receiver = receiver; // 結果を受け付けるメソッドを記憶
        
        // FRONT からも呼ばれる
		var st = "/XNOA/server.php?command=GET_MESSAGE_MENU"
		+ "&value=" + encodeObject(array);
		//alert(st); //return; //===
        
		xmlHttpObject.open("GET", encodeURI(st), true);
		xmlHttpObject.send(null);
	}
}

var _messagePanelIsOpen;
var _messageString;
function closeShelter(){
    // shelter モードを抜けパネルを開く
	var elm = document.getElementById("messageShelterArea");
    if (!elm){
        // 本体に必ず messageShelterArea を用意
        alert("messageShelterArea がありません"); return;
    }
	elm.innerHTML = "";
    _messageString = "";
    _messagePanelIsOpen = false;
}
function takeShelter(){
    // メッセージ・パネルを退避
    _messageString = document.getElementById("messageText").value; // plan に格納

    closeMessage();
    
    if (_messageString.length){
        var elm = document.getElementById("messageShelterArea");
        if (!elm){
            // 本体に必ず messageShelterArea を用意
            alert("messageShelterArea がありません"); return;
        }
        elm.innerHTML = "message: " + _messageString;
        elm.setAttribute("onclick", "closeShelter()");
        _messagePanelIsOpen = true; // パネルの自動表示を抑制
    }
}

function messengerHelp(){
	window.open("/XNOA/messengerHelp.html","Help"
                ,"width=450,height=700,scrollbars=yes,resizable=yes");
}

function clearMessage(){
    // メッセージ表示部分をクリア
	var elm = document.getElementById("messageText");
    elm.value = "";
    elm.focus();
}

function closeMessage(answer){
    //alert("puttedMessage->"+answer); //##
    var el = document.getElementById("_confirm");
    if (el) el.innerHTML = ""; // floatPanel から呼ばれることがある
    _messagePanelIsOpen = false;
}
function showMessenger(obj, comment){
	// メッセンジャーを表示
    //alert("showMessenger->"+encodeObject(obj)); //##
    var array = obj.sender.split("@"); // ohashi@NOA 型式
    var sender = array[0];
    var senderApp = array[1];
    var array2 = obj.receiver.split("@"); // suzuki@FRONT 型式
    var receiver = array2[0];
    var receiverApp = array2[1];
    var message = (comment) ? comment + obj.message : obj.message;
    var docId = obj.docId; // rowId が入る
    var updateTime = obj.updateTime;
    
	var elm = document.getElementById("_confirm");
    if (!elm){
        alert("_confirm がないのでメッセージを表示できません"); return;
    }
	// メッセージパネルがすでに表示されていれば何もしない
    if (_messagePanelIsOpen) return;
	
    _messagePanelIsOpen = true;
	elm.innerHTML = "";
    
	var tbl = newTABLE(elm, "");
	tbl.style.backgroundColor = "#ffc";
	tbl.style.fontSize = "9pt";
	tbl.style.width = "100%";

    // ===== HEADER =====
	var tr = newTR(tbl, "", "");
	tr.style.color = "#aaa";
    // === left side ===
	var td = newTD(tr, "", "");
	var sp = newSPAN(td, "receiverApp");
    sp.style.paddingLeft = "10px";
    sp.innerHTML = receiverApp;
	var sp = newSPAN(td, "docId");
    sp.style.paddingLeft = "10px";
    sp.innerHTML = docId;
    // === right side ===
	var td = newTD(tr, "", "");
	td.style.textAlign = "right";
	var sp = newSPAN(td, "");
    sp.style.paddingRight = "10px";
    sp.innerHTML = updateTime;
	// HELP
	var im = newIMAGE(td, "", "./Help.png", "?");
	im.setAttribute("onclick", "messengerHelp()");
	im.style.height = "20px";
	im.style.verticalAlign = "bottom";
   
    // ===== MESSAGE POPUP =====
    var tr = newTR(tbl, "", "");
	var td = newTD(tr, "messagePopupArea", "");
	td.setAttribute("colspan", "2");
    
    // ===== TEXT AREA =====
	var tr = newTR(tbl, "", "");
	var td = newTD(tr, "", "");
	td.setAttribute("colspan","2");
	var fd = newTEXTAREA(td, "messageText", 40, 10, message);
    fd.style.padding = "5px 5px";
    
    // ===== FOOTER =====
	var tr = newTR(tbl, "", "");
    tr.style.color = "#aaa";
    tr.style.border = "thin solid #000"; //###
    // === left side ===
	var td = newTD(tr, "", "");
    if (sender){
        var sp = newSPAN(td, "");
        sp.style.paddingLeft = "10px";
        var a = newA(td, "通信終了", "#", "");
        a.setAttribute("onclick", "NRRemoveMessage('" + docId + "')");
    }
    // === right side ===
	var td = newTD(tr, "", "");
	td.style.textAlign = "right";
    // ユーザ選択ポップアップ
    var sp = newSPAN(td, "userPopArea");
    sp.innerHTML = sender; // これで sender を受け渡す：ちょっと安易な方法
    var sp = newSPAN(td, "");
    sp.style.paddingLeft = "2px";
    sp.innerHTML = "@";
    // アプリ選択ポップアップ
    var appNames = ["","NOA","FRONT"];
	var pu = makePopupMenu(td, "appNamePopup", appNames, senderApp);
    var sp = newSPAN(td, "");
    sp.style.paddingRight = "10px";
    sp.innerHTML = "へ";
    // 送信ボタン
    var bt = newBUTTON(td, "", "送信");
    bt.setAttribute("onclick", "NRPutMessage()");

    // floating panel を生成
	var title = "メッセージ伝達パネル";
    if (sender) title = sender + "@" + senderApp + " からメッセージ";
    // パネルを閉じた場合 closeMessage() を呼んでおかないと status がおかしくなる
	openFloatPanel(tbl, 50, 50, title, "fixed", "closeMessage()");
    
    // メッセージパネルのポップアップ内容をサーバへリクエスト
    NRGetMessageMenu(owner(), gotMessageMenu);
}

///// MESSENGER ///////////////////////

///// 組込み周辺ツール //////////////////////////
///////////////////////////////////////////////


