/*
このファイルの中身は、NTT オープンソースライセンス　バージョン 1.0（「本
契約」という）の適用を受けます。
本契約を遵守しない限り、このファイルを使用してはなりません。
本契約のコピーは、次のＵＲＬから入手できます。
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

本契約に基づき頒布されるソフトウェアは、現状のまま、明示又は黙示のあらゆ
る種類の保証なしで、頒布されます。本契約に基づく権利及び制限を律する特定
の文言については、本契約を参照してください。

「オリジナルコード」は、 NTT Cyber Space Laboratories Code です。 
「オリジナルコード」の「初期開発者」は、日本電信電話株式会社です。  
日本電信電話株式会社により創作された部分は、Copyright (C) 2004 
日本電信電話株式会社 です。
全ての権利が留保されます。 
「コントリビュータ」：_____________________________________ 


The contents of this file are subject to the NTT Opensource License
Version 1.0 (the License); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

Software distributed under the License is distributed on an AS IS
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is NTT Cyber Space Laboratories Code .

The Initial Developer of the Original Code is NIPPON TELEGRAPH AND 
TELEPHONE CORPORATION.
Portions created by the NIPPON TELEGRAPH AND TELEPHONE CORPORATION 
are Copyright (C) 2004 NIPPON TELEGRAPH AND TELEPHONE CORPORATION. 
All Rights Reserved.

Contributor(s) ______________________________________.
*/

package jp.co.ntt.lms.installer.core.util;

import java.io.File;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;

import jp.co.ntt.lms.installer.core.InstallerException;
import jp.co.ntt.lms.installer.core.InstallerOverwriteXmlValue;
import jp.co.ntt.lms.installer.core.InstallerValues;
import jp.co.ntt.lms.installer.util.LoggerUtil;
import jp.co.ntt.lms.installer.util.StringUtil;
import jp.co.ntt.lms.installer.util.XmlUtil;

import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * ＸＭＬ書換ユーティリティ・クラス。
 * @author T.Nishiki
 */
public class InstallerXmlUtil {
	/**
	 * ログ出力オブジェクト。
	 */
	private static Logger _logger;

	/**
	 * スタティック・イニシャライザ。<br>
	 * ログ出力オブジェクトを取得します。
	 */
	static {
		_logger = LoggerUtil.getLogger(InstallerXmlUtil.class);
	}

	/**
	 * 指定されたリソースをDOM Documentとしてロードします。<br>
	 * @param values インストーラ共通データオブジェクト。
	 * @param resourceKey 取得するリソースの位置を取得するためのキー文字列。
	 * @return resourceKeyが指し示すパスのリソースから
	 *          生成されたDOM Documentを戻します。
	 * @throws InstallerException リソース情報取得に失敗した場合。
	 */
	public static Document load(InstallerValues values, String resourceKey)
			throws InstallerException {
		// メソッド開始タグ
		LoggerUtil.methodHead(_logger, "load(" + resourceKey + ")");
		// このメソッドの戻り値
		Document document = null;
		// リソースからの入力ストリーム
		InputStream stream = null;
		// 成功フラグ（成功した場合にtrueに変更）
		boolean successFlag = false;
		try {
			stream = values.getResourceKeyStream(resourceKey);
			document = XmlUtil.convertXmlStreamToDocument(stream);
			successFlag = true;
		}
		catch (InstallerException e) {
			throw e;
		}
		catch (Exception e) {
			LoggerUtil.throwable(_logger, e);
			throw new InstallerException(e);
		}
		finally {
			InstallerFileUtil.close(stream, successFlag);
		}
		// メソッド終了タグ
		LoggerUtil.methodTail(_logger, "load(" + resourceKey + ")");
		return document;
	}

