package com.eactive.eai.agent;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import com.eactive.eai.agent.command.Command;
import com.eactive.eai.common.dao.DAOFactory;
import com.eactive.eai.common.server.EAIServerDAO;
import com.eactive.eai.common.server.EAIServerVO;
import com.eactive.eai.common.util.Logger;


/**
* 1. 기능 : 등록된 EAI Server 에 Command를 broadcast
* 2. 처리 개요 : 등록된 EAI Server 에 Command를 broadcast
* 3. 주의사항
*
* @author
* @version  v 1.0.0
* @see  관련 기능을 참조
* @since
*/
public class AgentUtil
{
    private static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

    private static final String WEB_AGENT_SERVLET_URL = "/BAPAppWeb/WebAgent";


    //생성자 (private : 객체 생성 불가)
    private AgentUtil() {}


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

        EAIServerDAO dao = (EAIServerDAO) DAOFactory.newInstance().create(EAIServerDAO.class);
        ArrayList<EAIServerVO> serverList = dao.getAllServerList();
        if (serverList ==  null || serverList.size() == 0) return null;
        
        HashMap<String, String> urlLists = new HashMap<String, String>();
        
        for (int i = 0; i<serverList.size(); i++) {
            EAIServerVO vo = (EAIServerVO) serverList.get(i);
            if (vo.getName().equalsIgnoreCase("ALL")) continue;  //서버명이 'ALL' 인 경우는 무시
			urlLists.put(vo.getName(), vo.toURL(EAIServerVO.HTTP_PROTOCOL) + WEB_AGENT_SERVLET_URL);
			logger.debug("[ AgentUtil ] getAllSvrUrl - URL : " + urlLists.get(vo.getName()));
        }
        return urlLists;
	}

	private static HashMap<String, String> getSvrUrl(EAIServerVO vo) throws Exception {

        if (vo ==  null) return null;
        
        HashMap<String, String> urlLists = new HashMap<String, String>();
		urlLists.put(vo.getName(), vo.toURL(EAIServerVO.HTTP_PROTOCOL) + WEB_AGENT_SERVLET_URL);
		logger.debug("[ AgentUtil ] getAllSvrUrl - URL : " + urlLists.get(vo.getName()));
        return urlLists;
	}

    public static HashMap<String, Object> broadcast(EAIServerVO serverVO, Command command) throws Exception {
		return broadcast(getSvrUrl(serverVO), command);
	}

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

    public static HashMap<String, Object> callMainServer(Command command) throws Exception {
		return broadcast(getSvrUrl(getMainServerVO()), command);
	}
    
    public static EAIServerVO getServerVO(String serverName) throws Exception {
        if (serverName == null || serverName.equals("")) throw new Exception("서버명 파라미터가 null 또는 공백입니다.");
        
        EAIServerDAO dao = (EAIServerDAO) DAOFactory.newInstance().create(EAIServerDAO.class);
        ArrayList<EAIServerVO> serverList = dao.getAllServerList();
        if (serverList ==  null || serverList.size() == 0) return null;
        
        for (int i = 0; i < serverList.size(); i++) {
            EAIServerVO vo = (EAIServerVO) serverList.get(i);
            if (vo.getName().equals(serverName)) return vo;
        }
        
        return null;
    }
    
    public static EAIServerVO getMainServerVO() throws Exception {

        EAIServerDAO dao = (EAIServerDAO) DAOFactory.newInstance().create(EAIServerDAO.class);
        ArrayList<EAIServerVO> serverList = dao.getAllServerList();

        if ( serverList.size() > 0 )
        	return serverList.get(0);
//        //서버명 중에 xxxxxi11 로 끝나는 서버를 메인서버로 본다.
//        for (int i = 0; serverList != null && i < serverList.size(); i++) {
//        	EAIServerVO vo = serverList.get(i);
////            if (vo.getName().endsWith("i11")) return vo;
//            return vo;
//        }        
        throw new Exception("서버정보 테이블(TSEAIBP03) 에 메인서버를 설정하세요.");
    }

    /**
     * 1. 기능 :  등록된 EAI Server에 Command를 broadcast
     * 2. 처리 개요 : 등록된 EAI Server의 URLConnection을 생성하여 Command broadcast하고
     *               전송된 결과값의 HashMap을 생성하여 반환
     * 3. 주의사항
     *
     * @param    command     broadcast할 Command
     * @return   HashMap     broadcast후 전송된 결과값.
     *                       전송된 데이터가 sucess가 아니면 Exception이 전송된 것임.
     * @exception    Exception
     **/
    public static HashMap<String, Object> broadcast(HashMap<String, String> servers, Command command) throws Exception {

        HashMap<String, Object> returnValue = new HashMap<String, Object>();

		logger.debug("[ AgentUtil ] broadcast 시작...");
        if (servers != null) {

            logger.debug("[ AgentUtil ] 대상 서버수 =" + servers.size());
            Iterator<String> it = servers.keySet().iterator();
            while (it.hasNext()) {
                String svrName = (String) it.next();
                String url = (String) servers.get(svrName);
                URLConnection urlCon = getURLConnection(url);
                try {
                    logger.debug("[ AgentUtil ] COMMAND = " + command);
                    Object response = sendCommand(urlCon, command);
                    returnValue.put(svrName, response);
                    
                } catch (Exception e) {
                    logger.error("[ AgentUtil ] ★★★★★ broadcast 예외 발생 !! ★★★★★", e);
                    returnValue.put(svrName, e.getMessage());
                }
				logger.debug("[ AgentUtil ] 대상 서버 ["+svrName+"] 결과 = ["+ returnValue.get(svrName) +"]");
            }

        } else {
			logger.error("[ AgentUtil ] 대상 서버 없음.");
        }
		logger.debug("[ AgentUtil ] broadcast 완료.");
        
        return returnValue;
    }

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

		ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        Object response = "";

        try {
            HashMap<String, Command> hm = new HashMap<String, Command>();
            hm.put("command", command);

            oos = new ObjectOutputStream(urlCon.getOutputStream());
            oos.writeObject((Serializable) hm);
            oos.flush();
            logger.debug("[ AgentUtil ] SendCommand - " + urlCon.getURL().toString() +" ["+ command.getClass().getName() + "]");

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

        } finally {
            try { if (oos != null) oos.close(); } catch (Exception ex) {}
            try { if (ois != null) ois.close(); } catch (Exception ex) {}
        }

        return response;
    }

    /**
     * 1. 기능 :  지정된  url의 URLConnection 생성
     * 2. 처리 개요 : 지정된  url의 URLConnection 생성
     * 3. 주의사항
     *
     * @param    url     URLConnection을 생성을 위한 url
     * @return   URLConnection 생성된 URLConnection
     * @exception
     **/
    private static URLConnection getURLConnection(String url) throws Exception {
        
        URL u = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) u.openConnection();

        if (conn == null) throw new Exception("HttpURLConnection 을 생성할 수 없습니다. (URL : "+ url +")");
        
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-type", "application/octet-stream");
        
        return conn;
    }

}