package cokr.xit.fims.nxrp.service.bean;

import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.Field;
import java.net.http.HttpResponse;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import javax.annotation.Resource;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.JsonNode;

import cokr.xit.base.code.CommonCode;
import cokr.xit.base.code.service.bean.CodeBean;
import cokr.xit.base.file.ZIP;
import cokr.xit.base.file.service.FileQuery;
import cokr.xit.base.file.service.bean.FileBean;
import cokr.xit.base.user.service.bean.UserBean;
import cokr.xit.fims.FimsConf;
import cokr.xit.fims.base.OgdpQuery;
import cokr.xit.fims.base.service.bean.OgdpBean;
import cokr.xit.fims.cmmn.CmmnQuery;
import cokr.xit.fims.cmmn.service.bean.StngBean;
import cokr.xit.fims.crdn.Crdn;
import cokr.xit.fims.crdn.dao.CrdnInfoMapper;
import cokr.xit.fims.crdn.dao.CrdnStngMapper;
import cokr.xit.fims.crdn.dao.CrdnUpdtMapper;
import cokr.xit.fims.mngt.dao.TaskMapper;
import cokr.xit.fims.mngt.service.bean.TaskProcessor;
import cokr.xit.fims.nxrp.A01;
import cokr.xit.fims.nxrp.A03Rqst;
import cokr.xit.fims.nxrp.NisIndivQuery;
import cokr.xit.fims.nxrp.dao.NisA01Mapper;
import cokr.xit.fims.nxrp.dao.NisA02Mapper;
import cokr.xit.fims.nxrp.dao.NisA03Mapper;
import cokr.xit.fims.nxrp.support.AttachedTxtMaker;
import cokr.xit.fims.nxrp.support.LinkFileMaker;
import cokr.xit.fims.nxrp.support.OnlyImageMaker;
import cokr.xit.fims.sndb.SndngDtl;
import cokr.xit.foundation.component.AbstractBean;
import cokr.xit.foundation.data.DataObject;
import cokr.xit.foundation.data.JSON;
import cokr.xit.foundation.web.WebClient;
import cokr.xit.interfaces.filejob.JobConf;
import cokr.xit.interfaces.lntris.basic.a.LntrisA01;
import cokr.xit.interfaces.lntris.basic.a.LntrisA01.A01Response;
import cokr.xit.interfaces.lntris.basic.a.LntrisA03;
import cokr.xit.interfaces.lntris.basic.a.LntrisA03.A03Response;
import cokr.xit.interfaces.lntris.basic.a.service.LntrisAService;

/**과태료대장 단속정보 관리 Bean
 *
 * <p>상세 설명:
 *
 * <pre>
 * ============ 변경 이력 ============
 * 2024-02-16	JoJH 최초 작성
 * ================================
 * </pre>
 */
@Component("nisIndivBean")
public class NisIndivBean extends AbstractBean {
	private JSON json = new JSON();
	@Resource(name = "lntrisAService")
	private LntrisAService lntrisAService;
	/** 과태료대장 단속정보 DAO */
	@Resource(name = "nisA01Mapper")
	private NisA01Mapper nisA01Mapper;
	/** 과태료대장 일괄조회 DAO */
	@Resource(name = "nisA02Mapper")
	private NisA02Mapper nisA02Mapper;
	/** 과태료대장 상세조회 DAO */
	@Resource(name = "nisA03Mapper")
	private NisA03Mapper nisA03Mapper;
	/** 단속 대장 수정 정보 DAO */
	@Resource(name = "crdnUpdtMapper")
	private CrdnUpdtMapper crdnUpdtMapper;
	@Resource(name="crdnInfoMapper")
	private CrdnInfoMapper crdnInfoMapper;
	@Resource(name="crdnStngMapper")
	private CrdnStngMapper crdnStngMapper;
	@Resource(name="taskMapper")
	private TaskMapper taskMapper;
	@Resource(name="fileBean")
	private FileBean fileBean;
	/** 사용자 정보 DAO */
	@Resource(name="userBean")
	protected UserBean userBean;
	/** 코드 정보 DAO */
	@Resource(name="codeBean")
	protected CodeBean codeBean;
	/** 설정 정보 DAO */
	@Resource(name="stngBean")
	protected StngBean stngBean;
	/** 부서 정보 DAO */
	@Resource(name = "ogdpBean")
	private OgdpBean ogdpBean;

