// javascript library

function is_HL7_format(){
	// HL7 形式に設定すると「都道府県番号・点数表番号・医療機関コード」など
	// に対応していないので、それらのコードが印刷されない。
	return false;
}

function medicalEncodeType(buff){
	// buff がどのようなフォーマットで encode されているか調べて返す
	if ((buff.indexOf("MSH|") >= 0) && (buff.indexOf("PID|") >= 0))
		return "HL7";
	else if (buff.indexOf("(") && buff.indexOf(")"))
		return "NOA";
	else {
		alert("=== Undefined encode ===\n" + buff);
		return "";
	}
}

function nengouArray(){
	return ["西暦","平成","昭和","大正","明治"];
}

function weeks(){
	return ["日","月","火","水","木","金","土"];
}

// menuTypes() の順番と一致している必要あり
var _rotary_ = 0;
var _address_ = 1;
var _calendar_ = 2;
var _group_ = 3;
var _panel_ = 4;
var _date_ = 5;
var _none_ = 6;
var _number_ = 7;

function menuTypes(){
	// メニューの形式
	return ["Rotary","Address","Calendar","Group","Panel","Date","None","Number"]
}

function menuPositions(){
	// メニューを文中に挿入する位置
	return ["文末へ追加","最終行へ追加","置換"];
}

function buttonTypes(){
    // チェインするかどうかを設定
    return ["no chain", "chain"];
}

function insTable(){
	// HL7 保険種別（IOB_Insurance）を基準に設定
	return [" :","国保:C0^国民健康保険","国保退職:67^国民健康保険退職者","組合:06^組合管掌健康保険","政府:01^政府管掌健康保険","協会:KY^協会","学校共済:34^学校共済組合","警察共済:33^警察共済組合","国家共済:1^国家公務員共済組合","地方共済:332^地方公務員等共済組合","船員:02^船員保険","後期高齢:KK^後期高齢者","自衛:07^自衛官等","母子:23^母子保健法","老人:27^老人保健法による老人医療","公費:PE^公費","その他:OT^その他"];
}
var _insArray;
function insArray(){
	// (" ","国保","組合"..) のような配列
	if (!_insArray){
		var array = insTable();
		_insArray = new Array();
		for (var i=0,ct=array.length; i < ct; i++){
			var st = array[i];
			var ary = st.split(":");
			_insArray.push(ary[0]);
		}
	}
	return _insArray;
}

function publicInsArray(){
	return [" : ","老人:3","一人親:3","一人親(食):0","一人親(一部 食):1","子:0","障害:3","障害(食):0","障害(一部 食):1","乳幼児:0","介護保険:"];
}
function publicInsItems(){
	// (" ","老人","一人親"..) のような配列
	var array = new publicInsArray();
	var items = new Array();
	for (var i=0,ct=array.length; i < ct; i++){
		var st = array[i];
		var ary = st.split(":");
		items.push(ary[0]);
	}
	return items;
}
function publicInsObjects(){
	// insObj["老人"] = "3" (割)のようなオブジェクト
	var array = new publicInsArray();
	var objects = new Array();
	for (var i=0,ct=array.length; i < ct; i++){
		var st = array[i];
		var ary = st.split(":");
		var item = ary[0];
		objects[item] = (ary.length > 1) ? ary[1] : "3";
	}
	return objects;
}

function imageFiles(){
	// 画像ファイルの拡張子の入った配列を返す
	return ["jpg","JPG","jpeg","JPEG","tif","TIF","tiff","TIFF","png","PNG","gif","GIF","pdf","PDF"];
}
function isImageFile(filename){
	// 拡張子でイメージかどうかを判定
	var sfx = suffix(filename);
	var array = imageFiles();
	for (var i=0,ct=array.length; i < ct; i++){
		if (isSame(sfx, array[i]))
			return true;
	}
	return false;
}

function movieFiles(){
	// 動画ファイルの拡張子の入った配列を返す
	return ["mp4","MP4","mov","MOV","m4v","M4V"];
}
function isMovieFile(filename){
	// 拡張子で動画かどうかを判定
	var sfx = suffix(filename);
	var array = movieFiles();
	for (var i=0,ct=array.length; i < ct; i++){
		if (isSame(sfx, array[i]))
			return true;
	}
	return false;
}

var _menu_to_tail_ = 0;
var _menu_to_last_row_ = 1;
var _menu_replace_ = 2;

var _fieldTypes;
function fieldTypes(){
	if (!_fieldTypes){
		_fieldTypes = ["String","Text"];
	}
	return _fieldTypes;
}

function MML0026(){
	// 記録者分類および医療資格コード: groupCode
	return { "doctor":"医師","dentist":"歯科医師","nurse":"看護師","assistantNurse":"准看護師","lab":"臨床検査技師","rad":"レントゲン技師","pharmacist":"薬剤師","pt":"理学療法士","ot":"作業療法士","psy":"精神保健福祉士","cps":"臨床心理技術者","nutritionist":"栄養士","dentalHygienist":"歯科衛生士","dentalTechician":"歯科技工士","clinicalEngineer":"臨床工学士","careManager":"介護支援専門員","other":"その他の医療従事者","acupuncturist":"鍼灸師","patient":"患者およびその代理人","clerk":"書記","office worker":"事務" };
}

function MML0028(){
	// 医科診療科コード: sectionCode
	return { "01":"内科","02":"精神科","03":"神経科","04":"神経内科","05":"呼吸器科","06":"消化器科","07":"胃腸科","08":"循環器科","09":"小児科","10":"外科","11":"整形外科","12":"形成外科","13":"美容外科","14":"脳神経外科","15":"呼吸器外科","16":"心臓血管外科","17":"小児外科","18":"皮膚泌尿器科","19":"皮膚科","20":"泌尿器科","21":"性病科","22":"肛門科","23":"産婦人科","24":"産科","25":"婦人科","26":"眼科","27":"耳鼻咽喉科","28":"気管食道科","29":"理学療法科","30":"放射線科","31":"麻酔科","32":"人工透析科","33":"心療内科","34":"アレルギー","35":"リウマチ","36":"リハビリ","A1":"鍼灸","00":"その他" };
}

