package com.eactive.eai.rms.bat.common.service;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.eactive.eai.agent.command.Command;
import com.eactive.eai.rms.bat.manage.comm.server.BatServerService;
import com.eactive.eai.rms.onl.common.service.AgentUtilService;

/** 
* 1. 기능 : 등록된 EAI Server 에 Command를 broadcast
* 2. 처리 개요 : 등록된 EAI Server 에 Command를 broadcast
* 3. 주의사항 
*
* @see  관련 기능을 참조
* @since  
*  
*/

@Service("batAgentUtilService")
public class BatAgentUtilServiceImpl implements AgentUtilService {
    private final Logger logger = Logger.getLogger(getClass());
//    final static String SERVLET_URL = "/BATAppWeb/WebAgent";
    final static String SERVLET_URL = "/BATWeb/WebAgent";

    private static int DEFAULT_CONNECT_TIME_OUT = 300; // 0 값을 입력하면 디폴트 값이 쓰이는 듯.
    
    /**
     * eaiServerInfoService 를 대체한다. 
     */
    @Autowired
    @Qualifier("batServerService")
    private BatServerService batServerService;

    /** 
    * 1. 기능 :  AgentUtil 기본 생성자
    * 2. 처리 개요 : 
    * 3. 주의사항 
    *
    * @param 
    * @return 
    * @exception
    **/
    public BatAgentUtilServiceImpl() {
    }

	private List<HashMap<String, String>> getAllSvrUrl() throws Exception {

		List<HashMap<String, Object>> mapList = batServerService.getEaiServerIpPort();
		List<HashMap<String, String>> resultList = new ArrayList<>();

		for (HashMap<String, Object> map : mapList) {

			HashMap<String, String> resultMap = new HashMap<String, String>();

			//String svr = System.getProperty("eai.datasource.type");
			String svrIp = (String) map.get("EAISVRIP");
			//String hostName = (String) map.get("HOSTNAME") + ".pobis.kr";
			String svrPort = (String) map.get("EAISVRLSNPORT");
			StringBuffer urlBuf = new StringBuffer();
			urlBuf.append("http://");
			//urlBuf.append(svr.equals("LOCAL") ? svrIp + ":" + svrPort : hostName + ":" + svrPort);
			urlBuf.append(svrIp + ":" + svrPort);
			urlBuf.append(SERVLET_URL);

			resultMap.put((String) map.get("EAISVRINSTNM"), urlBuf.toString());

			resultList.add(resultMap);
		}

		return resultList;
	}
    
    public HashMap<String, Object> broadcast(String serviceKey, Command command) throws Exception {
    	return broadcast(command);
    }
    
	public HashMap<String, Object> broadcast(Command command) throws Exception {

		URLConnection urlCon;
		List<HashMap<String, String>> servers = getAllSvrUrl();
		HashMap<String, Object> returnValue = new HashMap<String, Object>();

		for (HashMap<String, String> server : servers) {
			if (servers != null) {
				Iterator<String> it = server.keySet().iterator();
				String svrName = "";
				String url = "";
				Object response = "";

				while (it.hasNext()) {
					svrName = it.next();
					url = server.get(svrName);

					urlCon = getURLConnection(url);

					if (logger.isDebugEnabled()) {
						logger.debug("메모리동기화:cmd=" + command.getClass().getSimpleName() + " ,url=" + url);
					}

					try {
						if (urlCon != null) {// 취약점소스 수정 2020.08.27
							response = sendCommand(urlCon, command);
						}

						returnValue.put(svrName, response);
					} catch (Exception e) {
						logger.error("AgentUtil] broadcast Excpetion - " + url + e.getMessage());
						returnValue.put(svrName, e.getMessage());
					}
				}
			} else {
				logger.error("AgentUtil] broadcast Error. - url is null");
			}
		}

		return returnValue;

	}
    
    /** 
    * 1. 기능 :  해당 URLConnection으로 command 전송 처리 결과를 반환
    * 2. 처리 개요 : 해당 URLConnection으로 command 전송하고 처리 결과를 반환
    * 3. 주의사항 
    *
    * @param    urlCon  연결할 URLConnection
    * @param    command 전송할 Command
    * @return   String 처리된 결과 
    * @exception    Exception
    **/
	private String sendCommand(URLConnection urlCon, Command command)
            throws Exception {
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        String response = "";

        // 2009.05.22 서버가 다운되어 있는 경우 응답시간이 너무 길어서 timeout 값을 지정함.
        // 2009.07.09 타임아웃 값을 3000 -> 100 으로 조정함.
        urlCon.setConnectTimeout(DEFAULT_CONNECT_TIME_OUT);
        
        try {
            oos = new ObjectOutputStream(urlCon.getOutputStream());
            oos.writeObject(command);
            oos.flush();
            if( logger.isDebugEnabled() ) {
                logger.debug("AgentUtil] SendCommand - " + urlCon.getURL().toString());                
            }

            ois = new ObjectInputStream(urlCon.getInputStream());
            response = (String) ois.readObject();

        } catch (ConnectException e) {
            logger.error("AgentUtil] sendCommand "+ command.getName()+ " ConnectException. - " + urlCon.getURL() + " can't Connect" + e.getMessage());
            throw e;
        } catch (IOException e2) {
            logger.error("AgentUtil] sendCommand "+ command.getName()+ " IOException. - " + urlCon.getURL() + " error=" + e2.getMessage());
            throw e2;
        } catch (Exception e) {
            logger.error("AgentUtil] sendCommand "+ command.getName()+ " Exception. - " + urlCon.getURL() + e.getMessage());
            throw e;
        } finally {
            try {
            	//취약점코드 수정 2019.08.22 SW
                if (oos != null) {
                    oos.close();
                }
               
                if(ois != null){
                    ois.close();
                }
            } catch (IOException e) {
                oos = null;
                logger.error("AgentUtil] sendCommand Error. - " + e.getMessage());
            }
        }

        return response;
    }

    /** 
    * 1. 기능 :  지정된  url의 URLConnection 생성
    * 2. 처리 개요 : 지정된  url의 URLConnection 생성
    * 3. 주의사항 
    *
    * @param    url     URLConnection을 생성을 위한 url
    * @return   URLConnection 생성된 URLConnection
    * @exception
    **/
    private URLConnection getURLConnection(String url) {
        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 );
        } catch (IOException ie) {
            logger.error( ie );
        } catch (Exception e) {
            logger.error( e );
        }

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

        try {
            if (conn != null) {
                conn.setRequestMethod("POST");
            }
        } catch (ProtocolException pe) {
            logger.error("AgentUtil] getURLConnection ProtocolException. - "
                    + pe.getMessage());
        }
        if (conn != null) {
            conn.setRequestProperty("Content-type", "application/octet-stream");
        }
        return conn;
    }

	@Override
	public HashMap<String, Object> broadcast(Command command, String instanceName) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

}