package com.eactive.eai.rms.onl.common.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.httpclient.NameValuePair;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.eactive.eai.rms.onl.common.exception.EMSRuntimeException;

/**
 * <pre>
 * 1. 기능 : Xml 데이터를 DataSet으로 변환, 클라이언트로 전송한다.
 * 2. 처리 개요 :
 *     - 원격지 URL을 받아 실행한 결과 데이터(XML)를 DataSet으로 변환하여 리턴하거나
 *       클라이언트로 바로 전송한다.
 * 3. 주의사항 :
 * </pre>
 * @author  : vs.net
 * @version : $Revision: 1.29 $
 * @since : rts 2.0
 */
public class DataSetUtil {
    private final Logger logger = Logger.getLogger(DataSetUtil.class);

    private NodeList nodes;
    private String rowNodeName = "Row";
    private String columnNodeName = "Column";
    private String columnAttributeName = "name";
    private String columnAttributeType = "type";
    private String columnAttributeSize = "size";
    private String decimalDelemeter = ",";
    private int firstRowSize = 100;
    private NameValuePair[] postParams = null;
    private int limitRowCount = -1;
    private boolean isCreatedDataSetHeader = false;
    
    private List<HashMap<String,String>> headers = new ArrayList<HashMap<String,String>>();
    private List<HashMap<String,Object>> rows = new ArrayList<HashMap<String,Object>>();
    private HashMap<String,String> filter = new HashMap<String,String>();

    public void setFilter(HashMap<String,String> filter){
    	this.filter = filter;
    }
    public void setLimitRowCount(int rowCount) {
        limitRowCount = rowCount;
    }

    public String getDecimalDelemeter() {
		return decimalDelemeter;
	}
	public int getFirstRowSize() {
		return firstRowSize;
	}
	public int getLimitRowCount() {
		return limitRowCount;
	}
	public void setPostParameter(NameValuePair[] postParameters) {
        if (postParameters == null || postParameters.length == 0)
            throw new IllegalArgumentException(
                    "Post parameters cannot not be null.");

        postParams = postParameters;
    }

    /*
     * FirstRow Size를 설정한다.
     */
    public void setFirstRowSize(int rowSize) {
        if (rowSize < 1) {
            logger.error("first row size must great than zero.");
            throw new IllegalArgumentException("first row size too small.");
        }

        firstRowSize = rowSize;
    }

    /*
     * Xml의 컬럼을 식별하는 노드명을 설정한다.
     */
    public void setColumnNodeName(String nodeName) {
        if (nodeName == null || nodeName.length() < 1) {
            logger.error("Column Node Name cannot be null");
            throw new IllegalArgumentException(
                    "Column Node Name cannot be null");
        }

        columnNodeName = nodeName;
    }

    /*
     * Xml의 행을 식별하는 노드명을 설정한다.
     */
    public void setRowNodeName(String nodeName) {
        if (nodeName == null || nodeName.length() < 1) {
            logger.error("Row Node Name cannot be null");
            throw new IllegalArgumentException("Row Node Name cannot be null");
        }

        rowNodeName = nodeName;
    }

    /*
     * Decimal 타인인 경우 정수와 소수의 구분자를 설정한다.(디폴드 : ,)
     */
    public void setDecimalDelemeter(String delemeter) {
        if (delemeter == null || delemeter.length() < 1) {
            logger.error("Decimal Delemeter cannot be null");
            throw new IllegalArgumentException(
                    "Decimal Delemeter cannot be null");
        }

        decimalDelemeter = delemeter;
    }



    /*
     * 노드로부터 데이터 셋을 만들고 컬럼정보를 생성한다.
     */
    private void makeDataSetHeader(NodeList nodeList) throws Exception {

        // Column List를 추출하여 DataSet Column을 만든다.
        for (int i = 0; i < nodeList.getLength(); i++) {
            NamedNodeMap nnm = nodeList.item(i).getAttributes();
            String columnName = null;
            String columnType = null;
            String columnSize = null;

            for (int j = 0; j < nnm.getLength(); j++) {
                Node n = nnm.item(j);

                if (n.getNodeName().equalsIgnoreCase(columnAttributeName))
                    columnName = n.getNodeValue();
                else if (n.getNodeName().equalsIgnoreCase(columnAttributeType))
                    columnType = n.getNodeValue();
                else if (n.getNodeName().equalsIgnoreCase(columnAttributeSize))
                    columnSize = n.getNodeValue();
            }

            // XML의 애드리뷰트중 컬럼명과 컬럼 타입이 없으면 오류이다.
            if (columnName == null || columnType == null || columnSize == null)
                throw new Exception(
                        "Column Info(Name/Type/Size) value cannot be null at XML Data.");

            // 컬럼 추가
            HashMap<String,String> column = new HashMap<String,String>();
            column.put(columnAttributeName, columnName);
            column.put(columnAttributeType, columnType);
            column.put(columnAttributeSize, columnSize);
            headers.add(column);
        }
    }