function isTouchDevice(){
    // device が iPad, iPhone, iPod かどうかを返す
    var ua = navigator.userAgent;
    if (ua.indexOf('iPad') >= 0) return true;
    if (ua.indexOf('iPhone') >= 0) return true;
    if (ua.indexOf('iPod') >= 0) return true;
    return false;
}

function foldNode(id){
	// id で識別されたノードを開いたり閉じたりする
	var elm = document.getElementById(id);
	if (elm){
		if (elm.style.display == "none")
            elm.style.display = "table-row"; // "block" 表示する
		else
			elm.style.display = "none"; // 表示しない
	}
}

/////////////////////////////////////////////////////
/// 配列関連の関数 /////////////////////////////////////

function indexOfArray(array, item){
	// array の中の item の存在する位置を返す
	// なければ (-1) を返す
    for (num in array){
		if (array[num] == item) return num;
	}
	return (-1);
}

function arrayHasItem(array, item){
	// array 中に item が含まれているかをチェックして返す
    for (i in array){
		if (isSame(array[i], item)) return true;
	}
	return false;
}

function hasMember(array, item){
	// array 中に item があれば 1 なければ 0 を返す
    for (i in array){
		if (isSame(array[i], item)) return 1;
	}
	return 0;
}

/// 配列関連の関数 /////////////////////////////////////
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
/// オブジェクト関連の関数 //////////////////////////////

function allKeys(obj){
    // key:value のオブジェクトから key の配列を返す
    var array = new Array();
    for (key in obj){
        array.push(key);
    }
    return array;
}

function keyForValueIn(obj, value){
    // obj 中の value に対する key を返す
    for (key in obj){
        if (value == obj[key])
            return key;
    }
    return null;
}

function objectCount(obj){
    // object の中の子供の数を返す
    if (!obj)
        return 0;
    
    var count = 0;
    for (key in obj)
        count++;
    return count;
}

/// オブジェクト関連の関数 //////////////////////////////
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
/// 文字列関連の関数 ///////////////////////////////////

function suffix(filename){
	// "filename.jpg" などのファイル名から拡張子 "jpg" を返す
    // '/' を含む filename の場合、最終 '/' の右側だけを取り出す
    var array = filename.split("/");
    if (array.length > 1)
        filename = array[array.length - 1];
    
	var array = filename.split(".");
	if (array.length > 1)
		return array[array.length - 1];
	else
		return "";
}

function convertSTRING(buff, from, to){
	// buff 中の from 文字すべてを to 文字に変換する
	if (!buff || (buff.length == 0)) return buff;
	buff = buff + ""; // 文字列にしておく必要あり
	if (buff.length == 0) return buff;
	
	var array = buff.split(from);
	if (array.length > 1) buff = array.join(to);
	return buff;
}

function replaceAll(st, regexp, newstring){
	// st 中の regexp に相当する文字をすべて newstring に置換して返す
	if (!st || (st.length == 0)) return st;

	while (st.indexOf(regexp) >= 0)
		st = st.replace(regexp, newstring);
    
	return st;
}

function transferCR(value){
	// 改行 "\n" を "<BR/>" に変換
	//if (!value || (value.length == 0)) return value;
	//var array = value.split("\n");
	//return array.join("<BR/>");
	return convertSTRING(value, "\n", "<BR/>");
}

function transferToCR(value){
	//  "<BR/>" を改行 "\n" に変換
	if (value.length){
		value = convertSTRING(value, "<BR/>", "\n");
		value = convertSTRING(value, "<br/>", "\n");
		value = convertSTRING(value, "<br>", "\n");
	}
	return value;
}

function transferSPACE(value){
	// 倍角スペースを半角スペースに変換
	var array = value.split("　");
	return array.join(" ");
}

function isDigit(val){
	// val が数値かどうかをチェックして返す
	val = "" + val;
	for (var i=0,ct=val.length; i < ct; i++){
		var ch = val.charAt(i);
        if ((ch == ".") || (ch == "-")) continue;
		if ((ch < "0") || (ch > "9")) return false;
	}
	return true;
}

function getRidOfSPACE(ln){
	// ln 中の空白を削除
	var st = "";
	for (var i=0,len=ln.length; i < len; i++){
		var ch = ln.charAt(i);
		if (ch == " ")
			continue;
		else if (ch == "　")
			continue;
		else
			st += ch;
	}
	return st;
}

function trim(value){
	// 文字列両端の 空白相当文字 を削除
    if (!value) return "";
    
	for (var i=0, len =value.length; i < len; i++){
		var ch = value.charAt(i);
		if ((ch == " ") || (ch == "　") || (ch == "\n")
			|| (ch == "\r") || (ch == "\t")) continue;
		break;
	}
	value = value.substring(i);
	for (var i=value.length-1; i >= 0; i--){
		var ch = value.charAt(i);
		if ((ch == " ") || (ch == "　") || (ch == "\n")
			|| (ch == "\r") || (ch == "\t")) continue;
		break;
	}
	return value.substr(0, i+1);
}

function trimQuotation(value){
    // value 両端の " あるいは ' を削除して返す
	if (value.charAt(0) == "\"")
        value = value.substring(1);
	if (value.charAt(value.length-1) == "\"")
		value = value.substring(0, value.length-1);
	if (value.charAt(0) == "\'")
        value = value.substring(1);
	if (value.charAt(value.length-1) == "\'")
		value = value.substring(0, value.length-1);
	
	return value;
}
function trimDoubleQuotation(value){
    // value 両端の " を削除して返す
	alert("Use trimQuotation(), not trimDoubleQuotation()");
	
	return trimQuotation(value);
}

/// 文字列関連の関数 ///////////////////////////////////
/////////////////////////////////////////////////////


//////////////////////////////
/// 日付関連 //////////////////

