package incheon.sgp.por.web;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.egovframe.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import incheon.ags.por.service.PorExternalService;
import incheon.ags.por.util.PorConnectUtils;
import incheon.ags.por.vo.PorRtmsVO;
import lombok.RequiredArgsConstructor;


/**
 * @ClassName : PorRtmsController.java
 * @Description : 공간정보포털 컨트롤러
 *
 * @author : 관리자
 * @since : 2025. 07. 17
 * @version : 1.0
 *
 *		  <pre>
 * << 개정이력(Modification Information) >>
 *
 *   수정일			  수정자			   수정내용
 *  -------------  ------------   ---------------------
 *   2023. 10. 10	관리자			   최초 생성
 *   2024. 12. 19	관리자			   패널 기반 플랫폼으로 전면 개편
 *   2025. 07. 17	관리자			   공간정보포털로 전환
 *		  </pre>
 *
 */
@Controller
@RequestMapping("/sgp/por")
@RequiredArgsConstructor
public class PorEstateInfoController {
    @Autowired private ObjectMapper objectMapper;

	private final PorExternalService porExternalService;
	private final PorConnectUtils porConnectUtils;
	
	private final String BROKERAGE_URL_IMAP = "https://imap.incheon.go.kr/real_estate_info/getBrokerageOfficeList.jsp";
	private final String BROKERAGEOFFICE_URL_IMAP = "https://imap.incheon.go.kr/real_estate_info/getBrokerageOffice.jsp";
	private final String BROKER_URL_IMAP = "https://imap.incheon.go.kr/real_estate_info/getBrokerList.jsp";
	private final String DEVELOPMENT_URL_IMAP = "https://imap.incheon.go.kr/real_estate_info/getDevelopmentListTest.jsp";
	private final String DEVELOPMENTVIEW_URL_IMAP = "https://imap.incheon.go.kr/real_estate_info/getDevelopment.jsp";
	private final String DEVELOPMENTTBP_URL_IMAP = "https://imap.incheon.go.kr/real_estate_info/getDevelopmentbp.jsp";
	
	final int BORKERAGE_RECORD_COUNT_PER_PAGE = 9;
	final int DEVELOPMENT_RECORD_COUNT_PER_PAGE = 9;
	
	@Value("${por.klis.api.mode}")
	private String klisMode;
	
	@Value("${por.klis.api.url}")
	private String klisUrl;
	
	private final String KLIS_KEY = "+dwUo1kGt+ISoo8o0PFmpH+7qlX+zKIi";
	