    /*
     * 노드로 부터 데이터(행)를 추가한다.
     */
    private void addDataRows(NodeList nodes) {
    	 
        for (int i = 0; i < nodes.getLength(); i++) {
            NodeList nl = nodes.item(i).getChildNodes();
            int colIndex = -1;
            HashMap<String,Object> row = new HashMap<String,Object>();
            for (int j = 0; j < nl.getLength(); j++) {
                Node n = nl.item(j);
                if (n.getNodeType() == 3)
                    continue;
                colIndex++;
                HashMap<String,String> col = headers.get(colIndex);
                row.put(col.get(columnAttributeName), n.getTextContent());
            }
            if (filter.size()>0){
            	boolean isInclude = true;
            	for(String key : filter.keySet()){
            		String data = (String)row.get(key);
            		String value = filter.get(key);
            		if (data.indexOf(value)< 0){
            			isInclude = false;
            		}
            	}
            	if (isInclude){
            		rows.add(row);
            	}
            }else{
            	rows.add(row);
            }
        }
    }



    /*
     * HttpServletResponse와 Agent URL을 받아 클라이언트로 Data를 전송한다.
     * 주의 : 에러메시지를 클라이언트로 직접 전송하므로 에러를 throw 하지 않는다.
     * Get 방식으로 원격 실행
     */
    public List<HashMap<String,Object>> flushXmlToClient(String url) {
        return flushXmlToClient( new String[] { url });
    }
    
	public List<HashMap<String, Object>> flushXmlToClient(List<String> urls) {
		if (urls == null || urls.isEmpty()) {
			throw new EMSRuntimeException("The url is not defined");
		}

		return flushXmlToClient(urls.toArray(new String[urls.size()]));
	}

    /*
     * HttpServletResponse와 Agent URL을 받아 클라이언트로 Data를 전송한다.
     * 주의 : 에러메시지를 클라이언트로 직접 전송하므로 에러를 throw 하지 않는다.
     */
    public List<HashMap<String,Object>> flushXmlToClient( String[] url) {
        for (int i = 0; i < url.length; i++) {
            try {
                // CallAgentUtil로 부터 Xml을 받는다.
                CallAgentUtil agent = new CallAgentUtil();
                Document doc = null;

                // NameValuePair 가 있으면 Post 방식으로 없으면 Get 방식으로 호출한다.
                if (postParams != null && postParams.length > 0)
                    doc = agent.getAgentDataToDocument(url[i], postParams);
                else
                    doc = agent.getAgentDataToDocument(url[i]);

                if (doc == null) {
                    //						throw new Exception("Xml Document is null. Check your Xml Data.");
                    continue;
                }

                // Xml 노드 중 Column 정보를 가져와서 데이터셋 생성 및 컬럼을 생성한다.
                nodes = doc.getElementsByTagName(columnNodeName);

                if (isCreatedDataSetHeader == false) {
                    makeDataSetHeader(nodes);
                    isCreatedDataSetHeader = true;
                }

                // 로우 인서트
                nodes = doc.getElementsByTagName(rowNodeName);
                addDataRows(nodes);
            } catch (Exception e) {
            }
        }
        return rows;
    }
    
    /*
     * HttpServletResponse와 Agent URL을 받아 클라이언트로 Data를 전송한다.
     * 주의 : 에러메시지를 클라이언트로 직접 전송하므로 에러를 throw 하지 않는다.
     */
    public Document flushXmlToClient_ETC( String[] url) {
    	Document doc = null;
        for (int i = 0; i < url.length; i++) {
            try {
                // CallAgentUtil로 부터 Xml을 받는다.
                CallAgentUtil agent = new CallAgentUtil();
                // NameValuePair 가 있으면 Post 방식으로 없으면 Get 방식으로 호출한다.
                doc = agent.getAgentDataToDocument_ETC(url[i]);              
                
            } catch (Exception e) {
            }
        }
        return doc;
    }
    
}