function wareki(dateString){
	// "2010-6-3" を "平成22年6月3日" へ変換して返す
	var array = dateString.split("-");
	if (array.length == 3){
		var yy = array[0] * 1;
		var mm = array[1] * 1;
		var dd = array[2] * 1;
        
		if (yy < 1868){
			return dateString;
		} else if (yy < 1912){
			return "明治"+(yy-1867)+"年"+mm+"月"+dd+"日";
		} else if (yy == 1912){
			if (mm < 7)
				return "明治"+(yy-1867)+"年"+mm+"月"+dd+"日";
			else if ((mm == 7) && (dd < 30))
				return "明治"+(yy-1867)+"年"+mm+"月"+dd+"日";
			else
				return "大正"+(yy-1911)+"年"+mm+"月"+dd+"日";
		} else if (yy < 1926){
			return "大正"+(yy-1911)+"年"+mm+"月"+dd+"日";
		} else if (yy == 1926){
			if ((mm == 12) && (dd >= 25))
				return "昭和"+(yy-1925)+"年"+mm+"月"+dd+"日";
			else
				return "大正"+(yy-1911)+"年"+mm+"月"+dd+"日";
		} else if (yy < 1989){
			return "昭和"+(yy-1925)+"年"+mm+"月"+dd+"日";
		} else if (yy == 1989){
			if ((mm == 1) && (dd < 7))
				return "昭和"+(yy-1925)+"年"+mm+"月"+dd+"日";
			else
				return "平成"+(yy-1988)+"年"+mm+"月"+dd+"日";
		} else
			return "平成"+(yy-1988)+"年"+mm+"月"+dd+"日";
	} else
		return dateString;
}

function separateYYMMDD(date){
	// 年月日を何らかのセパレータで分離し array に入れて返す
	// 1942-3-23, 1942年3月23日 昭和17年3月23日 などの形式に対応
	// array("昭和",17,3,23,0) のような形式で返す
	var num, i, len = date.length;
	var isWareki = 0, hasNum = 0;
	var array = new Array();
	for (i=num=0; i < len; i++){
		var ch = date.charAt(i);
		if ((ch != ' ') && (0 <= ch) && (ch <=9)){	// 数値
			if (i == 0)
				array.push("");		// 西暦
			else if (isWareki > 0){
				label = date.substring(0, i);
				array.push(label);	// 和暦
				isWareki = 0;
			}
			num = num * 10 + ch * 1;
			hasNum = 1;
		} else {					// 数値以外
			if (i == 0)
				isWareki = 1;
			else if (hasNum > 0)
				array.push(num);
			num = 0;
			hasNum = 0;
		}
	}
	array.push(num);
	
	// date がフォーマット通りでない場合は default 値を返す
	if (array.length < 4) array = ["", "1988", "1", "1"];
	
	return array;
}

function seireki(date){
	// 和暦を西暦に変換して返す
	// date は "昭和17年3月23日" のような形式
	var array = separateYYMMDD(date);
	var label = array[0];
	var yy = array[1]*1;
	var mm = array[2]*1;
	var dd = array[3]*1;
	
	if (isSame(label, "平成"))
		yy += 1988;
	else if (isSame(label, "昭和"))
		yy += 1925;
	else if (isSame(label, "大正"))
		yy += 1911;
	else if (isSame(label, "明治"))
		yy += 1867;
	
	return yy+"-"+mm+"-"+dd;
}

function nengou(yy){
	// 西暦に相当する和暦年号を返す
	if (yy < 1868)
		return "西暦";
	else if (yy < 1912)
		return "明治";
	else if (yy < 1926)
		return "大正";
	else if (yy < 1989)
		return "昭和";
	else
		return "平成";
}

function seirekiYear(nengou, yy){
	// 和暦を西暦にして返す
	if (isSame(nengou, "平成"))
		return yy * 1 + 1988;
	else if (isSame(nengou, "昭和"))
		return yy * 1 + 1925;
	else if (isSame(nengou, "大正"))
		return yy * 1 + 1911;
	else if (isSame(nengou, "明治"))
		return yy * 1 + 1867;
	else
		return yy * 1;
}

function warekiYear(nengou, year){
	// nengou に相当する和暦年を返す
    if (nengou == "平成")
		return year - 1988;
	else if (nengou == "昭和")
		return year - 1925;
	else if (nengou == "大正")
		return year - 1911;
	else if (nengou == "明治")
		return year - 1867;
	else
		return year;
}

function dayAndTime(time){
	// time(時刻)を "2008-05-04 16:35:00" のような文字列にして返す
	var date = new Date(time);
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	if (yy < 2000) { yy += 1900; }
	if (mm < 10) { mm = "0" + mm; }
	if (dd < 10) { dd = "0" + dd; }
	hr = date.getHours();
	if (hr < 10) { hr = "0" + hr; }
	mn = date.getMinutes();
	if (mn < 10) { mn = "0" + mn; }
	sc = date.getSeconds();
	if (sc < 10) { sc = "0" + sc; }
	return yy + "-" + mm + "-" + dd + " " + hr + ":" + mn + ":" + sc;
}

function todayAndTimeId(){
	// タイムスタンプ "2009-09-11 09:15:00" から
	// "20090911091500" のような ID を作成して返す
	var date = new Date();
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	var hr = date.getHours();
	var mn = date.getMinutes();
	var sc = date.getSeconds();
	if (yy < 2000) { yy += 1900; }
	if (mm < 10) { mm = "0" + mm; }
	if (dd < 10) { dd = "0" + dd; }
	if (hr < 10) { hr = "0" + hr; }
	if (mn < 10) { mn = "0" + mn; }
	if (sc < 10) { sc = "0" + sc; }
	
	return "" + yy + mm + dd + hr + mn + sc;
}

function todayAndTime(){
	// 現在の時刻を "2008-05-04 16:35:00" のような文字列にして返す
	return stringWithDate(new Date());
}

function today(){
	// 本日の年月日を "2008-05-04" のような文字列にして返す
	var date = new Date();
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	if (yy < 2000) { yy += 1900; }
	if (mm < 10) { mm = "0" + mm; }
	if (dd < 10) { dd = "0" + dd; }
	
	return yy + "-" + mm + "-" + dd;
}

function weekOfDate(date){
	// date:"2008-06-08 11:10:00" の曜日を返す
	var array1 = date.split(" ");
	var array2 = array1[0].split("-");
	if (array2.length > 2){
		var yy = array2[0] * 1;
		var mm = array2[1] * 1 - 1;
		var dd = array2[2] * 1;
		var aDate = new Date(yy,mm,dd);
		var week = aDate.getDay();
    //    alert("weekOfDate->"+date+"->"+aDate.toString()+"->"+week); //##
        
		var array = ["日","月","火","水","木","金","土"];
		return array[week];
	}
	return "";
}