	/**
	 * 통합포탈 메인화면 진입페이지
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/soapSample.do")
	public String index(HttpServletRequest request, ModelMap model) throws Exception {
		
		return "sgp/por/soapSample";
	}
	
	/**
	 * kb 데이터 변환 테스트 페이지
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/kbSample.do")
	public String kbSample(HttpServletRequest request, ModelMap model) throws Exception {
		
		return "sgp/por/kbSample";
	}
	
	/**
	 * 아이맵 소개 페이지
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/intro.do")
	public String intro(HttpServletRequest request, ModelMap model) throws Exception {
		
		return "sgp/por/introduce";
	}

	/**
	 * soap 결과 데이터
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@PostMapping("/soap.do")
	@ResponseBody
	public Map<String, Object> soap(@RequestBody Map<String, String> map, HttpServletRequest request, ModelMap model) throws Exception {
		String resultText = porConnectUtils.klisSoap(map);
		
		Map<String, Object> resultMap = new HashMap<String, Object>();
		resultMap.put("data", resultText);
		
		return resultMap;
	}
	
	/**
	 * 부동산정보조회 화면
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/info/brokerage.do")
	public String brokerage( @RequestParam(defaultValue = "1") int page , @ModelAttribute PorRtmsVO porRtmsVO, HttpServletRequest request, ModelMap model ) throws Exception {
		String svcCode = "SVC0000117";
		String lawdCd = "";
		String cmpNm = "";
		String raRegNo = "";
		String sort = "";
		String sortOrder = "";
		
		if(porRtmsVO.getLawdCd() != null) {
			lawdCd = porRtmsVO.getLawdCd();
		}else {
			// 페이징정보
			PaginationInfo paginationInfo = new PaginationInfo();
			paginationInfo.setTotalRecordCount(0);
			paginationInfo.setCurrentPageNo(page);
			paginationInfo.setRecordCountPerPage(BORKERAGE_RECORD_COUNT_PER_PAGE);
			paginationInfo.setPageSize(10);

			model.addAttribute("data", new JSONArray());
			model.addAttribute("paginationInfo", paginationInfo);
			model.addAttribute("totalCount", 0);
			
			return "sgp/por/info/brokerage";
		}
		if(porRtmsVO.getCmpNm() != null) {
			cmpNm = porRtmsVO.getCmpNm();
		}
		if(porRtmsVO.getRaRegno() != null) {
			raRegNo = porRtmsVO.getRaRegno();
		}
		if(porRtmsVO.getSort() != null) {
			sort = porRtmsVO.getSort();
		}
		if(porRtmsVO.getSortOrder() != null) {
			sortOrder = porRtmsVO.getSortOrder();
		}
		
		int perPage = BORKERAGE_RECORD_COUNT_PER_PAGE; // 9

		if(("prod").equals(klisMode)) {
			String cacheKey = porConnectUtils.makeCacheKey("BROKERAGE", lawdCd, cmpNm, raRegNo, sort, sortOrder);

			@SuppressWarnings("unchecked")
			Map<String, Object> cache = (Map<String, Object>) request.getSession().getAttribute("KLIS_ROWS_CACHE");

			JSONArray allRows = null;

			if(cache != null && cacheKey.equals(String.valueOf(cache.get("key")))){
				Object cached = cache.get("rows");
				if(cached instanceof JSONArray){
					allRows = (JSONArray) cached;
				}
			}

			if(allRows == null){
				allRows = new JSONArray();

				int chunk = 200;
				int startNumInt = 1;

				String lastFirstKey = null;

				for(int loop=0; loop<100; loop++){
					int endNumInt = startNumInt + chunk - 1;

					String soapRequest = buildBrokerageSoapRequest(svcCode, lawdCd, String.valueOf(startNumInt), String.valueOf(endNumInt), cmpNm, raRegNo, sort, sortOrder);

					Map<String, String> paramMap = new HashMap<String, String>();
					paramMap.put("soapRequest", soapRequest);
					paramMap.put("url", klisUrl);

					String resultText = porConnectUtils.klisSoap(paramMap);

					JSONObject response = parseKlisResponse(resultText);
					JSONArray part = rowsAsArray(response);

					if(part == null || part.size() == 0) break;

					String firstKey = "";
					Object firstRow = part.get(0);
					if(firstRow instanceof JSONArray){
						JSONArray r = (JSONArray) firstRow;
						String k1 = (r.size() > 2) ? String.valueOf(r.get(2)) : "";
						String k2 = (r.size() > 3) ? String.valueOf(r.get(3)) : "";
						firstKey = k1 + "|" + k2;
					}

					if(lastFirstKey != null && lastFirstKey.equals(firstKey) && part.size() == chunk) break;
					
					lastFirstKey = firstKey;

					allRows = porConnectUtils.mergeRows(allRows, part);

					if(part.size() < chunk) break;

					startNumInt += chunk;
				}

				Map<String, Object> newCache = new HashMap<String, Object>();
				newCache.put("key", cacheKey);
				newCache.put("rows", allRows);
				if(allRows.size() > 0){
					request.getSession().setAttribute("KLIS_ROWS_CACHE", newCache);
				}
			}

			int totalCount = allRows.size();
			JSONArray pageRows = porConnectUtils.sliceRows(allRows, page, perPage);

			PaginationInfo paginationInfo = new PaginationInfo();
			paginationInfo.setTotalRecordCount(totalCount);
			paginationInfo.setCurrentPageNo(page);
			paginationInfo.setRecordCountPerPage(perPage);
			paginationInfo.setPageSize(10);

			model.addAttribute("paginationInfo", paginationInfo);
			model.addAttribute("totalCount", totalCount);
			model.addAttribute("data", pageRows);

			return "sgp/por/info/brokerage";
		}else{
			Map<String, String> p = new HashMap<String, String>();

			p.put("url", this.BROKERAGE_URL_IMAP);
			p.put("param", "?sggCd=" + lawdCd + "&cmpNm=" + cmpNm + "&raRegno=" + raRegNo + "&sort=" + sort + "&sortOrder=" + sortOrder + "&pageIdx=" + page);

			JSONObject kras = porConnectUtils.kras(p);

			int totalCount = 0;
			JSONArray pageRows = new JSONArray();

			if(kras != null && kras.get("Rows") != null && !"0".equals(String.valueOf(kras.get("TotalCount")))){
				JSONObject rows = (JSONObject) kras.get("Rows");
				Object v = rows.get("Value");

				if(v instanceof JSONObject){
					JSONObject value = (JSONObject) v;
					JSONArray dataArr = (JSONArray) value.get("Data");
					if(dataArr != null){
						totalCount = Integer.parseInt(String.valueOf(dataArr.get(12)));
						pageRows.add(dataArr);
					}
				}else if(v instanceof JSONArray){
					JSONArray values = (JSONArray) v;
					for(int i=0;i<values.size();i++){
						JSONObject one = (JSONObject) values.get(i);
						JSONArray dataArr = (JSONArray) one.get("Data");
						if(dataArr != null){
							if(totalCount == 0){
								totalCount = Integer.parseInt(String.valueOf(dataArr.get(12)));
							}
							if(pageRows.size() < perPage){
								pageRows.add(dataArr);
							}
						}
					}
				}
			}

			PaginationInfo paginationInfo = new PaginationInfo();
			paginationInfo.setTotalRecordCount(totalCount);
			paginationInfo.setCurrentPageNo(page);
			paginationInfo.setRecordCountPerPage(perPage);
			paginationInfo.setPageSize(10);

			model.addAttribute("data", pageRows);
			model.addAttribute("paginationInfo", paginationInfo);
			model.addAttribute("totalCount", totalCount);

			return "sgp/por/info/brokerage";
			// end - 개발용 테스트 및 화면확인용
		}
	}
	
	/**
	 * 부동산정보 상세조회 화면
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/info/brokerageOffice.do")
	public String brokerageOffice(
			@ModelAttribute PorRtmsVO porRtmsVO
			, ModelMap model
			) throws Exception {
		// 오피스 정보
		Map<String, String> paramMap = new HashMap<String, String>();
		
		String svcCode = "SVC0000119";
		String cmbSgg = "";
		String sysRegno = "";
		String raRegno = "";
		
		if(porRtmsVO.getCmbSgg() != null) {
			cmbSgg = porRtmsVO.getCmbSgg();
		}
		if(porRtmsVO.getSysRegno() != null) {
			sysRegno = porRtmsVO.getSysRegno();
		}
		if(porRtmsVO.getRaRegnoData() != null) {
			raRegno = porRtmsVO.getRaRegnoData();
		}
		
		System.out.println("porRtmsVO : " + porRtmsVO);
		
		if(("prod").equals(klisMode)) {
			// 중개업장 정보
			String soapRequest = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://service.soap.wes.ows.skcc.com\">"
					+ "	<soapenv:Header/>"
					+ "	<soapenv:Body>"
					+ "		<ser:getKlisData soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
					+ "			<in0 xsi:type=\"ent:RequestEntity\""
					+ "				xmlns:ent=\"http://entity.soap.wes.ows.skcc.com\">"
					+ "				<hashMap xsi:type=\"xs:Map\""
					+ "					xmlns:xs=\"http://xml.apache.org/xml-soap\">"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">SVC_CODE</key>"
					+ "						<value xsi:type=\"xsd:string\">" + svcCode + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">V_SGG_CD</key>"
					+ "						<value xsi:type=\"xsd:string\">" + cmbSgg + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">V_SYS_REGNO</key>"
					+ "						<value xsi:type=\"xsd:string\">" + sysRegno + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">KLIS_KEY</key>"
					+ "						<value xsi:type=\"xsd:string\">" + KLIS_KEY + "</value>"
					+ "					</item>"
					+ "				</hashMap>"
					+ "			</in0>"
					+ "		</ser:getKlisData>"
					+ "	</soapenv:Body>"
					+ "</soapenv:Envelope>";
			
			System.out.println("soapRequest : " + soapRequest);
			
			paramMap.put("soapRequest", soapRequest);
			paramMap.put("url", klisUrl);
			
			String resultText = porConnectUtils.klisSoap(paramMap);
			System.out.println("resultText : " + resultText);
			model.addAttribute("resultText", resultText);

			JSONObject response = parseKlisResponse(resultText);
			JSONArray infoRows = rowsAsArray(response);
			JSONArray info = new JSONArray();
			if(infoRows.size() > 0){
				info = (JSONArray) infoRows.get(0);
			}
			model.addAttribute("info", info);
			
			// 중개업자 목록
			svcCode = "SVC0000103";
			soapRequest = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://service.soap.wes.ows.skcc.com\">"
					+ "	<soapenv:Header/>"
					+ "	<soapenv:Body>"
					+ "		<ser:getKlisData soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
					+ "			<in0 xsi:type=\"ent:RequestEntity\""
					+ "				xmlns:ent=\"http://entity.soap.wes.ows.skcc.com\">"
					+ "				<hashMap xsi:type=\"xs:Map\""
					+ "					xmlns:xs=\"http://xml.apache.org/xml-soap\">"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">SVC_CODE</key>"
					+ "						<value xsi:type=\"xsd:string\">" + svcCode + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">V_SGG_CD</key>"
					+ "						<value xsi:type=\"xsd:string\">" + cmbSgg + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">V_RA_REGNO</key>"
					+ "						<value xsi:type=\"xsd:string\">" + raRegno + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">KLIS_KEY</key>"
					+ "						<value xsi:type=\"xsd:string\">" + KLIS_KEY + "</value>"
					+ "					</item>"
					+ "				</hashMap>"
					+ "			</in0>"
					+ "		</ser:getKlisData>"
					+ "	</soapenv:Body>"
					+ "</soapenv:Envelope>";
			
			paramMap.put("soapRequest", soapRequest);
			resultText = porConnectUtils.klisSoap(paramMap);

			JSONObject response2 = parseKlisResponse(resultText);
			JSONArray brokerList = rowsAsArray(response2);

			model.addAttribute("brokerList", brokerList);
			model.addAttribute("page", porRtmsVO.getPageIndex());
			
			return "sgp/por/info/brokerageOffice";
		}else {
			paramMap.put("url", this.BROKERAGEOFFICE_URL_IMAP);
			paramMap.put("param", "?sggCd=" + porRtmsVO.getCmbSgg() + "&sysRegno=" + porRtmsVO.getSysRegno());
			
			// 2. Data조회
			JSONObject infoData = porConnectUtils.kras(paramMap);
			
			System.out.println("data : " + infoData);
			
			JSONArray infoArray = new JSONArray();
			if(infoData != null){
				if(!("0").equals(infoData.get("TotalCount")) && infoData.get("Rows") != null) {
					JSONObject rows = (JSONObject) infoData.get("Rows");
					if(("1").equals(String.valueOf(infoData.get("TotalCount")))){
						JSONObject value = (JSONObject) rows.get("Value");
						infoArray = (JSONArray) value.get("Data");
					}
				}
			}
			
			
			JSONArray brokerArray = new JSONArray();
			if(infoArray.size() > 0) {
				paramMap.put("url", this.BROKER_URL_IMAP);
				paramMap.put("param", "?sggCd=" + porRtmsVO.getCmbSgg() + "&raRegno=" + infoArray.get(2));
				
				// 2. Data조회
				JSONObject brokerData = porConnectUtils.kras(paramMap);
				
				System.out.println("data : " + brokerData);
				
				if(brokerData != null){
					JSONObject rows = (JSONObject) brokerData.get("Rows");
					if(("1").equals(String.valueOf(brokerData.get("TotalCount")))){
						JSONObject value = (JSONObject) rows.get("Value");
						JSONArray object = (JSONArray) value.get("Data");
						brokerArray.add(object);
					}else {
						JSONArray value = (JSONArray) rows.get("Value");
						JSONObject element = (JSONObject) value.get(0);
						JSONArray object = (JSONArray) element.get("Data");
						
						for(int i = 0; i < value.size(); i++){
							JSONObject valueObject = (JSONObject) value.get(i);
							JSONArray dataArray = (JSONArray) valueObject.get("Data");
							brokerArray.add(dataArray);
						}
						
					}
				}
			}
			
			model.addAttribute("page", porRtmsVO.getPageIndex());
			model.addAttribute("info", infoArray);
			model.addAttribute("brokerList", brokerArray);
		}
		
		return "sgp/por/info/brokerageOffice";
	}
	
	/**
	 * 중개보수 계산 화면
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/info/popup/calculate.do")
	public String calculate(
			) throws Exception {
		return "sgp/por/info/popup/calculate";
	}
	
	/**
	 * 교육기관 안내 화면
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/info/popup/guide.do")
	public String guide(
			) throws Exception {
		return "sgp/por/info/popup/guide";
	}
	
	/**
	 * 부동산정보조회 화면
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/info/development.do")
	public String development(@RequestParam(defaultValue = "1") int page, @ModelAttribute PorRtmsVO porRtmsVO, HttpServletRequest request, ModelMap model) throws Exception {
		String svcCode = "SVC0000104";
		String cmpNm = "";
		String regNm = "";
		String regStsCd = "";
		String corpGbn = "";
		String addrText = "";
		
		if(porRtmsVO.getCmpNm() != null) {
			cmpNm = porRtmsVO.getCmpNm();
		}
		if(porRtmsVO.getRegNm() != null) {
			regNm = porRtmsVO.getRegNm();
		}
		if(porRtmsVO.getRegStsCd() != null) {
			regStsCd = porRtmsVO.getRegStsCd();
		}
		// regStsCd 고정값
		regStsCd = "10";
		if(porRtmsVO.getCorpGbn() != null) {
			corpGbn = porRtmsVO.getCorpGbn();
		}
		if(porRtmsVO.getAddrText() != null) {
			addrText = porRtmsVO.getAddrText();
		}
		
		if(("prod").equals(klisMode)) {
			int perPage = DEVELOPMENT_RECORD_COUNT_PER_PAGE; // 9

			String cacheKey = porConnectUtils.makeCacheKey("DEVELOPMENT", "28", cmpNm, regNm, addrText, corpGbn);

			@SuppressWarnings("unchecked")
			Map<String, Object> cache = (Map<String, Object>) request.getSession().getAttribute("KLIS_ROWS_CACHE");

			JSONArray allRows = null;

			if(cache != null && cacheKey.equals(String.valueOf(cache.get("key")))) {
				Object cached = cache.get("rows");
				if(cached instanceof JSONArray) {
					allRows = (JSONArray) cached;
				}
			}

			if(allRows == null) {
				allRows = new JSONArray();

				int chunk = 200;
				int startNumInt = 1;

				String lastFirstKey = null;

				for(int loop=0; loop<100; loop++) {
					int endNumInt = startNumInt + chunk - 1;

					String soapRequest = buildDevelopmentSoapRequest(svcCode, cmpNm, regNm, addrText, regStsCd, corpGbn, "28", String.valueOf(startNumInt), String.valueOf(endNumInt));

					Map<String, String> paramMap = new HashMap<String, String>();
					paramMap.put("soapRequest", soapRequest);
					paramMap.put("url", klisUrl);

					String resultText = porConnectUtils.klisSoap(paramMap);

					JSONObject response = parseKlisResponse(resultText);
					JSONArray part = rowsAsArray(response);

					if(part == null || part.size() == 0) break;

					String firstKey = "";
					Object firstRow = part.get(0);
					if(firstRow instanceof JSONArray) {
						JSONArray r = (JSONArray) firstRow;
						String k1 = (r.size() > 0) ? String.valueOf(r.get(0)) : "";
						String k2 = (r.size() > 1) ? String.valueOf(r.get(1)) : "";
						firstKey = k1 + "|" + k2;
					}

					if(lastFirstKey != null && lastFirstKey.equals(firstKey)) break;
					lastFirstKey = firstKey;

					allRows = porConnectUtils.mergeRows(allRows, part);

					if(part.size() < chunk) break;

					startNumInt += chunk;
				}

				Map<String, Object> newCache = new HashMap<String, Object>();
				newCache.put("key", cacheKey);
				newCache.put("rows", allRows);
				if(allRows.size() > 0) {
					request.getSession().setAttribute("KLIS_ROWS_CACHE", newCache);
				}
			}

			int totalCount = allRows.size();
			JSONArray pageRows = porConnectUtils.sliceRows(allRows, page, perPage);

			PaginationInfo paginationInfo = new PaginationInfo();
			paginationInfo.setTotalRecordCount(totalCount);
			paginationInfo.setCurrentPageNo(page);
			paginationInfo.setRecordCountPerPage(perPage);
			paginationInfo.setPageSize(10);

			model.addAttribute("paginationInfo", paginationInfo);
			model.addAttribute("totalCount", totalCount);
			model.addAttribute("data", pageRows);

			return "sgp/por/info/development";
		}else{
			Map<String, String> p = new HashMap<String, String>();

			String encAddrText = "";
			if(addrText != null && !"".equals(addrText)){
				encAddrText = URLEncoder.encode(addrText, "UTF-8");
			}

			p.put("url", this.DEVELOPMENT_URL_IMAP);
			p.put("param", "?repNm=&regStsCd=" + regStsCd + "&addr=" + encAddrText + "&pageIdx=" + page + "&cmpNm=" + cmpNm);

			JSONObject kras = porConnectUtils.kras(p);

			int totalCount = 0;
			JSONArray pageRows = new JSONArray();

			if(kras != null && kras.get("Rows") != null && !"0".equals(String.valueOf(kras.get("TotalCount")))){
				JSONObject rows = (JSONObject) kras.get("Rows");
				Object v = rows.get("Value");

				if(v instanceof JSONObject){
					JSONObject value = (JSONObject) v;
					JSONArray dataArr = (JSONArray) value.get("Data");
					if(dataArr != null){
						totalCount = Integer.parseInt(String.valueOf(dataArr.get(10)));
						if(regNm != null && !"".equals(regNm)){
							if(String.valueOf(dataArr.get(3)).contains(regNm)){
								pageRows.add(dataArr);
							}
						}else{
							pageRows.add(dataArr);
						}
					}
				}else if(v instanceof JSONArray){
					JSONArray values = (JSONArray) v;
					for(int i=0;i<values.size();i++){
						JSONObject one = (JSONObject) values.get(i);
						JSONArray dataArr = (JSONArray) one.get("Data");
						if(dataArr != null){
							if(totalCount == 0){
								totalCount = Integer.parseInt(String.valueOf(dataArr.get(10)));
							}

							if(pageRows.size() >= DEVELOPMENT_RECORD_COUNT_PER_PAGE) continue;

							if(regNm != null && !"".equals(regNm)){
								if(String.valueOf(dataArr.get(3)).contains(regNm)){
									pageRows.add(dataArr);
								}
							}else{
								pageRows.add(dataArr);
							}
						}
					}
				}
			}

			PaginationInfo paginationInfo = new PaginationInfo();
			paginationInfo.setTotalRecordCount(totalCount);
			paginationInfo.setCurrentPageNo(page);
			paginationInfo.setRecordCountPerPage(DEVELOPMENT_RECORD_COUNT_PER_PAGE);
			paginationInfo.setPageSize(10);

			model.addAttribute("data", pageRows);
			model.addAttribute("paginationInfo", paginationInfo);
			model.addAttribute("totalCount", totalCount);

			return "sgp/por/info/development";
		}
	}
	
	/**
	 * 부동산정보조회 화면
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/info/development1.do")
	public String development1(
			@ModelAttribute PorRtmsVO porRtmsVO
			, ModelMap model
			) throws Exception {
		
		// 테스트용
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("endpointUrl", "http://10.10.232.13:8180/SoapSample/services/Development");
		paramMap.put("wsdlUrl", "http://10.10.232.13:8180/SoapSample/services/Development?wsdl");
		paramMap.put("qName", "http://DefaultNamespace");
		paramMap.put("serviceName", "DevelopmentService");
		paramMap.put("portName", "Development");
		paramMap.put("operationNameSpace", "http://DefaultNamespace");
		paramMap.put("operationName", "list");
		
		Map<String, Object> resultMap = porExternalService.connectSoap(paramMap);
		
		JSONArray list = (JSONArray) resultMap.get("list");
		
		if(list != null && list.size() > 10) {
			model.addAttribute("list", list.subList(0, 9));
		}else {
			model.addAttribute("list", list);
		}
		
		return "sgp/por/info/development";
	}
	
	/**
	 * 부동산정보 상세조회 화면
	 * @param model
	 * @return JSP 페이지
	 * @exception Exception
	 */
	@GetMapping("/info/developmentView.do")
	public String developmentView(
			@ModelAttribute PorRtmsVO porRtmsVO
			, ModelMap model
			) throws Exception {

		String svcCode = "SVC0000105";
		String edRegNo = "";
		
		if(porRtmsVO.getEdRegno() != null) {
			edRegNo = porRtmsVO.getEdRegno();
		}
		
		Map<String, String> paramMap = new HashMap<String, String>();
		
		if(("prod").equals(klisMode)) {
			// 중개업장 정보			
			String soapRequest = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://service.soap.wes.ows.skcc.com\">"
					+ "	<soapenv:Header/>"
					+ "	<soapenv:Body>"
					+ "		<ser:getKlisData soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
					+ "			<in0 xsi:type=\"ent:RequestEntity\""
					+ "				xmlns:ent=\"http://entity.soap.wes.ows.skcc.com\">"
					+ "				<hashMap xsi:type=\"xs:Map\""
					+ "					xmlns:xs=\"http://xml.apache.org/xml-soap\">"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">SVC_CODE</key>"
					+ "						<value xsi:type=\"xsd:string\">" + svcCode + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">V_ED_REGNO</key>"
					+ "						<value xsi:type=\"xsd:string\">" + edRegNo + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">V_SIDO_CD</key>"
					+ "						<value xsi:type=\"xsd:string\">28</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">KLIS_KEY</key>"
					+ "						<value xsi:type=\"xsd:string\">" + KLIS_KEY + "</value>"
					+ "					</item>"
					+ "				</hashMap>"
					+ "			</in0>"
					+ "		</ser:getKlisData>"
					+ "	</soapenv:Body>"
					+ "</soapenv:Envelope>";
			System.out.println("soapRequest : " + soapRequest);
			
			paramMap.put("soapRequest", soapRequest);
			paramMap.put("url", klisUrl);
			
			String resultText = porConnectUtils.klisSoap(paramMap);
			System.out.println("resultText : " + resultText);
			model.addAttribute("resultText", resultText);

			JSONObject response = parseKlisResponse(resultText);
			JSONArray infoRows = rowsAsArray(response);

			JSONArray info = new JSONArray();
			if(infoRows.size() > 0){
				info = (JSONArray) infoRows.get(0);
			}
			model.addAttribute("info", info);

			// 실적조회
			svcCode = "SVC0000106";
			soapRequest = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://service.soap.wes.ows.skcc.com\">"
					+ "	<soapenv:Header/>"
					+ "	<soapenv:Body>"
					+ "		<ser:getKlisData soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
					+ "			<in0 xsi:type=\"ent:RequestEntity\""
					+ "				xmlns:ent=\"http://entity.soap.wes.ows.skcc.com\">"
					+ "				<hashMap xsi:type=\"xs:Map\""
					+ "					xmlns:xs=\"http://xml.apache.org/xml-soap\">"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">SVC_CODE</key>"
					+ "						<value xsi:type=\"xsd:string\">" + svcCode + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">V_ED_REGNO</key>"
					+ "						<value xsi:type=\"xsd:string\">" + edRegNo + "</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">V_SIDO_CD</key>"
					+ "						<value xsi:type=\"xsd:string\">28</value>"
					+ "					</item>"
					+ "					<item xsi:type=\"xs:mapItem\">"
					+ "						<key xsi:type=\"xsd:string\">KLIS_KEY</key>"
					+ "						<value xsi:type=\"xsd:string\">" + KLIS_KEY + "</value>"
					+ "					</item>"
					+ "				</hashMap>"
					+ "			</in0>"
					+ "		</ser:getKlisData>"
					+ "	</soapenv:Body>"
					+ "</soapenv:Envelope>";
			paramMap.put("soapRequest", soapRequest);
			
			resultText = porConnectUtils.klisSoap(paramMap);

			JSONObject response2 = parseKlisResponse(resultText);
			JSONArray developList = rowsAsArray(response2);

			final int yearIdx = 2;

			List<Object> tmp = new ArrayList<Object>(developList);
			tmp.sort(new Comparator<Object>(){
				@Override
				public int compare(Object a, Object b){
					if(!(a instanceof JSONArray) || !(b instanceof JSONArray)) return 0;

					JSONArray ra = (JSONArray)a;
					JSONArray rb = (JSONArray)b;

					int ia = parseYear(ra, yearIdx);
					int ib = parseYear(rb, yearIdx);

					return Integer.compare(ib, ia);
				}

				private int parseYear(JSONArray row, int idx){
					if(row == null || row.size() <= idx || row.get(idx) == null) return 0;
					String y = String.valueOf(row.get(idx)).replaceAll("[^0-9]", "");
					if(y.isEmpty()) return 0;
					try{
						return Integer.parseInt(y);
					}catch(Exception e){
						return 0;
					}
				}
			});

			JSONArray sorted = new JSONArray();
			sorted.addAll(tmp);

			model.addAttribute("developList", sorted);
			model.addAttribute("page", porRtmsVO.getPageIndex());

			return "sgp/por/info/developmentView";
		}else {
		
			paramMap.put("url", this.DEVELOPMENTVIEW_URL_IMAP);
			paramMap.put("param", "?edRegno=" + porRtmsVO.getEdRegno());
			
			// 2. Data조회
			JSONObject infoData = porConnectUtils.kras(paramMap);
			
			System.out.println("data : " + infoData);
			
			JSONArray infoArray = new JSONArray();
			if(infoData != null){
				if(!("0").equals(infoData.get("TotalCount")) && infoData.get("Rows") != null) {
					JSONObject rows = (JSONObject) infoData.get("Rows");
					if(("1").equals(String.valueOf(infoData.get("TotalCount")))){
						JSONObject value = (JSONObject) rows.get("Value");
						infoArray = (JSONArray) value.get("Data");
					}
				}
			}
			
			
			JSONArray developArray = new JSONArray();
			if(infoArray.size() > 0) {
				paramMap.put("url", this.DEVELOPMENTTBP_URL_IMAP);
				paramMap.put("param", "?edRegno=" + porRtmsVO.getEdRegno());
				
				// 2. Data조회
				JSONObject brokerData = porConnectUtils.kras(paramMap);
				
				System.out.println("data : " + brokerData);
				
				if(brokerData != null){
					JSONObject rows = (JSONObject) brokerData.get("Rows");
					if(("1").equals(String.valueOf(brokerData.get("TotalCount")))){
						JSONObject value = (JSONObject) rows.get("Value");
						JSONArray object = (JSONArray) value.get("Data");
						developArray.add(object);
					}else {
						JSONArray value = (JSONArray) rows.get("Value");
						JSONObject element = (JSONObject) value.get(0);
						JSONArray object = (JSONArray) element.get("Data");
						
						for(int i = 0; i < value.size(); i++){
							JSONObject valueObject = (JSONObject) value.get(i);
							JSONArray dataArray = (JSONArray) valueObject.get("Data");
							developArray.add(dataArray);
						}
						
					}
				}
			}
			
			final int yearIdx = 2;

			List<Object> tmp = new ArrayList<Object>(developArray);
			tmp.sort(new Comparator<Object>(){
				@Override
				public int compare(Object a, Object b){
					if(!(a instanceof JSONArray) || !(b instanceof JSONArray)) return 0;

					JSONArray ra = (JSONArray)a;
					JSONArray rb = (JSONArray)b;

					int ia = parseYear(ra, yearIdx);
					int ib = parseYear(rb, yearIdx);

					return Integer.compare(ib, ia);
				}

				private int parseYear(JSONArray row, int idx){
					if(row == null || row.size() <= idx || row.get(idx) == null) return 0;
					String y = String.valueOf(row.get(idx)).replaceAll("[^0-9]", "");
					if(y.isEmpty()) return 0;
					try{
						return Integer.parseInt(y);
					}catch(Exception e){
						return 0;
					}
				}
			});

			JSONArray sorted = new JSONArray();
			sorted.addAll(tmp);
			developArray = sorted;
			
			model.addAttribute("page", porRtmsVO.getPageIndex());
			model.addAttribute("info", infoArray);
			model.addAttribute("developList", developArray);
		}
		
		// model.addAttribute("list", developmentTbpList);
		
		return "sgp/por/info/developmentView";
	}
	
