/**	@file
 *	@brief 共通して使えるオブジェクトや関数の定義
 *
 *	@author G.H.
 *	@date 05/09/13
 */

/**
 *	@brief プロパティとメソッドを継承させる
 *
 *	superClass から subClass に
 *	プロパティとメソッドをコピーする。
 *	これによって subClass で superClass の
 *	プロパティとメソッドが使えるようになる。
 *
 *	@param[in] subClass   サブクラス
 *	@param[in] superClass スーパークラス
 */
function inherit(subClass, superClass)
{
	for (var i in superClass.prototype)
		subClass.prototype[i] = superClass.prototype[i];
}

/**
 *	@brief 別の配列に要素をコピーする
 *
 *	配列 y の要素を, 配列 x にコピーする。
 *
 *	@param[in] x コピー先の配列
 *	@param[in] y コピー元の配列
 */
function copyArray(x, y)
{
	for (var i in y)
		x[i] = y[i];
}

/**
 *	@brief 配列から指定された要素を探す
 *
 *	配列 array から, value と等しい要素のインデックスを返す。
 *	見つからなかった場合は, null を返す。
 *
 *	@param[in] x コピー先の配列
 *	@param[in] y コピー元の配列
 *	@return      要素のインデックス。見つからなかった場合は null。
 */
function findElementInArray(array, value)
{
	for (var i in array)
	{
		if (array[i] == value)
			return i;
	}

	return null;
}

/**
 *	@brief 外部スクリプトファイルを読み込む
 *
 *	外部スクリプトファイルを読み込む。
 *	このスクリプトの関数などを使う場合は、
 *	読み込むが終了するまで待機しなければならない。
 *
 *	@param[in] src 外部スクリプトの URL
 */
function loadScript(src)
{
	var node = document.createElement("script");
	node.src = src;
	document.body.appendChild(node);
}

/**
 *	@brief XMLDocument オブジェクトを新規作成する
 *
 *	XMLDocument オブジェクトを新規作成する。
 *	IE と Mozilla に対応。
 *
 *	@param[in] url XML ファイルの URL
 *	@return        新しく作成した XMLDocument オブジェクトを返す。
 */
function createXMLDocument(url)
{
	if (document.all)
	{
		doc = new ActiveXObject("Microsoft.XMLDOM");
	}
	else
	{
		doc = document.implementation.createDocument("", "", null);
	}

	doc.async = false;

	if (url != undefined)
		doc.load(url);

	return doc;
}

/**
 *	@brief XSLT 変換を行う
 *
 *	XMLDocument オブジェクトを使って XSLT 変換を行う。
 *	IE と Mozilla に対応。
 *
 *	@param[in] xml    XML ファイルの XMLDocument オブジェクト
 *	@param[in] xsl    XSL ファイルの XMLDocument オブジェクト
 *	@param[in] target 結果が格納される HTMLElement オブジェクト
 *	@param[in] times  変換回数
 *	@return           なし。
 */
function transformXMLToTarget(xml, xsl, target, times)
{
	if (document.all)
	{
		try
		{
			var doc = xml;

			if (times != undefined)
			{
				for (var i = 0; i < times - 1; i++)
				{
					var result = new ActiveXObject("Microsoft.XMLDOM");

					result.async = false;
					result.validateOnParse = false;

					doc.transformNodeToObject(xsl, result);

					doc = result;
				}
			}

			target.innerHTML = doc.transformNode(xsl);
		}
		catch (e)
		{
			target.innerHTML = e.description;
		}
	}
	else
	{
		try
		{
			var processor = new XSLTProcessor();
			processor.importStylesheet(xsl);

			var doc = xml;

			if (times != undefined)
			{
				for (var i = 0; i < times - 1; i++)
					doc = processor.transformToDocument(doc);
			}

			var fragment = processor.transformToFragment(doc, document);

			target.innerHTML = "";
			target.appendChild(fragment);
		}
		catch (e)
		{
			target.innerHTML = e;
		}
	}
}

/**
 *	@brief XPath を使って単一の XMLNode オブジェクトを検索する
 *
 *	XPath を使って単一の XMLNode オブジェクトを検索する。
 *	IE と Mozilla に対応。
 *
 *	@param[in] node       XMLNode オブジェクト
 *	@param[in] expression XPath 文字列
 *	@return               expression で指定された XMLNode オブジェクトを返す。
 */
function selectSingleNode(node, expression)
{
	if (document.all)
	{
		return node.selectSingleNode(expression);
	}
	else
	{
		var doc = node.ownerDocument ? node.ownerDocument : node;
		var contextNode = node;
		var resolver = doc.createNSResolver(doc.documentElement);
		var type = XPathResult.FIRST_ORDERED_NODE_TYPE;

		var result = doc.evaluate(expression,
			contextNode, resolver, type, null);

		return result.singleNodeValue;
	}
}

/**
 *	@brief XPath を使って複数の XMLNode オブジェクトを検索する
 *
 *	XPath を使って複数の XMLNode オブジェクトを検索する。
 *	IE と Mozilla に対応。
 *
 *	@param[in] node       XMLNode オブジェクト
 *	@param[in] expression XPath 文字列
 *	@return               expression で指定された XMLNodeList オブジェクトを返す。
 */
function selectNodes(node, expression)
{
	if (document.all)
	{
		return node.selectNodes(expression);
	}
	else
	{
		var doc = node.ownerDocument ? node.ownerDocument : node;
		var contextNode = node;
		var resolver = doc.createNSResolver(doc.documentElement);
		var type = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE;

		var result = doc.evaluate(expression,
			contextNode, resolver, type, null);

		return new XPathResultForMozilla(result);
	}
}

/**
 *	@brief XPathResultForMozilla のコンストラクタ
 *
 *	XPathResultForMozilla のコンストラクタ。
 *	Mozilla 専用。
 *
 *	@param[in] result XPathResult オブジェクト
 */
function XPathResultForMozilla(result)
{
	this.length = result.snapshotLength;

	this.item = function(i)
	{
		return result.snapshotItem(i);
	};
}

/**
 *	@brief XMLmanager オブジェクトを新規作成する
 *
 *	XMLManager オブジェクトを新規作成する。
 *	IE と Mozilla に対応。
 *
 *	@param[in] xmlPath XML ファイルの URL
 *	@param[in] xslPath XSL ファイルの URL
 *	@param[in] target  変換結果を受け取る HTMLElement オブジェクト
 *	@param[in] times   変換回数
 *	@return            新しく作成した XMLManager オブジェクトを返す。
 */
function createXMLManager(xmlPath, xslPath, target, times)
{
	return new XMLManager(xmlPath, xslPath, target, times);
}

/**
 *	@brief XMLManager のコンストラクタ
 *
 *	XMLManager のコンストラクタ。
 *	IE と Mozilla に対応。
 *
 *	@param[in] xmlPath XML ファイルの URL
 *	@param[in] xslPath XSL ファイルの URL
 *	@param[in] target  変換結果を受け取る HTMLElement オブジェクト
 *	@param[in] times   変換回数
 */
function XMLManager(xmlPath, xslPath, target, times)
{
	this.xml = createXMLDocument(xmlPath);
	this.xsl = createXMLDocument(xslPath);
	this.target = target;
	this.times = times;

	this.transformToTarget = function()
	{
		return transformXMLToTarget(this.xml, this.xsl, this.target, this.times);
	}
}
