/*********************************************************************
*  All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名			：eo顧客基幹システム
*	モジュール名		：JKKXmlParser
*	ソースファイル名	：JKKXmlParser.java
*	作成者				：富士通　
*	作成日				：2011年8月11日
*＜機能概要＞
*　XML、Mapを解析する共通部品です。
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v1.00.00	2011/08/11	富士通		新規作成
*********************************************************************/
package eo.common.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;


/**
 * 引数で渡されたXML文、Mapを解析する共通部品です。
 * <br>
 * @author 富士通
 */
public class JKKXmlParser extends DefaultHandler 
{
	/**
	 * Map
	 */
	@SuppressWarnings("unchecked")
	private Map nowMapRef = null;
	/**
	 * データMap
	 */
	@SuppressWarnings("unchecked")
	private Map dataMap = new HashMap();

	/**
	 * 要素配列
	 */
	@SuppressWarnings("unchecked")
	private   List<String> elements = new ArrayList<String>();

	/**
	 * 表示用フォーマット格納用変数
	 * @return dataMap 
	 */
	@SuppressWarnings("unchecked")
	public Map getDataMap()
	{
		return dataMap;
	}

	/**
	 * オブジェクトをXML文字列に変換する
	 * @param obj オブジェクト
	 * @param listNames リスト名
	 * @throws Exception　例外
	 * @return Mapから生成したXML文
	 */
	public static String convertXml(Object obj, String...listNames) throws NullPointerException
	{
		// ■■■ 2012/6/27 Nullチェック追加改修 M.IKUMA START ■■■
		//パラメタチェックを行います
		if(null == listNames)
		// ■■■ 2012/6/27 Nullチェック追加改修 M.IKUMA   END ■■■
		{
			return "";
		}
		//情報領域を設定
		StringBuffer sb = new StringBuffer();
		//オブジェクトのnull判定
		if (null == obj) 
		{
			//空文字を設定
			sb.append("");
			//引数のオブジェクトがストリング型か判定する
		} 
		else if (obj instanceof String) 
		{
			//引数の文字列を情報領域に追加
			sb.append((String)obj);
			//引数のオブジェクトがMap型か判定する
		}
		else if (obj instanceof Map)
		{
			//オブジェクトをキャストします
			Map map = (Map)obj;
			//キーのセットビューを取得し、そこから反復子を取得
			Iterator iterator = map.keySet().iterator();
			//反復子が要素を持つか判定します
			while (iterator.hasNext()) 
			{
				//反復子の要素を取り出します
				String key = (String)iterator.next();
				// ■■■ 2012/6/27 Nullチェック追加改修 M.IKUMA START ■■■
				// keyをチェック
				if(key == null)
				{
					// 空白を返す
					return "";
				}
				// ■■■ 2012/6/27 Nullチェック追加改修 M.IKUMA   END ■■■
				//取り出した反復子からキーを元に値をとります
				Object val = map.get(key);
				//xml文字列領域を設定
				String xmlStr = null;
				//上記で取得した反復子がリスト型か判定します
				if (val instanceof List) 
				{
					//再起処理を行います
					xmlStr = convertXml(val, key);
				}
				else
				{
					//再起処理を行います
					xmlStr = convertXml(val);
				}
				//<キー>を設定し改行します
				sb.append("<" + key + ">");
				//値を設定し改行します
				sb.append(xmlStr);
				String[] keyAry =  key.split(" ");
				sb.append("</" + keyAry[0] + ">");
			}

		} 
		else if (obj instanceof List) 
		{
			// ■■■ 2012/6/27 Nullチェック追加改修 M.IKUMA START ■■■
			if(0 == listNames.length || null == listNames[0])
			{
				return "";
			}
			// ■■■ 2012/6/27 Nullチェック追加改修 M.IKUMA   END ■■■
			List list = (List)obj;
			String key = listNames[0];
			for (Object val : list) {
				String xmlStr = convertXml(val);
				sb.append("<" + key + ">");
				sb.append(xmlStr);
				String[] keyAry = key.split(" ");
				sb.append("</" + keyAry[0] + ">");
			}
		}

		return sb.toString();
	}