	private String buildBrokerageSoapRequest(String svcCode, String lawdCd, String startNum, String endNum, String cmpNm, String raRegNo, String sort, String sortOrder){
		return "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://service.soap.wes.ows.skcc.com\">"
				+ "<soapenv:Header/>"
				+ "<soapenv:Body>"
				+ "<ser:getKlisData soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
				+ " <in0 xsi:type=\"ent:RequestEntity\" xmlns:ent=\"http://entity.soap.wes.ows.skcc.com\">"
				+ "  <hashMap xsi:type=\"xs:Map\" xmlns:xs=\"http://xml.apache.org/xml-soap\">"
				+ item("SVC_CODE", svcCode)
				+ item("V_LAWD_CD", lawdCd)
				+ item("V_START_NUM", startNum)
				+ item("V_END_NUM", endNum)
				+ item("V_CMP_NM", cmpNm)
				+ item("V_RA_REGNO", raRegNo)
				+ item("V_SORT", sort)
				+ item("V_SORT_ORDER", sortOrder)
				+ item("KLIS_KEY", KLIS_KEY)
				+ "  </hashMap>"
				+ " </in0>"
				+ "</ser:getKlisData>"
				+ "</soapenv:Body>"
				+ "</soapenv:Envelope>";
	}
	
	private String buildDevelopmentSoapRequest(String svcCode, String cmpNm, String regNm, String addrText, String regStsCd, String corpGbn, String sidoCd, String startNum, String endNum) {
		return "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://service.soap.wes.ows.skcc.com\">"
				+ "<soapenv:Header/>"
				+ "<soapenv:Body>"
				+ "<ser:getKlisData soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
				+ " <in0 xsi:type=\"ent:RequestEntity\" xmlns:ent=\"http://entity.soap.wes.ows.skcc.com\">"
				+ "  <hashMap xsi:type=\"xs:Map\" xmlns:xs=\"http://xml.apache.org/xml-soap\">"
				+ item("SVC_CODE", svcCode)
				+ item("V_CMP_NM", cmpNm)
				+ item("V_REP_NM", regNm)
				+ item("V_ADDR", addrText)
				+ item("V_REG_STS_CD", regStsCd)
				+ item("V_CORP_GBN", corpGbn)
				+ item("V_SIDO_CD", sidoCd)
				+ item("V_START_NUM", startNum)
				+ item("V_END_NUM", endNum)
				+ item("KLIS_KEY", KLIS_KEY)
				+ "  </hashMap>"
				+ " </in0>"
				+ "</ser:getKlisData>"
				+ "</soapenv:Body>"
				+ "</soapenv:Envelope>";
	}
	
