package thyyxxk.webserver.service.inpatient.casefrontsheet;

import lombok.extern.slf4j.Slf4j;
import thyyxxk.webserver.constants.Capacity;
import thyyxxk.webserver.entity.casefrontsheet.CaseFrontsheetDisdiag;
import thyyxxk.webserver.entity.casefrontsheet.CaseFrontsheetMain;
import thyyxxk.webserver.entity.casefrontsheet.CaseFrontsheetSurgery;
import thyyxxk.webserver.entity.casefrontsheet.StandardAddressMember;
import thyyxxk.webserver.entity.dictionary.CodeName;
import thyyxxk.webserver.utils.*;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author dj
 */
@Slf4j
public class VerifyCaseFrontSheet {

    private static VerifyCaseFrontSheet INSTANCE;

    private VerifyCaseFrontSheet() { }

    public static VerifyCaseFrontSheet getInstance() {
        if (null == INSTANCE) {
            INSTANCE = new VerifyCaseFrontSheet();
        }
        return INSTANCE;
    }

    public List<CodeName> saveVerify(CaseFrontsheetMain sheet) {
        List<CodeName> array = new ArrayList<>();
        if (null != sheet.getLivePlace()) {
            try {
                byte[] livePlaceBytes = sheet.getLivePlace().getBytes("GBK");
                if (livePlaceBytes.length > 32) {
                    array.add(new CodeName("livePlace", "患者现住址不能超过32个字节，当前字节数为" +
                            livePlaceBytes.length + "（1汉字=2字节，1字母或数字=1字节）！"));
                }
            } catch (Exception e) {
                log.error("分析患者现住址长度出现异常", e);
            }
        }
        // 移除工作单位地址长度限制
        // if (null != sheet.getUnitPlace() && sheet.getUnitPlace().length() > 16) {
        //     array.add(new CodeName("unitPlace", "患者单位地址不能超过16个汉字！"));
        // }
        // 移除联系人地址字数限制验证
        // if (null != sheet.getContactAddrName() && sheet.getContactAddrName().length() > 16) {
        //     array.add(new CodeName("contactAddrName", "患者联系人地址不能超过16个汉字！"));
        // }
        if (DateUtil.daysBetween(sheet.getQualityControlDate(), sheet.getDismissDate()) > 7) {
            array.add(new CodeName("qualityControlDate", "质控日期不能大于出院7天！"));
        }
        return connectedVerify(array, sheet);
    }

    public List<CodeName> adviseVerification(String socialNo, Date birth, String mainDisdiagCode , Integer age , String marriage) {
        List<CodeName> array = new ArrayList<>();
        if (StringUtil.invalidValue(socialNo)) {
            array.add(new CodeName("socialNo","请补全患者身份证！"));
        }
        if (!IdCardUtil.isValidatedIdCard(socialNo)) {
            array.add(new CodeName("socialNo","患者身份证不合法！"));
        }
        if (StringUtil.notBlank(socialNo) && socialNo.length() == 18) {
            if (null == birth) {
                array.add(new CodeName("birthDate","患者出生日期与身份证不符！"));
            } else {
                String b = DateUtil.format(birth, "yyyyMMdd");
                if (!socialNo.substring(6,14).equals(b)) {
                    array.add(new CodeName("birthDate","患者出生日期与身份证不符！"));
                }
            }
        }
        if (null != age && age < 20 && !marriage.equals("1")) {
                array.add(new CodeName("marriage", "患者年龄小于20周岁，婚姻状况须填未婚。"));
        }
        validateMainDiagnose(mainDisdiagCode, array);
        return array;
    }