function lastDateTime(date){
	// date が "2008-06-18 08:01:00" であっても "2008-06-18" であっても
	// その日の最終時刻 "2008-06-18 23:59:59" を返す
	var array = date.split(" ");
	return array[0] + " 23:59:59";
}

function yyyymmdd(date){
	// date が "2008-06-18 08:01:00" であっても "2008-06-18" であっても
	// その日付部分 "2008-06-18" を返す
	var array = date.split(" ");
	return array[0];
}

function shortDate(date){
	// date が "2008-06-18 08:01:00" なら
	// その日付部分の短縮形 "080618" を返す
	if (date.length < 10) return date; // 日付が短すぎる
	
	var array = date.split(" ");
	var ymd = array[0];
	var array1 = ymd.split("-");
	if (array1.length < 3) return date; // "yyyy-mm-dd" 形式でない
	
	var yy = array1[0].substr(2,2);
	var mm = array1[1];
	var dd = array1[2];
	return yy+mm+dd;
}
function longDate(date){
	// date が "090830" なら "2009-08-30" にして返す
	if (date.length < 6){
		return date;
	} else if (date.length < 10){
		// date が "090830" の場合
		var yy = "20" + date.substr(0,2);
		var mm = date.substr(2,2);
		var dd = date.substr(4,2);
	} else {
		// date が "20090830" の場合
		var yy = date.substr(0,4);
		var mm = date.substr(4,2);
		var dd = date.substr(6,2);
	}
	return yy + "-" + mm + "-" + dd;
}

function getLastDate(Y,M){
	// Y 年 M 月の日数を返す
	// その年月の１日の「１秒前」の日付を出させている
	var d1 = new Date(Y, M, 1);
	var t1 = d1.getTime();
	d1.setTime(t1-1000)
	
	return d1.getDate();
}

function dateWithString(date){
	// date は "2008-05-04 16:35:00" のような文字列
	var array = date.split(" ");
	var array1 = array[0].split("-");
	var array2 = array[1].split(":");
	var yy = array1[0];
	var mm = array1[1] - 1;
	var dd = array1[2];
	var hou = array2[0];
	var min = array2[1];
	var sec = array2[2];
	return new Date(yy, mm, dd, hou, min, sec);
}

function stringWithDate(date){
	// Date() を "2008-05-04 16:35:00" のような文字列にして返す
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	if (yy < 2000) { yy += 1900; }
	if (mm < 10) { mm = "0" + mm; }
	if (dd < 10) { dd = "0" + dd; }
	hr = date.getHours();
	if (hr < 10) { hr = "0" + hr; }
	mn = date.getMinutes();
	if (mn < 10) { mn = "0" + mn; }
	sc = date.getSeconds();
	if (sc < 10) { sc = "0" + sc; }
	return yy + "-" + mm + "-" + dd + " " + hr + ":" + mn + ":" + sc;
}

function secondsBetween(date1, date2){
	// date1 から date2 までの経過秒数を返す
	// date は "2008-05-04 16:35:00" のような文字列
	var d1 = dateWithString(date1);
	var sec1 = d1.getTime();
	var d2 = dateWithString(date2);
	var sec2 = d2.getTime();
	return (sec2 - sec1) / 1000;
}

function isSameDate(st1, st2){
	// 年月日部分だけの比較をして同じかどうかを返す
	if (!st1 || !st2) return 0;
	
	st1 = st1.toString();
	st2 = st2.toString();
	if (st1.length < 10) return 0;
	if (st2.length < 10) return 0;
	
	var dt1 = st1.substr(0, 10);
	var dt2 = st2.substr(0, 10);
    //	return (isSame(dt1, dt2));
	return (dt1 == dt2) ? 1 : 0;
}

function isSameMonth(st1, st2){
	// 年月部分だけの比較をして同じかどうかを返す
	if (!st1 || !st2) return 0;
	
	st1 = st1.toString();
	st2 = st2.toString();
	if (st1.length < 10) return 0;
	if (st2.length < 10) return 0;
	
	var dt1 = st1.substr(0, 7);
	var dt2 = st2.substr(0, 7);
    //	return (isSame(dt1, dt2));
	return (dt1 == dt2) ? 1 : 0;
}

/// 日付関連 //////////////////
//////////////////////////////

//////////////////////////////
/// 年令関連 //////////////////

function age(birthYear, birthMonth, birthDay, ageMonthDate){
	// 本日の年齢を返す： age("2011-1-1") 形式も OK
    // ## age() へ渡す ageMonthDate　以外のパラメータは *** 文字列 *** として渡すこと
    // ageMonthDate パラメータがあれば、年齡を年・月・日で返す
	var array = birthYear.split("-");
	if (array.length == 3){
		// age("2011-1-1") 形式も OK
		birthYear = array[0];
		birthMonth = array[1];
		birthDay = array[2];
	}
    birthMonth -= 1;
	var now = new Date();
    var nowy = now.getFullYear();
    var nowm = now.getMonth();
    var nowd = now.getDate();
    
    var intervalY = nowy - birthYear;
    var intervalM = nowm - birthMonth;
    var intervalD = nowd - birthDay;
    if (intervalD < 0){
        intervalD = (new Date(nowy, nowm, 0)).getDate() - birthDay + nowd;
        intervalM--;
    }
    if (intervalM < 0){
        intervalM += 12;
        intervalY--;
    }
    
    if (ageMonthDate)
        return [intervalY, intervalM, intervalD];
    else
        return intervalY;
}

function ageAtDate(birthDate, someDate){
	// someDate における年齢を返す
	var array = birthDate.split(" ");
	var date = array[0];
	array = date.split("-");
	var bYear = array[0] * 1;
	var bMonth = array[1] * 1;
	var bDay = array[2] * 1;
	
	array = someDate.split(" ");
	date = array[0];
	array = date.split("-");
	var sYear = array[0] * 1;
	var sMonth = array[1] * 1;
	var sDay = array[2] * 1;
	
	var today = sYear * 10000 + sMonth * 100 + sDay;
	var birthdate = bYear * 10000 + bMonth * 100 + bDay * 1;
	return Math.floor((today - birthdate) / 10000);
}

