// javascript library

function _debug(){
	// rowid のレコードをサーバから読込み
	if ((xmlHttpObject.readyState == 4) && (xmlHttpObject.status == 200)){
		var value = xmlHttpObject.responseText;
		alert(value);
		document.getElementById("message").innerHTML = value;
	}
	else 
		document.getElementById("message").innerHTML = "Loading...";
}

var _menuTypes;
function menuTypes(){
	if (!_menuTypes){
		_menuTypes = new Array("String","Text","Rotary","Address","Calendar","Group");
	}
	return _menuTypes;
}

function indexOfArray(array, item){
	// array の中の item の存在する位置を返す
	for (var i=0,count=array.length; i < count; i++){
		if (isSame(array[i], item)) return i;
	}
	return (-1);
}

function setColor(element, color, bgcolor){
	element.style.backgroundColor=bgcolor;
	element.style.color=color;
}

function resetColor(element, color, bgcolor){
	element.style.backgroundColor=bgcolor;
	element.style.color=color;
}

function transferCR(value){
	// "\n" を "<BR/>" に変換
	var array = value.split("\n");
	return array.join("<br/>");
}

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

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 終端
				
				// "(", ")" は特定文字にしておく（ decode する時に元へ戻す）
				var array = value.split("(");
				value = array.join("^[^");
				var array = value.split(")");
				value = array.join("^]^");
				
				isInValue = 0;
				begin = p + 1; // key 開始位置
				obj[key] = bracketToObject(value);
			}
		}
	}
	return obj;
}
function objectToBracket(obj){
	// object を "key(value)" 形式にして返す
	var buff = "";
	for (key in obj){
		buff += key + "(" + obj[key] +")";
	}
	return buff;
}

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

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

function dayAndTime(time){
	// 現在の時刻を文字列で返す
	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 todayAndTime(){
	// 現在の時刻を文字列で返す
	return stringWithDate(new Date());
}

function today(){
	// 本日の年月日を返す
	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 date = new Date(yy,mm,dd);
		var week = date.getDay();
		var array = new 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 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){
	// 年月日部分だけの比較をして同じかどうかを返す
	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));
}

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

function age(birthYear, birthMonth, birthDay){
	// 本日の年齢を返す
	var date = new Date();
	var yy = date.getYear();
	var mm = date.getMonth() + 1;
	var dd = date.getDate();
	if (yy < 2000) { yy += 1900; }
	var today = yy * 10000 + mm * 100 + dd;
	var birthdate = birthYear * 10000 + birthMonth * 100 + birthDay * 1;
	return Math.floor((today - birthdate) / 10000);
}

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 limit = year.substr(2, 2); // 今年の西暦年の下２桁
	var y = pid.substr(4, 2) * 1;
	var limit2 = pid.substr(6, 2); // 今年の西暦年の下２桁
	var m = pid.substr(0, 2) * 1;
	var d = pid.substr(2, 2) * 1;
	y = (limit2 < limit) ? 1900 + y : 2000 + y;
	return y + "-" + m + "-" + d;
}

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

function hasMember(array, item){
	// array 中に item があれば 1 なければ 0 を返す
	for (var i=0,count=array.length; i < count; i++){
		if (isSame(array[i], item)) return 1;
	}
	return 0;
}

function hasPast(value){
	// "<PAST>過去データ</PAST>" があれば true なければ false を返す
	return (value.indexOf("</PAST>") > 0) ? true : false;
	/*
	var dom = document.createElement("JS");
	dom.innerHTML = value;
	var childNodes = dom.getElementsByTagName("PAST");
	
	return (childNodes.length > 0) ? true : false;
	 */
}

function pureValue(value){
	// "<PAST>過去データ</PAST>" の中身を返す
	// PAST> タグがなければ value そのままを返す
	var dom = document.createElement("JS");
	dom.innerHTML = value;
	var childNodes = dom.getElementsByTagName("PAST");
	if (childNodes.length)
		return childNodes[0].innerHTML;
	else
		return value;
}

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

function trimDoubleQuotation(value){
	if (value.charAt(0) == "\"") value = value.substring(1);
	if (value.charAt(value.length-1) == "\"")
		value = value.substring(0, value.length-1);
	
	return value;
}

function replaceAll(st, regexp, newstring){
	// st 中の regexp に相当する文字をすべて newstring に置換して返す
	while (st.indexOf(regexp) >= 0)
		st = st.replace(regexp, newstring);
	return st;
}

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;
}

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;
}

/* 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() を解凍する
	var array = val.split("%20");
	val = array.join(' ');
	var array = val.split("%22");
	val = array.join('"');
	var array = val.split("%26quot%3B");
	val = array.join('"');
	var array = val.split("%27");
	val = array.join("'");
	array = val.split("%3C");
	val = array.join("&lt;");
	array = val.split("%23");
	val = array.join("#");
	array = val.split("%26");
	val = array.join("&");
	array = val.split("%3E");
	val = array.join("&gt;");
	array = val.split("%7B");
	val = array.join("{");
	array = val.split("%7D");
	val = array.join("}");
	array = val.split("+");
	val = array.join(" ");
	return val;
}

function encodeSTRING(val){
	// #, &, +  < > などが URI 送信で化けるため encode して送る
	var array = val.split("#");
	val = array.join("%x0;");
	array = val.split("&");
	val = array.join("%x1;");
	array = val.split("+");
	val = array.join("%x2;");
	array = val.split("<");
	val = array.join("%x3;");
	array = val.split(">");
	val = array.join("%x4;");
	array = val.split(" ");
	val = array.join("%x5;");
	array = val.split("\n");
	val = array.join("%x6;");
	return val;
}
function decodeSTRING(val){
	// #, &, +  < > などが URI 送信で化けるため encode して送られたものを decode
	var array = val.split("%x0;");
	val = array.join("#");
	var array = val.split("%x1;");
	val = array.join("&");
	var array = val.split("%x2;");
	val = array.join("+");
	var array = val.split("%x3;");
	val = array.join("<");
	var array = val.split("%x4;");
	val = array.join(">");
	var array = val.split("%x5;");
	val = array.join(" ");
	var array = val.split("%x6;");
	val = array.join("\n");
	return val;
}


function decodeArgs(buff){
	return buff.split("_|_");
}

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

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

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