	private String item(String key, String value){
		String v = (value == null) ? "" : value;
		return "   <item xsi:type=\"xs:mapItem\">"
			 + "	<key xsi:type=\"xsd:string\">" + key + "</key>"
			 + "	<value xsi:type=\"xsd:string\">" + v + "</value>"
			 + "   </item>";
	}

	

	///////////////////////////////////////////////////////////////////////////////////////////////////////////
	private JSONObject parseKlisResponse(String responseXml) throws Exception {
		if(responseXml == null) responseXml = "";
		String normalized = responseXml.trim();

		if(normalized.contains(":Envelope") || normalized.contains("<soapenv:Envelope") || normalized.contains("<Envelope")) {
			String inner = tagInner(normalized, "return");
			if(inner.isEmpty()) inner = tagInner(normalized, "string");
			if(!inner.isEmpty()) normalized = inner.trim();
		}

		normalized = unescapeXmlLoose(normalized);

		XmlMapper xmlMapper = new XmlMapper();
		JSONParser parser = new JSONParser();

		JsonNode node = xmlMapper.readTree(normalized.getBytes(StandardCharsets.UTF_8));
		String json = objectMapper.writeValueAsString(node);

		if(json.contains("&quot;")) json = json.replace("&quot;", "\"");

		JSONObject root = (JSONObject) parser.parse(json);

		Object responseObj = root.get("Response");
		if(responseObj instanceof JSONObject) return (JSONObject) responseObj;

		return root;
	}