	/**지정한 조건에 따라 과태료대장 단속정보 목록을 조회하여 반환한다.
	 * @param req 과태료대장 단속정보 조회 조건
	 * @return 과태료대장 단속정보 목록
	 */
	public List<DataObject> getNisIndivA01List(NisIndivQuery req) {
		return nisA01Mapper.selectNisIndivA01List(req);
	}

	/**지정한 조건에 따라 과태료대장 단속정보 객체들을 반환한다.
	 * @param req 과태료대장 단속정보 조회 조건
	 * @return 과태료대장 단속정보 객체 목록
	 */
	public List<DataObject> getNisIndivA01s(NisIndivQuery req) {
		return nisA01Mapper.selectNisIndivA01s(req);
	}

	/**과태료대장 단속정보를 등록한다.
	 * @param nisIndivA01 과태료대장 단속정보
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String createNisIndivA01(NisIndivQuery req) {
		// 1. 사용자 정보
		DataObject userInfo = userBean.getUserInfo(currentUser().getId());
		// 2. 부서 정보
		DataObject deptInfo = ogdpBean.getDeptStngInfo(new OgdpQuery().setDeptCd(userInfo.string("DEPT_CD")));
		// 3. 세외수입 과태료대장에 연계할 단속정보를 조회
		DataObject crdnInfo = nisA01Mapper.selectCrdnInfo(req.getCrdnId());

		LocalDateTime now = LocalDateTime.now();							// 현재 날짜/시간
		String sggCd = crdnInfo.string("SGG_CD");
		String taskSeCd = crdnInfo.string("TASK_SE_CD");
		String crdnId = crdnInfo.string("CRDN_ID");
		String linkMngKey = sggCd + crdnId + '_' + now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
//		String linkMngKey = sggCd + crdnId;
		String nsttCd = userInfo.string("NSTT_CD");

		A01 a01 = new A01();
		a01.setTaskSeCd(taskSeCd);											// 업무 구분 코드
		a01.setSgbCd(nsttCd);							// 자치단체코드
		a01.setLinkTrgtCd(nsttCd + taskSeCd + "01001");	// 연계대상코드
		a01.setLinkMngKey(linkMngKey);										// 연계관리키 시군구코드 + 단속 ID + 년월일시분초
		a01.setDptCd(userInfo.string("DEPT_CD"));							// 부서코드
		a01.setRcptYr(req.getSndngYmd().substring(0, 4));					// 접수연도
		a01.setSpacBizCd(crdnInfo.string("SPCL_BIZ_CD"));				// 특별회계사업코드 (밤샘주차 0159:주차장특별회계)
		a01.setActSeCd(crdnInfo.string("ACNTG_SE_CD"));				// 회계구분코드
		a01.setRprsTxmCd(crdnInfo.string("TXITM_CD"));				// 대표세입과목코드
		a01.setOperItemCd(crdnInfo.string("OPER_ITEM_CD"));			// 운영항목코드

		TaskProcessor taskProcessor = TaskProcessor.get();
		a01.setFinScrgSeCd(taskProcessor.getFinScrgSeCd(taskSeCd));
		// 납부자구분코드(FIM011) 01:주민 02:외국인 03:법인 04:사업자 05:기타  ->  01:개인 02:법인 03:단체 05:외국인
		a01.setPyrSeCd(
			switch (crdnInfo.string("RTPYR_SE_CD")) {
			case "01" -> "01"; // 주민(01)  -> 개인(01)
			case "02" -> "05"; // 외국인(02) -> 외국인(05)
			case "03" -> "02"; // 법인(03)  -> 법인(02)
			case "04" -> "04"; // 사업자(04) -> 사업자(04)
			default -> "03";   // 기타(05)  -> 단체(03)
			}
		);
		String rtpyrNo = crdnInfo.string("RTPYR_NO");
		a01.setPyrNo(rtpyrNo);							// 납부자번호
		String rtpyrNm = crdnInfo.string("RTPYR_NM");
		a01.setPyrNm(rtpyrNm);							// 납부자명
		a01.setRprsPyrNo(rtpyrNo);						// 대표납부자번호 / 법인의 경우 대표 납부자번호 필수
		a01.setRprsPyrNm(rtpyrNm);						// 대표납부자명 / 법인의 경우 대표 납부자명 필수
		a01.setPyrTelno(crdnInfo.string("RTPYR_TELNO"));						// 납부자전화번호
		a01.setPyrMblTelno(crdnInfo.string("RTPYR_MBL_TELNO"));				// 납부자휴대전화번호
		a01.setPyrEmlAddr(crdnInfo.string("RTPYR_EML"));						// 납부자이메일주소
		a01.setPyrSttCd("10");														// 납부자상태코드('10')
		a01.setPyrLotnoRoadAddrSeCd(crdnInfo.string("ADDR_SE_CD"));			// 납부자지번도로주소구분코드 01:지번주소, 02:도로명주소
		a01.setPyrZip(crdnInfo.string("ZIP"));								// 납부자우편번호
		a01.setPyrRoadNmCd(crdnInfo.string("ROAD_NM_CD"));					// 납부자도로명코드
		// 납부자주소지하여부(FIM036) 0:지상 1: 지하 -> Y:지하, N:지상
		a01.setPyrAddrUdgdYn("1".equals(crdnInfo.get("ROAD_NM_CD")) ? "Y" : "N"); // 지하(1)	-> 지하(Y)
		a01.setPyrBmno(crdnInfo.string("BMNO"));								// 납부자건물본번
		a01.setPyrBsno(crdnInfo.string("BSNO"));								// 납부자건물부번
		a01.setPyrStdgCd(crdnInfo.string("STDG_CD"));							// 납부자법정동코드
		a01.setPyrDongCd(crdnInfo.string("DONG_CD"));							// 납부자행정동코드
		// 산 구분 코드(FIM037) 0: 1:산 -> 납부자산구분코드 01:일반번지, 02:산번지
		a01.setPyrMtnSeCd(crdnInfo.string("MTN_SE_CD").equals("1") ? "02" : "01"); // 산(1) -> 산번지(02) , 01:일반번지
		a01.setPyrBldgMngNo(crdnInfo.string("BLDG_MNG_NO"));					// 납부자건물관리번호
		a01.setPyrBldgNm("");														// 납부자건물명
		a01.setPyrMno(crdnInfo.string("MNO"));								// 납부자본번 / 번지. 지번주소인 경우 필수
		a01.setPyrSno(crdnInfo.string("SNO"));								// 납부자부번 / 호
		a01.setPyrSpclDg(crdnInfo.string("SPCL_DONG"));						// 납부자특수동 / 상세주소 동
		a01.setPyrSpclHo(crdnInfo.string("SPCL_HO"));							// 납부자특수호 / 상세주소 호
		a01.setPyrTong("");															// 납부자통
		a01.setPyrBan("");															// 납부자반
		a01.setPyrSpclAddr(crdnInfo.string("SPCL_ADDR"));						// 납부자특수주소
		a01.setPyrRoadNmAddr(crdnInfo.string("ADDR"));						// 납부자도로명주소
		a01.setPyrRoadNmDaddr(crdnInfo.string("DTL_ADDR"));					// 납부자도로명상세주소
		a01.setPyrRoadNmAlAddr(crdnInfo.string("WHOL_ADDR"));					// 납부자도로명전체주소
		a01.setGlNm(crdnInfo.string("VHRNO"));								// 물건지명
		a01.setLvyTrgtSeCd("01");													// 부과대상구분코드 01:차량
		a01.setRegYmd(crdnInfo.string("CRDN_YMD"));							// 등록일자 / 위반일자
		a01.setFinScrgAmt(crdnInfo.string("FFNLG_AMT"));						// 과태료과징금금액
		a01.setFcltSeCd("");														// 시설구분코드 / 금연구역흡연위반 과태료인 경우 활용
		a01.setRegSeCd("");															// 등록구분코드 / 폐기물관리법위반 과태료인 경우 01투기, 02소각, 99기타
		// 감경 사유 코드(FIM019) -> 감경사유구분코드
		a01.setRdtRsnSeCd(
			switch (crdnInfo.string("RDCT_RSN_CD")) {
			case "01" -> "0101"; // 국민기초생활수급자
			case "02" -> "0102"; // 한부모가족보호대상자
			case "03" -> "0103"; // 장애인(장애의 정도가 심한 장애인)
			case "04" -> "0104"; // 국가유공자(상이등급3급이상)
			case "05" -> "0105"; // 미성년자
			case "08" -> "";     // 의견진술감액
			case "09" -> "";     // 기타
			case "99" -> "0199"; // 타법령에의한감경
			default -> "0100";   // 해당없음
			}
		);
		a01.setVhrno(crdnInfo.string("VHRNO"));								// 자동차등록번호

		DataObject mngItemCn = taskProcessor.getMngItemCn(crdnInfo);
		Map<String, Consumer<String>> setMngItemCn = Map.of(
			"item1", a01::setMngItemCn1,
			"item2", a01::setMngItemCn2,
			"item3", a01::setMngItemCn3,
			"item4", a01::setMngItemCn4,
			"item5", a01::setMngItemCn5
		);
		mngItemCn.entrySet().forEach(entry -> setMngItemCn.get(entry.getKey()).accept((String)entry.getValue()));

		a01.setMngItemCn6(sggCd + crdnId);	// 관리6항목
		a01.setRmCn(crdnInfo.string("ETC_CN"));			// 비고내용
		a01.setCreatedBy(userInfo.string("USER_ID"));
		a01.setModifiedBy(userInfo.string("USER_ID"));

		// 차세대 세외수입 연계 서비스 호출 - A01 과태료대장 단속정보 등록
		// 연계서비스 별도 프로세스 여부
		if ("Y".equals(ifEmpty(FimsConf.get().getNxrpDemonYn(),() -> "Y"))) {
			String url = deptInfo.string("NXRP_LINK_SRVC_URL") + "/intf/lntris/a01/register";		// create
			// Json 파라미터 설정
			String jsonData = "{ "
				+ "  \"taskSeCd\":" + "\"" + a01.getTaskSeCd() + "\""
				+ ", \"msg\":" + json.stringify(a01)
				+ " }";

			// 연계 서비스 호출 후 메세지 return
			return jsonCall(url, jsonData);
		} else {
			LntrisA01.A01ReqDetail rd = (LntrisA01.A01ReqDetail) convert(a01, LntrisA01.A01ReqDetail.class);
			List<A01Response> res = lntrisAService.registerA01s(a01.getTaskSeCd(), List.of(rd));
			A01Response res0 = !res.isEmpty() ? res.get(0) : null;
			return json.stringify(res0);
		}
	}

	public SndngDtl registerNisIndivA01(NisIndivQuery req) {
		String hresp = createNisIndivA01(req);

		try {
			JsonNode linkRst = json.getObjectMapper().readTree(hresp);

			// 개별시스템 연계결과코드(linkRstCd) - 000:정상, 100:검증오류(연계관리키 중복), 101:검증오류(등록 시 자료 null, 길이체크), 900:필수값누락
			if ("000".equals(linkRst.get("linkRstCd").asText())) {
				// resVo1
				JsonNode resVo1 = linkRst.findValue("resVo1");

				// 발송 대장(TB_SNDNG) - 발송 상태 코드(SNDNG_DTL_STTS_CD) 수정
				SndngDtl uptSndngDtl = new SndngDtl();
				uptSndngDtl.setSndngDtlSttsCd("01");							// 발송 상태 코드(FIM050) 01:세외수입부과
				uptSndngDtl.setLinkTrgtCd(resVo1.get("linkTrgtCd").asText());	// 연계 대상 코드
				uptSndngDtl.setLinkMngKey(resVo1.get("linkMngKey").asText());	// 연계 관리 키
				return uptSndngDtl;
			} else
				return null;
		} catch (Exception e) {
			throw runtimeException(e);
		}
	}

	/**지정한 조건에 따라 과태료대장 일괄조회 목록을 조회하여 반환한다.
	 * @param req 과태료대장 일괄조회 조건
	 * @return 과태료대장 일괄조회 목록
	 */
	public List<DataObject> getNisIndivA02List(NisIndivQuery req) {
		return nisA02Mapper.selectNisIndivA02List(req);
	}