function birthDateWithPatientId(pid){
	// patientId から生年月日を計算して返す
	// 100才以上の場合はエラー値になる
	var year = today().substr(0, 4);
	var thisY = year.substr(2, 2); // 今年の西暦年の下２桁
	var y = pid.substr(4, 2) * 1;
	var pidY = pid.substr(4, 2); // patientId から取り出した西暦の下２桁
	var m = pid.substr(0, 2) * 1;
	var d = pid.substr(2, 2) * 1;
	y = (pidY <= thisY) ? 2000 + y : 1900 + y;
	return y + "-" + m + "-" + d;
}
function patientIdWithBirthdate(birthDate){
	// 生年月日から patientId の最初の６桁を生成して返す
	var array = birthDate.split("-");
	var yy = array[0].substr(2, 2);
	var mm = (array.length > 1) ? array[1] * 1 : 1;
	var dd = (array.length > 2) ? array[2] * 1 : 1;
	if (mm < 10) mm = "0" + mm;
	if (dd < 10) dd = "0" + dd;
	return "" + mm + dd + yy;
}

/// 年令関連 //////////////////
//////////////////////////////

function isSame(st1, st2){
	return ((st1.length == st2.length) && (st1.indexOf(st2) == 0)) ? 1 : 0;
}

function htmlToPlain(html){
    // html テキストから全ての <タグ> を取除いたテキストを返す
    var plain = "";
    var isTag = false;
    for (pos in html){
        var ch = html.charAt(pos);
        
        if (ch == "<") isTag = true;
        if (!isTag) plain += ch;
        if (ch == ">") isTag = false;
    }
    return plain;
}

function hasPast(value){
	// "<PAST>過去データ</PAST>" があれば true なければ false を返す
	if (!value || (value.length == 0)) return false;
	return (value.indexOf("</PAST>") > 0) ? true : false;
}

function pureValue(value){
	// "<PAST>過去データ</PAST>" からタグを削除して返す
	if (! value || (value.length == 0)) return "";
	value = convertSTRING(value, "<PAST>", "");
	value = convertSTRING(value, "</PAST>", "");
	return value;
}

function htmlForValue(val){
	// DB 値 val を HTML で表示する HTML 形式に変換
	// "<IMG:image.jpg>" 形式で記述されている部分を
	// "<A HREF=../Images/image.jpg TARGET=_blank>
	// <IMG SRC=../Images/image.jpg HEGHT=30>
	// </A>" のように拡張して表示
    
	var array = val.split("<IMG:");
	if (array.length > 1){
		// image タグを拡張表示
		//  image 格納フォルダー位置はサーバ側で任意に変更できるよう
		//  folder path は imageFolder() からダイナミックに得る
		for (var i=1,count=array.length; i < count; i++){
			var ln = array[i];
			var ary = ln.split(">");
			if (ary.length > 1){
				var url = trim(ary[0]);
                // "<IMG:/foo/bar.png/>" 型式の場合は "/>" をはずす
                if (url.charAt(url.length - 1) == "/")
                    url = url.substr(0, url.length - 1);
                //url = convertSTRING(url, "../NOA_ARCHIVE/", "/NOA_ARCHIVE/"); // 第８世代 NOA 用
				var buff = referenceOf(url);
//                alert("referenceOf->"+url+"->"+buff); //##
                
				ary[0] = buff;
				ln = ary.join(">");
				array[i] = ln;
			}
		}
		val = array.join("");
//		alert("htmlForValue->"+val);//##
	}
    
	val = pureValue(val);	// 過去データから <PAST></PAST>をはずす
	val = transferCR(val);	// "\n" を "<BR/>" に置換して表示
	return val;
	
	function referenceOf(url){
        var imageHeight = thumbNailSize(); // preference.js などで設定しておくこと
		var sfx = suffix(url);
		if (isImageFile(url)){
			var action = "openImage('"+url+"')";
			return "<A onclick=\"" + action + "\">"
			+ "<IMG SRC='" + url +"' HEIGHT=\'" + imageHeight + "\'></A";
		} else if (isMovieFile(url)){
			var action = "openImage('"+url+"')";
			return "<A onclick=\"" + action + "\">"
			+ "<IMG SRC='movie.jpg' HEIGHT=\'" + imageHeight + "\'></A";
		} else if (sfx == "zip"){
			var action = "openZip('"+url+"')";
			return "<A onclick=\"" + action + "\">"
			+ "<IMG SRC='folder.jpg' HEIGHT=\'" + imageHeight + "\'></A";
		} else if (sfx == "txt"){
			var action = "openImage('"+url+"')";
			return "<A onclick=\"" + action + "\">"
			+ "<IMG SRC='text.png' HEIGHT=\'" + imageHeight + "\'></A";
		} else {
			var action = "openImage('"+url+"')";
			return "<A onclick=\"" + action + "\">"
			+ "<IMG SRC='file.png' HEIGHT=\'" + imageHeight + "\'></A";
		}
	}
}

/* Function Equivalent to java.net.URLEncoder.encode(String, "UTF-8")
 Copyright (C) 2002, Cresc Corp.
 Version: 1.0
 */
function encodeURL(str){
	var s0, i, s, u;
	s0 = ""; // encoded str
	for (i = 0; i < str.length; i++){ // scan the source
		s = str.charAt(i);
		u = str.charCodeAt(i); // get unicode of the char
		if (s == " "){s0 += "+";} // SP should be converted to "+"
		else {
			if ( u == 0x2a || u == 0x2d || u == 0x2e || u == 0x5f || ((u >= 0x30) && (u <= 0x39)) || ((u >= 0x41) && (u <= 0x5a)) || ((u >= 0x61) && (u <= 0x7a))){ // check for escape
				s0 = s0 + s; // don't escape
			}
			else { // escape
				if ((u >= 0x0) && (u <= 0x7f)){ // single byte format
					s = "0"+u.toString(16);
					s0 += "%"+ s.substr(s.length-2);
				}
				else if (u > 0x1fffff){ // quaternary byte format (extended)
					s0 += "%" + (oxf0 + ((u & 0x1c0000) >> 18)).toString(16);
					s0 += "%" + (0x80 + ((u & 0x3f000) >> 12)).toString(16);
					s0 += "%" + (0x80 + ((u & 0xfc0) >> 6)).toString(16);
					s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
				}
				else if (u > 0x7ff){ // triple byte format
					s0 += "%" + (0xe0 + ((u & 0xf000) >> 12)).toString(16);
					s0 += "%" + (0x80 + ((u & 0xfc0) >> 6)).toString(16);
					s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
				}
				else { // double byte format
					s0 += "%" + (0xc0 + ((u & 0x7c0) >> 6)).toString(16);
					s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
				}
			}
		}
	}
	return s0;
}


