
<?php
    
    function decodeSTRING($val){
        // #, &, +  < > などが URI 送信で化けるため encode して送られたものを decode
        $array = explode("%x0;", $val);
        $val = implode("#", $array);
        $array = explode("%x1;", $val);
        $val = implode("&", $array);
        $array = explode("%x2;", $val);
        $val = implode("+", $array);
        $array = explode("%x3;", $val);
        $val = implode("<", $array);
        $array = explode("%x4;", $val);
        $val = implode(">", $array);
        $array = explode("%x5;", $val);
        $val = implode(" ", $array);
        $array = explode("%x6;", $val);
        $val = implode("\n", $array);
        $array = explode("%x7;", $val);
        $val = implode("\"", $array);
        $array = explode("%x8;", $val);
        $val = implode("$", $array);
        $array = explode("%x9;", $val);
        $val = implode("'", $array);
        $array = explode("%xa;", $val); // DocMaker の Image 用
        $val = implode("\\'", $array);
        return $val;
    }
    
    function leftBrackets(){
        // $leftBrackets = "\^\[\^" では誤作動
        //	return "\^\[\^"; // encode 中で使う '(' -- クライアント側との約束 lib.js
        return "^[^"; // encode 中で使う '(' -- クライアント側との約束 lib.js
    }
    function rightBrackets(){
        return "^]^"; // encode 中で使う '(' -- クライアント側との約束 lib.js
        //	return "\^\]\^"; // encode 中で使う '(' -- クライアント側との約束 lib.js
    }
    function decodeObject($buff){
        // "key(value)" 形式の文字列を OBJECT に decode して返す
        $obj = array();
        //	echo "decodeObject ===\n$buff\n"; //##
        for ($p=$begin=$nest=0, $len=strlen($buff); $p < $len; $p++){
            $ch = substr($buff, $p, 1);
            if (strcmp($ch, "(") == 0){
                if ($nest == 0){
                    $key = trim(substr($buff, $begin, $p - $begin)); // key 終端
                    $begin = $p + 1; // value 開始位置
                }
                $nest++;
            } else if (strcmp($ch, ")") == 0){
                if (--$nest == 0){
                    if ($nest == 0){
                        // value 終端 ( trim しない )
                        $value = substr($buff,$begin,$p-$begin);
                        $begin = $p + 1; // key 開始位置
                    }
                    if (ereg(")", $value)){ // まだ入れ子になっているなら
                        $obj[$key] = decodeObject($value);
                    } else {
                        // 特定文字を "(", ")" へ戻す
                        $array = explode(leftBrackets(), $value);
                        $value = join("(", $array);
                        $array = explode(rightBrackets(), $value);
                        $value = join(")", $array);
                        
                        $obj[$key] = $value;
                    }
                    //echo "$key{".$obj[$key]."}\n"; //##
                }
            }
        }
        return $obj;
    }
    
    function timestamp(){
        // 現在のタイムスタンプを返す updateTime に使う
        date_default_timezone_set("Asia/Tokyo");
        return date("Y-m-d H:i:s",time());
    }
	
	
    ///////////////////////////////////////
    ///// レコードの文字列化はここで管理     ///
    ///// vin.php 側では newItem() で管理 ///
    
    function decodeItem($st){
        $array = explode("_|_", $st);
        $array['isOwn'] = $array[0];
        $array['code'] = $array[1];
        $array['alias'] = $array[2];
        $array['name'] = $array[3];
        $array['standard'] = $array[4]; // dose の意味
        $array['unitName'] = $array[5];
        $array['freq'] = $array[6];
        $array['point'] = $array[7];
        $array['isMix'] = $array[8];
        return $array;
    }
    
    function encode_item($isOwn, $code, $alias, $name,
                        $dose, $unitName, $freq, $point, $isMix){
        $array = array();
        $array['isOwn'] = $isOwn;
        $array['code'] = $code;
        $array['alias'] = $alias;
        $array['name'] = $name;
        $array['dose'] = $dose;
        $array['unitName'] = $unitName;
        $array['freq'] = $freq;
        $array['point'] = $point;
        $array['isMix'] = $isMix;
        return $array;
    }
	
    function decdeArgs($args){
        $array = explode("_|_", $args);
        $array['owner'] = $array[0];
        $array['patientId'] = $array[1];
        $array['currentDate'] = $array[2];
        $array['ageOfTheMoon'] = $array[3];
        $array['timeZone'] = $array[4];
        return $array;
    }
    
    ///// レコードの文字列化はここで管理 ///
    ///////////////////////////////////
    
    
    /////////////////////////
    ///// header 関連 ////////
    
    function getHospitalInfo($hospitalId, $key){
        // 該当する診療行為（薬剤、処置名、など）を DB から取り出して返す
        $query = "SELECT `key`,`value` FROM `HospitalTable` WHERE `hospitalId`='$hospitalId' AND `key`='$key'";
        $result=mysql_query($query);
        
        if (mysql_num_rows ($result) > 0){
            $row=mysql_fetch_array($result);
            return $row['value'];
        }
        return "";
    }
    
    function hospitalInfo($hid, $owner){
        $array['round'] = getHospitalInfo($hid, "まるめ係数");
        $array['ownRate'] = getHospitalInfo($hid, "自費係数");
        return $array;
    }
	
    function codeName($code){
        switch ($code){
            case 11: return "初診";
            case 12: return "再診";
            case 13: return "診他";
            case 21: return "内服";
            case 22: return "屯服";
            case 23: return "外用";
            case 29: return "薬加";
            case 31: return "皮注";
            case 32: return "静注";
            case 33: return "点滴";
            case 41: return "処置";
            case 48: return "処薬";
            case 51: return "手術";
            case 52: return "麻酔";
            case 58: return "手薬";
            case 60: return "検査";
            case 69: return "判断";
            case 70: return "画像";
            case 80: return "其他";
            case 90: return "入院";
            case 91: return "入他";
            default: return "";
        }
    }
    function codeName2code($codeName){
        if ($codeName == "初診") return 11;
        else if ($codeName == "再診") return 12;
        else if ($codeName == "診他") return 13;
        else if ($codeName == "内服") return 21;
        else if ($codeName == "屯服") return 22;
        else if ($codeName == "外用") return 23;
        else if ($codeName == "薬加") return 29;
        else if ($codeName == "皮注") return 31;
        else if ($codeName == "静注") return 32;
        else if ($codeName == "点滴") return 33;
        else if ($codeName == "処置") return 41;
        else if ($codeName == "処薬") return 48;
        else if ($codeName == "手術") return 51;
        else if ($codeName == "麻酔") return 52;
        else if ($codeName == "手薬") return 58;
        else if ($codeName == "検査") return 60;
        else if ($codeName == "判断") return 69;
        else if ($codeName == "画像") return 70;
        else if ($codeName == "其他") return 80;
        else if ($codeName == "入院") return 90;
        else if ($codeName == "入他") return 91;
        else if ($codeName == "合計") return 99;
        else return 0;
    }
	
    function encodeRecords($records){
        // 1_|_12_|_alias_|_name_|_dose_|_unitName_|_freq_|_point
        // を "codeName[name(dose unitName)] point*freq 自費" に変換して返す
        $count = count($records);
        $results = array();
        for ($i=0; $i < $count; $i++){
            $rec = trim($records[$i]);
            if (strlen($rec) == 0) continue;
            $array = decodeItem($rec);
            $codename = codeName($array['code']);
            
            $name = $array['name'];
            $dose = ($array['standard'] * 1 > 0) ? $array['standard'] : 1;
            $unitName = $array['unitName'];
            $freq = $array['freq'] * 1;
            $isOwn = ($array['isOwn'] * 1 > 0) ? " 自費" : "";
            $unit = (($array['code'] != "60") && (strlen($unitName) > 0))
			? "($dose $unitName)" : "";
            if ($array['code'] == "99"){
                $results[] = $name;
            } else {
                $point = $array['point'];
                if ($freq > 1)
                    $results[] = "$codename\[$name$unit\] $point x $freq $isOwn";
                else
                    $results[] = "$codename\[$name$unit\] $point $isOwn";
            }
        }
        return $results;
    }
    function decodeRecords($buff){
        // codeName[name(dose unitName)] point x freq isOwnFee 形式を
        // "isOwnFee(..)code(..)alias(..)name(..)dose(..)unitName(..)freq(..)point(..)isMix(..)" へ変換し返す
        
        $results = array();
        $records = explode("\n", $buff);
        $count = count($records);
        for ($i=0; $i < $count; $i++){
            $rec = trim($records[$i]);
            if (strlen($rec) == 0) continue;
            
            // get CODE
            $ary = explode("[", $rec, 2);
            $code = codeName2code($ary[0]);
            
            // コードが13 または コード末尾が９ の自動付加項目はスキップ
            if (($code % 10) == 9) continue;
            if (($code * 1) == 13) continue;
            if (($code * 1) == 0) continue;
            
            // get NAME, DOSE, UNITNAME
            $st = $ary[1];
            $ary = explode("]", $st, 2);
            $name_unit_mix = $ary[0]; // "ピドキサール注１０ｍｇ(1 管)"
            $pointAndOwnFee = trim($ary[1]);
            $ary = explode("(", $name_unit_mix, 2);
            $isMix = "";
            if (count($ary) > 1){
                $name = $ary[0]; // "ピドキサール注１０ｍｇ"
                $dose_unit_mix = $ary[1]; // "1 管)"
                $ary = explode(" ", $dose_unit_mix, 2);
                if (count($ary) > 1){
                    $dose = $ary[0]; // "1"
                    $ary = explode(")", $ary[1], 2);
                    $unitName = $ary[0]; // "管"
                }
            } else {
                $name = $name_unit_mix;
                $dose = "";
                $unitName = "";
            }
            
            // get ISOWNFEE from "210 x 7 自費"
            $pos = strpos($pointAndOwnFee, "自費");
            if ((strcmp($pointAndOwnFee, "自費") == 0) || ($pos > 0)){
                $isOwn = "1";
                $pointAndFreq = trim(substr($pointAndOwnFee, 0, $pos));
            } else {
                $isOwn = "0";
                $pointAndFreq = $pointAndOwnFee;
            }
            
            // get POINT, FREQ from "210 x 7"
            $array = explode("x", $pointAndFreq);
            if (count($array) > 1){
                $pont = trim($array[0]);
                $freq = trim($array[1]);
            } else {
                $pont = trim($array[0]);
                $freq = "1";
            }
            
            $array = array();
            if ($code == 99){
                $array['isOwn'] = "";
                $array['code'] = $code;
                $array['alias'] = "";
                $array['name'] = $rec;
                $array['dose'] = "";
                $array['unitName'] = "";
                $array['freq'] = "";
                $array['point'] = "";
                $array['isMix'] = "";
            } else {
                $array['isOwn'] = $isOwn;
                $array['code'] = $code;
                $array['alias'] = "";
                $array['name'] = $name;
                $array['dose'] = $dose;
                $array['unitName'] = $unitName;
                $array['freq'] = $freq;
                $array['point'] = $pont;
                $array['isMix'] = $isMix;
            }
            $results[] = $array;
        }
        
        return $results;
    }

    function putTimeStamp(){
        // データ更新のタイムスタンプを記憶
        $timestamp = timestamp();
        $sql = "SELECT `rowid` FROM `FrontTable` WHERE `patientId`='STAMP'";
        $result=mysql_query($sql);
        if (mysql_num_rows ($result) > 0){	// STAMP が存在した
            $row=mysql_fetch_array($result);
            $sql = "UPDATE `FrontTable` SET 
			`updateTime`='$timestamp'
			WHERE `patientId`='STAMP'";
        } else {							// STAMP が存在しなかった
            $sql = "INSERT INTO `FrontTable` (`patientId`, `updateTime` )
			VALUES ('STAMP', '$timestamp')";
        }
        mysql_query($sql);
    }
    
    function save($patientId, $currentDate, $records){
        // records をサーバへ書き戻す
        if ($records){
            $records = encodeRecords($records); // ここを削除すると "_|_" 形式のまま保存
            $st = (count($records) > 0) ? join("\n", $records) : " ";
        } else {
            $st = "";
        }
        
        // カルテへの書き込み
        $timestamp = timestamp();
        $sql = "UPDATE `ProgressSection`
		SET `treatment`='$st', `updateTime`='$timestamp' WHERE `patientId`='$patientId' AND `entryDate`='$currentDate'";
        mysql_query($sql);
        putTimeStamp();
    }
	
    function getGroupCode($patientId, $max){
        // 当日の保険種別を調べて返す
        $sql = "SELECT * FROM `HealthInsurance` WHERE `patientId`='$patientId' AND `entryDate`<='$max' ORDER BY `entryDate` DESC";
        $result=mysql_query($sql);
        while ($row = mysql_fetch_array($result)){
            //echo "--- ".$row['shubetsu'].":".$row['kubun']."\n"; //###
            
            if (strcmp($row['shubetsu'], "ko") == 0)
                return 2;
            else if (strcmp($row['shubetsu'], "国保") == 0)
                return 2;
            else if (strcmp($row['shubetsu'], "国保退職") == 0)
                return 2;
            else if (strcmp($row['shubetsu'], "後期高齢") == 0)
                return 2;
            else if (strcmp($row['kubun'], "S") == 0)
                return 0;
            else if (strcmp($row['kubun'], "本人") == 0)
                return 0;
            else if (strcmp($row['kubun'], "F") == 0)
                return 1;
            else if (strcmp($row['kubun'], "家族") == 0)
                return 1;
        }
        return 0;
    }
	
    function updateFront($patientId, $dateTime, $owner, $isNew, $isIn,
                         $point, $insFee, $ownFee){
        // 会計レコードを更新
        // 新患(初診料の有無)・健保料金・自費料金・診療終了時刻・updateTime・計画 を記録
        
        // 当日の保険種別を調べる
        $groupCode = getGroupCode($patientId, $dateTime);
        
        // ### 同日再診への対応：FRONT と NOA の登録時刻差は３０分以内とする ###
        // NOA 時刻の３０分前を検索範囲とする：FRONT で登録後３０分後に NOA でページ追加したとして
        $date = new DateTime($dateTime); // "2013-02-12 17:51:04" を dateTime()に
        $date->sub(new DateInterval('PT60M')); // 60分前の日時：60分以下では拾えないことあり
        $fromDate = $date->format("Y-m-d H:i:s");
        // NOA 時刻の３０分後を検索範囲とする：NOA でページ追加後３０分に FRONT で登録したとして
        $date = new DateTime($dateTime); // "2013-02-12 17:51:04" を dateTime()に
        $date->add(new DateInterval('PT60M')); // 60分後の日時：60分以下では拾えないことあり
        $toDate = $date->format("Y-m-d H:i:s");
        $timestamp = timestamp();

        // $dateTime から前後１時間以内のレコードを探して更新
        $sql = "SELECT `rowid` FROM `FrontTable` WHERE `patientId`='$patientId' AND `entryDate`<='$toDate' AND `entryDate`>='$fromDate'";
        $result=mysql_query($sql);
        echo "\n=== updateFront\n$sql\n";//##
        
        if (mysql_num_rows ($result) > 0){
            $sql = "UPDATE `FrontTable` SET
            `groupCode`='$groupCode',
            `inOut`='$isIn',
            `newPatient`='$isNew',
            `point`='$point',
            `insFee`='$insFee',
            `ownFee`='$ownFee',
            `owner`='$owner',
            `endTime`='$timestamp',
            `updateTime`='$timestamp'
            WHERE `patientId`='$patientId' AND `entryDate`<='$toDate' AND `entryDate`>='$fromDate' ";
            echo "---\n$sql\n";//##
            mysql_query($sql);
        }
    }
	
    function load($patientId, $currentDate){
        // カルテの treatment フィールドのデータを読み出す
        // # freq が 1 のレコードは削除されたレコード
        $query = "SELECT `treatment` FROM `ProgressSection` WHERE `patientId`='$patientId' AND `entryDate`<='$currentDate' AND (`freq` IS NULL OR `freq`<1) ORDER BY `entryDate` DESC"; 
        echo "===load: $query \n"; //##
        $result=mysql_query($query);
        
        while ($row=mysql_fetch_array($result)){
            $buff = $row['treatment'];
            if (strlen($buff) > 0){
                // 直近の ProgressSection.treatment データを読み出して返す
                // コード末尾が９の自動加算項目は省略される
                echo "\nload($buff)===========\n";//####
                return decodeRecords($buff);
            }
        }
        return array();
    }
	
    function countCheck($patientId, $currentDate, $codeName){
        // $codeName:"特定疾患療養指導料" の存在する回数を返す
        $monthBegin = substr($currentDate, 0, 8)."01 00:00:00";
        $query = "SELECT `treatment` FROM `ProgressSection` "
        ."WHERE `patientId`='$patientId' "
        ."AND `entryDate`>'$monthBegin' AND `entryDate`<'$currentDate' "
        ."ORDER BY `entryDate` DESC"; 
        $result=mysql_query($query);
        echo "\n countCheck($query)===========\n";//####
        $count = 0;
        while ($row=mysql_fetch_array($result)){
            // treatment 中に $codeName が存在すればカウントをインクリメント
            if (strpos($row['treatment'], $codeName) > 0)
                $count++;
        }
        echo "\n countCheck($count)===========\n";//####
        return $count;
    }
	
    function isTokuteiShikkan($treatments){
        // 特定疾患指導料を算定できる傷病名であれば TRUE を返す
        // ## 決め打ち ## 
        $diseases = array("高血圧","胃炎","糖尿病","不整脈","喘息");
        for ($i=0,$ct=count($diseases); $i < $ct; $i++){
            if (strpos($treatments, $diseases[$i]) > 0){
                echo "\n isTokuteiShikkan(".$diseases[$i].")===========\n";//####
                return TRUE;
            }
        }	
        return FALSE;
    }
    
    function hasGeneric($patientId, $currentDate){
        // 処方箋に一般名（一般名は薬剤行に'[般]'）が存在すれば TRUE を返す
        // カルテの prescription フィールドに一般名の薬剤があれば TRUE を返す
        // # freq が 1 のレコードは削除されたレコード
        echo "== hasGeneric $patientId $currentDate  \n"; //##

        $query = "SELECT * FROM `ProgressSection` WHERE `patientId`='$patientId' AND `entryDate`<='$currentDate' AND (`freq` IS NULL OR `freq`<1) ORDER BY `entryDate` DESC"; 
        $result=mysql_query($query);
        
        while ($row=mysql_fetch_array($result)){
            $buff = $row['prescription'];
            
            if (strlen($buff) > 0){
                // 直近の prescription データを読み出し [般] の有無をチェック
                // $buff が空の場合は（画面では透けて見える）以前のデータを使う
                $ary = explode("[般]", $buff); // ### prescription.js との約束ごと ###
                if (count($ary) > 1) return TRUE;
                return FALSE;
            }
        }
        return FALSE;
    }
    
    function tokuteiByoumeiList($patientId, $currentDate){
        // 特定疾患名が存在すれば、$currentDate における傷病名配列を返す
        $diseases = array();
        $monthEnd = substr($currentDate, 0, 10)." 23:59:59";
        $sql = "SELECT * FROM `ProgressSection`
        WHERE `patientId`='$patientId' 
        AND `entryDate`<'$monthEnd'
        ORDER BY `entryDate` DESC"; 
        $result = mysql_query($sql);
        while ($row = mysql_fetch_array($result)){
            if (! $row['disease'] || (strlen($row['disease']) == 0)) continue;
            $array = explode("\n", $row['disease']);
            for ($i=0,$ct=count($array); $i < $ct; $i++){
                $st = $array[$i];
                if (isTokuteiShikkan($st)) // 傷病名に特定疾患名が含まれる
                    $diseases[] = $st;
            }
            return $diseases;
        }
        return $diseases;
    }
    function monthsBetween($date1, $date2){
        // $date1 から $date2 までの経過月数を返す
        // $date1:"081201" 形式
        $yy1 = substr($date1, 0, 2);
        $mm1 = substr($date1, 2, 2);
        $dd1 = substr($date1, 4, 2);
        // $date2:"2009-01-12 11:19:37" 形式
        $yy2 = substr($date2, 2, 2);
        $mm2 = substr($date2, 5, 2);
        $dd2 = substr($date2, 8, 2);
        
        $diffMonth = (($yy2 - $yy1) * 12) + $mm2 - $mm1;
        if ($dd1 > $dd2) // 前月の日付より小さい日付
            $diffMonth -= 1;
        
        return $diffMonth;
    }
    function hasShohou($records){
        // 処方の有無を返す
        for ($i=0,$ct=count($records); $i < $ct; $i++){
            $array = explode("_|_", $records[$i]);
            $cd = $array[1];
            $name = $array[3];
            if (($cd * 1 == 80) && (strpos($name, "処方") > 0)){
                return TRUE;
            }
        }
        return FALSE;
    }
    function tokuteiShikanCheck($hasIns, $records, $pid, $cdate, $owner){
        // 特定疾患指導料・特定疾患処方管理加算 を加算
        $results = array();
        if ($hasIns == 0)
            return $results; // 健保項目がなかったので抜ける
        
        // $cdate の傷病名に含まれる特定疾患名リストを取得
        $diseases = tokuteiByoumeiList($pid, $cdate);
        if (count($diseases) > 0){
            // ## 決め打ち ## 特定疾患療養指導料は月２回まで算定できる
            if (countCheck($pid, $cdate, "特定疾患療養指導料") < 2){
                for ($i=0,$ct=count($diseases); $i < $ct; $i++){
                    $st = $diseases[$i]; // $st:"080811 高血圧"
                    $ary = explode(" ", $st);
                    if (count($ary) > 1){
                        // 日付が限定された月数を越えているかどうかチェック
                        $date = $ary[0];
                        if (monthsBetween($date, $cdate) >= 1){
                            // ## 決め打ち ## 初診日から１ヶ月経過していれば算定できる
                            $alias = "tokuteishikkanryouyoushidouryou";
                            $results[] = getRecord(0, "13", $alias, $owner);
                            break;
                        }
                    }
                }
            } 
            if (hasShohou($records)){
                // ## 決め打ち ##
                if (countCheck($pid, $cdate, "特定疾患処方管理加算28日以上") <= 2){
                    //if (countCheck($pid, $cdate, "特定疾患処方管理加算") <= 2){
                    //$alias = "tokutei-shohou-kanri";
                    $alias = "tokutei-shohou-kanri-28";
                    $results[] = getRecord(0, "13", $alias, $owner);
                }
            }
        }
        return $results;
    }
    
    ///// header 関連 /////
    /////////////////////////
    
    /////////////////////////
    ///// childSelector /////
    
    function showItemSelector($selectorNum){
        // 診療行為のリストを返す（薬剤、処置名、など）
        echo "<SEPARATOR>";
        $array = array();
        if ($selectorNum * 1 == 0){ // 一括入力メニュー
            $query = "SELECT * FROM `ProgressSection` WHERE `patientId`='GroupMenu' ORDER BY `freq` DESC";
            $result=mysql_query($query);
            
            while ($row=mysql_fetch_array($result)){
                $subject = $row['subject'];
                $array["$subject"] = $subject;
            }
        } else {
            $query = "SELECT `code`,`alias`,`name` FROM `PriceList` WHERE `code`like'%$selectorNum%' and `code` < 100 ORDER BY `alias";
            $result=mysql_query($query);
            
            while ($row=mysql_fetch_array($result)){
                $name = $row['name'];
                $alias = $row['alias'];
                $array["$name"] = $alias;
            }
        }
        echo json_encode($array);
    }
    
    ///// childSelector /////
    /////////////////////////
    
    /////////////////////////
    ///// データベースから個々のアイテムをピックアップ
    
    function getPoint($code, $alias){
        // code, alias に相当するレコードの点数を返す
        $query = "SELECT `point` FROM `PriceList` 
		WHERE `code`='$code' and `alias`='$alias'";
        $result=mysql_query($query);
        if (mysql_num_rows ($result) > 0){
            $row=mysql_fetch_array($result);
            $point = $row['point'];
        }
        
        return $point;
    }
    
    function ownRate($hid, $owner){
        return getHospitalInfo($hid, "自費係数");
    }
	
    function handanRecord($isOwn, $handan, $ownRate){
        // 判断料のレコードを返す
        if (strcmp($handan, "病") == 0)
            $alias = "byouri-handan";
        else if (strcmp($handan, "尿") == 0)
            $alias = "nyou-handan";
        else if (strcmp($handan, "血") == 0)
            $alias = "ketsueki-handan";
        else if (strcmp($handan, "生1") == 0)
            $alias = "seika1-handan";
        else if (strcmp($handan, "生2") == 0)
            $alias = "seika2-handan";
        else if (strcmp($handan, "免") == 0)
            $alias = "menneki-handan";
        else if (strcmp($handan, "微") == 0)
            $alias = "biseibutsu-handan";
        else if (strcmp($handan, "外") == 0) // 超音波
            $alias = "";
		
        $query = "SELECT `name`, `point` FROM `PriceList` WHERE `code`='**69' and `alias`='$alias'";
        $result=mysql_query($query);
        if (mysql_num_rows ($result) > 0){
            $row=mysql_fetch_array($result);
            $point = ($isOwn * 1 > 0) ?  $row['point'] * $ownRate : $row['point'];
            return encode_item($isOwn, "69", $alias, $row['name'], "", "", "", $point,"");
        }
        return NULL;
    }
    
    function getRecord($isOwn, $code, $alias, $owner){
        // 該当する診療行為（薬剤、処置名、など）を DB から取り出して返す
        $query = "SELECT * FROM `PriceList` WHERE `code`like'%$code%' and `alias`='$alias' ORDER BY `alias`";
        echo "sql: $query \n"; //##
        $result=mysql_query($query);
        
        $results = array();
        if (mysql_num_rows ($result) > 0){
            $row=mysql_fetch_array($result);
            
            // $row['code'] は "21,23" のような複合形式なので $code を使う
            return encode_item($isOwn, $code, $row['alias'], $row['name'], $row['standard'], $row['unitName'], "", $row['point'],"");
//           $results[] = encode_item($isOwn, $code, $row['alias'], $row['name'], $row['standard'], $row['unitName'], "", $row['point'],"");
        }
        return NULL;
//        return $results;
    }
	
    function getTeigenRecord($isOwn, $point, $code, $alias){
        // 該当する診療行為の点数に低減率を掛けたものを作成して返す
        $query = "SELECT * FROM `PriceList` WHERE `code` LIKE '%$code%' AND `alias`='$alias'";
        $result=mysql_query($query);
        if (mysql_num_rows ($result) > 0){
            $row = mysql_fetch_array($result);
            $point = (-1 * $point / 100) * $row['point'];
            
            // isMix を使う可能性はないと思われるので isMix は ""
            return encode_item($isOwn,$code,$alias,$row['name']
                              ,"","","1",$point,"");
        }
        return NULL;
    }
	
    function echoCountOfThisMonth($patientId, $currentDate){
        // 今月実施した超音波検査の回数を返す（本日を含まず）
        $yyyymm = substr($currentDate,0,7);
        $begin = date($yyyymm."-01 00:00:00");
        $yyyymmdd = substr($currentDate,0,10);
        $end = date($yyyymmdd." 00:00:00"); // 本日を含まず
        
        // freq が 0 以外のレコードは編集前のレコードなので無視
        $sql = "SELECT * FROM `ProgressSection` WHERE `patientId`='$patientId' AND (`freq` IS NULL OR `freq`<1) AND `entryDate`>='$begin' AND `entryDate`<='$end'";
        echo "$sql ---\n\n"; //##
        $result = mysql_query($sql);
        
        $count = 0;
        while ($row = mysql_fetch_array($result)){
            $date = $row['entryDate'];
            $update = $row['updateTime'];
            $treatment = $row['treatment'];
            $ary = explode("\n", $treatment);
            for ($i=0,$ct=count($ary); $i < $ct; $i++){
                $st = $ary[$i];
                if (strpos($st, "超音波") !== FALSE){
                    if (strpos($st, "自費") > 0) continue; // 自費は除く
                    echo "$date($update) $treatment ---\n\n"; //##
                    $count++;
                }
            }
        }
        return $count;
    }
	
    function getPointWithCodeAndName($code, $name){
        // 該当する診療行為（薬剤、処置名、など）の点数を DB から取り出して返す
        $sql = "SELECT `point` FROM `PriceList` WHERE `code`like'%$code%' and `name`='$name' ORDER BY `alias`";
        //echo "getPointWithCodeAndName --\n $sql \n"; //##
        $result=mysql_query($sql);
        if (mysql_num_rows ($result) > 0){
            $row=mysql_fetch_array($result);
            
            // $row['code'] は "21,23" のような複合形式なので $code を使う
            return $row['point'];
        }
        return "";
    }
    
    function _insRatio($patientId, $currentDate){
        // 保険の負担割合
        $query = "SELECT `paymentRatio` FROM `HealthInsurance` WHERE `patientId`='$patientId' AND `entryDate`<='$currentDate' ORDER BY `entryDate` DESC";
        $result=mysql_query($query);
        if (mysql_num_rows ($result) > 0){
            while ($row=mysql_fetch_array($result)){
                if ($row['paymentRatio'] <> null) return  $row['paymentRatio'];
            }
        }
        return 10;
    }
    function _publicInsRatio($patientId, $currentDate){
        // 公費の負担割合
        $query = "SELECT `paymentRatio` FROM `PublicInsurance` WHERE `patientId`='$patientId' AND `entryDate`<='$currentDate' ORDER BY `entryDate` DESC";
        $result=mysql_query($query);
        if (mysql_num_rows ($result) > 0){
            while ($row=mysql_fetch_array($result)){
                if ($row['paymentRatio'] <> null) return  $row['paymentRatio'];
            }
        }
        return null;
    }
    function paymentRatio($patientId, $currentDate){
        // 保険の負担割合
        $publicInsRatio = _publicInsRatio($patientId, $currentDate);
        
        // 公費の負担割合が指定されていれば、そちらを優先して使う
        if ($publicInsRatio * 1 > 0 || ($publicInsRatio == "0")){
            return $publicInsRatio;
        } else {
            return _insRatio($patientId, $currentDate);
        }
    }
    
    function discountRatio($patientId){
        // 割引率を返す
        $query = "SELECT `discountRatio` FROM `HealthInsurance`
        WHERE `patientId`='$patientId'
        ORDER BY `entryDate` DESC";
        $result=mysql_query($query);
        if (mysql_num_rows ($result) > 0){
            while ($row=mysql_fetch_array($result)){
                if ($row['discountRatio'] <> null) return  $row['discountRatio'];
            }
        }
        return 0;
    }
    
    ///// データベースから個々のアイテムをピックアップ
    /////////////////////////
    
    /////////////////////////
    ///// 集計機能 ///////////
    
    function hasShosin($records){
        // $records に初診があれば 1 なければ 0 を返す
        $count = count($records);
        for ($i=0; $i < $count; $i++){
            $rec = $records[$i]; // encode_item() 形式
            if ($rec['code'] != "11") continue;
            if (strpos($rec['name'], "初診") >= 0) return 1;
        }
        return 0;
    }
    
    function hasNyuuin($records){
        // $records に入院があれば 1 なければ 0 を返す
        $count = count($records);
        for ($i=0; $i < $count; $i++){
            $rec = $records[$i]; // encode_item() 形式
            if ($rec['code'] != "90") continue;
            if (strpos($rec['name'], "入院") >= 0) return "on";
        }
        return "";
    }
    
    function saishinCheck($hasIns, $records, $args, $owner){
        // 健保の場合のみ機能する
        $currentDate = $args['entryDate'];
        $hospId = $args['hospitalId'];
        $timeZone = $args['timeZone'];
        $isInTime = $args['isInTime']; // カルテ時刻が時間内なら 1 外なら 0
        $isHoliday = $args['isHoliday']; // カルテ時刻が祝日なら 1
        $isOwn = ($hasIns == 0) ? "1" : "0";
        
        // 初診または入院がなければ再診を自動付加
        // 初診も処置もなければ外来管理加算を自動付加
        $count = count($records);
        $hasShochi = 0;
        $hasOpe = 0;
        $hasOwnShoshin = 0;
        $hasInsShoshin = 0;
        $hasSaishin = 0;
        $jikanKasan = FALSE;
        
        // 電話再診を後日、再診とともに請求する時にも対応できるよう
        // 再診だけは先に検出しておく
        for ($i=0; $i < $count; $i++){
            $rec = $records[$i];
            if (($rec['code'] * 1 == 12) && (strpos($rec['name'], "再診") == 0))
                $hasSaishin = 1;
        }
        
        for ($i=0; $i < $count; $i++){
            $rec = $records[$i];
            // ### $rec:$newRecord の構造が考えているのと違う？？？ ###
            // $rec は encode_item() 型式のはず
            $_own = $rec['isOwn'] * 1;
            switch ($rec['code'] * 1){
                case 41: $hasShochi = 1; break;
                case 51: $hasOpe = 1; break;
                case 11:
                    if (strpos($rec['name'], "初診") >= 0){
                        if ($_own > 0)
                            $hasOwnShoshin = 1;
                        else
                            $hasInsShoshin = 1;
                        // 診療時間外なら所定加算を追加する
                        if (strcmp($timeZone, "時間外") == 0){
                            $items[] = getRecord($_own, "13", "shoshin-jikangai", $owner);
                            $jikanKasan = TRUE;
                        } else if (strcmp($timeZone, "深夜") == 0){
                            $items[] = getRecord($_own, "13", "shoshin-shinya", $owner);
                            $jikanKasan = TRUE;
                        } else if (strcmp($timeZone, "休日") == 0){
                            $items[] = getRecord($_own, "13", "shoshin-kyuujitsu", $owner);
                            $jikanKasan = TRUE;
                        }
                    }
                    break;
                case 12:
                    // 再診は事前に検出済みなのでここではスキップ
                    // if (strpos($rec['name'], "再診") !== FALSE) $hasSaishin = 1;
                    if (strpos($rec['name'], "電話等再診") == 0){
                        // 再診時に前回の電話再診を徴収する場合を除き
                        if ($hasSaishin != 1) 
                            $hasShochi = 1; // 外来管理加算を抑止
                        $hasSaishin = 1;
                    }
                    break;
                case 60:
                    // 自費の公費検診において再診関連の自動付加を抑止するため
                    // ### 問題は自費の検査が全部これに該当すること ###
                    $hasOwnShoshin = 1;
                    break;
                case 90:
                    return NULL; // 入院があったので抜ける
            }
        }
        
        // 夜間・早朝等加算が届出されていれば加算：初診チェックの前に実行
        $hasYakanSoucho = getHospitalInfo($hospId, "夜間・早朝等加算");
        // $inTime は Vin のタイムゾーン・ポップアップの表示が「診療時間内」か否かで判定
        $inTime = ($isInTime > 0) ? TRUE : FALSE;
        if ($hasYakanSoucho && (strcmp($hasYakanSoucho,"yes") == 0 ) && $inTime){
            // 下記時間帯に受付した場合、初・再診に関わらず加算ができる
            // 平日 18：00～22：00、6：00～8：00
            // 土曜 12：00～22：00、6：00～8：00
            // 日祝  6：00～22：00
            $hm = substr($currentDate, 11, 5); // 時刻を '17:33' 型式で取り出す
            $time = strtotime($currentDate);
            $week = date("w", $time);
            echo "夜間・早朝等加算 timeZone: $timeZone HM: $hm week: $week \n"; //##
            
            if (($week == 0) || ($isHoliday > 0)){ // 日曜・祝日
                if ((strcmp($hm, "06:00") >= 0) && (strcmp($hm, "22:00") <= 0)){
                    $items[] = getRecord($isOwn, "12", "yakan-souchou-kasan", $owner);
                    echo "--- 日曜 早朝・夜間 --- \n"; //##
                }
            } else if ($week == 6){ // 土曜
                if ((strcmp($hm, "06:00") >= 0) && (strcmp($hm, "08:00") <= 0)){
                    $items[] = getRecord($isOwn, "12", "yakan-souchou-kasan", $owner);
                    echo "--- 土曜 早朝 --- \n"; //##
                }
                if ((strcmp($hm, "12:00") >= 0) && (strcmp($hm, "22:00") <= 0)){
                    $items[] = getRecord($isOwn, "12", "yakan-souchou-kasan", $owner);
                    echo "--- 土曜 夜間 --- \n"; //##
                }
            } else { // 平日
                if ((strcmp($hm, "06:00") >= 0) && (strcmp($hm, "08:00") <= 0)){
                    $items[] = getRecord($isOwn, "12", "yakan-souchou-kasan", $owner);
                    echo "--- 平日 早朝 --- \n"; //##
                }
                if ((strcmp($hm, "18:00") >= 0) && (strcmp($hm, "22:00") <= 0)){
                    $items[] = getRecord($isOwn, "12", "yakan-souchou-kasan", $owner);
                    echo "--- 平日 夜間 --- \n"; //##
                }
            }
        }

        // 初診があったら、ここで「抜ける」
        if (!$isOwn && $hasInsShoshin){
            return $items; // 初診があったので以下の処理をせず抜ける
        } else if ($isOwn && $hasOwnShoshin){ // 妊婦検診にも外来管理加算がついてしまう
            return $items; // 初診があったので以下の処理をせず抜ける
        }
        
        // 診療時間外なら所定加算を追加する
        if (strcmp($timeZone, "時間外") == 0)
            $items[] = getRecord($isOwn, "13", "jikangai-kasan", $owner);
        else if (strcmp($timeZone, "深夜") == 0)
            $items[] = getRecord($isOwn, "13", "shinnya-kasan", $owner);
        else if (strcmp($timeZone, "休日") == 0)
            $items[] = getRecord($isOwn, "13", "kyuujitsu-kasan", $owner);
        
        if ($hasIns > 0){
            // 再診がなかったので再診を追加する
            if ($hasSaishin == 0){
                $items[] = getRecord($isOwn, "12", "saishin", $owner);
            }
            
            if (($hasShochi == 0) && ($hasOpe == 0)){
                // 処置も手術も存在しなかったので外来管理加算を追加する
                $items[] = getRecord($isOwn, "13", "gairai-kanri-kasan", $owner);
            }
            
            // 明細書発行加算が届出されていれば加算
            $hasMeisaisho = getHospitalInfo($hospId, "明細書発行体制等加算");
            echo "$hospId 明細書発行体制加算($hasMeisaisho) \n"; //##
            if ($hasMeisaisho && (strcmp($hasMeisaisho,"yes") == 0 ))
                $items[] = getRecord($isOwn, "13", "meisaisho", $owner);
        }
        
        return $items;
    }
    
    function getHandanArray($isOwn, $code, $name, $ownRate){
        // 判断料のレコードの入った配列を返す
        $records = array();
        $query = "SELECT `handan` FROM `PriceList` WHERE `code`='$code' and `name`='$name'";
        $result=mysql_query($query);
        if (mysql_num_rows ($result) > 0){
            $row=mysql_fetch_array($result);
            // $row['handan'] は "生1 生2 免" のように複数値が入っている可能性あり
            $st = $row['handan'];
            $array = explode(" ", $st);
            for ($i=0, $count=count($array); $i < $count; $i++){
                $handan = $array[$i];
                $ary = handanRecord($isOwn, $handan, $ownRate); // encode_item() 形式
                if ($ary) $records[] = $ary; // $ary は NULL のことあり
            }
        }
        return $records;
    }
	
    function chouzai($isOwn, $code, $alias, $ownRate){
        // alias に対応するレコードを返す
        $query = "SELECT `name`, `point` FROM `PriceList`  WHERE `code`='$code' and `alias`='$alias'";
        $result=mysql_query($query);
        if (mysql_num_rows ($result) > 0){
            $row=mysql_fetch_array($result);
            $point = ($isOwn * 1 > 0) ?  $row['point'] * $ownRate : $row['point'];
            return encode_item($isOwn, "29", $alias, $row['name'], "", "", "", $point,"");
        }
        return NULL;
    }
    
    function getChouzaiKasan($isOwn, $code, $name, $ownRate){
        // 調剤料のレコードを返す
        switch ($code){
            case "21":
                return chouzai($isOwn, "**29", "naifuku-chouzairyou", $ownRate);
            case "22":
                return chouzai($isOwn, "**29", "tonpuku-chouzairyou", $ownRate);
            case "23":
                return chouzai($isOwn, "**29", "gaiyou-chouzairyou", $ownRate);
            default:
                return NULL;
        }
    }
    
    function marume($round, $val){
        // 小数点以下を $round 係数により丸める
        $val = floor(($val + $round) / 10);
        return $val * 10;
    }
    function isNotMarume($patientId, $currentDate){
        // マル障・マル親など患者負担が１円単位で請求するものなら true を返す
        return false; //### 2015-05-01 以後この行を削除　#########
        
        $query = "SELECT `ownerName` FROM `PublicInsurance` WHERE `patientId`='$patientId' AND `entryDate`<='$currentDate' ORDER BY `entryDate` DESC";
        //echo "isNotMarume == $query\n"; //###

        $result=mysql_query($query);
        if ($row=mysql_fetch_array($result)){
            $ownerName = $row['ownerName'];
            if(strpos($ownerName, '親') !== false )
                return true;
            else if (strpos($ownerName, '障') !== false )
                return true;
        }
        return false;
    }
    
    function sumFormat($insFee, $paymentRatio, 
                       $insRoundSum, $ownRoundSum, $discount, $tax)
    {
        // 合計行の表示文字列を作成して返す
        $kenpoSt = ($insFee > 0) ? "健保($insFee x $paymentRatio = $insRoundSum)" : "";
        $st = ($tax * 1 > 0) ? "$ownRoundSum 消費税:$tax" : "$ownRoundSum";
        $jihiSt = ($ownRoundSum * 1 != 0) ? "自費($st)" : "";
        $discountSt = ($discount * 1 > 0) ? "- 割引($discount)" : "";
        $total = $insRoundSum * 1 + $ownRoundSum * 1 + $tax - $discount * 1;
        
        return "合計[$kenpoSt $jihiSt $discountSt] $total";
    }
    
    function ownFee($rec, $freq){
        return ($rec['isOwn'] * 1 > 0) ? $rec['point'] * $freq : 0;
    }
    
    function insFee($rec, $freq){
        return ($rec['isOwn'] * 1 > 0) ? 0 : $rec['point'] * $freq;
    }
	
    function pointWithCode($isOwn, $code, $alias, $point, $dose, $hid, $owner, $isMix){
        // code ごとに点数計算の根拠が異なる
        // 薬価の場合：
        //  1) 薬価 * 数量		53.0(円) * 28(Tab) = 1484.0(円)
        //  2) 薬価のまるめ計算	(1484.0 - 15.0) / 10.0 + 1.99 = 148.89 = 148(点)
        //  3) 自費掛率をかける	148(小数点以下切り捨て) * 20(自費掛率) = 2960
        $point = ($dose > 1) ? $point * $dose : $point;
        switch ($code * 1){
            case 21: case 22: case 23: // 内服・頓服・外用
            case 33: case 48: case 58: // 点滴・処置薬・麻酔薬
                $point = ($point > 15.0) ? ($point - 15.0) / 10.0 + 1.99 : 1;
                break;
            case 31: // 筋注
                $point =  ($point + 6) / 10 + getPoint('**39','kinchuu-shugiryou');
                break;
            case 32: // 静注
            case 33: // 点滴 500cc 以下
                $point =  ($point + 6) / 10;
                if ($isMix * 1 == 0)
                    $point += getPoint('**39','jyouchuu-shugiryou');
                break;
        }
        if ($isOwn * 1 > 0){
            // 自費の場合は $point を自費料金に換算
            $ownRate = ownRate($hid, $owner);
            $point = floor($point) * $ownRate;
        }
        return floor($point);
    }
	
    function modifyWith($records, $pos, $ary, $hid, $owner, $isMix){
        // 点数を code,dose,freq を元に処理する
        // ##### ここが診療費計算のキモ #####
        // $records は各行の配列 $pos は配列内の現在位置
        $code = $ary['code'];
        $alias = $ary['alias'];
        $name = $ary['name'];
        $isOwn = $ary['isOwn'];
        $dose = ($ary['dose'] * 1 > 0) ? $ary['dose'] : 1;
        $freq = $ary['freq'];
        $unitName = $ary['unitName'];
        $point = $ary['point'];
        
        echo "modifyWith: $name -- isMix($isMix) point($point) <br>\n"; //##
        
        // $point が "" の場合は以下の pointWIthCode() 処理を行う：混注は処理せず
        // $point が "0" の場合は以下の処理は行わず "0" を尊重する
        if (strlen($point) == 0){
            // $point が "" の場合は getRecord() で priceList の点数で補完
            if (!$isMix || (strlen($isMix) == 0)){ // 混注の子供は無視
                // * 元データがカルテの場合 alias がないので $name で検索
                $point = getPointWithCodeAndName($code, $name); // PriceList から点数を得る
                echo "priceList から得た点数:$code($name)-->$point \n"; //##
                
                // この親の子供があれば、その点数をスキャンして親点数に加算
                $count = count($records);
                for ($i=$pos+1; $i < $count; $i++){
                    $ary = $records[$i];
                    if ($ary['isMix'] * 1 == 0) break; // 混注の子供でなければ処理終了
                    
                    $pt = getPointWithCodeAndName($ary['code'], $ary['name']); // PriceList から点数を得る
                    $point += $pt * $ary['freq'];
                    echo "混注を追加: point:$pt freq:".$ary['freq']." = $point \n"; //##
                }
                echo "混注の子供を加算した点数: $point \n"; //##
                
                // point x dose に code 毎固有の処理を行う
                // 手技料の加算など
                $point = pointWithCode($isOwn,$code,$alias,$point,$dose,$hid,$owner,$isMix);
                echo "手技料などを加算した点数-->$point \n"; //##
            }
        }
        
        return encode_item($isOwn, $code, $alias, $name, $dose, $unitName, $freq, $point, $isMix);
    }
	
    function getHandanOfThisMonnth($patientId, $currentDate){
        // 今月請求した判断料を入れた配列を返す
        // NOA ページ作成時刻 $currentDate 以前直近のデータを探す（同日再診へ対応）
        // ## currentDate より前のレコードについて判断料の存在を検証
        $monthBegin = substr($currentDate, 0, 8)."01 00:00:00";
        // # freq が 1 のレコードは削除されたレコード
        $sql = "SELECT * FROM `ProgressSection`
        WHERE `patientId`='$patientId' 
        AND (`freq` IS NULL OR `freq`<1)
        AND `entryDate`<'$currentDate'
        AND `entryDate`>='$monthBegin' ORDER BY `entryDate` DESC";
        
        echo "getHandanOfThisMonnth == $sql\n"; //###
        
        $result = mysql_query($sql);
        $records = array();
        while ($row = mysql_fetch_array($result)){
            // ProgressSection.treatment データを読み出す
            $rec = $row['treatment'];
            $array = explode("\n", $rec);
            for ($i=0,$count=count($array); $i < $count; $i++){
                $ln = $array[$i]; // "判断[病理学的検査等判断料] 146" 形式
                // multi byte 文字の場合、１文字は 3 char になる
                if (strcmp(mb_substr($ln, 0, 6), "判断") == 0){
                    // $ln = "判断[病理学的検査等判断料] 146"
                    $ary1 = explode("[", $ln);
                    if (count($ary1) > 1){
                        $ary2 = explode("]", $ary1[1]);
                        $records[] = $ary2[0];
                    }
                }
            }
        }
        return $records;
    }
    
    function calc($records, $args){
        // アイテム・リストを集計し結果を表示
        // value = "1_|_21_|_adona30mg_|_アドナ30mg_|_3_|_Tab_|_5_|_12.9 \n
        // 1_|_12_|_saishin_|_再診料_|_1_|__|_1_|_71"
        // args = "ohashi_|_03234202_|_2008-05-18 10:53:32_|_793_|_時間内"
        $owner = $args['owner'];
        $hid = $args['hospitalId'];
        $patientId = $args['patientId'];
        $currentDate = $args['entryDate'];
        $taxRate = $args['taxRate'];
        $ownRate = ownRate($hid, $owner);
        
        if (count($records) == 0){ // 過去の履歴が透けて見えるようになる
            echo "<SEPARATOR>";
            return;
        } else
            $newrecords = array();
        
        // FRONT の画面表示を更新する
        putTimeStamp(); // ### save() が生きていればその中で行われる ###
        
        // 今月請求した判断料の配列 ("病理学的検査等判断料","微生物学的検査判断料",,)
        $handans = getHandanOfThisMonnth($patientId, $currentDate);
        $paymentRatio = paymentRatio($patientId, $currentDate);
        $discountRatio = discountRatio($patientId);
        
        $insSum = 0; $ownSum = 0; $hasIns = 0; $hasOwn=0; $echoFullName="";
        for ($mode=0; $mode < 2; $mode++){
            // $mode: 0 なら保険、1 なら自費を計算
            // 保険・自費の小計表示のため、それぞれのモードでスキャン
            $count = count($records);
            $hasItem = FALSE; // $count 内の処理された項目数
            for ($i=0; $i < $count; $i++){
                $ary = $records[$i];
                $code = $ary['code'];
                $name = $ary['name'];
                $isOwn = $ary['isOwn'];
                $isMix = $ary['isMix'];
                $dose = ($ary['dose'] * 1 > 0) ? $ary['dose'] : 1;
                $freq = $ary['freq'];
                $point = $ary['point']; // 保険のみ計算
                
                if (($mode == 0) && $isOwn){
                    $hasOwn = 1; // セパレータ可否の判定に必要
                    continue; // 保険モードなら自費をスキップ
                }
                if (($mode == 1) && ($isOwn < 1)) continue; // 自費モードなら保険をスキップ

                // 既存の自動付加項目は、次行の健保チェック前にスキップし後で自動付加
                if ($code % 10 == 9) continue;
                if ($code * 1 == 13) continue;
                
                // 再診をスキップする前にチェック
                // でないと健保再診のみの場合、健保有無が未チェックになってしまう
                if ($isOwn < 1) $hasIns = 1;
                
                // 再診は後で自動追加（これにより常に再診は１回のみとなる）するためスキップ
                if (!$isOwn && ($code == "12") && ($name == "再診料")) continue;
                
                if ($mode == 0){ // 保険の場合のみの処理
                    // 投薬に伴う付加項目を $records[] へ付加
                    if (substr($code, 0, 1) == "2"){
                        $rec = getChouzaiKasan($isOwn, $code, $name, $ownRate);
                        // 重複した調剤料を防止
                        if ($rec && (! in_array($rec, $newrecords))){
                            $newrecords[] = $rec;
                            $ownSum += ownFee($rec, 1);
                            $insSum += insFee($rec, 1);
                        }
                        $rec = chouzai($isOwn, "**29", "shohouryou", $ownRate);
                        // 重複した調剤料を防止
                        if ($rec && (! in_array($rec, $newrecords))){
                            $newrecords[] = $rec;
                            $ownSum += ownFee($rec, 1);
                            $insSum += insFee($rec, 1);
                        }
                    }
                    
                    // 判断料を $records[] へ付加
                    if ($code * 1 == 60){
                        // 判断料には "生1 生2 免" のように複数が入っている可能性あり
                        // $hArray は encode_item() 形式の入った配列：空配列のこともあり
                        $hArray = getHandanArray($isOwn, $code, $name, $ownRate);
                        for ($n=0, $ct=count($hArray); $n < $ct; $n++){
                            $_rec = $hArray[$n]; // encode_item() 形式
                            // 当日の重複した判断料を防止
                            if (in_array($_rec, $newrecords)) continue;
                            
                            // 今月の重複した判断料を防止 (既に $handans に存在すれば無視)
                            $_name = $_rec['name'];
                            if (! in_array($_name, $handans)){
                                $newrecords[] = $_rec;
                                $ownSum += ownFee($_rec, 1);
                                $insSum += insFee($_rec, 1);
                            }
                        }
                        if (strpos($name, "超音波") !== FALSE)
                            $echoFullName = $name; // 超音波検査があった
                    }
                    
                    
                    if ($code * 1 == 80){
                        if (($isOwn < 1) && hasGeneric($patientId, $currentDate)){
                            
                            // 処方箋に一般名処方がある時のみ「一般名処方加算」を実行
                            $rec = chouzai($isOwn, "80", "yakuzai-ippannmei-shohousen", $ownRate);
                            if ($rec && (! in_array($rec, $newrecords))){
                                $newrecords[] = $rec;
                                $ownSum += ownFee($rec, 1);
                                $insSum += insFee($rec, 1);
                            }
                        }
                    }
                }
                
                // 点数を code,dose,freq を元に処理する
                // ##### ここが診療費計算のキモ #####
                // $records[] の値を $newrecords[] にコピー
                $rec = modifyWith($records, $i, $ary, $hid, $owner, $isMix);
                $newrecords[] = $rec;
                if ($isOwn * 1 > 0)
                    $ownSum += ownFee($rec, $freq);
                else
                    $insSum += insFee($rec, $freq);
                $hasItem = TRUE; // 処理された項目があった
            }
            
            // 上記ループで処理された（無視されない）保険の項目があれば
            if (($mode == 0) && ($hasItem && $hasIns)){
                // 初診または入院がなければ再診を自動付加
                // 初診も処置もなければ外来管理加算を自動付加
                $items = saishinCheck($hasIns,$newrecords,$args,$owner);
                if ($items && (count($items) > 0)){
                    for ($i=0; $i < count($items); $i++){
                        $rec = $items[$i];
                        $newrecords[] = $rec;
                        $ownSum += ownFee($rec, 1);
                        $insSum += insFee($rec, 1);
                    }
                }
                
                // 超音波検査があった場合の処理
                if (($isOwn * 1 < 1) && (strlen($echoFullName) > 0)){
                    // 今月の超音波使用回数を検出しておく
                    $echoCount = echoCountOfThisMonth($patientId, $currentDate);
                    if ($echoCount == 0){
                        // 超音波が過去に使用されていないので何もせず
                    } else if ($echoCount >= 1){
                        // 超音波が今月１回しか使われていなければ２回目の逓減点数を追加
                        $pt = getPointWithCodeAndName("60",$echoFullName);
                        $rec = getTeigenRecord($isOwn,$pt,"69","kensa-teigen");
                        if ($rec){
                            $newrecords[] = $rec;
                            $ownSum += ownFee($rec, 1);
                            $insSum += insFee($rec, 1);
                        }
                    }
                }
            }
            
            // 小計を付加
            if ($mode == 0){ // 保険の場合
                if (isNotMarume($patientId, $currentDate)){ // マル障・マル親
                    // 小数点以下切り捨て
                    $insRoundSum = floor($insSum * $paymentRatio);
                } else {
                    // ## まるめ係数は ORCA では 0（小数点以下切り捨て） に設定
                    $round = getHospitalInfo($hid, "まるめ係数");
                    $insRoundSum = marume($round, $insSum * $paymentRatio);
                }
                // 保険・自費両方があるなら、保険の小計表示
                if ($hasIns && $hasOwn){ // 保険と自費の両方がある場合のみ小計を表示
                    $kenpoSt = "健保($insSum x $paymentRatio = $insRoundSum)";
                    $total = $insRoundSum * 1 + $discount * 1;
                    $name = "　小計[$kenpoSt] $total";
                    // 保険の小計表示
                    $newrecords[] = encode_item("", "99", "", $name, "", "", "", "", "");
                    // 保険の小計のあとにセパレータとして空白行を追加
                    $newrecords[] = encode_item("", "00", "", "", "", "", "", "", "");
                }
            } else { // 自費の場合
                // 自費最終料金 = 自費 - ((保険窓口 + 自費）* 割引 / 100)
                // すなわち割引がある場合、自費料金は保険窓口も含めたものから計算されるので
                $discount = ($insSum * $paymentRatio + $ownSum) * $discountRatio / 100;
                $discount = marume($round, $discount) * 1;
                $ownRoundSum = marume($round, $ownSum) * 1;
                if ($taxRate && ($taxRate * 1 > 0))
                    $tax = marume($round, $ownRoundSum * $taxRate);
                // 保険・自費両方があるなら、自費の小計表示
                if ($hasIns && $hasOwn){ // 保険と自費の両方がある場合のみ小計を表示
                    $st = ($tax * 1 > 0) ? "$ownRoundSum 消費税:$tax" : "$ownRoundSum";
                    $jihiSt = ($ownRoundSum != 0) ? "自費($st)" : "自費";
                    $discountSt = ($discount > 0) ? "- 割引($discount)" : "";
                    $total = $ownRoundSum + $tax - $discount;
                    $name = "　小計[$jihiSt $discountSt] $total";
                    // 自費の小計表示
                    $newrecords[] = encode_item("", "99", "", $name, "", "", "", "", "");
                }
            }
        }
 
        // 診療費 EDITOR への集計表示
        $tax = 0; // 消費税
        if ($taxRate && ($taxRate * 1 > 0))
            $tax = marume($round, $ownRoundSum * $taxRate);
        $name = sumFormat($insSum, $paymentRatio, 
                          $insRoundSum, $ownRoundSum, $discount, $tax);
        $newrecords[] = encode_item("", "99", "", $name, "", "", "", "", "");
        
        // FrontTable の窓口会計レコードを更新
        $isNew = hasShosin($newrecords);
        $isIn = hasNyuuin($newrecords);
        
        echo "初診:$isNew \n"; //##
        echo "入院:$isIn \n"; //##
        
        echo "<SEPARATOR>";
        //　$newrecords のソートはクライアント側で行う
        echo json_encode($newrecords);
        echo "<SEPARATOR>";
        
        // 会計に現れる自費料金 = (自費 - 割引額) なので
        // 保険診療だけの場合に割引があると、保険窓口は変わらないがマイナスの自費が発生する
        updateFront($patientId,$currentDate,$owner,$isNew,$isIn,
                    $insSum, $insRoundSum, $ownRoundSum + $tax - $discount);
    }
    
    ///// 集計機能 ///////////
    /////////////////////////
    
    ///////////////////////////////
    ///// テンプレート登録 ///////////
    
    function putTemplate($menuItem, $treatment, $owner){
        // テンプレートを登録または更新する
        $patientId = "GroupMenu"; // テンプレートの場合の決め打ち
        $timestamp = timestamp();
        // # freq が 1 のレコードは削除されたレコード
        $sql = "SELECT * FROM `ProgressSection` WHERE `patientId`='$patientId' AND (`freq` IS NULL OR `freq`<1) AND `subject`='$menuItem'";
        $result=mysql_query($sql);
        if (mysql_num_rows ($result) > 0){	// 同じ menuItem が存在した
            $row=mysql_fetch_array($result);
            $rowid = $row['rowid'];
            $sql = "UPDATE `ProgressSection` SET `treatment`='$treatment', `owner`='$owner', `updateTime`='$timestamp'  WHERE `rowid`=$rowid";
        } else {							// 同じ menuItem が存在しなかった
            $sql = "INSERT INTO `ProgressSection` ( `patientId`, `subject`, `treatment`, `entryDate`, `updateTime`, `freq`, `owner` ) VALUES ( '$patientId','$menuItem','$treatment','$timestamp','$timestamp','0','$owner')";
        }
        echo "putTemplate: $sql ----------\n"; //####
        mysql_query($sql);
    }
    
    function removeTemplate($menuItem, $owner){
        // テンプレートを削除
        $sql = "DELETE FROM `ProgressSection` WHERE `patientId`='GroupMenu' AND `owner`='$owner' AND `subject`='$menuItem'";
        mysql_query($sql);
        echo "removeTemplate: $sql ----------\n"; //####
    }
    
    ///// テンプレート登録 ///////////
    ///////////////////////////////
    
    function getPriceList($code, $alias){
        // PriceList のレコードを検索して返す
        $sql = "SELECT * FROM `PriceList` WHERE `code`='$code' AND `alias`='$alias'";
        echo "$sql ------\n";
        $result=mysql_query($sql);
        
        $array = array();
        if ($row = mysql_fetch_array($result)){
            $array['code'] = $row['code'];
            $array['alias'] = $row['alias'];
            $array['classCode'] = $row['classCode'];
            $array['requestCode'] = $row['requestCode'];
            $array['name'] = $row['name'];
            $array['point'] = $row['point'];
            $array['unitCode'] = $row['unitCode'];
            $array['unitName'] = $row['unitName'];
            $array['handanCode'] = $row['handanCode'];
            $array['effectCode'] = $row['effectCode'];
            $array['enforceDate'] = $row['enforceDate'];
        }
        return $array;
    }
	
	
    $command=$_GET['command']; $command=htmlspecialchars($command);
    $args=$_GET['args']; $args=htmlspecialchars($args);
    $isOwn=$_GET['isOwn']; $isOwn=htmlspecialchars($isOwn);
    $code=$_GET['code']; $code=htmlspecialchars($code);
    $alias=$_GET['alias']; $alias=htmlspecialchars($alias);
    $alias = decodeSTRING($alias);
    $alias = stripslashes($alias);
    $value=$_GET['value']; $value=htmlspecialchars($value);
    $value = stripslashes($value);
    $value = urldecode($value);
    $value = decodeSTRING($value); // lib.php
    
    // DB を開いて該当レコードを読み込む
    // ### セキュリティーを保つには、以下のファイルを外からアクセスできない 
    // ### directory に置き、以下の cfg.php の pass をそこへ変更
    require_once('cfg.php');
    
    $dbc = mysql_connect($db['host'], $db['user'], $db['pwd']);
    $db_select=mysql_select_db($db['dbname']);
    mysql_query("set names utf8");
    
    
    if (strcmp($command,"GET_VIN_HEADER") == 0){
        // VIN panel が開き初期化する時のデータを返す
        $args = decodeObject($value);
        $owner = $args['owner'];
        $hid = $args['hospitalId'];
        $patientId = $args['patientId'];
        $entryDate = $args['entryDate'];
        $results = array();
        echo "GET_VIN_HEADER: value($value)\n"; //##
        
        // 診療行為マトリックス内容を返す
        // 診療行為種別のリストを JSON 形式で返す（再診、内服、など）
        $sql = "SELECT * FROM `PriceList` WHERE `alias`like'/%' ORDER BY `alias";
        $result=mysql_query($sql);
        echo "GET_VIN_HEADER: $sql\n"; //##
        
        $array = array();
        while ($row=mysql_fetch_array($result)){
            $name = substr($row['name'], 2);
            $code = substr($row['name'], 0, 2);
            $ch = substr($row['name'], 0, 1);
            if (($ch < '0') || ('9' < $ch)) continue; // code は数値
            $array["$name"] = $code;
        }
        $results['itemMatrix'] = $array;
        
        // 診療時間帯ポップアップ内容を返す
        // 診療時間 = ",,0000,0600,深夜\n,,0900,1200,時間内" 形式
        $results['timeZone'] = getHospitalInfo($hid, "診療時間");
       
        // 施設固有値を HospitalTable などから読み出す：まるめ係数・自費係数
        $results['hospitalInfo'] = hospitalInfo($hid, $owner);
        
        // カルテの treatment フィールドのデータを ProgressSection.treatment から読み出す
        $results['itemList'] = load($patientId, $entryDate);

        // vin 初期化データを読み込む
        $sql = "SELECT * FROM `MenuTable` WHERE `tag`='VIN_PREFERENCE'";
        $result=mysql_query($sql);
        echo "$sql ========\n"; //##
        $recs = array();
        while ($row=mysql_fetch_array($result)){
            $ary = array();
            $ary['owner'] = $row['owner'];
            $ary['tag'] = $row['tag'];
            $ary['value'] = $row['value'];
            //$ary['public'] = $row['public'];
            //$ary['freq'] = $row['freq'];
            $ary['menu'] = $row['menu'];
            //$ary['template'] = $row['template'];
            $recs[] = $ary;
        }
        $results['preferences'] = $recs;

        echo "<SEPARATOR>";
        echo json_encode($results);
    } else if (strcmp($command,"PUT_VIN_FILTER") == 0){
        // VIN 用フィルターを保存
        $args = decodeObject($value);
        $tag = "VIN_FILTER";
        $menu = $args['key'];
        $value = $args['value'];
        $updateTime = timestamp();
        
        if (strlen($value) == 0){
            // $value が "" (クライアント側では "" でなく null) ならレコードを削除
            $sql = "DELETE FROM `MenuTable` WHERE `tag`='$tag' AND  `menu`='$menu'";
        } else {
            $sql = "SELECT * FROM `MenuTable` WHERE `tag`='$tag' AND `menu`='$menu'";
            $result=mysql_query($sql);
            if (mysql_num_rows ($result) > 0){ // 同じ tag menu のデータが存在した
                $row=mysql_fetch_array($result);
                $sql="UPDATE `MenuTable` SET `value`='$value',`updateTime`='$updateTime' WHERE `rowid`=".$row['rowid'];
            } else { // 同じ tag menu のデータが存在しなかった
                $sql = "INSERT INTO `MenuTable` (`tag`,`menu`,`value`,`updateTime`) VALUES ('$tag','$menu','$value','$updateTime')";
            }
        }
        echo "$sql \n"; // message
        mysql_query($sql);
        
        $result = getVinFilter($tag, $menu);
        echo "<SEPARATOR>";
        echo $result;
    } else if (strcmp($command,"GET_VIN_FILTER") == 0){
        // VIN 用フィルターを取り出す
        $sql = "SELECT * FROM `MenuTable` WHERE `tag`='VIN_FILTER'";
        $result = mysql_query($sql);
        echo "$sql \n"; // message
        
        $results = array();
        while ($row = mysql_fetch_array($result)){
            $key = $row['menu'];
            $results[$key] = $row['value'];
        }
        
        echo "<SEPARATOR>";
        echo json_encode($results);
    } else if (strcmp($command,"GET_CHILD_SELECTOR") == 0){
        // コードに一致する診療行為レコードの配列を返す
        $args = decodeObject($value);
        $code = $args['code'];

        showItemSelector($code);
    } else if (strcmp($command,"GET_ITEM") == 0){
        // 該当する診療行為（薬剤、処置名、など）を DB から取り出して返す
        $args = decodeObject($value);
        $isOwn = $args['isOwn'];
        $code = $args['code'];
        $alias = $args['alias'];
        $owner = $args['owner'];
        
        // isOwn, code, alias, args
        if ($code * 1 == 0){
            // 一括メニュー
            // ProgressSection から patientId='GroupMenu' AND subject='$alias' を抽出
            // $alias の末尾に改行が入っている場合は改行の前迄を subject として扱う
            $sql = "SELECT * FROM `ProgressSection` WHERE `patientId`='GroupMenu' AND `subject`='$alias'";
            $result=mysql_query($sql);
            $row = mysql_fetch_array($result);
            
            // codeName[name(dose unitName)] point isOwnFee 形式を
            // isOwnFee_|_code_|_alias_|_産科健診料_|_dose_|_unitName_|_freq_|_point_|_isMix 形式へ変換
            if ($row){
                $results = decodeRecords($row['treatment']);
                echo "<SEPARATOR>";
                echo json_encode($results);
            } else {
                echo "<SEPARATOR>";
            }
        }
        else {
            // 該当する診療行為（薬剤、処置名、など）を DB から取り出して返す
            $results[] = getRecord($isOwn, $code, $alias, $owner);
            echo "<SEPARATOR>";
            echo json_encode($results);
        }
    } else if (strcmp($command,"CALC") == 0){
        // 診療行為を計算して返す
        $args = decodeObject($value);
        $records = $args['records'];
        $args = $args['arguments'];

        calc($records, $args);
    } else if (strcmp($command,"PUT_TREATMENT_GROUP") == 0){
        // 診療行為をテンプレートとして登録
        $args = decodeObject($value);
        $owner = $args['owner'];
        $menuItem = $args['title'];
        $treatment = $args['records'];
        echo "owner:$owner title:$title treatment:$treatment \n"; //##
        putTemplate($menuItem, $treatment, $owner);
        echo "<SEPARATOR>PUT_TREATMENT_GROUP done";
    } else if (strcmp($command,"REMOVE_TREATMENT_GROUP") == 0){
        // 診療行為のテンプレートを削除
        $args = decodeObject($value);
        $owner = $args['owner'];
        $menuItem = $args['title'];
        echo "owner:$owner title:$title \n"; //##
        removeTemplate($menuItem, $owner);
        echo "<SEPARATOR>REMOVE_TREATMENT_GROUP done";
    } else if (strcmp($command,"GET_GLOBAL_LIST") == 0){
        // グローバル・レコードを返す
        $args = decodeObject($value);
        // client 側との約束ごと
        $code = $args['code'];
        $name = $args['name'];
        
        $sql = "SELECT * FROM `PriceListGlobal` 
        WHERE `name` LIKE '%$name%' AND `code` LIKE '$code%'
        ORDER BY `name`";
        echo "$sql ------\n";
        $result=mysql_query($sql);
        
        echo "<SEPARATOR>[";
        while ($row=mysql_fetch_array($result)){
            $array = array();
            $array['code'] = $row['code'];
            $array['classCode'] = $row['classCode'];
            $array['requestCode'] = $row['requestCode'];
            $array['name'] = $row['name'];
            $array['point'] = $row['point'];
            $array['unitCode'] = $row['unitCode'];
            $array['unitName'] = $row['unitName'];
            $array['handanCode'] = $row['handanCode'];
            $array['effectCode'] = $row['effectCode'];
            $array['enforceDate'] = $row['enforceDate'];
            // 全体を json_encode() 使用とすると巨大データでコケるので
            // レコードを一行ずつ encode する
            echo json_encode($array).",";
        }
        echo "{}]";
    } else if (strcmp($command,"GET_GLOBAL_PRICE") == 0){
        // グローバル辞書から検索結果を取り出して返す
        $args = decodeObject($value);
        $code = $args['code'];
        $name = $args['name'];
        if (strcmp($code, "*") == 0){
            // ワイルドカード：全レコードを表示
            $sql = "SELECT * FROM `PriceListGlobal` ORDER BY `code`,`name`";
        } else {
            $_code = (strlen($code)) ? "`code` LIKE '$code%' AND " : "";
            
            $sql = "SELECT * FROM `PriceListGlobal` WHERE $_code `name` LIKE '%$name%' ORDER BY `code`,`name`";
        }
        
        echo "$sql ------\n";
        $result=mysql_query($sql);
        
        echo "<SEPARATOR>";
        $results = array();
        while ($row=mysql_fetch_array($result)){
            $array = array();
            $array['code'] = $row['code'];
            $array['classCode'] = $row['classCode'];
            $array['requestCode'] = $row['requestCode'];
            $array['name'] = $row['name'];
            $array['point'] = $row['point'];
            $array['unitCode'] = $row['unitCode'];
            $array['unitName'] = $row['unitName'];
            $array['handanCode'] = $row['handanCode'];
            $array['effectCode'] = $row['effectCode'];
            $array['enforceDate'] = $row['enforceDate'];
            // 全体を json_encode() 使用とすると巨大データでコケるので
            // レコードを一行ずつ encode する
            $results[] = $array;
        }
        echo json_encode($results);
    } else if (strcmp($command,"PUT_PRICE_LIST") == 0){
        // PriceList にグローバル・レコードをマージ
        $args = decodeObject($value);
        // client 側との約束ごと
        $code = $args['code'];
        $requestCode = $args['requestCode'];
        $alias = $args['alias'];
        $name = $args['name'];
        $generic = $args['generic'];
        $point = $args['point'];
        $unitName = $args['unitName'];
        $handan = $args['handan'];
        $min = $args['min'];
        $standard = $args['standard'];
        $max = $args['max'];
        $width = $args['width'];
        $effectCode = $args['effectCode'];
        $effect = $args['effect'];
        $memo = $args['memo'];
        $enforceDate = $args['enforceDate'];
        $updateTime = timestamp();
        
        $sql = "SELECT * FROM `PriceList` WHERE `code`='$code' AND `alias`='$alias'";
        echo "$sql ------\n";
        $result=mysql_query($sql);
        
        if (mysql_num_rows ($result)){
            $sql = "UPDATE `PriceList` SET
            `requestCode`='$requestCode'
            ,`name`='$name'
            ,`generic`='$generic'
            ,`point`='$point'
            ,`unitName`='$unitName'
            ,`handan`='$handan'
            ,`min`='$min'
            ,`standard`='$standard'
            ,`max`='$max'
            ,`width`='$width'
            ,`effectCode`='$effectCode'
            ,`effect`='$effect'
            ,`memo`='$memo'
            ,`enforceDate`='$enforceDate'
            ,`updateTime`='$updateTime'
            WHERE `code`='$code' AND `alias`='$alias'";
        } else {
            $sql = "INSERT INTO `PriceList`
            (`code`,`requestCode`,`alias`,`name`,`generic`,`point`,`unitName`,`handan`,`min`,`standard`,`max`,`width`,`effectCode`,`effect`,`memo`,`enforceDate`,`updateTime`)
            VALUES
            ('$code','$requestCode','$alias','$name','$generic','$point','$unitName','$handan','$min','$standard','$max','$width','$effectCode','$effect','$memo','$enforceDate','$updateTime')";
        }
        mysql_query($sql);
        echo "$sql ------\n";
        
        // 保存したレコードを再検索して返す
        $array = getPriceList($code, $alias);
        echo "<SEPARATOR>";
        echo json_encode($array);
    } else if (strcmp($command,"GET_PRICE_LIST") == 0){
        // PriceList のレコードを検索して返す
        $args = decodeObject($value);
        $code = $args['code'];
        $alias = $args['alias'];
        
        $rec = getPriceList($code, $alias);
        echo "<SEPARATOR>";
        echo json_encode($rec);
    } else {
        echo "*** unknown command: $command";
    }
    
?>
