_U = new function(){
	this.between = function( a , min , max ){
		return ( a >= min ) && ( a <= max );
	};
	this.isIdx = function( idx , ary ){
		return ary && ary.length && this.between( idx , 0 , ary.length - 1 );
	};
	this.find = function( a , ary ){
		for( var i = ary.length - 1 ; this.isIdx( i , ary ) && a!= ary[i] ; i -- );
		return i;
	};
	this.htmlEscape = function( str ){
		var wkStr = str;
		if( str === null || str === undefined ){
			wkStr = "";
		}else if( str.prototype != String ){
			wkStr = str.toString();
		}

		var ret = wkStr.replace(/\&/g,"&amp;").replace(/\</g,"&lt;").replace(/\>/g,"&gt;").replace(/\"/g,"&quot;");
		return ret;
	};
}();
_O = new function(){
	this.isHas = function( obj , strProp ){
		return obj.hasOwnProperty( strProp );
	};
	//hta対応の為の空関数
	this.defPro = function(){};
	Object.defineProperty( this , "defPro" , {
		get : function(){ 
			return Object.defineProperty;
		},
		set : function( ){  },
		enumerable : true,
		configurable : true
	});
}();
//DOM操作関連
_D = new function(){
	if( ! window.event ){
		var isEvent = function( targ ){
			for( var wk = targ ; wk != null ; wk = wk.__proto__ ){
				if( wk.constructor == Event ){
					return true;
				};
			};
			return false;
		};
		_O.defPro(
			window,"event",{
				get : function(){ 
					var caller = arguments.callee.caller;
					while(caller){
						var ob = caller.arguments[0];
						if(ob && isEvent( ob )) return ob;
						caller = caller.caller;
					};
					return null;
				},
				set : function( ){  },
				enumerable : true,
				configurable : true
			}
		);
	};

	var dc = document;

	//単純ラッパ
	this.g= function(id){ return dc.getElementById(id);};
	this.gTN = function( targ ){
		var ret =[];
		for( var i = 0 ; targ && _U.isIdx( i , targ.childNodes ) ; i++ ){
			if( targ.childNodes[i].nodeName == "#text" ){
				ret.push( targ.childNodes[i].nodeValue );
			};
		};
		return ret;
	};
	this.gN = function( name ){ return dc.getElementsByName(name);};
	var cE = function( str ){ return dc.createElement(str); }
	this.cE = cE;
	this.addEL = function( e , type , f , b ){ return e.addEventListener( type , f , b ); };
	this.delEL = function( e , type , f , b ){ return e.removeEventListener( type , f , b ); };
	this.isC = function( p , e , isRec ){
		if( ! isRec ){
			return e && p == this.par( e );
		};
		for( var pr = this.par( e ) ; pr != null && pr != document ; pr = this.par( pr ) ){
			if( pr == p ){
				return true;
			};
		};
		if( pr == p ){
			return true;
		};
		return false;
	};
	//対象が見えるまでスクロールさせる。
	this.scrollVFor = function( targ , scl , force ){
		if( ! targ || ! scl  || ! this.isC( scl , targ , true ) ){
			return;
		};
		var scRect = scl.getBoundingClientRect();
		var targRect = targ.getBoundingClientRect();
		if( force==true || targRect.top < scRect.top ){
			scl.scrollTop -= scRect.top - targRect.top;
		}else if( force == false || targRect.bottom > scRect.bottom){
			scl.scrollTop += targRect.bottom - scRect.bottom ;
		};
	};

	//親ノードを指定して、下階層からnameが一致するものを取得する。
	//rcが0で子のみ、1で孫、負または省略時で際限なく取得する。
	//その他の値の場合の動作は保証しない。
	this.gNP = function( name , parent , rc ){
		var wkRc = rc;
		if( isNaN(rc) ){
			wkRc = -1;
		};
		var ret =[];
		for( var el = parent.firstElementChild ; el != null ; el = el.nextElementSibling ){
			if( el.name == name ){
				ret.push( el );
			};
			if( wkRc != 0 ){
				ret= ret.concat( this.getNP( name , el , wkRc - 1 ) );
			};
		};
		return ret;
	};

	this.aC = function( p , c ){
		return p.appendChild( c );
	};
	this.rC = function( c , delZIdx ){
		if( delZIdx ){
			this.zIdx.del( c , null , true );
		};
		if( this.par( c ) ){
			return this.par( c ).removeChild( c );
		};
		return c;
	};
	this.iB = function( b , c ){
		return this.par( c ).insertBefore( b , c );
	};
	this.iA = function( b , c ){
		return this.par( c ).insertBefore( b , this.nx( c ) );
	};
	this.par = function( c ){ return c.parentNode ; };
	this.nx = function( c ){ return c.nextSibling ; };
	this.pr = function( c ){ return c.previousSibling ; };
	this.nxE = function( c ){ return c.nextElementSibling ; };
	this.prE = function( c ){ return c.previousElementSibling ; };
	this.fEC = function( c ){ return c.firstElementChild ; };
	this.lEC = function( c ){ return c.lastElementChild ; };

	
	this.getCNP = function( targ , recLim ){

		if( this.fEC( targ ) ){
			return this.fEC( targ );
		} else if( this.nxE(targ) ){
			return this.nxE(targ) ;
		} else {
			for( var p = this.par(targ) ; p != null  ; p = this.par( p ) ){
				if( p == recLim ){
					return null;
				};
				if( this.nxE( p ) ){
					return this.nxE( p );
				};
				if( this.par(p) == p ){
					return null;
				};
			};
		};
		return null;
	};


	var canCreateWithOutName = null;
	this.aCAndCN = function( targ , obj ){
		if( ! _O.isHas( obj , "attr" ) ){
			var ret = dc.createTextNode( obj );
			this.aC( targ , ret );
			return ret;
		};

		var ret = null;
		if( _O.isHas( obj.attr , "tagname" ) ){
			if( canCreateWithOutName == false && _O.isHas( obj.attr , "name") ){
				ret = this.cE( "<" + obj.attr.tagname + " name=\"" + obj.attr.name +  "\">" )
			}else{
				ret = this.cE( obj.attr.tagname );

				if( _O.isHas( obj.attr , "name" ) ){
					ret.name = obj.attr.name;

					if( canCreateWithOutName == null ){
						if( ret.name == obj.attr.name ){
							canCreateWithOutName = true;
						} else {
							canCreateWithOutName = false;
							return this.aCAndCN( targ , obj );
						};
					};
				};
			};
		};
		for( var key in obj.attr ){
			if( key == "name" || key == "tagname" ){
				continue;
			};
			ret[ key ] = obj.attr[ key ];
		};
		this.aC( targ , ret );
		if( _O.isHas( obj , "children") ){
			for( var i = 0 ; i < obj.children.length ; i ++ ){
				this.aCAndCN( ret , obj.children[i] );
			};
		};
		return ret;
	};
	this.cN = function( obj ){
		var ret = this.aCAndCN( document.body , obj );
		this.rC( ret );
		return ret;
	};
	this.cc = function( c , name ){
		c.className = name;
	};
	this.evT = function(){
		return window.event.target;
	};
	this.evCT = function(){
		return window.event.currentTarget;
	};
	this.evBC = function (){ window.event.stopPropagation();};

	this.evPrDef = function(){
		if (window.event.preventDefault) {
			window.event.preventDefault();
		};
		window.event.returnValue = false;
	};


	var classHidden = "_disp_none_";
	var classSelector = null;

	this.show = function ( e , on ){
		if( classSelector == null ){
			var classText = "." + classHidden +"{ display : none !important ;}";
			classSelector = this.css.add( classText );
		};
		if( on == null ){
			this.eCL.tgl( e,classHidden );
		} else {
			if( on ){
				this.eCL.del( e,classHidden );
			}else{
				this.eCL.add( e,classHidden );
			};
		};
	};
	this.isNone = function ( e ){
		return this.eCL.has( e , classHidden );
	};

	//css関連。
	this.css = new function( D ){
		var style = D.cE( "style" );
		dc.head.appendChild( style );
		var sheet = style.sheet;

		//ルールを追加する。cssとして記載する必要あり。
		this.add = function( rule ){
			sheet.insertRule( rule , sheet.cssRules.length );
			return sheet.cssRules[sheet.cssRules.length -1 ].selectorText;
		};
		this.del = function( selector ){
			var ret ="";
			for( var i = 0 ; _U.isIdx( i , sheet.cssRules ) ; i ++ ){
				if( sheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase() ){
					ret += sheet.cssRules[i].cssText ;
					sheet.deleteRule( i );
				};
			};
			return ret;
		};
		//引数は[{attr:XX,value:YY}]の形式
		this.chg = function( selector , ary ){
			var cssTexts = [];
			var aryStyle = document.getElementsByTagName("style");
			var targSheets = [];
			var targIdxs = [];
			//全styleElementを対象に、該当するcssを探す。
			for( var idx = 0 ; _U.isIdx( idx , aryStyle ) ; idx++ ){
				var sheet = aryStyle[idx].sheet;
				for( var i = 0 ; _U.isIdx( i , sheet.cssRules ) ; i ++ ){
					if( sheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase() ){
						cssTexts.push( sheet.cssRules[i].cssText );
						targSheets.push( sheet );
						targIdxs.push(i);
					};
				};
			};

			for( var i = 0 ; _U.isIdx( i , targSheets ) ; i ++ ){
				for( var j = 0 ; _U.isIdx( j , ary ) ; j ++ ){
					targSheets[i].cssRules[ targIdxs[i] ].style[ ary[j].attr ] = ary[j].value;
				};
			};
		};
	}( this );
	this.eCL = new function( D ){
		this.add = function( e , classname ){
			e.classList.add( classname );
		};
		this.del = function( e , classname ){
			e.classList.remove( classname );
		};
		this.tgl = function( e, classname ){
			e.classList.toggle( classname );
		};
		this.has = function( e, classname ){
			return e.classList.contains( classname );
		};
	}( this );
	this.zIdx = new function(){
		var aryElmGrps=[];
		var objGrps ={};
		var aryTop =[];
		var aryBottom =[];
		var getGrpIdx = function( grpName ){
			var ret = _U.find( grpName , aryElmGrps );
			if( ret < 0 ){
				ret = null;
			};
			return ret;
		};
		var getElmIdx = function( elm , grp ){
			var ret = null;
			if( grp ){
				var idx = _U.find( elm , grp );
				if( idx >= 0 ){
					ret = {grp:grp , idx: idx};
				};
			} else {
				ret = getElmIdx( elm , aryTop );
				if( ! ret ){
					for( var key in objGrps ){
						ret = getElmIdx( elm , objGrps[key] );
						if( ret ){
							break;
						};
					};
					if( ! ret ){
						ret = getElmIdx( elm , aryBottom );
					};
				};
			};
			return ret;
		};

		var setZIdx = function( aryDelTarg ){
			var zidx = 0 ;
			var inner= function( grp ){
				for( var i = 0 ; _U.isIdx( i , grp ) ; i ++ , zidx ++ ){
					grp[i].style.zIndex = zidx + 1 ;
				};
			};
			if( aryDelTarg ){
				delZIdx( aryDelTarg );
			};

			inner( aryTop );
			for( var i = 0 ; _U.isIdx( i , aryElmGrps ) ; i ++ ){
				inner( objGrps[ aryElmGrps[i] ] );
			};
			inner( aryBottom );
		};
		var delZIdx = function( aryDelTarg ){
			for( var i = 0 ; _U.isIdx( i , aryDelTarg ) ; i ++ ){
				aryDelTarg[i].style.zIndex = null;
			};
		};

		this.addGrp = function( grpName , ary , unreflesh ){
			//既に名前がある場合、末尾に移動させる。
			var idx = getGrpIdx( grpName );
			if( idx ){
				aryElmGrps.splice( idx , 1 );
			};

			aryElmGrps.push( grpName );
			if( ! _O.isHas( objGrps, grpName ) ){
				objGrps[ grpName ] = [];
			};

			if( ary ){
				this.addA( ary , grpName , unreflesh );
			};
		};
		this.delGrp = function( grpName ){
			//既に名前がある場合、削除する。
			var idx = getGrpIdx( grpName );
			if( idx ){
				aryElmGrps.splice( idx , 1 );
			};
			if( _O.isHas( objGrp , grpName )){
				delZIdx( objGrps[ grpName ] );
				delete objGrps[ grpName ];
			};
		};
		this.insGrp = function( grpName , targGrpName , ary , unreflesh ){
			//既に名前がある場合、先頭に移動させる。
			var idx = getGrpIdx( grpName );
			if( idx ){
				aryElmGrps.splice( idx , 1 );
			};

			var targIdx = null;
			if( targGrpname ){
				targIdx = getGrpIdx( targGrpName );
			}
			if( targIdx == null ){
				targIdx = 0;
			};

			aryElmGrps.splice( targIdx , 0 , grpName );

			if( ! _O.isHas( objGrps , grpName ) ){
				objGrps[ grpName ] = [];
			};

			if( ary ){
				this.addA( ary , grpName , unreflesh );
			};
		};


		this.del = function( elm , grp , unreflesh ){
			var inner = function( elm , grp ){
				for( var i = grp.length - 1 ; _U.isIdx( i , grp )  ; i -- ){
					if( grp[i] == elm ){
						grp.splice( i , 1 );
						delZIdx( [elm] );
					};
				};
			};
			if( grp ){
				inner( elm , grp );
			}else{
				inner( elm , aryTop );
				for( var key in objGrps ){
					inner( elm , objGrps[key] )
				};
				inner( elm , aryBottom );
			};
			if( unreflesh != true ){
				setZIdx( [ elm ] );
			};


		};
		this.add = function( elm , grpName , unreflesh ){
			//省略時は無名末尾グループに対して処理。
			var targGrp = null;
			if( grpName ){
				if( getGrpIdx( grpName ) == null ){
					this.addGrp( grpName );
				};
				targGrp = objGrps[ grpName ];

			}else{
				targGrp = aryBottom;
			};

			//既に存在するかチェックする。のは面倒なので、事前に削除。
			this.del( elm , null , true );

			targGrp.push( elm );

			if( unreflesh != true ){
				setZIdx();
			};

		};
		this.addA = function( ary , grpName , unreflesh ){
			for( var i = 0 ; _U.isIdx( i , ary ) ; i ++ ){
				this.add( ary[i] , grpName , true )
			};
			if( unreflesh != true ){
				setZIdx();
			};
		};
		this.ins = function( elm , targ , grpName , unreflesh ){
			var targGrp = null;


			var targIdx = null;

			//グループ省略時でターゲット指定時は
			//ターゲットが存在するか確認し、
			//存在する場合は該当グループを対象とする。
			//存在しない場合はターゲット省略時と同様とする。
			if( ! grpName ){
				var rettarg = null;
				if( targ ){
					var rettarg = getElmIdx( targ );
				};

				if( rettarg ){
					targGrp = rettarg.grp;
					targIdx = rettarg.idx;
				} else {
					targGrp = aryTop;
					targIdx = 0;
				};
			} else if( grpName ){
				//グループ指定時でグループが存在しない場合は
				//グループを追加する。
				var grpIdx = getGrpIdx( grpName );
				if( grpIdx == null ){
					this.addGrp( grpName );
				};
				targGrp = objGrps[ grpName ];

				//ターゲット指定時はターゲットが存在するか確認し、
				//存在しない場合は、指定グループの先頭に追加する。
				if( grpIdx && targ ){
					var rettarg = getElmIdx( targ , targGrp );
					if( rettarg ){
						targIdx = rettarg.idx;
					}else{
						targIdx = 0;
					};
				}else{
					targIdx = 0;
				};
			};
			
			//既に存在するかチェックする。のは面倒なので、事前に削除。
			this.del( elm , null , true );
			//追加の実処理
			targGrp.splice( targIdx , 0 , elm );

			if( unreflesh != true ){
				setZIdx();
			};
		};
		this.insA = function( ary , grpName , unreflesh ){
			for( var i = ary.length - 1  ; _U.isIdx( i , ary ) ; i -- ){
				this.ins( ary[i] , grpName , true )
			};
			if( unreflesh != true ){
				setZIdx();
			};
		};
		this.reflesh = setZIdx;
		var innerGC = function( targGrp ){
			for( var i = targGrp.length -1 ; _U.isIdx( i , targGrp ) ; i -- ){
				if( ! _D.isC( document , targGrp[i] , true ) ){
					targGrp.splice( i , 1 );
				};
			};
		};
		this.GC = function(){
			innerGC( aryTop );
			for( var key in objGrps ){
				innerGC( objGrps[key] );
			};
			innerGC( aryBottom );
		};
	}();

}();