/* Function Equivalent to java.net.URLDecoder.decode(String, "UTF-8")
 Copyright (C) 2002, Cresc Corp.
 Version: 1.0
 */
function decodeURL(str){
	var s0, i, j, s, ss, u, n, f;
	s0 = ""; // decoded str
	for (i = 0; i < str.length; i++){ // scan the source str
		s = str.charAt(i);
		if (s == "+"){s0 += " ";} // "+" should be changed to SP
		else {
			if (s != "%"){s0 += s;} // add an unescaped char
			else{ // escape sequence decoding
				u = 0; // unicode of the character
				f = 1; // escape flag, zero means end of this sequence
				while (true) {
					ss = ""; // local str to parse as int
					for (j = 0; j < 2; j++ ) { // get two maximum hex characters for parse
						sss = str.charAt(++i);
						if (((sss >= "0") && (sss <= "9")) || ((sss >= "a") && (sss <= "f")) || ((sss >= "A") && (sss <= "F"))) {
							ss += sss; // if hex, add the hex character
						} else {--i; break;} // not a hex char., exit the loop
					}
					n = parseInt(ss, 16); // parse the hex str as byte
					if (n <= 0x7f){u = n; f = 1;} // single byte format
					if ((n >= 0xc0) && (n <= 0xdf)){u = n & 0x1f; f = 2;} // double byte format
					if ((n >= 0xe0) && (n <= 0xef)){u = n & 0x0f; f = 3;} // triple byte format
					if ((n >= 0xf0) && (n <= 0xf7)){u = n & 0x07; f = 4;} // quaternary byte format (extended)
					if ((n >= 0x80) && (n <= 0xbf)){u = (u << 6) + (n & 0x3f); --f;} // not a first, shift and add 6 lower bits
					if (f <= 1){break;} // end of the utf byte sequence
					if (str.charAt(i + 1) == "%"){ i++ ;} // test for the next shift byte
					else {break;} // abnormal, format error
				}
				s0 += String.fromCharCode(u); // add the escaped character
			}
		}
	}
	return s0;
}

function urldecode(val){
	// PHP の urlencode() を解凍する
	value = convertSTRING(value, "%20", ' ');
	value = convertSTRING(value, "%22", '"');
	value = convertSTRING(value, "%26quot%3B", '"');
	value = convertSTRING(value, "%27", "'");
	value = convertSTRING(value, "%3C", "&lt;");
	value = convertSTRING(value, "%23", "#");
	value = convertSTRING(value, "%26", "&");
	value = convertSTRING(value, "%3E", "&gt;");
	value = convertSTRING(value, "%7B", "{");
	value = convertSTRING(value, "%7D", "}");
	value = convertSTRING(value, "+", ' ');
	return val;
}

function encodeSTRING(value){
	// #, &, +  < > などが URI 送信で化けるため encode して送る
	if (value.length == 0) return value;
	value = convertSTRING(value, "#", "%x0;");
	value = convertSTRING(value, "&", "%x1;");
	value = convertSTRING(value, "+", "%x2;");
	value = convertSTRING(value, "<", "%x3;");
	value = convertSTRING(value, ">", "%x4;");
	value = convertSTRING(value, " ", "%x5;");
	value = convertSTRING(value, "\n", "%x6;");
	value = convertSTRING(value, "\"", "%x7;");
	value = convertSTRING(value, "$", "%x8;");
	value = convertSTRING(value, "'", "%x9;");
	//value = convertSTRING(value, "(", "%xa;");
	//value = convertSTRING(value, ")", "%xb;");
	return value;
}
function decodeSTRING(value){
	// #, &, +  < > などが URI 送信で化けるため encode して送られたものを decode
	value = convertSTRING(value, "%x0;", "#");
	value = convertSTRING(value, "%x1;", "&");
	value = convertSTRING(value, "%x2;", "+");
	value = convertSTRING(value, "%x3;", "<");
	value = convertSTRING(value, "%x4;", ">");
	value = convertSTRING(value, "%x5;", " ");
	value = convertSTRING(value, "%x6;", "\n");
	value = convertSTRING(value, "%x7;", "\"");
	value = convertSTRING(value, "%x8;", "$");
	value = convertSTRING(value, "%x9;", "'");
	//value = convertSTRING(value, "%xa;", "(");
	//value = convertSTRING(value, "%xb;", ")");
	return value;
}

function encodeRecords(array){
	return array.join("_||_");
}
function decodeRecords(buff){
	return buff.split("_||_");
}

function encodeArgs(array){
	// 配列 array を encode
	return array.join("_|_");
}
function decodeArgs(buff){
	return buff.split("_|_");
}

function encodeArguments(obj){
	// 配列 array を encode
	var array = new Array();
	for (key in obj){
		array.push(key + "_|_" + obj[key]);
	}
	return encodeRecords(array);
}

var _leftbrackets = "^[^"; // encode 中で使う '('
var _rightbrackets = "^]^"; // encode 中で使う ')'
function encodeObject(obj){
	// obj を "key(value)" の文字列に encode して返す -- NOA format と呼ぶ
	// encode 方法として JSON 形式その他が考えられるが NOA format が最も軽いので採用
	// ### 現状では配列はサポートしていない
	var buff = "";
	for (key in obj){
		var value = obj[key];
		if (typeof(value) == "object"){
			buff += key + "(" + encodeObject(value) +")";
		} else {
			// "(", ")" は特定文字にしておく（ decode する時に元へ戻す）
			value = convertSTRING(value, "(", _leftbrackets);
			value = convertSTRING(value, ")", _rightbrackets);
			
			buff += key + "(" + value +")";
		}
	}
	return buff;
}
function decodeObject(buff){
	// "key(value)" 形式の文字列を OBJECT に decode して返す
	var obj = new Object();
	var len = buff.length, begin, end;
	var key, value;
	for (var p=begin=nest=0; p < len; p++){
		var ch = buff.charAt(p);
		if (ch == '('){
			if (nest == 0){
				key = trim(buff.substring(begin, p)); // key 終端
				begin = p + 1; // value 開始位置
			}
			nest++;
		} else if (ch == ')'){
			if (--nest == 0){
				if (nest == 0){
					value = buff.substring(begin, p); // value 終端:trim しない
					begin = p + 1; // key 開始位置
				}
				
				if (value.indexOf(")") > 0){ // まだ入れ子になっているなら
					obj[key] = decodeObject(value);
				} else {
					// 特定文字を "(", ")" へ戻す
					value = convertSTRING(value, _leftbrackets, "(");
					value = convertSTRING(value, _rightbrackets, ")");
					
					obj[key] = value;
				}
			}
		}
	}
	return obj;
}