	/**
	 * 指定されたロケーションパスに対応するノードの初期値を取得します。<br>
	 * 基点となるドキュメントと、参照するドキュメントとを見比べて、
	 * 両者の指定のノードに差異がある場合は、参照するドキュメントのノード値をします。
	 * 差異がない場合は、nullを戻します。
	 *
	 * @param targetDoc 差異を取得のために参照するDOM Document。
	 * @param originDoc 差異の基点となるDOM Document。
	 * @param xpath 差異を確認するXPathロケーションパス。
	 * @return 指定されたパスのノードに差異があれば、
	 *          targetDocのノードの値を戻す。
	 *          差異がなければnullを戻す。
	 * @throws InstallerException ノードの取得に失敗した場合。
	 */
	public static String determineInitialNodeValue(
			Document targetDoc,	Document originDoc, String xpath)
			throws InstallerException {
		// メソッド開始タグ
		LoggerUtil.methodHead(_logger,
			"determineInitialNodeValue("
				+ targetDoc + "," + originDoc + "," + xpath + ")");

		String initialValue = null;
		try {
			// 両方のノード値を取得
			if (targetDoc != null) {
				String targetValue = XmlUtil.getNodeValue(targetDoc, xpath);
				String originValue = XmlUtil.getNodeValue(originDoc, xpath);
				if (StringUtil.isEmpty(targetValue)) {
					initialValue = null;
				}
				else if (StringUtil.isEmpty(originValue)) {
					initialValue = targetValue;
				}
				else if (targetValue.equals(originValue)) {
					initialValue = null;
				}
				else {
					initialValue = targetValue;
				}
			}
		}
		catch (Exception e) {
			LoggerUtil.throwable(_logger, e);
			throw new InstallerException(e);
		}
		// メソッド終了タグ
		LoggerUtil.methodTail(_logger,
			"determineInitialNodeValue("
				+ targetDoc + "," + originDoc + "," + xpath + ")",
			initialValue);

		return initialValue;
	}

	/**
	 * ＸＭＬファイルを上書きします。<br>
	 * @param values インストーラ共通データオブジェクト。
	 * @param xmlValue 上書きする項目について取得できるデータ。
	 * @throws InstallerException プロパティファイルの取得・書込に失敗した場合。
	 */
	public static void overwriteXml(
			InstallerValues values,
			InstallerOverwriteXmlValue xmlValue)
			throws InstallerException {
		// メソッド開始タグ
		LoggerUtil.methodHead(_logger,
			"overwriteXml(InstallerValues," + xmlValue + ")");

		try {
			// =================================================================
			// 原本となるＸＭＬの取得
			Document doc
				= InstallerXmlUtil.load(values, xmlValue.getTargetFileKey());
			// =================================================================
			// 上書き対象となるノードの値
			Properties nodeValues
				= xmlValue.getOverwrittenNodeValues(values);
			// ノードの値の上書き
			if (nodeValues != null) {
				Set keySet = nodeValues.keySet();
				for (Iterator it = keySet.iterator(); it.hasNext();) {
					String nodeXPath = (String)it.next();
					_logger.info("Node XPath:[" + nodeXPath + "]");
					String nodeValue = nodeValues.getProperty(nodeXPath);
					_logger.info("Node Value:[" + nodeValue + "]");
					Node node = XPathAPI.selectSingleNode(doc, nodeXPath);
					if (node == null) {
						_logger.info(
							"selectSingleNode[" + nodeXPath + "] is Null");
						continue;
					}
					node.setNodeValue(nodeValue);
				}
			}
			// =================================================================
			// 書き込み対象のファイル
			File targetFile = values.getFileOnSystem(
				xmlValue.getTargetFileKey());
			_logger.info("XML Output target[" + targetFile + "]");
			// XML変換プロパティを生成
			String xmlEncode = values.getProperty(
					xmlValue.getXmlFileEncodeKey());
			Properties outputProperties = new Properties();
			if (xmlEncode != null) {
				outputProperties.setProperty("encoding", xmlEncode);
			}
			// ファイルに出力
			XmlUtil.convertDocumentToFile(doc, targetFile, outputProperties);
		}
		catch (InstallerException e) {
			throw e;
		}
		catch (Exception e) {
			LoggerUtil.throwable(_logger, e);
			throw new InstallerException(e);
		}
		// メソッド終了タグ
		LoggerUtil.methodTail(_logger,
			"overwriteXml(InstallerValues," + xmlValue + ")");
	}
}
