package kr.gmtc.tss.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import kr.gmtc.tss.util.vo.NodeValue;



public class XmlParseUtil {
	

	/** Logger. */
	private static final Logger logger = LoggerFactory.getLogger(XmlParseUtil.class);
	



	public static Map<String,Object> parseXml(String fileDir) {

		File file = new File(fileDir);
		if(file==null||!file.exists()) {
			return null;
		}
		return parseXml(file);
	}
	
	public static Map<String,Object> parseXml(File file) {
//	String fileDir="D:\\TEMP\\20200714\\EXCH_ROOT\\CATALOG.XML";
		Map<String,Object> map=null;
		

		if(file==null||!file.exists()) {
			return map;
		}
		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = null;
		try {
			builder = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			
//			e.printStackTrace();
			logger.error("",e);
		}
		org.w3c.dom.Document doc = null;
		try {
			doc = builder.parse(file);
		} catch (SAXException | IOException e) {
			
//			e.printStackTrace();
//			logger.error("",e);
			InputStream inputStream = null;
			try {
				inputStream = new FileInputStream(file.getPath());
			} catch (FileNotFoundException e1) {
				
				logger.error("",e);
			}// Your InputStream from your database.
			Reader reader = null;
			try {
				reader = new InputStreamReader(inputStream, "UTF-8");
			} catch (UnsupportedEncodingException e1) {
				
				logger.error("",e);
			}

			InputSource is = new InputSource(reader);
			is.setEncoding("UTF-8");
			try {
				doc = builder.parse(is);
			} catch (SAXException | IOException e1) {
				
				logger.error("",e);
			}
		}

		if(doc==null) {
			return map;
		}
		
		NodeList nodeList = doc.getChildNodes();
		
		
		map=nodeListToMap(nodeList);

//		System.out.println(getNodeValue(map, "S-111_exchangeCatalogue/identiFier/daTe", true));
//		
//		System.out.println("content : "+getNodeTextContents(map, "S-111_exchangeCatalogue/identiFier/daTe", true));
//		System.out.println("end");
		return map;
	}
	
	
	
	
	private static String checkNode(String nodePath) {
		String firstNode="";

		if(nodePath.isEmpty()) {
			return firstNode;
		}
		
		if(nodePath.indexOf("/")==0) {
			nodePath=nodePath.substring(1);
		}
		firstNode=nodePath;
		return firstNode;
	}
	
	private static String getFirstNode(String nodePath) {
		String firstNode="";

		if(nodePath.isEmpty()) {
			return firstNode;
		}
		
		if(nodePath.contains("/")) {
			String [] nodeNms = nodePath.split("/");
			firstNode=nodeNms[0];
		}else {
			firstNode=nodePath;
		}
		
		return firstNode;
		
	}

	public static String getFirstPath(Map<String,Object> nodeMap) {
		String firstNode="";

		if(nodeMap.isEmpty()) {
			return firstNode;
		}
		
		ArrayList<String> keyList=MapUtil.toKeyArray(nodeMap);
		
		if(keyList.size()>0) {
			firstNode=keyList.get(0);
		}
//		
		
		return firstNode;
		
	}
	
	private static String getOtherNode(String curNode,String nodePath) {
		String otherNode="";

		if(nodePath.isEmpty()) {
			return otherNode;
		}
		
		nodePath=checkNode(nodePath);

		if(nodePath.contains("/")||nodePath.equals(curNode)) {
			otherNode=	nodePath.substring(curNode.length());
		}else {
			otherNode=nodePath;
		}
		
		return otherNode;
		
	}
	

	private static String getMapKey(Map<String,Object> nodeMap,String curNode) {
		return getMapKey(nodeMap, curNode, true);
	}
	
	
	private static String getMapKey(Map<String,Object> nodeMap,String curNode,boolean noCase) {
		String mapKey="";
		
		if(!noCase) {
			return curNode;
		}else {
			ArrayList<String> list=MapUtil.toKeyArray(nodeMap);
			
			for (int i = 0; i < list.size(); i++) {
				if(list.get(i).toLowerCase().equals(curNode.toLowerCase())) {
					mapKey=list.get(i);
				}
			}
			
		}
		return mapKey;
	}
	
	public static Object getNodeObject(Map<String,Object> nodeMap,String nodePath) {
		return getNodeObject(nodeMap, nodePath, true);
	}
	