	/**
	 * リクエストから取得したXMLを解析しMapに変換する
	 * @param servletInputStream XML文
	 * @return XML文から生成したMap
	 */
	@SuppressWarnings("unchecked")
	public static Map parseXml(InputStream servletInputStream)
	{
		// 受信したXMLデータを解析
		JKKXmlParser myXmlParser = new JKKXmlParser();
		try 
		{
			SAXParserFactory spfactory = SAXParserFactory.newInstance();
			SAXParser parser = spfactory.newSAXParser();
			parser.parse(servletInputStream, myXmlParser);
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		} 
		catch (ParserConfigurationException e)
		{
			e.printStackTrace();
		} 
		catch (SAXException e) 
		{
			e.printStackTrace();
		}

		return myXmlParser.getDataMap();
	}


	/**
	 * エレメントの開始時
	 * @param uri URL
	 * @param localName 
	 * @param tagName 
	 * @param attr 
	 * @throws SAXException
	 */
	
	@SuppressWarnings("unchecked")
	@Override
	public void startElement(String uri, String localName, String tagName,
			Attributes attr) throws SAXException
	{
		Object nowObj = dataMap;
		for (int i = 0; i < elements.size(); i++)
		{
			String elementName = elements.get(i);
			Map nowMap = null;
			if (nowObj instanceof Map) 
			{
				nowMap = (Map)nowObj;
			}
			else if (nowObj instanceof List)
			{
				List nowList = (List)nowObj;
				nowMap = (Map)nowList.get(nowList.size() - 1);
			}
			nowObj = nowMap.get(elementName);
		}

		Map nowMap = null;
		if (nowObj instanceof Map)
		{
			nowMap = (Map)nowObj;
		} 
		else if (nowObj instanceof List) 
		{
			List nowList = (List)nowObj;
			nowMap = (Map)nowList.get(nowList.size() - 1);
		}

		if (!nowMap.containsKey(tagName))
		{
			nowMap.put(tagName, new HashMap());
		} 
		else 
		{
			Object nowBase = nowMap.get(tagName);
			List nowList = null;
			if (nowBase instanceof List)
			{
				nowList = (List)nowBase;
			} 
			else 
			{
				nowList = new ArrayList();
				nowList.add((Map)nowBase);
			}
			nowList.add(new HashMap());
			nowMap.put(tagName, nowList);
		}
		nowMapRef = nowMap;
		elements.add(tagName);
	}

	/**
	 * エレメントのボディ部を取得
	 * @param chars
	 * @param offset
	 * @param length
	 * @throws SAXException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void characters(char[] chars, int offset, int length) throws SAXException 
	{

		String nodeData = new String(chars, offset, length);
		String checkData = nodeData;
		checkData = checkData.replaceAll("\r\n", "");
		checkData = checkData.replaceAll("\n", "");
		checkData = checkData.replaceAll("\t", "");
		checkData = checkData.replaceAll(" ", "");
		if (checkData.length() > 0)

		{
			String nowName = elements.get(elements.size() - 1);
			nowMapRef.put(nowName, nodeData);
		}
	}

	/**
	 * エレメントの終了時
	 * @param arg0
	 * @param arg1
	 * @param arg2
	 * @throws SAXException
	 */
	@Override
	public void endElement(String arg0, String arg1, String arg2)
	throws SAXException
	{
		elements.remove(elements.size() - 1);
	}

	/**
	 * ドキュメントの終了時
	 * @throws SAXException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void endDocument() throws SAXException 
	{
		dataMap = (Map)replaceEmptyMap(dataMap);
	}

	/**
	 * 空のマップをnullに置き換える
	 * @param obj オブジェクト
	 * @return オブジェクト
	 */
	@SuppressWarnings("unchecked")
	private Object replaceEmptyMap(Object obj)
	{

		if (obj instanceof Map)
		{
			Map nowMap = (Map)obj;
			if (nowMap.isEmpty())
			{
				return null;
			}
			else 
			{
				Iterator iterator = nowMap.keySet().iterator();
				while (iterator.hasNext())
				{
					String mapKey = (String)iterator.next();
					Object recObj = replaceEmptyMap(nowMap.get(mapKey));
					nowMap.put(mapKey, recObj);
				}
			}
		}
		else if(obj instanceof List) 
		{
			List nowList = (List)obj;
			for (int i = 0; i < nowList.size(); i++) 
			{
				Object nowObj = nowList.get(i);
				nowObj = replaceEmptyMap(nowObj);
				nowList.set(i, nowObj);
			}
		}
		return obj;
	}

}
