package com.eactive.eai.rms.onl.manage.rule.layoutsync;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import org.apache.commons.httpclient.util.DateUtil;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.eactive.eai.rms.common.base.OnlBaseService;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.util.StringUtils;
import com.eactive.eai.rms.data.entity.onl.layout.LayoutService;
import com.eactive.eai.rms.onl.manage.rule.layout.LayoutDao;
import com.eactive.eai.rms.onl.manage.serviceinfo.eaimsg.EaiMsgDao;

@Service("layoutSyncService")
public class LayoutSyncService extends OnlBaseService {
    @Autowired
    @Qualifier("layoutDao")
    private LayoutDao dao;
    
    @Autowired
    private EaiMsgDao eaiMsgDao;
    
    @Autowired
    private LayoutService layoutService;

    public List<HashMap<String,Object>> getAllEAIMessages(HashMap<String, String> param) throws Exception {
    	return eaiMsgDao.selectListAll(param);
    }
    
    public void addLayoutSyncLog(HashMap<String, String> param) throws Exception {
    	dao.addLayoutSyncLog(param);
    }
    
    public void insertLayout(HashMap<String,Object> vo, List<HashMap<String,Object>> items) 
            throws Exception {
    	deleteLayout(vo);
    	dao.insert(vo);
    	
    	for(HashMap<String,Object> item : items) {
    		dao.insertItem(item);
    	}
    }
    
    public void insertLayoutItems(String layoutName, List<HashMap<String,Object>> items) 
    		throws Exception {
    	
    	HashMap<String,Object> paramMap = new HashMap<>();
    	paramMap.put("loutName", layoutName);
    	dao.deleteItemAll(paramMap);
    	for(HashMap<String,Object> item : items) {
    		dao.insertItem(item);
    	}
    }

    public void deleteLayout(HashMap<String,Object> vo) 
            throws Exception {
    	layoutService.findById(Objects.toString(vo.get("loutName"))).ifPresent(layoutService::delete);
    }
    
    public List<HashMap<String,Object>> getAllLayouts() throws Exception {
    	HashMap<String,Object> param = new HashMap<String,Object>();
    	return dao.selectListAll(param);
    }
    