	private String tagInner(String xml, String tagName) {
		if(xml == null || xml.isEmpty()) return "";
		String open1 = "<" + tagName + ">";
		String close = "</" + tagName + ">";
		int s = xml.indexOf(open1);
		if(s >= 0) {
			int e = xml.indexOf(close, s + open1.length());
			if(e > s) return xml.substring(s + open1.length(), e);
		}

		String open2 = "<" + tagName;
		s = xml.indexOf(open2);
		if(s >= 0) {
			int gt = xml.indexOf(">", s);
			if(gt >= 0) {
				int e = xml.indexOf(close, gt + 1);
				if(e > gt) return xml.substring(gt + 1, e);
			}
		}
		return "";
	}

	private String unescapeXmlLoose(String s) {
		if(s == null) return "";
		String prev = s;
		for(int i = 0; i < 2; i++) {
			String cur = prev.replace("&quot;", "\"").replace("&lt;", "<").replace("&gt;", ">").replace("&apos;", "'").replace("&amp;", "&");
			if(cur.equals(prev)) break;
			prev = cur;
		}
		return prev;
	}

	private JSONArray rowsAsArray(JSONObject response) {
		JSONArray rowsArray = new JSONArray();
		if(response == null) return rowsArray;

		Object resultDataObj = response.get("ResultData");
		if(resultDataObj == null) return rowsArray;

		if(resultDataObj instanceof JSONArray) {
			return (JSONArray) resultDataObj;
		}

		if(!(resultDataObj instanceof JSONObject)) return rowsArray;

		JSONObject resultData = (JSONObject) resultDataObj;
		JSONObject rows = (JSONObject) resultData.get("Rows");
		if(rows == null) return rowsArray;

		Object valueObj = rows.get("Value");
		if(valueObj == null) return rowsArray;

		if(valueObj instanceof JSONObject) {
			JSONObject v = (JSONObject) valueObj;
			Object data = v.get("Data");
			if(data instanceof JSONArray) rowsArray.add((JSONArray) data);
		} else if(valueObj instanceof JSONArray) {
			JSONArray values = (JSONArray) valueObj;
			for(int i = 0; i < values.size(); i++) {
				Object one = values.get(i);
				if(one instanceof JSONObject) {
					Object data = ((JSONObject) one).get("Data");
					if(data instanceof JSONArray) rowsArray.add((JSONArray) data);
				}
			}
		}
		return rowsArray;
	}

}