	public static Object getNodeObject(Map<String,Object> nodeMap,String nodePath,boolean noCase) {
		Object nodeValue = null;
		try {
			
		
		String checkedNodePath=checkNode(nodePath);
		
		String curNode=getFirstNode(checkedNodePath);
		
		String otherNode=getOtherNode(curNode,checkedNodePath);
		
		if(!curNode.isEmpty()) {
			nodeValue= nodeMap.get(getMapKey(nodeMap, curNode, noCase));
			
			if(nodeValue!=null) {
//				nodeValue=getNodeValue(nodeMap, checkedNodePath, noCase);
				String chkdOtherNode=checkNode(otherNode);
				if(!chkdOtherNode.isEmpty()) {
					nodeValue=getNodeObject(((NodeValue)nodeValue).getChildMap(), otherNode, noCase);
				}
				
			}
			
		}
		} catch (NullPointerException e) {
			
//			e.printStackTrace();
			logger.error("",e);
		}
		return nodeValue;
	}

	

	public static NodeValue getNodeValue(Map<String,Object> nodeMap,String nodePath) {
		return getNodeValue(nodeMap, nodePath, true);
	}
	
	public static NodeValue getNodeValue(Map<String,Object> nodeMap,String nodePath,boolean noCase) {
		NodeValue nodeValue = null;
		try {
			
		
		String checkedNodePath=checkNode(nodePath);
		
		String curNode=getFirstNode(checkedNodePath);
		
		String otherNode=getOtherNode(curNode,checkedNodePath);
		
		if(!curNode.isEmpty()) {
			nodeValue=(NodeValue) nodeMap.get(getMapKey(nodeMap, curNode, noCase));
			
			if(nodeValue!=null) {
//				nodeValue=getNodeValue(nodeMap, checkedNodePath, noCase);
				String chkdOtherNode=checkNode(otherNode);
				if(!chkdOtherNode.isEmpty()) {
					nodeValue=getNodeValue(nodeValue.getChildMap(), otherNode, noCase);
				}
				
			}
			
		}
		} catch (NullPointerException e) {
			
//			e.printStackTrace();
			logger.error("",e);
		}
		return nodeValue;
	}


	public static List<NodeValue> getNodeValueList(Map<String,Object> nodeMap,String nodePath) {
		return getNodeValueList(nodeMap, nodePath, true);
	}
	

	public static List<NodeValue> getNodeValueList(Map<String,Object> nodeMap,String nodePath,boolean noCase) {
		
		Object nodeObj=getNodeObject(nodeMap, nodePath, noCase);
		
		if(nodeObj!=null&&(nodeObj.getClass()==List.class||nodeObj.getClass()==ArrayList.class)) {
			return (List<NodeValue> )nodeObj;
		}else {
			List<NodeValue> result = new ArrayList<>();
			if(nodeObj!=null)
				result.add((NodeValue)nodeObj);
			return result;
		}
		
	}

	public static Object getNodeData(Map<String,Object> nodeMap,String nodePath,int category) {
		return getNodeData(nodeMap, nodePath, true,category);
	}
	
	public static Object getNodeData(Map<String,Object> nodeMap,String nodePath,boolean noCase,int category) {
		NodeValue nodeValue=getNodeValue(nodeMap, nodePath, noCase);
		
		if(nodeValue!=null) {
			//1 : text
			//2 : ns
			//3 : nodename
			//4 : nodeFullname
			//5 : ndoeAttr
			//6 : nodeChild
			switch (category) {
			case 2:
				return getNodeValue(nodeMap, nodePath, noCase).getNodeNs();
			case 3:
				return getNodeValue(nodeMap, nodePath, noCase).getNodeName();
			case 4:
				return getNodeValue(nodeMap, nodePath, noCase).getNodeFullName();
			case 5:
				return getNodeValue(nodeMap, nodePath, noCase).getAttrMap();
			case 6:
				return getNodeValue(nodeMap, nodePath, noCase).getChildMap();
			default:
				return getNodeValue(nodeMap, nodePath, noCase).getText();
//				break;
			}
		}else {
			return null;
		}
		
	}

	public static String getNodeTextContents(Map<String,Object> nodeMap,String nodePath) {
		return getNodeTextContents(nodeMap, nodePath, true);
	}
	
	public static String getNodeTextContents(Map<String,Object> nodeMap,String nodePath,boolean noCase) {
		NodeValue nodeValue=getNodeValue(nodeMap, nodePath, noCase);
		
		if(nodeValue!=null) {
			return getNodeValue(nodeMap, nodePath, noCase).getText();	
		}else {
			return "";
		}
		
	}
	
	public static String getNodeNamespaceNm(Map<String,Object> nodeMap,String nodePath) {
		return getNodeNamespaceNm(nodeMap, nodePath, true);
	}
	