//////////////////////////////////////////////////
///// XML のエンコード・デコード //////////////////////

var _space="%x5;";
function encodeForTag(st){
    // '<record arg1="foo bar" arg2="any">' 形式から arguments を
    // 取り出すため "..." 中のスペースを他の文字列に置換
    var isArgument = false;
    var buff = "";
    for (i in st){
        var ch = st[i];
        if (ch == '"'){
            isArgument = (isArgument) ? false : true;
        }
        
        if ((ch == ' ') && (isArgument)){
            ch = _space;
        }
        buff += ch;
    }
    return buff;
}
function decodeForTag(st){
    // encodeForTag() 処理をした文字列を元へ戻す
    return convertSTRING(st, "%x5;", " ");
}


function XML2Object(xml, nest){
    // 文字列 xml を object にする
    // nest はデバッグ用で普段は使わない
    var obj = new Object();
    var num = 0; // object number
    var indent = 0;
    var ix = 0;
    var ct = xml.length;
    while (ix < ct){
        ix = nextBeginTag(xml, ix); // 次の '<' までスキップ
        var ch = xml.charAt(ix);
        if (ch == '<'){
			//_showDebug("----- XML2Object "+nest+" ---\n"+ xml.substr(ix)+"\n");
            var buff = xml.substr(ix + 1);
            var fullKey = tagOf(buff); // buff から最初に見つかった '>' までの文字列
            _debug("-- buff->"+buff); //##
            _debug("-- fullKey->"+fullKey); //##
            
            if (fullKey == null){
                var ary = buff.split(">");
                if (ary.length == 1){
                    // 対応する </tag> がみつからなかった
                    alert(fullKey + " に対応する終端タグが見つかりませんでした->"+ ix);
                    return fullKey; // '>' が見つからなかった
                } else {
                    if (ary[0].indexOf(ary[0].length - 1) != "/"){
                        // 対応する "/>" がみつからなかった
                        alert(fullKey + " に対応する終端タグが見つかりませんです->"+ ix);
                        return fullKey; // '/>' が見つからなかった
                    }
                }
            }
            
            if (fullKey.charAt(0) == '?'){
                // XML 宣言:<?xml version="1.0" encoding="UTF-8"?>
                //_showDebug("XML 宣言("+fullKey+")\n"); //##
                ix += fullKey.length + 2;
            } else {
                // <key ...> のオブジェクトを処理
                var key = keyOfFullKey(fullKey);
                if (fullKey.charAt(fullKey.length - 1) == '/'){
                    // <tag/> 形式の場合
                    var anObj = new Object();
                    fKey = fullKey.substr(0, fullKey.length - 1);
                    anObj = setParamaters(anObj, fKey);
                    _debug(key + " " + num+"--> "+encodeObject(anObj)); //##
                    
                    obj[key + " " + num++] = anObj; // 同名オブジェクト識別のため
                    ix += fullKey.length + 3;
                } else {
                    // <tag>...</tag> 形式の場合
                    var target = xml.substr(ix + fullKey.length + 2);
                    var val = contentsOf(target, key);
                    //_showDebug("-------- OK "+nest+" --------"); //##
                    //_showDebug(fullKey+"("+val+")"); //##
                    //_showDebug("-----------------------\n"); //##
                    if (val){
                        // パラメータがあれば anObj へ記憶
                        var anObj = new Object();
                        anObj = setParamaters(anObj, fullKey);
                        
                        if (val.indexOf('<') >= 0){
                            anObj.value = XML2Object(val, nest+1);
                        } else {
                            anObj.value = val;
                        }
                        _debug(key + " " + num+"==> "+encodeObject(anObj)); //##
                        
                        obj[key + " " + num++] = anObj; // 同名オブジェクト識別のため
                        // ix ポインターを終端タグの次の位置へ進める
                        ix += fullKey.length+2 + val.length + key.length+3;
                    } else {
                        //alert("<"+fullKey + "> に対応する終端タグがみつかりません");
                        _debug("fullKey==> "+fullKey); //##
                    //    obj.value = fullKey;
                    //    return obj;
                        return fullKey;
                    }
                }
            }
        } else {
            _debug("--- "+encodeObject(obj)); //##
            return obj;
        }
    }
    _debug("=== "+encodeObject(obj)); //##
    return obj;
    
    function nextBeginTag(xml, ix){
        // ix 以後、最初の開始タグの頭へ ix を移動して返す
        var buff = xml.substr(ix);
        var pos = buff.indexOf('<'); //ixp += pos;
        while ((pos >= 0) && (buff.substr(pos, 2) == '</')){
            var st = buff.substr(pos + 2);
            var p = st.indexOf('<');
            if (p < 0){
                return xml.length;
                break;
            }
            pos += 2 + p;
        }
        return ix + pos;
    }
    
    function contentsOf(st, key){
        // <key> で括られた value を返す
        var beginTag = "<" + key;
        var bLen = beginTag.length;
        var endTag = "</" + key + ">";
        var eLen = endTag.length;
        var nest = 0;
        var pos;
        var ct = st.length;
        for (pos=0 ; pos < ct; pos++){
            if (beginTag == st.substr(pos, bLen)){
                nest++;
            } else if (endTag == st.substr(pos, eLen)){
                if (nest == 0){
                    return st.substr(0, pos);
                }
                nest--;
            }
        }
        return null;
    }
    
    function setParamaters(anObj, fullKey){
        // fullKey にパラメータがあれば anObj へ記憶させる
        // ## <key arg="foo bar"> のようにパラメータに空白が含まれた場合、最初の処理
        // ## fullKey.split(" ") で千切られてしまうので一旦空白をエンコード
        var buff = encodeForTag(fullKey); // パラメータ分析用にエンコード
        var array = buff.split(" ");
        if (array.length > 1){
            for (i in array){
                var ln = array[i];
                if (i > 0){
                    var st = array[i];
                    var ary = st.split("=");
                    if (ary.length > 1){
                        var key = ary[0];
                        var val = trimQuotation(ary[1]);
                        anObj[key] = decodeForTag(val); // エンコードを元へ戻す
                    }
                }
            }
        }
        return anObj;
    }
    
    function tagOf(st){
        // st から最初に見つかった '>' までの文字列を返す
        var pos = st.indexOf('>');
        if (pos >= 0)
            return st.substr(0, pos);
        else
            return null;
    }
    
    function keyOfFullKey(key){
        // 'string name="ohashi" のような文字列から string を返す
        var array = key.split(" ");
        return array[0];
    }
}
function object2XML(nest, xml){
    alert("object2XML は未対応");
    return null;
}

