/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JCKCtrlCisInfo
*   ソースファイル名：JCKCtrlCisInfo.java
*   作成者          ：富士通
*   日付            ：2015年05月25日
*＜機能概要＞
*   CISシステム SOAP連携（抽象）コマンド発行部品です。
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v16.00.00   2015/05/25	FJ)酒井		【ANK-2480-00-00】対応 新電力
*   v16.00.01   2015/08/18	FJ)頼経		【IT1-2015-0000075】対応 
*
**********************************************************************/
package eo.ejb.common;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * eo電気サービス契約お客様変更処理部品クラスです。
 * @author 富士通
 */
public abstract class JCKCtrlCisInfo
{
	/**
	 * CISシステム接続モード
	 */
	private static final String CIS_CONNECTION_MODE = "CIS_CONNECTION_MODE";

	/**
	 * 1:CISシステム
	 */
	private static final String CIS_SYSTEM = "1";

	/**
	 * 2:スタブ
	 */
	private static final String CIS_STUB = "2";
	
	/**
	 * リクエストＩＤ
	 */
	public static final String REQUESTID = "requestID";
	

	/**
	 * サービスＩＤ
	 */
	public static final String SERVICEID = "serviceID";
	
	/**
	 * 依頼元システム区分
	 */
	public static final String CHANNEL = "channel";
	
	/**
	 * 画面ＩＤ
	 */
	public static final String VIEWID = "viewID";
	
	/**
	 * オペレーターID
	 */
	public static final String OPERATORID = "operatorID";
	
	/**
	 * 依頼元IPアドレス
	 */
	public static final String IPADDRESS = "ipAddress";
	
	/**
	 * 操作日時
	 */
	public static final String OPERATEDATETIME = "operateDatetime";
	
    /**
     * エラーレベル
     */
    public static final String ERROR_LEVEL = "errorLevel";

    /**
     * リターンコード
     */
    public static final String RETURN_CD = "returnCode";

    /**
     * リターンメッセージ
     */
    public static final String RETURN_MESSAGE = "returnMessage";
	
	/**
	 * 外部インターフェイスID
	 */
	public static final String OUT_IF_ID = "outIfID";
	
	/**
	 * サービスIF
	 */
	public static final String SERVICEIF = "service_if";
	
	/**
	 * サービスIF_ID
	 */
	public static final String SERVICEIFID = "serviceIfID";

	/**
	 * 機能コード
	 */
	public static final String FUNC_CODE = "func_code";

	/**
	 * レコード
	 */
    public static final String RECORD = "record";

	/**
	 * コマンド実行結果
	 */
    public static final String CMD_RESULT_CD = "CMD_RESULT_CD";

	/**
	 * コマンド実行結果（エラー）
	 */
    public static final String CMD_ERROR_MESSAGE = "CMD_ERROR_MESSAGE";

	/**
	 * CIS外部システムコード
	 */
    protected static final String CIS_OUT_SYS_CD = "CIS_OUT_SYS_CD";
	
	/**
	 *CIS連携タイムアウト値
	 */
	
	protected static final String CIS_SOAP_TIMEOUT = "CIS_SOAP_TIMEOUT";

	/**
	 * XML作成時のエンコーディング
	 */
	protected static final String ENCODING = "UTF-8";
	
	/**
	 * HTTPヘッダ Content-TYPE
	 */
	protected static final String CONTENT_TYPE = "Content-Type";
	
	/**
	 * HTTPヘッダ Conten-TYPE（値）
	 */
	protected static final String CONTENT_TYPE_VALUE = "text/xml; charset=UTF-8";

	/**
	 * HTTPヘッダ リクエストメソッド定数
	 */
	protected static final String HTTP_REQUEST_METHOD = "POST";

	/**
	 * SOALFAULT（処理例外）
	 */
	private static final String SOAP_FAULT = "fault";

	/**
	 * SOALFAULT（エラーコード）
	 */
	private static final String SOAP_FAULT_CODE = "reason";