	public static String getNodeNamespaceNm(Map<String,Object> nodeMap,String nodePath,boolean noCase) {
		NodeValue nodeValue=getNodeValue(nodeMap, nodePath, noCase);
		
		if(nodeValue!=null) {
			return getNodeValue(nodeMap, nodePath, noCase).getNodeNs();	
		}else {
			return "";
		}
		
	}
	
//	public static void main(String[] args) {
//		System.out.println("node : "+getFirstNode("/asdfzxxcvzxc/saedf/asdf"));
//	}
	
	
	/*public static void main(String[] args) {
		String fileDir="D:\\TEMP\\20200714\\EXCH_ROOT\\CATALOG.XML";
		
		
		Map<String,Object> map=parseXml(fileDir);
		
//		System.out.println("content : "+getNodeTextContents(map, "S-111_exchangeCatalogue/identiFier/daTe", true));
//		System.out.println("end");
	}*/
	

	
	private static NodeValue putNodeData(Map<String,Object> map, Node node) {
		NodeValue nodeValue = new NodeValue(node.getNodeName(),node.getTextContent());
		
		
		if (node.hasAttributes()) {
			NamedNodeMap namedNodeMap = node.getAttributes();
			for (int j = 0; j < namedNodeMap.getLength(); j++) {
				// System.out.println("NodeNm : "+node.getNodeName()+", Name :
				// "+namedNodeMap.item(i).getNodeName()+", Value :
				// "+namedNodeMap.item(i).getNodeValue());
				nodeValue.putAttr(namedNodeMap.item(j).getNodeName(), namedNodeMap.item(j).getNodeValue());
			}
		}
		

		if(map.containsKey(nodeValue.getNodeName())) {
			Object data = map.get(nodeValue.getNodeName());
			if(data instanceof List<?>) {
				((List<NodeValue>) data).add(nodeValue);
			}else {
				List<NodeValue> valueList = new ArrayList<>();
				//기존데이터 리스트에 입력
				valueList.add((NodeValue) data);
				//현재 데이터 입력
				valueList.add(nodeValue);
				
//				map.put(node.getNodeName(), valueList);
				map.put(nodeValue.getNodeName(), valueList);
			}
		}else {
//			map.put(node.getNodeName(), nodeValue);
			map.put(nodeValue.getNodeName(), nodeValue);
		}
		
		
		return nodeValue;
		
		
	}
	
	
	  private static Map<String, Object> nodeListToMap(NodeList nodeList) {
		  
          Map<String, Object> map = new HashMap<String, Object>();
          for (int i = 0; i < nodeList.getLength(); i++) {
              Node node = nodeList.item(i);
              //#text로 잘못 생성되는 node 제거를 위함
              if("#text".equals(node.getNodeName())||"#comment".equals(node.getNodeName()))
              	continue;

              NodeValue nodeValue= putNodeData(map, node);

              if(node.hasChildNodes()) {
            	  
            	  nodeValue.setChildMap(nodeListToMap(node.getChildNodes()));
              }
//              if (x.hasChildNodes() == true) {
//                  int y = 1;
//                  String key = x.getNodeName();
//                  String tempkey = "";
//                  if (map.containsKey(key)) {
//                      do {
//                          y++;
//                          tempkey = key + "_" + y;
//                      } while (map.containsKey(tempkey) == true);
//                      map.put(tempkey, x.getTextContent().trim());
//                      tempkey = "";
//                  } else {
//                      map.put(key, x.getTextContent().trim());
//                  }
//              }
          }

          return map;
      }
	
	  

		public static Map<String,String> getAllNsOrXsiMap(Map<String,Object> nodeMap,boolean isNsMap){
			Map<String,String> nsMap = new HashMap<>();

			try {

				ArrayList<String> list = MapUtil.toKeyArray(nodeMap);

				for (int i = 0; i < list.size(); i++) {
					if(nodeMap.get(list.get(i)).getClass()!=NodeValue.class) {
						continue;
					}
						NodeValue nodeValue = (NodeValue) nodeMap.get(list.get(i));

					if(isNsMap)
						nsMap.putAll(nodeValue.getNsMap());
					else
						nsMap.putAll(nodeValue.getXsiMap());

					if (nodeValue.getChildMap() != null) {
						nsMap.putAll(getAllNsOrXsiMap(nodeValue.getChildMap(),isNsMap));
					}
				}
			} catch (NullPointerException e) {
				e.printStackTrace();
			}

			return nsMap;
		}
		
		
	
	
}