    public HashMap<String, String> migrationLayoutToXML(HashMap<String, String> param) {
    	HashMap<String, String> result = new HashMap<String, String>();

        try {
	        // 1. 전문 설정 
	    	SAXBuilder builder = new SAXBuilder();
	    	String fileName =  param.get("path") + "/layout-messagesync-req.xml";
	    	File f = new File( fileName );
	    	logger.debug("=== JDOM BUILD ===");
	    	Document doc = null;
	    	try {
				doc = builder.build(f);
			} catch (JDOMException e) {
				// TODO Auto-generated catch block
				logger.error("build error", e); 
				//e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				//e.printStackTrace();
				logger.error(" error", e); 
			}

			Element root = doc.getRootElement();
			List<Element> messages = root.getChildren();
			logger.debug("messages.size() : " + messages.size());
			logger.debug("messages(0) : " + messages.get(0).getName());
			logger.debug("messages(1) : " + messages.get(1).getName());
			Element header = messages.get(0);
			Element serviceName = header.getChild("ServiceName");
			Element command = header.getChild("Command");
			logger.debug("messages(0)(serviceName) : " + serviceName.getText());
			logger.debug("messages(0)(command) : " + command.getValue());
	
			Element body = root.getChild("Body");
			body.removeChild("Layout");  // 샘플 레이아웃 삭제
			
			//2. LAYOUT Format 설정 
        	Element Layout = new Element("Layout");
        	Element id = new Element("id");
        	Element data = new Element("data");
        	// 레이아웃 항목 조회 (XML 변환 용으로 조회 )     	
        	List<LayoutSyncVo> xmlList = dao.getMigrationLayout(param);
        	result.put("layoutName", xmlList.get(0).getId());
    	
			Layout.addContent(id);
			Layout.addContent(data);
			body.addContent(Layout);
			id.setText(xmlList.get(0).getId());
			logger.debug("messages(1)(id) : " + id.getText());
		
			// 3. data 부의 CDATA 생성 
			Document lDoc = new Document();
			Element format = new Element(LayoutSyncVo.TYPE_FORMAT);
			Element group = null;
			boolean isPut = false;
	        //전문데이터
	    	for(LayoutSyncVo lout : xmlList) {    		
	    		lout.setType(lout.getType().trim());
//	    		logger.info(xmlList.get(0).getId() + "[group=" + (group == null ? "group" : group.getParentElement()) + "]" +  lout);
	    		
	    		if( LayoutSyncVo.TYPE_FORMAT.equals(lout.getFieldType()) ) {
	    			String useSys  = DataSourceContextHolder.getDataSourceType().getName();
	    			
	    			// 레이아웃 Format 정보 확인
	    			HashMap<String,Object> vo = new HashMap<String,Object>();
	    			vo.put("loutName",param.get("LoutName"));
	    			
	    			
	    			HashMap<String,Object> detail = dao.selectDetail(vo);
	    			List dateFormat = new ArrayList();
	    			dateFormat.add("yyyyMMddhhmmssSS");
	    			dateFormat.add("yyyyMMddhhmmss");
	    			String date    = DateUtil.formatDate(DateUtil.parseDate((String)detail.get("LASTAMNDHMS"), dateFormat), "yyyy-MM-dd hh:mm:ss");
	    			String[] str   = lout.getId().split("_");
	    			String ioType  = str[str.length-1];
	    			
	    			String msgType = "";
	    			if( "BYTES".equals(detail.get("LOUTPTRNNAME")) ) {
			        	msgType = "ASCII";
			        } else if( "VBYTES".equals(detail.get("LOUTPTRNNAME")) ) {
			        	msgType = "VASCII";
			        }
	    			format.setAttribute("id"   ,     StringUtils.trimToEmpty(lout.getId()            ) );   // 전문레이아웃ID
	    			format.setAttribute("desc",      StringUtils.trimToEmpty(lout.getDesc()          ) );   // 전문레이아웃 설명
	    			format.setAttribute("author",    StringUtils.trimToEmpty(param.get("userId")     ) );   // 작업자
	    			format.setAttribute("usesystem", StringUtils.trimToEmpty(useSys                  ) );   // 사용시스템
	    			format.setAttribute("group",     StringUtils.trimToEmpty((String)detail.get("EAIBZWKDSTCD")) );   // 업무그룹
	    			format.setAttribute("date",      StringUtils.trimToEmpty(date                    ) );   // 작업일시 (최종수정일시)
	    			format.setAttribute("msgType",   StringUtils.trimToEmpty(msgType                 ) );   // 메세지타입
	    			format.setAttribute("ioType",    StringUtils.trimToEmpty(ioType                  ) );   // 입출력구분
	    			format.setAttribute("part",      StringUtils.trimToEmpty(""                      ) );   // 전문 part     ( for MCI )
	    			format.setAttribute("type",      StringUtils.trimToEmpty(""                      ) );   // 채널, 업무구분 ( for MCI )
	    		} else {
	    			Element el = new Element(lout.getFieldType());
	    			//Grid 고정카운트면 maxCnt에 값넣구 count="" 가변카운트면 count에 값넣구 maxCnt="0"
	    			el.setAttribute( "no"         , StringUtils.trimToEmpty(String.valueOf(lout.getNo())    ) );  // 번호
	    			el.setAttribute( "id"         , StringUtils.trimToEmpty(lout.getId()                    ) );  // 항목명
					el.setAttribute( "desc"       , StringUtils.trimToEmpty(lout.getDesc()                  ) );  // 한글항목명
					el.setAttribute( "depth"      , StringUtils.trimToEmpty(String.valueOf(lout.getDepth()) ) );  // 깊이
					el.setAttribute( "maxCnt"     , StringUtils.trimToEmpty(String.valueOf(lout.getMaxCnt())) );  // 반복최대갯수
					el.setAttribute( "count"      , StringUtils.trimToEmpty(lout.getCount()                 ) );  // 반복횟수참조정보
					el.setAttribute( "type"       , StringUtils.trimToEmpty(lout.getType()                  ) );  // 데이터타입
					el.setAttribute( "len"        , StringUtils.trimToEmpty(String.valueOf(lout.getLen())   ) );  // 데이터길이
					el.setAttribute( "scale"      , StringUtils.trimToEmpty(String.valueOf(lout.getScale()) ) );  // 소수점자리수
					el.setAttribute( "default"    , StringUtils.trimToEmpty(lout.getDefault()               ) );  // 기본값
					el.setAttribute( "object"     , StringUtils.trimToEmpty(""                              ) );  // 화면오브텍트
					el.setAttribute( "mask"       , StringUtils.trimToEmpty(lout.getMask()                  ) );  // 마스킹여부
					el.setAttribute( "point_yn"   , StringUtils.trimToEmpty(""                              ) );  // 소수점포함여부
					el.setAttribute( "batc_info"  , StringUtils.trimToEmpty(""                              ) );  // 레코드유형
					el.setAttribute( "rec_tp_yn"  , StringUtils.trimToEmpty(""                              ) );  // 레코드유형구분여부
					el.setAttribute( "rec_tp_val" , StringUtils.trimToEmpty(""                              ) );  // 레코드유형값

	    			if( "Group".equals(lout.getFieldType()) || "Grid".equals(lout.getFieldType()) ) {
	    				if( group != null ) { format.addContent(group); isPut = true;}
	    				group = (Element) el.clone();
	    				isPut = false;
	    				logger.info(lout.getFieldType() + ":" + format.getContentSize());
	    			} else if ("Field".equals(lout.getFieldType()) || "Column".equals(lout.getFieldType()) ) {
	    				if( group != null ) { group.addContent(el); }
	    				else { format.addContent(el); }
	    			} else {
	    				format.addContent(el);
	    				logger.info("none:" + format.getContentSize());
	    			}
	    		}
	    	} // end for data
	    	if( !isPut && group != null ) { format.addContent(group); } 
	    	lDoc.addContent(format);
    	
	    	try {
	        	data.setText("<![CDATA[" + StringUtils.toXMLString(lDoc, 5, true) + StringUtils.rightPad(" ", 3) + "]]>");
	    		logger.debug("messages(1)(data) : " + doc.getProperty("endocing"));
	    		result.put("xmlQuery", StringUtils.toXMLString(doc, true));
			} catch (Exception e) {
				// TODO Auto-generated catch block
				//e.printStackTrace();
				logger.error("messages error", e); 
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			logger.error(" error", e); 
		}
    	return result;
    }
    
    public String getLayoutMappingXMLList(HashMap<String, String> param) throws Exception {
    	List<HashMap<String, String>> xmlList = dao.getLayoutMappingXMLList(param);

		Document doc = new Document();
		Element root = new Element("Message");
		
		//1. Header 설정
		Element head = new Element("Header");
		Element svcn = new Element("ServiceName");
		svcn.setText("MessageMapping");
		head.addContent(svcn);
		root.addContent(head);
		
		//2. Body 설정
		Element body = new Element("Body");
        //전문데이터
    	for(HashMap<String, String> vo : xmlList) {    	
    		Element lout = new Element("Layout");
    		lout.setAttribute("cmd", param.get("cmd"));
    		
    		Iterator<String> keys = vo.keySet().iterator();    		
    		while(keys.hasNext()) {
    			String key = keys.next();
    			lout.setAttribute(key, StringUtils.defaultString(vo.get(key),""));
    		}
    		body.addContent(lout);
    	}
    	root.addContent(body);
    	doc.setRootElement(root);
    	
    	//3. xml표현
    	String xmlQuery = StringUtils.toXMLString(doc, true);
    	
    	return xmlQuery;
    }

    public void addLayoutMappingSyncLog(HashMap<String, String> param) throws Exception {
    	dao.addLayoutMappingSyncLog(param);
    }
    
    public void recvLayoutMappingSyncLog(HashMap<String, String> param) throws Exception {
    	dao.recvLayoutMappingSyncLog(param);
    }
    
    public HashMap<String, String> getLayoutXMLList(HashMap<String, String> param) {
    	HashMap<String, String> result = new HashMap<String, String>();
    	
    	List<LayoutSyncVo> xmlList = dao.getLayoutXMLList(param);
    	result.put("layoutName", xmlList.get(0).getId());
    	
    	SAXBuilder builder = new SAXBuilder();
    	String fileName =  param.get("path") + "/layout-messagesync-req.xml";
    	File f = new File( fileName );
    	logger.info("=== JDOM BUILD ===");
    	Document doc = null;
    	try {
			doc = builder.build(f);
		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			logger.error("build error", e); 
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			logger.error("build error", e); 
		}
		Element root = doc.getRootElement();
		List<Element> messages = root.getChildren();
		logger.debug("messages.size() : " + messages.size());
		logger.debug("messages(0) : " + messages.get(0).getName());
		logger.debug("messages(1) : " + messages.get(1).getName());
		Element header = messages.get(0);
		Element serviceName = header.getChild("ServiceName");
		Element command = header.getChild("Command");
		logger.debug("messages(0)(serviceName) : " + serviceName.getText());
		logger.debug("messages(0)(command) : " + command.getValue());
		
		Element body = root.getChild("Body").getChild("Layout");
		Element id = body.getChild("id");
		Element data = body.getChild("data");
		id.setText(xmlList.get(0).getId());
		logger.debug("messages(1)(id) : " + id.getText());
		
		Document layout = new Document();
		Element format = new Element(LayoutSyncVo.TYPE_FORMAT);
		
        //전문데이터
    	for(LayoutSyncVo lout : xmlList) {    		
    		lout.setType(lout.getType().trim());
    		
    		if( LayoutSyncVo.TYPE_FORMAT.equals(lout.getFieldType()) ) {
    			format.setAttribute(LayoutSyncVo.LAYOUT_ID   , lout.getId());
    			format.setAttribute(LayoutSyncVo.LAYOUT_DESC , lout.getDesc());
    			format.setAttribute(LayoutSyncVo.LAYOUT_MSGTP, "Offset"      );
    			format.setAttribute(LayoutSyncVo.LAYOUT_PART , "data"        );
    			format.setAttribute(LayoutSyncVo.LAYOUT_TYPE , "business"    );
    		} else if( LayoutSyncVo.TYPE_GRID.equals(lout.getFieldType()) ) {
    			Element grid = new Element(LayoutSyncVo.TYPE_GRID);
                grid.setAttribute( LayoutSyncVo.LAYOUT_ID   , lout.getId()                    );
                grid.setAttribute( LayoutSyncVo.LAYOUT_DESC , lout.getDesc()                  );
                grid.setAttribute( LayoutSyncVo.LAYOUT_TYPE , lout.getType()                  );
                grid.setAttribute( LayoutSyncVo.LAYOUT_LEN  , String.valueOf(lout.getLen())   );
                grid.setAttribute( LayoutSyncVo.LAYOUT_SCALE, String.valueOf(lout.getScale()) );
                grid.setAttribute( LayoutSyncVo.LAYOUT_COUNT, lout.getCount()                 );
                format.addContent(grid);
    		} else {
    			Element el = new Element(lout.getFieldType());
	            el.setAttribute( LayoutSyncVo.LAYOUT_ID   , lout.getId()                    );  
	            el.setAttribute( LayoutSyncVo.LAYOUT_DESC , lout.getDesc()                  );  
	            el.setAttribute( LayoutSyncVo.LAYOUT_TYPE , lout.getType()                  );  	            
                el.setAttribute( LayoutSyncVo.LAYOUT_LEN  , String.valueOf(lout.getLen())   );
                el.setAttribute( LayoutSyncVo.LAYOUT_SCALE, String.valueOf(lout.getScale()) );
	            format.addContent(el);
    		}
    	}
    	layout.addContent(format);
    	
    	//String sb = null;
    	try {
        	data.setText("<![CDATA[" + StringUtils.toXMLString(layout, 5, true) + StringUtils.rightPad(" ", 3) + "]]>");
    		logger.debug("messages(1)(data) : " + doc.getProperty("endocing"));
    		result.put("xmlQuery", StringUtils.toXMLString(doc, true));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			logger.error("messages error", e); 
		}
    	return result;
    }
    

    public String syncLayout(String url, String xmlQuery) throws Exception {
        logger.info("[XML] " + xmlQuery);
        OutputStream oos    = null;  
        InputStream  ois    = null;
		StringBuffer result = new StringBuffer();

        // Connection 연결
        URL u = null;
        try {
            u = new URL(url);
        } catch (MalformedURLException e) {
            logger.error("", e );
        }

        HttpURLConnection conn = null;

        try {
            conn = (HttpURLConnection) u.openConnection();            
        } catch (ConnectException ce) {
            logger.error("", ce );
            //ce.printStackTrace();
        } catch (IOException ie) {
            logger.error("", ie );
            //ie.printStackTrace();
        } catch (Exception e) {
            logger.error("", e );
           // e.printStackTrace();        
        }

        if (conn != null) {
//            conn.setDoInput(true);
            conn.setDoOutput(true);
//            conn.setUseCaches(false);
        } else {
            logger.error("LayoutSyncManController.syncLayout] getURLConnection Error. - " 
            		   + url + " 의 HttpURLConnection 을 생성할 수 없습니다.");
        }

        try {
            if (conn != null) {
                conn.setRequestMethod("POST");
            }
        } catch (ProtocolException pe) {
            logger.error("LayoutSyncManController.syncLayout] getURLConnection ProtocolException. - "
            		   + pe.getMessage());
        }
        if (conn != null) {
        	conn.setRequestProperty( "User-Agent", "Mozilla/4.0" );
            conn.setRequestProperty( "Content-type", "application/xml"); //application/octet-stream
//            conn.setRequestProperty( "Content-Length", ""+xmlQuery.toString().getBytes("utf-8").length);
            conn.setConnectTimeout(10 * 1000);  // 10sec
        }
        try {
        	// SEND
        	oos = conn.getOutputStream();
        	oos.write(xmlQuery.getBytes());
        	oos.flush();
        	oos.close();
        	
        	// RECV
        	ois = conn.getInputStream();

    		BufferedInputStream buf = null;
    		byte[] byteBuffer = new byte[1024];
			buf = new BufferedInputStream(ois);
			int i = -1;
			while((i = buf.read(byteBuffer, 0, 1024)) != -1)
			{
				result.append(new String(byteBuffer,0 , i));
			}
			
        	logger.info("LayoutSyncManController.syncLayout] get Result XML - " + result.toString());
        } catch (ConnectException e) {
            logger.error("LayoutSyncManController.syncLayout] sendCommand ConnectException. - " 
            		   + conn.getURL()+ " can't Connect"+e.getMessage());
            throw e;
        } catch (IOException e2) {
            logger.error("LayoutSyncManController.syncLayout] sendCommand IOException. - "
            		   + conn.getURL()+ " can't IO" +e2.getMessage());
            throw e2;
        } catch (Exception e) {
            logger.error("LayoutSyncManController.syncLayout] sendCommand Exception. - "
            		   + conn.getURL()+e.getMessage());
            throw e;
        } finally {
            try {
                if (oos != null ) oos.close();
                else if( ois != null ) ois.close();
            } catch (IOException e) {
                oos = null;
                ois = null;
                logger.error("LayoutSyncManController.syncLayout] sendCommand Error. - "+e.getMessage());
            }  catch (Exception e) {
                oos = null;
                ois = null;
                logger.error("LayoutSyncManController.syncLayout] sendCommand Error. - "+e.getMessage());
            } 
        } // end of finally
    	return result.toString();
    }
}