///// XML のエンコード・デコード //////////////////////
//////////////////////////////////////////////////


function bracketToObject(buff){
	// "key(value)" 形式を OBJECT に変換して返す
	// ## このバージョンでは「入れ子」と「データ内の ( や )」に未対応 ##
	var obj = new Object();
	var len = buff.length, begin, end;
	var key, value, isInValue = 0;
	for (var p=begin=nest=0; p < len; p++){
		var ch = buff.charAt(p);
		if (ch == '('){
			key = trim(buff.substring(begin, p)); // key 終端
			isInValue = 1;
			begin = p + 1; // value 開始位置
			nest++;
		} else if (ch == ')'){
			if (--nest == 0){
				value = trim(buff.substring(begin, p)); // value 終端
				
				// 特定文字を "(", ")" へ戻す
				value = convertSTRING(value, _leftbrackets, "(");
				value = convertSTRING(value, _rightbrackets, ")");
				
				isInValue = 0;
				begin = p + 1; // key 開始位置
				obj[key] = bracketToObject(value);
			}
		}
	}
	return obj;
}
function objectToBracket(obj){
	// object を "key(value)" 形式にして返す
	var buff = "";
	for (key in obj){
		var value = obj[key];
		if (typeof(value) == "object"){
			buff += key + "(" + encodeObject(value) +")";
		} else {
			// "(", ")" は特定文字にしておく（ decode する時に元へ戻す）
			value = convertSTRING(value, "(", _leftbrackets);
			value = convertSTRING(value, ")", _rightbrackets);
			
			buff += key + "(" + value +")";
		}
	}
	return buff;
}

function object2json(obj){
	// オブジェクトを JSON 形式の文字列にして返す
    // ## JSON.stringify(obj) を使うと NOAManager の MenuTable アーカイブ保存でコケル
    //return JSON.stringify(obj);
	var buff = "{";
	for (key in obj){
		var val = obj[key];
		if (val == null){
			buff += '"' + key + '":"",';
		} else if (typeof(val) == "object"){
			buff += '"' + key + '":' + object2json(val) + ',';
		} else {
			// ### UniversalSection.documentName のアーカイブでの問題
			// val 中の '"' を '\"' に置換
			val = convertSTRING(val, '"', '^');
			// val 中の改行を '<br/>' に置換
			val = convertSTRING(val, '\r\n', '<BR/>');
			
			buff += '"' + key + '":"' + val + '",';
		}
	}
    buff = (buff.length > 1) ? buff.substr(0, buff.length-1) + "}" : '""';
	return buff;
}

function makeArray(firstItem, count){
	// firstItem から count 数の配列を作成して返す
	var array = new Array();
	for (var i=0; i < count; i++)
		array[i] = firstItem++;
    
	return array;
}

///////////////////////////
/// debug 用メソッド ////////


/// debug 用メソッド ////////
///////////////////////////


///////////////////////////
/// Ajax による処理 /////////

function createXMLHttpRequest(func){
	var xmlHttpObject = null;
	
	if (window.XMLHttpRequest){ // Safari, Firefox
		xmlHttpObject = new XMLHttpRequest();
	} else if (window.ActieXObject){ // IE
		try{
			xmlHttpObject = new ActiveXObject("Msxml2.XMLHTTP"); // IE6
		} catch(e){
			try{
				xmlHttpObject = new ActiveXObject("Microsoft.XMLHTTP"); // IE5
			} catch(e){
				return null;
			}
		}
	}
	
	// xmlHttpObject が生成できたら、状態が変わった時に func が実行される
	if (xmlHttpObject) xmlHttpObject.onreadystatechange = func;
	return xmlHttpObject;
}

/// Ajax による処理 /////////
///////////////////////////

////////////////////////////////
/// 文字列の暗号化・複合化 /////////
/// http://www.keynavi.net/ja/tipsj/ienc.html
/// 上記から使わせて頂きました、謝々、、

//--------------------------------------
//kl_encrypt/decrypt(s)
//返り値：暗号化/複合化した文字列
//s：文字列(日本語入力時はescape()実行)
//KL_CRYPT_KEY：キーとして用いる文字列
//KL_COOKIE_CHARS：クッキーで利用可能な文字
//--------------------------------------
KL_CRYPT_KEY="Rain Drops Falling On My Head...";
KL_COOKIE_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%./_";
function kl_crypt(s,enc){
	var chars=KL_COOKIE_CHARS;
	var key=escape(KL_CRYPT_KEY);
	var t=""; var c,n,m;
	for(var i=0;i<s.length;i++){
		c=s.charAt(i);
		n=chars.indexOf(c);
		if(n>=0){
			m=chars.indexOf(key.charAt(i%key.length));
			if(enc) n=n+m; else n=n-m;
			if(n<0) n=n+chars.length;
			if(n>=chars.length) n=n-chars.length;
			c=chars.charAt(n);
		}
		t+=c;
	}
	return t;
}
function kl_encrypt(s){ return kl_crypt(s,1); }
function kl_decrypt(s){ return kl_crypt(s,0); }

//入力文字列が日本語の場合は以下を利用//
function kl_encryptj(s){ return kl_crypt(escape(s),1); }
function kl_decryptj(s){ return unescape(kl_crypt(s,0)); }

/// 文字列の暗号化・複合化 /////////
////////////////////////////////