	/**지정한 조건에 따라 과태료대장 일괄조회 객체들을 반환한다.
	 * @param req 과태료대장 일괄조회 조건
	 * @return 과태료대장 일괄조회 객체 목록
	 */
	public List<DataObject> getNisIndivA02s(NisIndivQuery req) {
		return nisA02Mapper.selectNisIndivA02s(req);
	}

	/**지정한 조건에 따라 과태료대장 상세조회 목록을 조회하여 반환한다.
	 * @param req 과태료대장 상세조회 조건
	 * @return 과태료대장 상세조회 목록
	 */
	public List<DataObject> getNisIndivA03List(NisIndivQuery req) {
		return nisA03Mapper.selectNisIndivA03List(req);
	}

	/**지정한 조건에 따라 과태료대장 상세조회 객체들을 반환한다.
	 * @param req 과태료대장 상세조회 조건
	 * @return 과태료대장 상세조회 객체 목록
	 */
	public List<DataObject> getNisIndivA03s(NisIndivQuery req) {
		return nisA03Mapper.selectNisIndivA03s(req);
	}

	/**과태료대장 상세조회 정보에서 업무 적용 정보를 수정한다.
	 * @param nisIndivA03 과태료대장 상세조회
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String createNisIndivA03(NisIndivQuery req) {
		// 1. 사용자 정보
		DataObject userInfo = userBean.getUserInfo(currentUser().getId());
		// 2. 부서 정보
		DataObject deptInfo = ogdpBean.getDeptStngInfo(new OgdpQuery().setDeptCd(userInfo.string("DEPT_CD")));
		// 3. 세외수입 과태료대장에 연계할 단속정보를 조회
		DataObject selectCrdnInfo = nisA01Mapper.selectCrdnInfo(req.getCrdnId());

		A03Rqst a03Rqst = new A03Rqst();
		a03Rqst.setTaskSeCd(selectCrdnInfo.string("TASK_SE_CD"));		// 업무 구분 코드
		a03Rqst.setSgbCd(userInfo.string("NSTT_CD"));					// 자치단체코드
		a03Rqst.setLinkTrgtCd(req.getLinkTrgtCd());						// 연계대상코드
		a03Rqst.setLinkMngKey(req.getLinkMngKey());						// 연계관리키 시군구코드 + 단속 ID + 년월일시분초

		// 차세대 세외수입 연계 서비스 호출 - A01 과태료대장 단속정보 등록
		// 연계서비스 별도 프로세스 여부
		if ("Y".equals(ifEmpty(FimsConf.get().getNxrpDemonYn(),() -> "Y"))) {
			String url = deptInfo.string("NXRP_LINK_SRVC_URL") + "/intf/lntris/a03/info";						// create
			String jsonData = "{ "
				+ "  \"taskSeCd\":"	+ "\"" + a03Rqst.getTaskSeCd() + "\""
				+ ", \"msg\":" + json.stringify(a03Rqst)
				+ " }";

			// 연계 서비스 호출 후 메세지 return
			return jsonCall(url, jsonData);
		} else {
			LntrisA03.A03ReqDetail rd = new LntrisA03.A03ReqDetail();
			rd.setSgbCd(a03Rqst.getSgbCd());
			rd.setFinScrgAcbKey(a03Rqst.getFinScrgAcbKey());
			rd.setLinkMngKey(a03Rqst.getLinkMngKey());
			rd.setLinkTrgtCd(a03Rqst.getLinkTrgtCd());

			A03Response res = lntrisAService.getA03(a03Rqst.getTaskSeCd(), rd);
			return json.stringify(res);
		}
	}

	/**지정한 조건에 따라 과태료대장 일괄조회 목록을 조회하여 반환한다.
	 * @param req 과태료대장 일괄조회 조건
	 * @return 과태료대장 일괄조회 목록
	 */
	public String jsonCall(String url, String jsonData) {
		HttpResponse<String> hresp = new WebClient().post(req ->
			req.uri(url)
			   .json(json)
			   .bodyData(jsonData)
		);
		return hresp.body();
	}