	/**
	 * SOALFAULT（エラー詳細）
	 */
	private static final String SOAP_FAULT_STRING = "detail";

	/**
	 * タグ名
	 */
	private static final String[] tagNames = {"Envelope","Body","Header","initResponse"};

	/**
	 * タグ属性(=TYPE)
	 */
	private static final String[] typeValues = {"service_if","service_if_list"};
	

	/**
	 * CIS_URL（eo電気契約お客様変更）
	 */
	protected static final String CIS_URL_KKIFE253 = "CIS_URL_KKIFE253";

	/**
	 * CIS_URL（eo電気契約一覧照会）
	 */
	protected static final String CIS_URL_KKIFE264 = "CIS_URL_KKIFE264";

	/**
	 * CIS連携の本番／スタブ切り替え処理
	 * 
	 * @return インスタンス
	 */
	public static JCKCtrlCisInfo getInstance()
	{
		/**
		 * CISシステム接続モードフラグ
		 */
		String str_flag = JCCModelCommon.getApplicationConst(CIS_CONNECTION_MODE);
		
		if(str_flag.equals(CIS_SYSTEM))
		{
			return JCKCtrlCisInfoImpl.getInstance();
		}
		else if(str_flag.equals(CIS_STUB))
		{
			return JCKCtrlCisInfoStubImpl.getInstance();
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * KKIFE253_eo電気契約お客様変更
	 * 
	 * @param serviceMap サービスマップハッシュテーブル
	 * @return サービスマップ戻り値
	 * @throws Exception
	 */
	public abstract Map<String, Object> call_KKIFE253(Map<String, Object> serviceMap) throws Exception;

	/**
	 * KKIFE264_eo電気契約一覧照会
	 * 
	 * @param serviceMap サービスマップハッシュテーブル
	 * @return サービスマップ戻り値
	 * @throws Exception
	 */
	public abstract Map<String, Object> call_KKIFE264(Map<String, Object> serviceMap) throws Exception;

	/**
	 * リクエストXMLDocumentの作成
	 * 
	 * @param serviceMap サービスマップハッシュテーブル
	 * @return リクエストで送信するXMLドキュメント
	 * @throws Exception
	 */
	protected Document createXml(Map<String, Object> serviceMap) throws Exception {
	//		<?xml version="1.0" encoding="UTF-8"?>
	//		<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
	//		    <soapenv:Header>
	//		        <requestID>a9jaieija98320110101160010000</requestID>
	//		        <serviceID>KKSV0808</serviceID>	
	//		        <channel>3</channel>
	//		        <viewID>XXXX</viewID>
	//		        <operatorID>XXXX</operatorID>
	//		        <ipAddress></ipAddress>
	//		        <operateDatetime></operateDatetime>
	//		    </soapenv:Header>	
	
			// root要素が"<soapenv:Envelope>"のドキュメント
			DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = dbfactory.newDocumentBuilder();
			Document doc = builder.getDOMImplementation().createDocument("http://schemas.xmlsoap.org/soap/envelope/", "soapenv:Envelope", null);
			Element soap = doc.getDocumentElement();
			
			// Header部
			// <soapenv:Header>
			Element header = doc.createElement("soapenv:Header");
			soap.appendChild(header);
			
			// <requestID>
			Element requestId = doc.createElement(JCKCtrlCisInfo.REQUESTID);
			requestId.setTextContent((String)serviceMap.get(JCKCtrlCisInfo.OUT_IF_ID) + "_reqId" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()));
			header.appendChild(requestId);
			
			// <serviceID>
			Element serviceId = doc.createElement(JCKCtrlCisInfo.SERVICEID);
			serviceId.setTextContent((String)serviceMap.get(JCKCtrlCisInfo.SERVICEID));
			header.appendChild(serviceId);
			
			// <channel>
			Element channel = doc.createElement(JCKCtrlCisInfo.CHANNEL);
			channel.setTextContent("3");
			header.appendChild(channel);
			
			// <viewID>
			Element viewId = doc.createElement(JCKCtrlCisInfo.VIEWID);
			if(null != JCCModelCommon.getApplicationConst(CIS_OUT_SYS_CD))
			{
				viewId.setTextContent((String)JCCModelCommon.getApplicationConst(CIS_OUT_SYS_CD));
			}
			header.appendChild(viewId);
			// <operatorID>
			Element operatorId = doc.createElement(JCKCtrlCisInfo.OPERATORID);
			if(null != JCCModelCommon.getApplicationConst(CIS_OUT_SYS_CD))
			{
				operatorId.setTextContent((String)JCCModelCommon.getApplicationConst(CIS_OUT_SYS_CD));
			}
			header.appendChild(operatorId);
			// <ipAddress>
			Element ipAddress = doc.createElement(JCKCtrlCisInfo.IPADDRESS);
			ipAddress.setTextContent("");
			header.appendChild(ipAddress);
			// <operateDatetime>
			Element operateDatetime = doc.createElement(JCKCtrlCisInfo.OPERATEDATETIME);
			operateDatetime.setTextContent((String)serviceMap.get(JCKCtrlCisInfo.OPERATEDATETIME));
			header.appendChild(operateDatetime);
			
	//		<soapenv:Body>
	//		  <init>
	//		    <KKSV081501SC type="service_if">
	//		        <service_if>
	//		            <func_code>1</func_code>
	//		            <kykychtn_tkt_no>99999999999999</kykychtn_tkt_no>
	//		        </service_if>
	//		    </KKSV081501SC >
	//		  </init>
	//		</soapenv:Body>
	//		</soapenv:Envelope>
	
			// Body部
			// <soapenv:Body>
			Element body = doc.createElement("soapenv:Body");
			soap.appendChild(body);
			// IT1-2015-0000075 MOD START
			// <initResponse>
			// Element init = doc.createElement("initResponse");
			// <init>
			Element init = doc.createElement("init");
			// IT1-2015-0000075 MOD END
			body.appendChild(init);
	
			// <xxxxxxxxxxSC type="service_if">
			Element serviceIfID = doc.createElement((String)serviceMap.get(JCKCtrlCisInfo.SERVICEIFID));
			init.appendChild(serviceIfID);
			
			List<LinkedHashMap<String, Object>> serviceifList = (List<LinkedHashMap<String, Object>>) serviceMap.get(JCKCtrlCisInfo.SERVICEIF);
			
			if(serviceifList.size() == 1){
				// <xxxxxxxxxxSC type="service_if">
				serviceIfID.setAttribute("type", JCKCtrlCisInfo.SERVICEIF);	
			}else {
				// <xxxxxxxxxxSC type="service_if_list">
				serviceIfID.setAttribute("type", JCKCtrlCisInfo.SERVICEIF + "_list");	
			}
			
			for(LinkedHashMap<String, Object> map : serviceifList){
			
				// <service_if>
				Element serviceIf = doc.createElement(JCKCtrlCisInfo.SERVICEIF);
				serviceIfID.appendChild(serviceIf);
				
				// <func_code>
				// <kykychtn_tkt_no>
				for(Entry<String,Object> entry : map.entrySet()){
					Element item = doc.createElement(entry.getKey());
					item.setTextContent((String)entry.getValue());
					serviceIf.appendChild(item);
				}
				
			}
			
			// スタンドアロンの設定
			doc.setXmlStandalone(true);
			
			return doc;
		}

	/**
	 * 電文読み込み処理
	 * @param soapResponse
	 * @return XML電文解析結果
	 * @throws IOException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 */
	protected Hashtable<String, Object> read(Document soapResponse) throws IOException, ParserConfigurationException, SAXException {
		// レスポンス解析
		Element root =  soapResponse.getDocumentElement();//ルート要素(<SOAP-ENV:Envelope>)	
		Hashtable<String, Object> result = analyzeXml(root, true);
	
		return result;
	}

	/**
	 * XMLFAULT電文解析処理
	 * 
	 * @param elem XMLFAULT電文
	 * @return ArrayListエラー情報
	 */
	private String analyzeFaultXml(Node elem) {
		Node node = elem.getFirstChild();
		String errmsg = "";
		
		while(node != null)
		{
			if(node.getNodeType() == Node.ELEMENT_NODE) 
			{
				String nodename = node.getLocalName();
				
				if(SOAP_FAULT_CODE.equals(nodename.toLowerCase()))
				{
					Node child = node.getFirstChild();
					if(child != null)
					{
						errmsg = errmsg + "エラーコード：" + child.getTextContent();
					}
				}
				if(SOAP_FAULT_STRING.equals(nodename.toLowerCase()))
				{
					errmsg = errmsg + "エラー詳細：" + node.getTextContent();
				}
			}
			
			node = node.getNextSibling();
		}
		
		return errmsg;
	}

	/**
	 * コマンド送信戻り電文解析処理
	 * @param elem コマンド解析電文rootXML要素
	 * @param rootflag ルートフラグ
	 * @return XML解析結果
	 */
	private Hashtable<String, Object> analyzeXml(Node elem, boolean rootflag) {
		Node node = elem.getFirstChild();
		Hashtable<String, Object> resultMap = null;
		List<Map<String, Object>>Bodynodelist = new ArrayList<Map<String, Object>>();
		
		//電文の要素をすべて解析する。
		while(node != null)
		{
			if(node.getNodeType() == Node.ELEMENT_NODE) 
			{
				
				String nodename = node.getLocalName();
				String typeValue = null;
				if(node.getAttributes().getNamedItem("type") != null){
					typeValue = node.getAttributes().getNamedItem("type").getNodeValue();
				}
				
				String childname = "";
				
				NodeList nodelist = node.getChildNodes();
				if(nodelist != null)
				{
					for(int i = 0 ; i < nodelist.getLength() ; i++)
					{
						Node child = nodelist.item(i);
						
						if(child.getNodeType() == Node.ELEMENT_NODE)
						{
							childname = child.getLocalName();
							break;
						}
					}
				}
				
				// SOAP例外の場合
				if(SOAP_FAULT.equals(nodename.toLowerCase()) || SOAP_FAULT.equals(childname.toLowerCase()))
				{
					resultMap = new Hashtable<String, Object>();
					String faultinfo = analyzeFaultXml(node);
					resultMap.put(JCKCtrlCisInfo.CMD_RESULT_CD,"1");
					resultMap.put(JCKCtrlCisInfo.CMD_ERROR_MESSAGE,faultinfo);	
					return resultMap;
				}
				else
				{
					if(resultMap == null) {
						resultMap = new Hashtable<String, Object>();
					}
					Hashtable<String, Object>resultinfo = analyzeXml(node, false);
					if(JCKCtrlCisInfo.RECORD.equals(nodename) || JCKCtrlCisInfo.SERVICEIF.equals(nodename))
					{
						if(resultinfo != null && !resultinfo.isEmpty())
						{
							Bodynodelist.add(resultinfo);
						}
						
						resultMap.put(nodename,Bodynodelist);
					
					}
					
					else if(Arrays.asList(tagNames).contains(nodename) || Arrays.asList(typeValues).contains(typeValue))
					{
						resultMap.putAll(resultinfo);
					}
					else
					{
						resultMap.put(nodename,node.getTextContent());
						if(node.getAttributes().getNamedItem("err") != null)
						{
							String StrErr = node.getAttributes().getNamedItem("err").getTextContent();
							resultMap.put(nodename + "_err", StrErr);
						}
					}
					
				}
			}
			
			node = node.getNextSibling();
		}
		
		if(rootflag)
		{
			if(resultMap == null)
			{
				resultMap = new Hashtable<String, Object>();
			}
			
			resultMap.put(JCKCtrlCisInfo.CMD_RESULT_CD,"0");
			return resultMap;
		}
		
		return resultMap;
	}
}
