// baselib.js
// Basic JavaScript Library
// Version 1.9
(function() {
// ----------------------------------------------------------------------------
// UA: UA 情報
// ----------------------------------------------------------------------------
function UA() {/* EMPTY */}

(function() {
	var uastr = navigator.userAgent;
	UA.prototype.engine = UA.engine = { // UA rendering engine type
		isPresto  : false,
		isGecko   : false,
		isTrident : false,
		isWebKit  : false,
		isKHTML   : false,
		isUnknown : false
	};
	var type = window.opera          ? "isPresto"  :
		window.attachEvent           ? "isTrident" :
		(/AppleWebKit/i).test(uastr) ? "isWebKit"  :
		(/KHTML/i).test(uastr)       ? "isKHTML"   :
		(/Gecko\//i).test(uastr)     ? "isGecko"   : "isUnknown";
	UA.prototype.engine[type] = UA.engine[type] = true;
})();


// ----------------------------------------------------------------------------
// convArray: 与集合を新規 Array オブジェクトに変換
// ----------------------------------------------------------------------------
// 複数個与えられた場合はすべてを concat する
function convArray(/* arguments */) {
	var ret = [];
	var args = arguments;
	var nargs = args.length;
	for (var a = 0; a < nargs; a++) {
		if (null === args[a] || undefined === args[a]) { continue; }
		var nsets = args[a].length;
		for (var s = 0; s < nsets; s++) { ret.push(args[a][s]); }
	}
	return ret;
};


// ----------------------------------------------------------------------------
// EventControl: 汎用イベント処理
// ----------------------------------------------------------------------------
// Note:
// IE のメモリリークは、DOM ノード上にある循環参照要素に対しては修正された
// （DOM ノードへ append されていない要素が循環参照している場合は未修正）
// 故に、本イベントリスナラッパーはメモリリーク対策を講じていない
// See also:
// http://support.microsoft.com/kb/929874/
// http://www.microsoft.com/japan/msdn/ie/general/ie_leak_patterns.aspx
// http://d.hatena.ne.jp/zorio/20070626/1182875782
// http://d.hatena.ne.jp/zorio/20070918/1190135017
// http://ajaxian.com/archives/ie-memory-leaks-be-gone
// http://ajaxian.com/archives/ies-memory-leak-fix-greatly-exaggerated
// ----------------------------------------------------------------------------
function EventControl() {/* EMPTY */};

EventControl.prototype.add =
EventControl.add = function(element, type, listener, useCapture) {
	if (element.addEventListener) {
		return element.addEventListener(type, listener, useCapture);
	} else if (element.attachEvent) {
		return element.attachEvent("on"+type, listener);
	} else {
		return null;
	}
};

EventControl.prototype.remove =
EventControl.remove = function(element, type, listener, useCapture) {
	if (element.removeEventListener) {
		return element.removeEventListener(type, listener, useCapture);
	} else if (element.detachEvent) {
		return element.detachEvent("on"+type, listener);
	} else {
		return null;
	}
};

EventControl.prototype.getCurrentElement =
EventControl.getCurrentElement = function(event) {
	return (event.currentTarget)     ? event.currentTarget     :
			(event.srcElement)        ? event.srcElement        :
			(window.event.srcElement) ? window.event.srcElement : null;
};

EventControl.prototype.preventDefault =
EventControl.preventDefault = function(event) {
	if (undefined !== event.preventDefault) {
		event.preventDefault();
	} else {
		event.returnValue = false;
	}
};


// ----------------------------------------------------------------------------
// DOMNodeControl: 汎用 DOM ノード制御
// ----------------------------------------------------------------------------
function DOMNodeControl() {/* EMPTY */}

DOMNodeControl.prototype.createByList =
DOMNodeControl.createByList = function(list) {
	var df = document.createDocumentFragment();
	var nlist = list.length;
	for (var l = 0; l < nlist; l++) {
		df.appendChild(this.createNode(list[l]));
	}
	return df;
};

DOMNodeControl.prototype.createNode =
DOMNodeControl.createNode = function(node) {
	if (!(node instanceof Array)) { return this._createNodeSub(node); }
	var domNode = this._createNodeSub(node[0]);
	var nnode = node.length;
	for (var n = 1; n < nnode; n++) {
		domNode.appendChild(this.createNode(node[n]));
	}
	return domNode;
};

DOMNodeControl.prototype._createNodeSub =
DOMNodeControl._createNodeSub = function(node) {
	var domNode;
	if (typeof node == "string") {
		domNode = document.createTextNode(node);
	} else {
		domNode = document.createElement(node["0"]);
		var tmp = node["0"];
		delete node["0"];
		for (var n in node) { domNode.setAttribute(n, node[n]); }
		node["0"] = tmp;
	}
	return domNode;
};


// ----------------------------------------------------------------------------
// getElementsByClassName: class 名による要素の収集
// ----------------------------------------------------------------------------
// 実装されている UA では無視
if (undefined === document.getElementsByClassName) {(function() {
	var func = null;
	if (document.evaluate) { // XPath が利用できる
		func = function(name) {
			var elems = [];
			var query = document.evaluate( // XPath で収集
				'.//*[contains(concat(" ",@class," "),'+'" '+name+' ")]',
				document,
				null,
				XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
				null
			);
			var nquery = query.snapshotLength;
			for (var i = 0; i < nquery; i++) { // 配列に変換
				elems.push(query.snapshotItem(i));
			}
			return elems;
		};
	} else { // XPath が利用できない
		var spc = "[\t ]";
		var rp = "(?:^|"+spc+")";
		var rs = "(?:"+spc+"|$)";
		func = function(name) {
			var elems = [];
			var regexp = new RegExp(rp+name+rs, "g");
			/*@cc_on @if (@_jscript_version < 5.6)
			var all = document.all;
			@else @*/
			var all = document.getElementsByTagName("*");
			/*@end @*/
			var nall = all.length;
			for (var i = 0; i < nall; i++) { // 全要素を線形探索 (DOM Level 1)
				if (regexp.test(all[i].className)) { elems.push(all[i]); }
			}
			return elems;
		};
	}
	document.getElementsByClassName = func;
})();}


// ----------------------------------------------------------------------------
// 描画領域の各種サイズ取得
// ----------------------------------------------------------------------------
(function() {
	var elem = "documentElement";
	// 表示サイズ（スクロールバーは除外）
	window.getInnerSize = function() {
		var w = 0;
		var h = 0;
		if (UA.engine.isWebKit && !document.evaluate) {
			// Safari 2.x before
			w = window.innerWidth;
			h = window.innerHeight;
		} else {
			// Anothers
			w = document[elem].clientWidth;
			h = document[elem].clientHeight;
		}
		return {width : w, height : h};
	};

	// フルサイズ（スクロール含）
	window.getPageSize = function() {
		return {
			width  : document[elem].scrollWidth,
			height : document[elem].scrollHeight
		};
	};

	// スクロールオフセット
	window.getPageOffset = function() {
		return {
			x : (window.pageXOffset || document[elem].scrollLeft),
			y : (window.pageYOffset || document[elem].scrollTop)
		};
	};

	// スクロールバーサイズ（window load 後の呼出必須）
	window.getScrollBarSize = function() {
		var size = document.createElement("div");
		var sizeCont = document.createElement("div");
		size.style.width = "100px";
		size.style.height = "100px";
		size.style.overflow = "auto";
		sizeCont.style.width = "101px";
		sizeCont.style.height = "101px";
		document.body.appendChild(size).appendChild(sizeCont);
		var width  = size.offsetWidth - size.clientWidth;
		var height = size.offsetHeight - size.clientHeight;
		document.body.removeChild(size);
		window.getScrollBarSize = function() {
			return {width : width, height : height};
		};
		return {width : width, height : height};
	};

	// viewport スクロール状態 (y:true, n:false)
	window.isScroll = function() {
		var ps = window.getPageSize();
		var is = window.getInnerSize();
		return {
			width  : (ps.width > is.width),
			height : (ps.height > is.height)
		};
	};
})();


// ----------------------------------------------------------------------------
// AnotherWindow: 新規ウィンドウ制御
// ----------------------------------------------------------------------------
function AnotherWindow(/* arguments */) {
	this.uri    = null;     // 対象 URI
	this.name   = "_blank"; // ウインドウ名
	this.ref    = null;     // ウインドウへのリファレンス
	this.params = {         // ウインドウに渡すパラメタ
		// 状態
		left   : null, // 横位置
		top    : null, // 縦位置
		height : null, // 縦幅
		width  : null, // 横幅
		// 表示切替（非推奨）
		menubar  : "yes", // メニューバー
		toolbar  : "yes", // ツールバー
		location : "yes", // ロケーションバー
		status   : "yes"  // ステータスバー
	};

	this.setOptions.apply(this, arguments);
}

// 変更不可パラメタ
AnotherWindow.prototype._constParams = {
	resizable  : "yes",
	scrollbars : "yes"
};

// オプション設定
AnotherWindow.prototype.setOptions = function(uri, options) {
	this.setURI(uri);
	this.setName(options);
	this.setParams(options);
};

// 生成
AnotherWindow.prototype.create = function(/* arguments */) {
	this.setOptions.apply(this, arguments);
	this.setRef(
		window.open(this.uri, this.name, this.getParamStr())
	);
};

// ウインドウ名設定
AnotherWindow.prototype.setName = function(options) {
	if (typeof options != "object" ||
		typeof options.name != "string") { return; }
	this.name = options.name;
};

// リファレンス値の妥当性検証・設定
AnotherWindow.prototype.setRef = function(ref) {
	if (undefined === ref || null === ref) { return; }
	this.ref = ref;
};

// URI 値の妥当性検証・設定
AnotherWindow.prototype.setURI = function(uri) {
	if (typeof uri != "string") { return; }
	this.uri = uri;
};

// パラメタ設定
AnotherWindow.prototype.setParams = function(params) {
	if (typeof params != "object") { params = {}; }
	delete params.name;
	for (var p in this.params) {
		if (undefined !== params[p]) {
			this.params[p] = this.convParamValue(params[p]);
		}
	}
};

// 与パラメタ値を実利用値にコンバート
AnotherWindow.prototype.convParamValue = function(value) {
	return ((true === value) ? "yes" :
			(false === value) ? "no" : value);
};

// 実際に window.open へ与えるパラメタ文字列取得
AnotherWindow.prototype.getParamStr = function() {
	var ret = [];
	for (var p in this.params) {
		if (null === this.params[p]) { continue; }
		ret.push(p+"="+this.params[p]);
	}
	for (var cp in this._constParams) {
		ret.push(cp+"="+this._constParams[cp]);
	}
	return ret.join(",");
};


// ----------------------------------------------------------------------------
// openNewWindow: "AnotherWindow" wrapper interface
// ----------------------------------------------------------------------------
window.openNewWindow = function(event, options) {
	var elem = EventControl.getCurrentElement(event);
	// IE: event.srcElement はイベントの add されたノードだけでなく、その子孫
	//     ノードのうちで実際にアクティブになったものを拾ってしまう仕様
	//     故に親ノードを辿り、実際に目的としている要素まで行かなければならない
	do {
		// event.currentTarget がサポートされていればループしない
		if (elem.nodeName && "a" == elem.nodeName.toLowerCase()) {
			var uri = elem.getAttribute("href");
			var win = new AnotherWindow(uri, options);
			win.create();
			break;
		}
		// event.srcElement の場合は目的とするノードに到達するまでループ
		elem = elem.parentNode;
	} while (elem); // root に到達してしまっても何もしない
	EventControl.preventDefault(event);
}


// ----------------------------------------------------------------------------
// Rollover: ロールオーバーの付与
// ----------------------------------------------------------------------------
function Rollover() {
	this.targets = []; // 対象要素集合
}

// イベントタイプ別 元 src 属性値変換対応
Rollover.prototype.events = {
	mouseover : {cond : /(\.[^\.]+)$/g, replace : "-on$1"},
	mouseout  : {cond : "",             replace : ""},
	focus     : {cond : /(\.[^\.]+)$/g, replace : "-on$1"},
	blur      : {cond : "",             replace : ""}
};

// 各種クラス属性値
Rollover.prototype.classNames = {
	enable : { // 適用条件
		str    : "rollover",
		regexp : /(^|[\t ])rollover([\t ]|$)/
	},
	disable : { // 除外条件
		str    : "current",
		regexp : /(^|[\t ])current([\t ]|$)/
	}
};

// ロールオーバー許可
Rollover.prototype.enable = function() {
	this._setTargets();
	var ntargets = this.targets.length;
	for (var t = 0; t < ntargets; t++) {
		for (var type in this.targets[t].events) {
			EventControl.add(this.targets[t].element,
							type,
							this.targets[t].events[type],
							false);
		}
	}
};

// ターゲット要素取得
Rollover.prototype._getElements = function(className) {
	var ret = []; // 取得した要素集合
	var es = document.getElementsByClassName(className);
	var nes = es.length;
	for (var e = 0; e < nes; e++) {
		var nodeName = es[e].nodeName.toLowerCase();
		if ("img" == nodeName ||
			("input" == nodeName && "image" == es[e].getAttribute("type"))) {
			ret.push(es[e]);
		} else {
			ret = ret.concat(
				convArray(es[e].getElementsByTagName("img"))
			);
			var inputs = es[e].getElementsByTagName("input");
			var ninputs = inputs.length;
			var imgInputs = [];
			for (var i = 0; i < ninputs; i++) {
				if ("image" == inputs[i].getAttribute("type")) {
					imgInputs.push(inputs[i]);
				}
			}
			ret = ret.concat(imgInputs);
		}
	}
	return ret;
};

// 対象外要素を除外した要素集合を得る
Rollover.prototype._getElementsWithoutExcludes = function() {
	var ret = [];
	var targets = this._getElements(this.classNames.enable.str).concat(
		this._getElements(this.classNames.disable.str)
	);
	var ntargets = targets.length;
	for (var t = 0; t < ntargets; t++) {
		if (!this._isEnableNode(targets[t])) { continue; }
		ret.push(targets[t]);
	}
	return ret;
};

// 自身ないし最も近い祖先要素が効果を許可しているか否か
Rollover.prototype._isEnableNode = function(node) {
	var d = this.classNames.disable.regexp;
	var e = this.classNames.enable.regexp;
	do {
		if (d.test(node.className)) { return false; }
		if (e.test(node.className)) { return true; }
		node = node.parentNode;
	} while (node);
	// 判別不能だった場合は例外とせず disable として処理
	return false;
};

// 対象要素、イベント、イベントリスナのコレクションを生成
Rollover.prototype._setTargets = function() {
	var elems = this._getElementsWithoutExcludes();
	var nelems = elems.length;
	for (var e = 0; e < nelems; e++) {
		var src = elems[e].getAttribute("src");
		var item = { element : elems[e], events : {} };
		for (var v in this.events) {
			var rsrc = src.replace(this.events[v].cond,
									this.events[v].replace);
			item.events[v] = this._getChanger(rsrc);
			this._createCache(rsrc);
		}
		this.targets.push(item);
	}
};

// 画像置換を実現するクロージャの生成機
Rollover.prototype._getChanger = function(src) {
	return function(event) {
		EventControl.getCurrentElement(event).setAttribute("src", src);
	};
};

// キャッシュ
// 1ドキュメントに1つでよいため prototype へ保存
Rollover.prototype._caches = {};

// キャッシュ生成
Rollover.prototype._createCache = function(src) {
	// 同一ファイルが既にキャッシュ済 -> キャッシュ不要
	// 但し、同一パスのみ対応する
	// 故に、例えば次のパスが全て同一ファイル示していても全てキャッシュされる
	//  /img/test.png
	//  img/test.png
	//  ./img/test.png
	//  http://foo/img/test.png
	if (this._caches[src]) { return; }
	// img 要素を生成し、キャッシュに格納
	this._caches[src] = document.createElement("img");
	this._caches[src].setAttribute("src", src);
};


// ----------------------------------------------------------------------------
// BackButton: class 属性値をフックとした history.back() 実装
// ----------------------------------------------------------------------------
function BackButton(/* ... */) {
	this.className = "historyBack"; // 対象要素の class 属性値
	this.targets   = [];            // 対象要素集合
	this.init.apply(this, arguments);
}

BackButton.prototype = {
	init : function(className) {
		if (className) {
			this.className = className;
		}
	},

	enable : function(className) {
		this.targets = document.getElementsByClassName(this.className);
		var targets  = this.targets,
			ntargets = targets.length;
		for (var t = 0; t < ntargets; t++) {
			EventControl.add(targets[t], "click", this.listener, false);
		}
	},

	listener : function(event) {
		window.history.back();
		EventControl.preventDefault(event || window.event);
	}
};


// ----------------------------------------------------------------------------
// FlashStat: Flash plugin status
// ----------------------------------------------------------------------------
var FlashStat = {
	type      : "application/x-shockwave-flash", // MIME Type
	obj       : null,     // Flash plugin interface object
	isActiveX : false,    // ActiveX y/n (y: true, n: false)
	isEnable  : false,    // Plugin e/d (e: true, d: false)
	version   : [0,0,0,0] // Version info (major,minor,revision,optional)
};

// バージョン比較（major バージョンのみ）
FlashStat.compVersion = function(version) {
	version = parseInt(version); // 小数点以下切捨
	var v = this.version[0];
	// バージョン > 比較数値:1
	// バージョン = 比較数値:0
	// バージョン < 比較数値:-1
	return ((v > version) ? 1 : (v == version) ? 0 : -1);
};

// バージョン情報取得
(function () {
	var fs = FlashStat;
	var cond = [ // バージョン文字列整形条件
		// 適合条件                  置換文字列
		{regexp : /^\D+/,            replace : ""},
		{regexp : /[\s\D]+/g,        replace : ","},
		{regexp : /^(\d+,\d+,\d+)$/, replace : "$1,0"}
	];
	var ncond = cond.length;
	var axid = { // ActiveX ID 対応表
		latest : "ShockwaveFlash.ShockwaveFlash.7",
		v6     : "ShockwaveFlash.ShockwaveFlash.6",
		v3     : "ShockwaveFlash.ShockwaveFlash.3",
		v2     : "ShockwaveFlash.ShockwaveFlash"
	};

	// バージョン文字列整形
	function setVersion(str) {
		if (!str) { try { // 3.x (ActiveX) 対策
			str = fs.obj.GetVariable("$version");
		} catch (e) { throw e; } }
		// 文字列整形
		for (var c = 0; c < ncond; c++) {
			str = str.replace(cond[c].regexp, cond[c].replace);
		}
		// 数値に変換
		var arr = str.split(",");
		var narr = arr.length;
		for (var a = 0; a < narr; a++) {
			fs.version[a] = parseInt(arr[a]);
		}
	};

	try {		 // NON-IE
		fs.obj = navigator.mimeTypes[fs.type].enabledPlugin;
		setVersion(fs.obj.description);
	} catch (e) { // IE
		try {
			// Version 7 以降
			fs.obj = new ActiveXObject(axid.latest);
			setVersion();
		} catch (e) {
			// Version 6.x
			// 6.0.22 - 6.0.29 では GetVariable("$version") でクラッシュ
			try {
				fs.obj = new ActiveXObject(axid.v6);
				setVersion("6,0,21,0"); // 6.x first release
				// 6,0,47 以上なら AllowScriptAccess が利用可能
				// AllowScriptAccess で例外を投げさせクラッシュを回避
				fs.obj.AllowScriptAccess = "always";
				setVersion();
			} catch (e) {
				// オブジェクトが存在しない -> 6.x 系ではない
				if (!fs.obj) {
					try {
						// Version 5.x, 4.x, 3.x
						fs.obj = new ActiveXObject(axid.v3);
						setVersion("3,0,18,0"); // 3.x first release
						// 3.x は GetVariale() で例外を投げる
						setVersion();
					} catch (e) {
						try {
							// Version 2.x
							fs.obj = new ActiveXObject(axid.v2);
							setVersion("2,0,0,11"); // 2.x first release
						} catch (e) {
							// Flash プラグインが存在しない
							// 2.x より前のバージョン
						}
					}
				}
			}
		}
		fs.isActiveX = true;
	}
	if (fs.obj) { fs.isEnable = true; }
})();


// ----------------------------------------------------------------------------
// FlashControl: Flash コントロール
// ----------------------------------------------------------------------------
function FlashControl(/* arguments */) {
	this.node       = null; // DOM node
	this.file       = "";   // Flash file name
	this.width      = null; // object width
	this.height     = null; // object height
	this.alt        = null; // alternate content
	this.anchor	    = null; // Flash plugin get recommend paragraphs
	this.minVersion = null; // old version time "get flash" wording content
	this.params     = {     // 'param' element attribute values
		bgcolor : "#ffffff"
		// more...
	};
	this.options = { // another options
		version : 0 // minimum requirement version
	};
	this.isEnable = false; // is valid flash? (y:true, n:false)
	this.setOptions.apply(this, arguments);
}

// 各種定数
FlashControl.prototype.cons = {
	type      : FlashStat.type, // MIME Type
	pluginurl : "http://www.adobe.com/go/getflashplayer",
	// IE ActiveX Control ONLY
	classid   : "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000",
	codebase  : "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"
}

// オブジェクト別オプションの設定
FlashControl.prototype.setOptions = function(file, width, height /* ... */) {
	if (arguments.length <= 0) { return; }
	this.file   = file;
	this.width  = width;
	this.height = height;
	this._setOptionals.apply(this, convArray(arguments).slice(3));
};

// 可変オプションの設定
FlashControl.prototype._setOptionals = function(alt, rest) {
	this.alt = new FlashAlternate(alt);
	this.anchor = new FlashGetAnchor();

	if (!(alt instanceof Array)) { rest = alt; }

	if (null !== rest && "object" == typeof rest) {
		for (var o in this.options) { // オプション抽出
			if (undefined === rest[o]) { continue; }
			this.options[o] = rest[o];
			delete rest[o];
		}
		for (var p in rest) {  // param 抽出
			this.params[p] = rest[p];
		}
	}
	// version は rest 内にあるため抽出後にセット
	this.anchor.setVersion(this.options.version);
};

// 要素生成
FlashControl.prototype.create = function(/* arguments */) {
	this.setOptions.apply(this, arguments);
	this.isEnable = false; // リセット
	this.node = this.alt.create()    || // no plugin
				this.anchor.create() || // old version
				this._createObject();   // default
	return this.node;
};

// IE バグ対策アクティベータ
// IE は object 要素を DOM ツリーへ append してから ActiveX をアクティブにしな
// いと正常なレンダリングを行わない
// see also: http://www.microsoft.com/japan/msdn/workshop/author/dhtml/overview/activating_activex.aspx#loading
FlashControl.prototype.activate = function() {
	if (!FlashStat.isActiveX || !this.isEnable) { return; }
	// ActiveX をアクティブにするスイッチは classid 属性値
	this.node.setAttribute("classid", this.cons.classid);
};

// object/param 要素生成と属性設定
FlashControl.prototype._createObject = function() {
	var obj   = document.createElement("object");
	var param = document.createElement("param");
	// All UA
	obj.setAttribute("width", this.width);
	obj.setAttribute("height", this.height);
	// 'object' attributes & param
	if (FlashStat.isActiveX) { // IE
		obj.setAttribute("codebase", this.cons.codebase);
		param.setAttribute("name", "movie");
		param.setAttribute("value", this.file);
	} else {                   // Others
		obj.setAttribute("type", this.cons.type);
		obj.setAttribute("data", this.file);
		param.setAttribute("name", "pluginurl");
		param.setAttribute("value", this.cons.pluginurl);
	}
	obj.appendChild(param);
	for (var p in this.params) { // param セット
		if (null === this.params[p]) { continue; }
		param = document.createElement("param");
		param.setAttribute("name", p);
		param.setAttribute("value", this.params[p]);
		obj.appendChild(param);
	}
	this.isEnable = true; // 正常な Flash 用 object 要素を生成した
	return obj;
};


// ----------------------------------------------------------------------------
// FlashAlthernate: Flash 代替要素
// ----------------------------------------------------------------------------
function FlashAlternate() {
	this.node = {"0":"img"};
	this.domNode = null;
	this.isEnable = false;
	this.setOptions.apply(this, arguments);
}

// オプション設定
FlashAlternate.prototype.setOptions = function(options) {
	if (!(options instanceof Array)) {
		this.isEnable = false;
		return;
	}
	if (options.length < 2) {
		throw Error("option item insufficiency");
	}
	this.node.src = options[0];
	this.node.alt = options[1];
	if (null !== options[2] && "object" == typeof options[2]) {
		for (var o in options[2]) {
			this.node[o] = options[2][o];
		}
	}
	this.domNode = DOMNodeControl.createNode(this.node);
	this.isEnable = !FlashStat.isEnable;
};

// 生成
FlashAlternate.prototype.create = function() {
	return (this.isEnable ? this.domNode.cloneNode(true) : null);
};


// ----------------------------------------------------------------------------
// FlashGetAnchor: Flash ダウンロード先リンク & 誘導文言
// ----------------------------------------------------------------------------
function FlashGetAnchor(version) {
	this.version  = 0;
	this.isEnable = false;
	if (null === this.constNode) { // 初回のみ生成
		this.constNode = DOMNodeControl.createByList(this.nodeList);
	}
	this.setVersion(version);
}

// 挿入文言 (固定値)
FlashGetAnchor.prototype.nodeList = [
	[{"0":"p"}, "現在お使いのAdobe Flash Playerのバージョンではこのコンテンツを表示することはできません。"],
	[{"0":"p"}, "このコンテンツをご覧になるには最新のAdobe Flash Playerが必要ですので、下記のボタンをクリックして最新バージョンのプラグインをダウンロードしてください。"],
	[{"0":"p", "class":"getFlash"},
		[{"0":"a", href:"http://www.macromedia.com/shockwave/download/download.cgi?P5_Language=Japanese&amp;Lang=Japanese&amp;Lang=Japanese&amp;P1_Prod_Version=ShockwaveFlash", onclick:"openNewWindow(event);"},
			 {"0":"img", src:"/common/img/banner/get-flash.gif", alt:"Get Macromedia Flash Player：別ウィンドウが開きます", width:88, height:31}
		]
	]
];

// 生成済 DOM Node
FlashGetAnchor.prototype.constNode = null;

// バージョン番号設定 (major のみ)
FlashGetAnchor.prototype.setVersion = function(version) {
	version = parseInt(version);
	if (isNaN(version)) { version = 0; }
	this.version = version;
	this.isEnable = (FlashStat.compVersion(this.version) < 0) ||
					!FlashStat.isEnable;
};

// 生成
FlashGetAnchor.prototype.create = function() {
	return (this.isEnable ? this.constNode.cloneNode(true) : null);
};


// ----------------------------------------------------------------------------
// addFlash: "FlashControl" wrapper interface
// ----------------------------------------------------------------------------
window.addFlash = function(target /* arguments */) {
	var args = convArray(arguments).slice(1);
	var flash = new FlashControl();
	flash.create.apply(flash, args);
	if (null === flash.node) { return; }
	document.getElementById(target).appendChild(flash.node);
	flash.activate();
}


// ----------------------------------------------------------------------------
// openFlashDoc: Flash をサポートしていれば与 URI の文書を参照する
// ----------------------------------------------------------------------------
window.openFlashDoc = function(event, uri) {
	// Flash 無効 (ActiveX Off) なら何もしない: static に書かれた URI を利用
	if (!FlashStat.isEnable) { return; }
	var elem = EventControl.getCurrentElement(event);
	// IE: event.srcElement はイベントの add されたノードだけでなく、その子孫
	//     ノードのうちで実際にアクティブになったものを拾ってしまう仕様
	//     故に親ノードを辿り、実際に目的としている要素まで行かなければならない
	do {
		// event.currentTarget がサポートされていればループしない
		if (elem.nodeName && "a" == elem.nodeName.toLowerCase()) {
			if (elem.getAttribute("href") == uri) { break; }
			elem.setAttribute("href", uri);
			break;
		}
		// event.srcElement の場合は目的とするノードに到達するまでループ
		elem = elem.parentNode;
	} while (elem); // root に到達してしまっても何もしない
}


// ----------------------------------------------------------------------------
// TbodyScroll: tbody 要素スクロール
// ----------------------------------------------------------------------------
function TbodyScroll() {
	this.targets = null,
	this.offset = {top : 20, bottom : 20}, // 上下のオフセット (px)
	this.classNames = {
		target   : "flexible-y", // target table
		active   : "active",     // scroll active
		gecko    : "type1",      // Gecko
		anothers : "type2",      // WebKit, Presto
		// Trident
		cont     : "flexibleTable",
		contBody : "flexibleTableBody",
		first    : "first",
		last     : "last"
	};
}

// tbody スクロール実装（レンダリングエンジン別）
(function() {
	var func = function() {};
	if (UA.engine.isTrident) {
		func = function(table) {
			// コンテナ生成
			var cont = document.createElement('div');
			var contBody = document.createElement('div');
			// non active -----------------------------------------------------
			this._setClassName(cont, this.classNames.cont);
			this._setClassName(contBody, this.classNames.contBody);
			table.cellPadding = 0;
			table.cellSpacing = 0;
			// 挿入
			table.parentNode.insertBefore(cont, table);
			cont.appendChild(contBody).appendChild(table);
			// width 設定
			var tw = table.offsetWidth;
			cont.style.width = contBody.style.width
							 = table.style.width = tw+"px";
			// table margin をコンテナに移植
			cont.style.margin = table.currentStyle.margin;
			table.style.margin = "0";
			// tbody の最終行にクラス付与
			var lastTbody = table.tBodies[table.tBodies.length-1];
			var lastTbodyRow = lastTbody.rows[lastTbody.rows.length-1];
			this._setClassName(lastTbodyRow, this.classNames.last);
			// 全セルにクラス付与
			this._setCellClassName(table);
			// active ---------------------------------------------------------
			this._activateTrident(table, cont, contBody);
			this._setScrollBarAreaTrident(table);
		};
	} else if (UA.engine.isGecko) {
		func = function(table) {
			this._setClassName(table, this.classNames.gecko);
			// active ---------------------------------------------------------
			this._activate(table);
			// スクロールバー領域確保
			var rows = [];
			var ntb = table.tBodies.length;
			for (var b = 0; b < ntb; b++) {
				rows = rows.concat(convArray(table.tBodies[b].rows));
			}
			this._setScrollBarArea(rows, "paddingRight");
		};
	} else if (UA.engine.isWebKit) {
		func = function(table) {
			var dv = document.defaultView;
			var sw = window.getScrollBarSize().width;
			// non active -----------------------------------------------------
			this._setClassName(table, this.classNames.anothers);
			table.setAttribute("cellpadding", "0");
			table.setAttribute("cellspacing", "0");
			var tw = table.offsetWidth;
			var atw = tw-sw;
			table.style.width = atw+"px";
			// スタイル変更後の値を取得しないようにキャッシュ
			var cells = convArray(table.getElementsByTagName("th"),
								  table.getElementsByTagName("td"));
			var ncache = cells.length;
			var cache = new Array(ncache);
			for (var c = 0; c < ncache; c++) {
				cache[c] = {
					element : cells[c],
					width   : dv.getComputedStyle(cells[c], null).width
				};
			}
			// active ---------------------------------------------------------
			this._activate(table);
			// 幅固定
			table.style.width = tw+"px";
			for (var c = 0; c < ncache; c++) {
				cache[c].element.style.width = cache[c].width
			}
			// スクロールバー領域確保
			var rows = convArray(
				(table.tHead ? table.tHead.rows : []),
				(table.tFoot ? table.tFoot.rows : [])
			);
			this._setScrollBarArea(rows, "width");
		};
	} else {
		// NONE
	}

	TbodyScroll.prototype.enable = function() {
		var tables = this.targets = document.getElementsByClassName(
			this.classNames.target
		);
		var ntables = tables.length;
		for (var t = 0; t < ntables; t++) {
			if (this._isEnable(tables[t])) {
				func.apply(this, [tables[t]]);
			}
		}
	};
})();

// スクロールを ON にするかの是非 (是: true, 非: false)
TbodyScroll.prototype._isEnable = function(table) {
	return (table.offsetHeight > window.getInnerSize().height
								- this.offset.top
								- this.offset.bottom);
};

// スクロールをアクティブにする
// tbody ひとつの高さを次の計算式により導出する
//	 tb = tb - |vh-t-at-ab|
//   at: table 上方空白領域 height
//   ab: table 下方空白領域 height
//   vh: 描画領域 height
//	t: table height
//   tb: tbody height
TbodyScroll.prototype._activate = function(table) {
	this._setClassName(table, this.classNames.active);
	var at = this.offset.top;
	var ab = this.offset.bottom;
	var vh = window.getInnerSize().height;
	var t  = table.offsetHeight;
	var tb = table.tBodies[0].offsetHeight-Math.abs(vh-t-at-ab)+"px";
	var ntBodies = table.tBodies.length;
	for (var b = 0; b < ntBodies; b++) {
		table.tBodies[b].style.height = tb;
	}
};
// Trident 用
TbodyScroll.prototype._activateTrident = function(table, cont, contBody) {
	var thh	= table.tHead ? table.tHead.offsetHeight : 0;
	var tfh	= table.tFoot ? table.tFoot.offsetHeight : 0;
	var height = window.getInnerSize().height
				- this.offset.top
				- this.offset.bottom
				- thh
				- tfh;

	contBody.style.height = height+"px";
	contBody.style.marginTop = thh+"px";
	contBody.style.marginBottom = tfh+"px";

	// thead/tfoot 上下位置調整
	if (table.tHead) {
		var thr = table.tHead.rows;
		var nthr = thr.length;
		var top = 0;
		for (var h = 0; h < nthr; h++) {
			top += thr[h-1] ? thr[h-1].offsetHeight : 0;
			thr[h].style.top = top+"px";
		}
	}
	if (table.tFoot) {
		var tfr = table.tFoot.rows;
		var ntfr = tfr.length;
		var bottom = 0;
		for (var f = ntfr-1; f >= 0; f--) {
			bottom += tfr[f+1] ? tfr[f+1].offsetHeight : 0;
			tfr[f].style.bottom = bottom+"px";
		}
	}
};

// 与行群の各行末セルに対し、スクロールバー幅分の name スタイルを +- する
TbodyScroll.prototype._setScrollBarArea = function(rows, styleName) {
	var sw = window.getScrollBarSize().width;
	var dv = document.defaultView;
	var nrows = rows.length;
	for (var r = 0; r < nrows; r++) {
		var cell = rows[r].cells[rows[r].cells.length-1];
		cell.style[styleName] = (
			parseInt(dv.getComputedStyle(cell, null)[styleName])+sw
		)+"px";
	}
};
// Trident 用
TbodyScroll.prototype._setScrollBarAreaTrident = function(table) {
	var sw = window.getScrollBarSize().width;
	var ntb = table.tBodies.length;
	for (var b = 0; b < ntb; b++) {
		var rows = table.tBodies[b].rows;
		var nrows = rows.length;
		for (var r = 0; r < nrows; r++) {
			var cell = rows[r].cells[rows[r].cells.length-1];
			var ccont = document.createElement("div");
			var childs = cell.childNodes;
			var nchilds = childs.length;
			for (var c = 0; c < nchilds; c++) {
				ccont.appendChild(childs[0]);
			}
			ccont.style.paddingRight = sw+"px";
			cell.appendChild(ccont);
		}
	}
};

// クラス名設定
TbodyScroll.prototype._setClassName = function(target, className) {
	target.className += ((target.className == "") ? "" : " ") + className;
};

// 全セルにクラス設定
TbodyScroll.prototype._setCellClassName = function(table) {
	var rows = table.getElementsByTagName("tr");
	var nrows = rows.length;
	for (var r = 0; r < nrows; r++) {
		var cells = rows[r].cells;
		var ncells = cells.length;
		if (ncells <= 0) { continue; }
		this._setClassName(cells[0], this.classNames.first);
		this._setClassName(cells[ncells-1], this.classNames.last);
	}
};


// ----------------------------------------------------------------------------
// 実行
// ----------------------------------------------------------------------------
EventControl.add(window, "load", function() {
	(new Rollover()).enable();
	(new BackButton("historyBack")).enable();
	/*@cc_on @if (@_jscript_version >= 5.6) @*/
	(new TbodyScroll()).enable();
	/*@end @*/
}, false);

// ----------------------------------------------------------------------------
})();