	// SSL 무시 /////////////////////////////////////////////////////////////////
	public void ignoreSsl() throws Exception {
		trustAllHttpsCertificates();
		HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
			@Override
			public boolean verify(String urlHostName, SSLSession session) {
				return true;
			}
		});
	}

	public void trustAllHttpsCertificates() throws Exception {
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, new TrustManager[] {new miTM()}, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    static class miTM implements TrustManager, X509TrustManager {
        @Override
		public X509Certificate[] getAcceptedIssuers() {
        	return null;
        }

        public boolean isServerTrusted(X509Certificate[] certs) {
        	return true;
        }

        public boolean isClientTrusted(X509Certificate[] certs) {
        	return true;
        }

        @Override
		public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
        	return;
        }

        @Override
		public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
        	return;
        }
    }
	// SSL 무시 /////////////////////////////////////////////////////////////////

	public String createNisIndivB01C01(NisIndivQuery req) {
		Map<String, List<CommonCode>> codes = codeBean.getCodesOf("FIM004", "NTR055");
		List<CommonCode> fimsVltnCodes = codes.get("FIM004");
		List<CommonCode> nxrpVltnCodes = codes.get("NTR055");

		DataObject deptStng = stngBean.getStng("dept");
		String gujesi = deptStng.string("NXRP_RGN_SE_CD");
		String rtnMsg = "[F]";

		for (String crdnID : req.getCrdnIds()) {
			DataObject crdnInfo = crdnInfoMapper.selectCrdnInfo(crdnID);

			if ("Y".equals(crdnInfo.get("NXRP_CRDN_LINK_YN")))
				throw new RuntimeException(rtnMsg += "이미 연계 처리된 세외수입 단속 자료입니다.");

			String sggCd = crdnInfo.string("SGG_CD");
			String firstTaskSeCd = "";
			String taskSeCd = crdnInfo.string("TASK_SE_CD");
			if (isEmpty(firstTaskSeCd))
				firstTaskSeCd = taskSeCd;

			if (!taskSeCd.equals("PVS") && !taskSeCd.equals("BPV"))
				throw new RuntimeException(rtnMsg += "주정차위반 또는 전용차로위반 자료만 처리할 수 있습니다.");
			if (!firstTaskSeCd.equals(taskSeCd))
				throw new RuntimeException(rtnMsg += "과태료 구분이 동일한 자료만 처리할 수 있습니다.");
			if (toInt(crdnInfo.get("ATCH_FILE_CNT")) < 1)
				throw new RuntimeException(rtnMsg += "단속사진이 없습니다.");

			CmmnQuery cmmnQuery = new CmmnQuery()
				.setUseYn("Y")
				.setSggCd(sggCd)
				.setTaskSeCd(taskSeCd);
			DataObject nxrpLinkInfo = taskMapper.selectTaskInfo(cmmnQuery);
			if (nxrpLinkInfo == null)
				throw new RuntimeException(rtnMsg += "과태료 설정 정보가 없습니다.");

			String nxrpLinkSeCd = nxrpLinkInfo.string("NXRP_LINK_SE_CD");
			String nxrpLinkSeDtlSn = nxrpLinkInfo.string("NXRP_LINK_SE_DTL_SN");

			if (!nxrpLinkSeCd.equals("B01") && !nxrpLinkSeCd.equals("C01"))
				throw new RuntimeException(rtnMsg += "세외수입 연계 구분 코드 설정 오류입니다.");
			if (!nxrpLinkSeDtlSn.equals("01") && !nxrpLinkSeDtlSn.equals("02"))
				throw new RuntimeException(rtnMsg += "세외수입 연계 구분 상세 순번 설정 오류입니다.");

			String instDigit7 = currentUser().getInstitute();

			//법정동코드 구하기
			if (!isEmpty(crdnInfo.string("CRDN_STDG_NM"))) {
				DataObject stdgQuery = new DataObject()
					.set("sggCd", sggCd)
					.set("emdNm", crdnInfo.string("CRDN_STDG_NM"));
				List<String> stdgCds = crdnStngMapper.selectStdgCdListByStdgNm(stdgQuery);
				String stdgCd = !stdgCds.isEmpty() ? stdgCds.get(0) : null;
				if (!isEmpty(stdgCd))
					crdnInfo.put("STDG_CD", stdgCd);
			}

			LinkFileMaker linkFileMaker = null;
			if (nxrpLinkSeDtlSn.equals("01")) {
				linkFileMaker = new AttachedTxtMaker(nxrpLinkSeCd, instDigit7);
				if (nxrpLinkSeCd.equals("B01")) {
					((AttachedTxtMaker)linkFileMaker).appendVltnCodeInfo(fimsVltnCodes, nxrpVltnCodes);
				}
			} else {
				linkFileMaker = new OnlyImageMaker(nxrpLinkSeCd, instDigit7);
			}

			if (!isEmpty(gujesi))
				linkFileMaker.setGujesiStng(gujesi);

			String workPath = "files/temp/sendCrdn/"+sggCd+"/"+crdnInfo.string("CRDN_ID");
			File workFolder = new File(workPath);
			if (workFolder.exists()) {
				boolean del = false;
				File[] lf = workFolder.listFiles();
				if (lf != null && lf.length > 0) {
					for (File f : lf) {
						del = f.delete();
						if (!del)
							throw new RuntimeException("[F]파일삭제오류");
					}
				}
				del = workFolder.delete();
				if (!del)
					throw new RuntimeException("[F]파일삭제오류");
			}
			workFolder.mkdirs();

			try {
				String[] items = null;
				boolean includeTxt = nxrpLinkSeDtlSn.equals("01");

				if (taskSeCd.equals("PVS")) {
					items = linkFileMaker.extractForPVS(crdnInfo,includeTxt).get();
				} else if (taskSeCd.equals("BPV")) {
					items = linkFileMaker.extractForBPV(crdnInfo,includeTxt).get();
				}

				if (nxrpLinkSeDtlSn.equals("01"))
					((AttachedTxtMaker)linkFileMaker).writeTextFileContents(workPath, items);

				FileQuery fileQuery = new FileQuery()
					.setInfoType(Crdn.INF_TYPE)
					.setInfoKeys(crdnID)
					.setOrderBy("SRT_ORD");
				List<DataObject> crdnFileList = fileBean.getFileList(fileQuery);
				for (int j=0; (j<crdnFileList.size()) && (j < linkFileMaker.getMaxImageFileCnt()); j++) {
					linkFileMaker.copyFile(workPath, crdnFileList.get(j).string("FILE_PATH"), j, items);
				}

				File[] fileList = workFolder.listFiles(new FilenameFilter() {
					@Override
					public boolean accept(File dir, String name) {
						return !(name.toUpperCase().endsWith(".ZIP"));
					}
				});
				String[] fileNameList = new String[fileList.length];
				for (int i = 0; i < fileList.length; i++) {
					fileNameList[i] = fileList[i].getPath();
				}

				String zipFilePath = workPath + "/" + linkFileMaker.getZipFileName();
				new ZIP().compress(zipFilePath, fileNameList);

				for (File file : fileList) {
					if (!file.delete())
						throw new RuntimeException("[F]파일 삭제 중 오류가 발생하였습니다.");
				}

				String ESB_Folder_Path = JobConf.get().getDir("send")+"/"+JobConf.get().getDirCode("lntris");
				ensureDir(ESB_Folder_Path);
				File src = new File(zipFilePath);
				File dst = new File(ESB_Folder_Path+"/"+linkFileMaker.getZipFileName());
				src.renameTo(dst);

				Crdn crdn = new Crdn();
				crdn.setCrdnId(crdnID);
				crdn.setModifiedBy(currentUser().getId());
				int affected = crdnUpdtMapper.updateNxrpCrdnLinkYn(crdn);
				if (affected != 1)
					throw new RuntimeException(rtnMsg += "세외수입 연계 여부 변경 중 오류가 발생하였습니다.");
			} catch (Exception e) {
				throw runtimeException(e);
			}
		}
		return "[S]처리되었습니다.";
	}

	private Object convert(Object s, Class<? extends Object> t) {
		DataObject convert = json.getObjectMapper().convertValue(s, DataObject.class);
		DataObject convert2 = new DataObject();

		Field[] fs = t.getDeclaredFields();
		for (Field f :  fs) {
			String fn = f.getName();
			String val = convert.string(fn);
			convert2.set(fn, val);
		}
		return json.getObjectMapper().convertValue(convert2, t);
	}
}