    public List<CodeName> printVerify(CaseFrontsheetMain info) {
        List<CodeName> array = new ArrayList<>();
        if (StringUtil.isBlank(info.getPayMethod())) {
            array.add(new CodeName("payMethod", "医疗付费方式不能为空！"));
        }
        if (StringUtil.invalidValue(info.getName())) {
            array.add(new CodeName("name", "患者姓名不能为空！"));
        }
        if (null == info.getBirthDate()) {
            array.add(new CodeName("birthDate", "患者出生日期不能为空！"));
        }
        if (null == info.getAge()) {
            array.add(new CodeName("age","患者年龄不能为空！"));
        }
        if (StringUtil.invalidValue(info.getCountry())) {
            array.add(new CodeName("country","患者国籍不能为空！"));
        }
        if (StringUtil.invalidBirthPlace(info.getBirthPlace()) || StringUtil.invalidValue(info.getBirthPlaceName())) {
            array.add(new CodeName("birthPlaceName","患者出生地不能为空！"));
        }
        if (StringUtil.invalidValue(info.getNativePlace())) {
            array.add(new CodeName("nativePlaceName","患者籍贯不能为空！"));
        }
        if (StringUtil.invalidValue(info.getNation())) {
            array.add(new CodeName("nation","患者民族不能为空！"));
        }
        if (StringUtil.invalidValue(info.getOccupation())) {
            array.add(new CodeName("occupation","患者职业不能为空！"));
        }
        if (StringUtil.invalidValue(info.getMarriage())) {
            array.add(new CodeName("marriage","患者婚姻状况不能为空！"));
        }
        if (null == info.getStandardAddress() || info.getStandardAddress().length == 0 || null == info.getStandardAddress()[0]) {
            array.add(new CodeName("livePlace1","患者现住址(省/市/区)不能为空！"));
        }
        if (StringUtil.invalidValue(info.getLivePlace())) {
            array.add(new CodeName("livePlace2","患者现住址(街道/小区/乡镇)不能为空！"));
        }
        if (info.isDoctorPrint() && null != info.getAddressMember() && StringUtil.notBlank(info.getLivePlace())) {
            String liveAddress = info.getLivePlace();
            StandardAddressMember member = info.getAddressMember();
            if (liveAddress.contains(member.getProvinceName()) || liveAddress.contains(member.getCityName()) ||
                    liveAddress.contains(member.getDistrictName())) {
                array.add(new CodeName("livePlace2","患者现住址有冗余重复！"));
            }
        }

        try {
            byte[] livePlaceBytes = info.getLivePlace().getBytes("GBK");
            if (livePlaceBytes.length > 32) {
                array.add(new CodeName("livePlace", "患者现住址不能超过32个字节，当前字节数为" + livePlaceBytes.length + "（1汉字=2字节，1字母或数字=1字节）！"));
            }
        } catch (Exception e) {
            log.error("分析患者现住址长度出现异常", e);
        }
        if (StringUtil.invalidValue(info.getPhone())) {
            array.add(new CodeName("phone","患者电话不能为空！"));
        }
        if (StringUtil.invalidValue(info.getHkPlaceName())) {
            array.add(new CodeName("hkPlaceName","患者户口地址不能为空！"));
        }
        // 移除工作单位及地址不能为空验证
        // if (StringUtil.invalidValue(info.getUnitName()) || StringUtil.invalidValue(info.getUnitPlace())) {
        //     array.add(new CodeName("unitName","患者工作单位及地址不能为空！"));
        // }
        // 移除单位电话不能为空验证
        // if (StringUtil.isBlank(info.getUnitPhone())) {
        //     array.add(new CodeName("unitPhone","患者单位电话不能为空！"));
        // }
        // 移除单位邮编不能为空验证
        // if (StringUtil.isBlank(info.getUnitZipCode()) || info.getUnitZipCode().contains("-")) {
        //     array.add(new CodeName("unitZipCode", "患者工作单位邮编不能为空！"));
        // }
        if (StringUtil.isBlank(info.getAddrZipCode()) || info.getAddrZipCode().contains("-")) {
            array.add(new CodeName("addrZipCode", "患者现住址邮编不能为空！"));
        }
        if (StringUtil.isBlank(info.getHkZipCode()) || info.getHkZipCode().contains("-")) {
            array.add(new CodeName("hkZipCode", "患者户口邮编不能为空！"));
        }
        if (StringUtil.invalidValue(info.getContactName())) {
            array.add(new CodeName("contactName","患者联系人姓名不能为空！"));
        }
        if (StringUtil.invalidValue(info.getContactRelation())) {
            array.add(new CodeName("contactRelation","患者联系人关系不能为空！"));
        }
        if (StringUtil.invalidValue(info.getContactAddrName())) {
            array.add(new CodeName("contactAddrName","患者联系人地址不能为空！"));
        }
        // 移除联系人地址字数限制验证，保留非空验证
        // else {
        //     if (info.getContactAddrName().length() > 16) {
        //         array.add(new CodeName("contactAddrName", "患者联系人地址不能超过16个汉字！"));
        //     }
        // }
        if (StringUtil.invalidValue(info.getContactPhone())) {
            array.add(new CodeName("contactPhone","患者联系人电话不能为空！"));
        }
        if (StringUtil.invalidValue(info.getZyAdmissWay())) {
            array.add(new CodeName("zyAdmissWay","患者入院途径不能为空！"));
        }
        if (null == info.getAdmissDate()) {
            array.add(new CodeName("admissDate","患者入院时间不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAdmissDept())) {
            array.add(new CodeName("admissDept","患者入院科别不能为空！"));
        }
        if (StringUtil.invalidValue(info.getHasSurgery())) {
            array.add(new CodeName("hasSurgery","患者是否手术不能为空！"));
        }
        if (null == info.getDismissDate()) {
            array.add(new CodeName("dismissDate","患者出院时间不能为空！"));
        }
        if (StringUtil.invalidValue(info.getDismissDept())) {
            array.add(new CodeName("dismissDept","患者出院科别不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAdmissDays())) {
            array.add(new CodeName("admissDays","患者住院天数不能为空！"));
        }
        if (StringUtil.isBlank(info.getClinicDiagCode()) || StringUtil.isBlank(info.getClinicDiagStr())) {
            array.add(new CodeName("clinicDiag", "患者门（急）诊诊断需要填写标准诊断，请补充。"));
        } else {
            validateClinicDiagnose(info.getClinicDiagCode(), array);
        }
        CaseFrontsheetDisdiag disdiag = info.getDisdiagList().get(0);
        if (StringUtil.isBlank(disdiag.getName())) {
            array.add(new CodeName("disdiagMain","患者主要诊断不能为空！"));
        } else {
//            validateMainDiagnose(disdiag.getCode(), array);
        }
        if (null == info.getDisdiagList().get(0).getAdmissStatus()) {
            array.add(new CodeName("disdiagMainAdmStatus","患者主要诊断入院病情不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAllergy())) {
            array.add(new CodeName("allergy","患者有无药物过敏不能为空！"));
        }
        if (StringUtil.isBlank(info.getBloodType())) {
            array.add(new CodeName("bloodType","患者ABO血型不能为空！"));
        }
        if (StringUtil.isBlank(info.getRh())) {
            array.add(new CodeName("rh","患者Rh血型不能为空！"));
        }
        if (StringUtil.invalidValue(info.getDeptLeader())) {
            array.add(new CodeName("deptLeaderName","科主任不能为空！"));
        }
        if (StringUtil.invalidValue(info.getLeaderDoctor())) {
            array.add(new CodeName("leaderDoctorName","主任（副主任）医师不能为空！"));
        }
        if (StringUtil.invalidValue(info.getMainDoctor())) {
            array.add(new CodeName("mainDoctorName","主治医师不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAdmissDoctor())) {
            array.add(new CodeName("admissDoctorName","住院医师不能为空！"));
        }
        if (StringUtil.invalidValue(info.getDutyNurse())) {
            array.add(new CodeName("dutyNurseName","责任护士不能为空！"));
        }
        if (StringUtil.invalidValue(info.getCoder())) {
            array.add(new CodeName("coderName","编码员不能为空！"));
        }
        if (StringUtil.invalidValue(info.getQualityControlLevel())) {
            array.add(new CodeName("qualityControlLevel","病案质量不能为空！"));
        }
        if (StringUtil.invalidValue(info.getZyDismissWay())) {
            array.add(new CodeName("zyDismissWay","患者离院方式不能为空！"));
        }
        if (StringUtil.invalidValue(info.getAdmissAgainInOneMonth())) {
            array.add(new CodeName("admissAgainInOneMonth","患者是否有出院31天内再住院计划不能为空！"));
        }
        if (StringUtil.invalidValue(info.getQualityControlDoctor())) {
            array.add(new CodeName("qualityControlDoctorName","质控医生不能为空！"));
        }
        if (StringUtil.invalidValue(info.getQualityControlNurse())) {
            array.add(new CodeName("qualityControlNurseName","质控护士不能为空！"));
        }
        if (StringUtil.invalidValue(info.getCaseClassification())) {
            array.add(new CodeName("caseClassification","病例分型不能为空！"));
        }
//        if (StringUtil.invalidValue(info.getHasIcu())) {
//            array.add(new CodeName("hasIcu","实施重症监护不能为空！"));
//        }
        if (StringUtil.isBlank(info.getMonopathyManagement())) {
            array.add(new CodeName("monopathyManagement","单病种管理不能为空！"));
        }
        if (StringUtil.isBlank(info.getClinicalPathwayManagement())) {
            array.add(new CodeName("clinicalPathwayManagement","实施临床路径管理不能为空！"));
        }
        if (StringUtil.isBlank(info.getUseAntibiotic())) {
            array.add(new CodeName("useAntibiotic","抗生素使用不能为空！"));
        }
        if (StringUtil.isBlank(info.getBacilliculture())) {
            array.add(new CodeName("bacilliculture","细菌培养标本送检不能为空！"));
        }
        if (zipCodeLengthWrong(info.getAddrZipCode())) {
            array.add(new CodeName("addrZipCode","现住址邮编长度错误！"));
        }
        // 移除邮编长度限制
        // if (zipCodeLengthWrong(info.getHkZipCode())) {
        //     array.add(new CodeName("hkZipCode","户口地址邮编长度错误！"));
        // }
        // if (zipCodeLengthWrong(info.getUnitZipCode())) {
        //     array.add(new CodeName("unitZipCode","工作地址邮编错误！"));
        // }
        if (phoneLengthWrong(info.getPhone())) {
            array.add(new CodeName("phone","患者电话号码长度错误！"));
        }
        if (phoneLengthWrong(info.getContactPhone())) {
            array.add(new CodeName("contactPhone","联系人电话号码长度错误！"));
        }
        // 移除单位电话长度限制
        // if (phoneLengthWrong(info.getUnitPhone())) {
        //     array.add(new CodeName("unitPhone","工作单位电话长度错误！"));
        // }
        if (DateUtil.daysBetween(info.getDismissDate(), info.getAdmissDate()) < 0) {
            array.add(new CodeName("dismissDate","出院时间不能小于入院时间！"));
        }
        if (DateUtil.daysBetween(info.getBirthDate(), info.getAdmissDate()) > 0) {
            array.add(new CodeName("birthDate","出生时间不能大于入院时间！"));
        }
        if (DateUtil.daysBetween(info.getQualityControlDate(), info.getDismissDate()) < 0) {
            array.add(new CodeName("qualityControlDate","质控日期不能小于出院日期！"));
        }
        if (DateUtil.daysBetween(info.getQualityControlDate(), info.getDismissDate()) > 7) {
            array.add(new CodeName("qualityControlDate","质控日期不能大于出院7天！"));
        }
        // 移除户口地址和单位地址长度限制
        // if (StringUtil.notBlank(info.getHkPlaceName()) && info.getHkPlaceName().length() > 10) {
        //     array.add(new CodeName("hkPlaceName", "患者户口地址不能超过10个汉字！"));
        // }
        // if (StringUtil.notBlank(info.getUnitPlace()) && info.getUnitPlace().length() > 16) {
        //     array.add(new CodeName("unitPlace", "患者单位地址不能超过16个汉字！"));
        // }
        if (null != info.getAgeDays() && !isPositiveDigital(String.valueOf(info.getAgeDays()))) {
            array.add(new CodeName("ageDays", "不足1周岁婴儿的年龄请填写正整数。"));
        }
        if (null != info.getAgeDays() && info.getAgeDays() <= 28) {
            if (null == info.getNewBornWeight() || null == info.getNewBornAdmissWeight()) {
                array.add(new CodeName("newBornWeight","请填写新生儿出生体重和入院体重！"));
            }
            if (null != info.getNewBornWeight() && info.getNewBornWeight() < 1000) {
                array.add(new CodeName("newBornWeight","请填写合理的新生儿出生体重（不得少于1000g）！"));
            }
            if (null != info.getNewBornAdmissWeight() && info.getNewBornAdmissWeight() < 1000) {
                array.add(new CodeName("newBornAdmissWeight","请填写合理的新生儿入院体重（不得少于1000g）！"));
            }
            if (StringUtil.invalidValue(info.getXxeApgar())) {
                array.add(new CodeName("xxeApgar","新生儿Apgar评分不能为空！"));
            }
        }
        if (null != info.getAgeDays() && info.getAgeDays() > 28) {
            if (null != info.getNewBornWeight() || null != info.getNewBornAdmissWeight()) {
                array.add(new CodeName("newBornWeight","非新生儿请保持新生信息为空！"));
            }
        }
        if (null == info.getAgeDays() || 0 == info.getAgeDays()) {
            if (null != info.getNewBornWeight() || null != info.getNewBornAdmissWeight()) {
                array.add(new CodeName("ageDays","新生儿年龄不能为空！"));
            }
        }
        return connectedVerify(array, info);
    }

    private List<CodeName> connectedVerify(List<CodeName> array, CaseFrontsheetMain info) {
        if (StringUtil.notBlank(info.getMarriage())) {
//            if (null != info.getAge() && info.getAge() < 20 && !info.getMarriage().equals("1")) {
//                array.add(new CodeName("marriage", "患者年龄小于20周岁，婚姻状况须填未婚。"));
//            }
            if (info.getMarriage().equals("1") || info.getMarriage().equals("3") || info.getMarriage().equals("4")) {
                if (StringUtil.notBlank(info.getContactRelation()) &&
                        info.getContactRelation().equals("1")) {
                    array.add(new CodeName("contactRelation", "当婚姻状况为未婚、丧偶、离婚时，患者联系人关系不允许为配偶！"));
                }
            }
        }

        if (StringUtil.notBlank(info.getZyDismissWay())) {
            if ("1".equals(info.getZyDismissWay())  || "2".equals(info.getZyDismissWay())) {
                if (StringUtil.invalidValue(info.getDismissDestination())) {
                    array.add(new CodeName("dismissDestination","患者转入医疗机构不能为空！"));
                }
            }
            if ("3".equals(info.getZyDismissWay())) {
                if (StringUtil.invalidValue(info.getFyzlyyy())) {
                    array.add(new CodeName("fyzlyyy", "非医嘱离院原因不能为空！"));
                }
            } else {
                info.setFyzlyyy(null);
            }
        }
        if (StringUtil.notBlank(info.getHasSurgery())  && "0".equals(info.getHasSurgery()) && !"0".equals(info.getDiagConform3())) {
            array.add(new CodeName("diagConform3","无手术时，诊断符合情况中的术前与术后需要为【未做】！"));
        }
        if (StringUtil.notBlank(info.getHasSurgery())) {
            if ("1".equals(info.getHasSurgery())   || "2".equals(info.getHasSurgery()) || "3".equals(info.getHasSurgery())) {
                if ("0".equals(info.getDiagConform3())) {
                    array.add(new CodeName("diagConform3","有手术时，诊断符合情况中的术前与术后不可为【未做】！"));
                }
            }
        }
        if (StringUtil.notBlank(info.getZyDismissWay()) && "4".equals(info.getZyDismissWay())) {
            if (StringUtil.isBlank(info.getAutopsy())) {
                array.add(new CodeName("autopsy", "离院方式为死亡时，尸检不能为空！"));
            }
        }
        if (StringUtil.validValue(info.getAutopsy()) && !"".equals(info.getAutopsy())) {
            if (!"4".equals(info.getZyDismissWay())) {
                array.add(new CodeName("zyDismissWay","尸检不为空时，需要离院方式为死亡！"));
            }
        }
        boolean hasAnaesthesia = false;
        boolean hasAnaesthesiaor = false;
        for (CaseFrontsheetSurgery surgery : info.getSurgeryList()) {
            checkSurgery(array, surgery, info.getAdmissDate(), info.getDismissDate());
            if (StringUtil.notBlank(surgery.getAnaesthesia())) {
                hasAnaesthesia = true;
            }
            if (StringUtil.notBlank(surgery.getAnaesthesiaor())) {
                hasAnaesthesiaor = true;
            }
        }
        if (DecimalUtil.biggerThanZero(info.getAnesthetizeFee())) {
            if (ListUtil.isBlank(info.getSurgeryList())) {
                array.add(new CodeName("surgeryMain", "患者有麻醉费，手术列表不能为空！"));
            } else {
                if (!hasAnaesthesia) {
                    array.add(new CodeName("surgeryMain", "患者有麻醉费，麻醉方式不能为空！"));
                }
                if (!hasAnaesthesiaor) {
                    array.add(new CodeName("surgeryMain", "患者有麻醉费，麻醉医师不能为空！"));
                }
            }
        }
        if (needPathologicDiag(info.getDisdiagList().get(0).getCode()) &&
                (StringUtil.isBlank(info.getPathologicDiagStr()) || StringUtil.isBlank(info.getPathologicDiagCode()))) {
            array.add(new CodeName("pathologicDiagCode","根据患者出院主要诊断，病理诊断不能为空！"));
        }
//        if (StringUtil.validValue(info.getHasIcu()) && "2".equals(info.getHasIcu()) &&
//                (StringUtil.invalidValue(info.getIcuDays())  || StringUtil.invalidValue(info.getIcuHours()))) {
//            array.add(new CodeName("icuHours","患者ICU时间不能为空！"));
//        }
        if (StringUtil.notBlank(info.getHasSurgery()) && hasSurgery(info.getHasSurgery()) &&
                StringUtil.isBlank(info.getSurgeryList().get(0).getName())) {
            array.add(new CodeName("surgeryMain","患者有手术时，手术列表不能为空！"));
        }
        if (StringUtil.validValue(info.getAllergy())  && "2".equals(info.getAllergy()) && StringUtil.invalidValue(info.getAllergicMedicine())) {
            array.add(new CodeName("allergicMedicine","患者有药物过敏时，过敏药物名称不能为空！"));
        }
        if (DecimalUtil.biggerThanZero(info.getPathologicDiagFee()) && StringUtil.invalidValue(info.getBlh())) {
            array.add(new CodeName("blh","患者有病理诊断费，病理号不能为空！"));
        }
        if (DecimalUtil.biggerThanZero(info.getSurgeryFee()) && StringUtil.isBlank(info.getSurgeryList().get(0).getName())) {
            array.add(new CodeName("surgeryMain","患者有手术费，手术列表不能为空！"));
        }
        if (needHurtReason(info.getDisdiagList().get(0).getCode()) &&
                (StringUtil.invalidValue(info.getHurtReasonName()) || StringUtil.invalidValue(info.getHurtReasonCode()))) {
            array.add(new CodeName("hurtReasonName","根据患者出院主要诊断，损伤中毒诊断不能为空！"));
        }
        if (StringUtil.notBlank(info.getBloodType())) {
            if (!"5".equals(info.getBloodType()) && !"6".equals(info.getBloodType())) {
                if (!"1".equals(info.getRh()) && !"2".equals(info.getRh())) {
                    array.add(new CodeName("rh","患者血型确定时，Rh血型应为阴或阳！"));
                }
            }
        }
        if (hasDuplicateDiag(info.getDisdiagList())) {
            array.add(new CodeName("diagTable","出院诊断不能存在相同的诊断编码！"));
        }
        if (invalidBirthDiag(info.getDisdiagList())) {
            array.add(new CodeName("diagTable", "当主要诊断或者其它诊断编码出现O80-O84编码，且无流产结局时，其它诊断编码必须有分娩结局编码Z37。"));
        }
        if (hasSameSurgeryInOneDay(info.getSurgeryList())) {
            array.add(new CodeName("surgeryTable","同一天不能有相同的手术！"));
        }
        if (surgeryDateWrong(info.getSurgeryList(), info.getAdmissDate(), info.getDismissDate())) {
            array.add(new CodeName("surgeryTable","手术时间必须在入院时间24小时之前和出院时间之间！"));
        }
        if ((StringUtil.notBlank(info.getBloodType()) && ("5".equals(info.getBloodType()) || "6".equals(info.getBloodType()))) &&
                (StringUtil.notBlank(info.getRh()) && !"0".equals(info.getRh()) && !"3".equals(info.getRh()))) {
            array.add(new CodeName("rh","患者血型不确定时，Rh血型应为不详或未查！"));
        }
        if (StringUtil.notBlank(info.getRescueTimes()) && Integer.parseInt(info.getRescueTimes()) < 0) {
            array.add(new CodeName("rescueTimes","抢救次数不能为负数！"));
        }
        if (Integer.parseInt(info.getRescueTimes()) < Integer.parseInt(info.getRescueSuccessTimes())) {
            array.add(new CodeName("rescueSuccessTimes","抢救成功次数不能大于抢救次数！"));
        }
        if (Integer.parseInt(info.getRescueTimes()) - Integer.parseInt(info.getRescueSuccessTimes()) > 1) {
            array.add(new CodeName("rescueSuccessTimes","抢救成功次数不能少于抢救次数两次！"));
        }
        return array;
    }

    private boolean hasSurgeryFee(String str) {
        if (StringUtil.invalidValue(str)) {
            return false;
        }
        return Float.parseFloat(str) > 0;
    }

    private boolean hasSurgery(String flag) {
        return "1".equals(flag)  || "2".equals(flag) || "3".equals(flag);
    }

    private boolean isHighLevelSurgery(String level) {
        return StringUtil.notBlank(level) && ("3".equals(level) || "4".equals(level));
    }

    private void checkSurgery(List<CodeName> array, CaseFrontsheetSurgery surgery,
                              Date admissDate, Date dismissDate) {
        if (StringUtil.isBlank(surgery.getName())) {
            return;
        }
        if (surgery.getType() == 1) {
            if (StringUtil.isBlank(surgery.getAnaesthesia())) {
                array.add(new CodeName("surgeryTable","手术" + surgery.getNo() + "，麻醉方式不能为空！"));
            }
            if (StringUtil.isBlank(surgery.getAnaesthesiaor())) {
                array.add(new CodeName("surgeryTable","手术" + surgery.getNo() + "，麻醉医师不能为空！"));
            }
        }
        if (StringUtil.isBlank(surgery.getOperator())) {
            array.add(new CodeName("surgeryTable","手术" + surgery.getNo() + "，术者不能为空！"));
        }
        if (surgery.getType() < 3 && StringUtil.isBlank(surgery.getLevel())) {
            array.add(new CodeName("surgeryTable","手术" + surgery.getNo() + "手术操作编码为介入治疗或手术时，手术级别不能为空！"));
        }
        if (isHighLevelSurgery(surgery.getLevel())) {
            if (StringUtil.isBlank(surgery.getAssistantOne())) {
                array.add(new CodeName("surgeryTable","手术" + surgery.getNo() + "，三、四级手术I助不能为空！"));
            }
            if (StringUtil.isBlank(surgery.getCutHeal())) {
                array.add(new CodeName("surgeryTable","手术" + surgery.getNo() + "，三、四级手术切口愈合等级不能为空！"));
            }
            if (StringUtil.isBlank(surgery.getAssistantTwo())) {
                array.add(new CodeName("surgeryTable","手术" + surgery.getNo() + "，三、四级手术II助不能为空！"));
            }
        }
        if (needAnstTimeButNotPresent(surgery)) {
            array.add(new CodeName("surgeryTable","手术" + surgery.getNo() + "，麻醉开始时间和结束时间不能为空！"));
        }
        List<String> msgs = logicalSurgeryTime(admissDate, dismissDate, surgery.getDate(), surgery.getOpEndDate(),
                surgery.getAnstStartDate(), surgery.getAnstEndDate());
        for (String msg : msgs) {
            array.add(new CodeName("surgeryTable", "手术" + surgery.getNo() + "，" + msg));
        }
    }

    private boolean needAnstTimeButNotPresent(CaseFrontsheetSurgery surgery) {
        if (StringUtil.isBlank(surgery.getAnaesthesia()) || surgery.getAnaesthesia().equals("23")
                || surgery.getAnaesthesia().equals("29")) {
            return false;
        }
        return StringUtil.notBlank(surgery.getAnaesthesiaor()) &&
                (null == surgery.getAnstStartDate() || null == surgery.getAnstEndDate());
    }

    public static List<String> logicalSurgeryTime(Date admDate, Date disDate,
            Date opStart, Date opEnd, Date anstStart, Date anstEnd) {
        List<String> errors = new ArrayList<>();
        if (null == opStart) {
            errors.add("手术开始时间不能为空。");
        }
        if (null == opEnd) {
            errors.add("手术结束时间不能为空。");
        }
        if (null != opStart && null != admDate) {
            long admstamp = admDate.getTime() - (24 * 60 * 60 * 1000);
            long srgstamp = opStart.getTime();
            if (admstamp > srgstamp) {
                errors.add("手术开始时间不能早于入院时间前24小时");
            }
        }
        if (null != opStart && null != disDate && opStart.after(disDate)) {
            errors.add("手术开始时间不能晚于出院时间。");
        }
        if (null != opStart && null != opEnd && opEnd.before(opStart)) {
            errors.add("手术开始时间不能晚于手术结束时间。");
        }
        if (null != anstStart && null != opStart && anstStart.after(opStart)) {
            errors.add("麻醉开始时间不能晚于手术开始时间。");
        }
        if (null != anstStart && null != opEnd && anstStart.after(opEnd)) {
            errors.add("麻醉开始时间不能晚于手术结束时间。");
        }
        if (null != anstEnd && null != opEnd && anstEnd.before(opEnd)) {
            errors.add("麻醉结束时间不能早于手术结束时间。");
        }
        if (null != anstEnd && null != opStart && anstEnd.before(opStart)) {
            errors.add("麻醉结束时间不能早于手术开始时间。");
        }
        return errors;
    }

    private void validateClinicDiagnose(String code, List<CodeName> errors) {
        String fstLetter = code.substring(0, 1).toUpperCase();
        if (isNumeric(fstLetter)) {
            errors.add(new CodeName("clinicDiag", "门（急）诊诊断编码范围应为:A~U开头和Z开头的编码;不包括字母V、W、X、Y开头的编码。"));
            return;
        }
        if (fstLetter.equals("V") || fstLetter.equals("W") ||
                fstLetter.equals("X") || fstLetter.equals("Y")) {
            errors.add(new CodeName("clinicDiag", "门（急）诊诊断编码范围应为:A~U开头和Z开头的编码;不包括字母V、W、X、Y开头的编码。"));
        }
    }

    private void validateMainDiagnose(String code, List<CodeName> errors) {
        if (StringUtil.isBlank(code)) {
            return;
        }
        String header = code.substring(0, 3);
        String tail = header.substring(1);
        if (isNumeric(tail)) {
            int tailNumber = Integer.parseInt(tail);
            if (code.charAt(0) == 'R' && tailNumber <= 99) {
                errors.add(new CodeName("disdiagMain", "症状体征异常情况不能作为患者主要诊断！"));
            }
        }
        if (code.startsWith("B95.") || code.startsWith("B96.") || code.startsWith("B97.")) {
            errors.add(new CodeName("disdiagMain", "某些传染和寄生虫病编码中的细菌、病毒和其他传染性病原体（B95-B97）不能作为患者主要诊断！"));
        }
        if (code.startsWith("T31.") || code.startsWith("T32.")) {
            errors.add(new CodeName("disdiagMain", "烧伤及腐蚀面积不能作为患者主要诊断！"));
        }
        if (code.startsWith("Z37.") || code.startsWith("Z38.")) {
            errors.add(new CodeName("disdiagMain", "分娩结局不能作为患者主要诊断！"));
        }
        if (code.startsWith("Z85.")) {
            errors.add(new CodeName("disdiagMain", "恶性肿瘤个人史不能作为患者主要诊断！"));
        }
        if (code.startsWith("Z86.") || code.startsWith("Z87.")) {
            errors.add(new CodeName("disdiagMain", "既往病史不能作为患者主要诊断！"));
        }
        if (code.startsWith("Z93.")) {
            errors.add(new CodeName("disdiagMain", "人工造口状态不能作为患者主要诊断！"));
        }
        if (code.startsWith("Z98.")) {
            errors.add(new CodeName("disdiagMain", "手术后状态不能作为患者主要诊断！"));
        }
    }

    private boolean isNumeric(String str){
        Pattern pattern = Pattern.compile("[0-9]*");
        return pattern.matcher(str).matches();
    }

    private boolean needPathologicDiag(String diag) {
        if (StringUtil.invalidValue(diag)) {
            return false;
        }
        final char firstLetter = diag.toUpperCase().charAt(0);
        if (firstLetter != 'C' && firstLetter != 'D') {
            return false;
        }
        final String diagBase = diag.substring(1, 3);
        final int code;
        try {
            code = Integer.parseInt(diagBase);
        } catch (NumberFormatException e) {
            return false;
        }
        if (firstLetter == 'C') {
            return code >= 0 && code <= 97;
        } else {
            return (code >= 0 && code <= 9) || (code >= 10 && code <= 36) || (code >= 37 && code <= 48);
        }
    }

    private boolean needHurtReason(String diag) {
        if (StringUtil.invalidValue(diag)) {
            return false;
        }
        diag = diag.toUpperCase();
        if (diag.startsWith("SY")) {
            return false;
        }
        final char firstLetter = diag.charAt(0);
        return firstLetter == 'S' || firstLetter == 'T';
    }

    private boolean hasDuplicateDiag(List<CaseFrontsheetDisdiag> disdiags) {
        Map<String, String> map = new HashMap<>(Capacity.DEFAULT);
        for (CaseFrontsheetDisdiag diag : disdiags) {
            if (StringUtil.validValue(diag.getCode())) {
                if (map.containsKey(diag.getCode())) {
                    return true;
                }
                map.put(diag.getCode(), diag.getName());
            }
        }
        return false;
    }

    /**
     * 当主要诊断或者其它诊断编码出现O80-O84编码，且无流产结局编码出现O00-O08编码时，其它诊断编码必须有分娩结局编码Z37
     * */
    private boolean invalidBirthDiag(List<CaseFrontsheetDisdiag> disdiags) {
        boolean isBirth = false;
        boolean isAbortion = false;
        boolean isDelivered = false;
        for (CaseFrontsheetDisdiag diag : disdiags) {
            String code = diag.getCode();
            if (StringUtil.isBlank(code)) {
                continue;
            }
            if (code.startsWith("O80.") || code.startsWith("O81.") || code.startsWith("O82.")
                    || code.startsWith("O83.") || code.startsWith("O84.")) {
                isBirth = true;
            }
            if (code.startsWith("O00.") || code.startsWith("O01.") || code.startsWith("O02.")
                    || code.startsWith("O03.") || code.startsWith("O04.") || code.startsWith("O05.")
                    || code.startsWith("O06.") || code.startsWith("O07.") || code.startsWith("O08.")) {
                isAbortion = true;
            }
            if (code.startsWith("Z37.")) {
                isDelivered = true;
            }
        }
        return isBirth && !isAbortion && !isDelivered;
    }

    private boolean hasSameSurgeryInOneDay(List<CaseFrontsheetSurgery> surgeries) {
        Map<String, String> map = new HashMap<>(Capacity.DEFAULT);
        for (CaseFrontsheetSurgery surgery : surgeries) {
            if (StringUtil.validValue(surgery.getCode())) {
                if (map.containsKey(surgery.getCode() + DateUtil.formatDatetime(surgery.getDate(), "yyyy-MM-dd HH:mm:ss"))) {
                    return true;
                }
                map.put(surgery.getCode() + DateUtil.formatDatetime(surgery.getDate(), "yyyy-MM-dd HH:mm:ss"), surgery.getCode());
            }
        }
        return false;
    }

    private boolean zipCodeLengthWrong(String zipCode) {
        return StringUtil.notBlank(zipCode) && zipCode.length() != 6;
    }

    private boolean surgeryDateWrong(List<CaseFrontsheetSurgery> surgeries, Date admissDate, Date outmissDate) {
        if (null == outmissDate) {
            return false;
        }
        long admstamp = admissDate.getTime() - (24 * 60 * 60 * 1000);
        long disstamp = outmissDate.getTime();
        for (CaseFrontsheetSurgery item : surgeries) {
            if (StringUtil.isBlank(item.getCode())) {
                continue;
            }
            if (StringUtil.notBlank(item.getCode()) && null == item.getDate()) {
                return true;
            }
            long srgstamp = item.getDate().getTime();
            if (admstamp > srgstamp || srgstamp > disstamp) {
                return true;
            }
        }
        return false;
    }

    private boolean phoneLengthWrong(String phone) {
        if (StringUtil.isBlank(phone)) {
            return false;
        }
        return phone.length() != 11 && phone.length() != 12 && phone.length() != 8;
    }

    private boolean isPositiveDigital(String string) {
        String regEx1 = "\\d+";
        Pattern p;
        Matcher m;
        p = Pattern.compile(regEx1);
        m = p.matcher(string);
        return m.matches();
    }
}
