/*
 * pettanR common.js
 *   version 0.4.37
 * 
 * author: itozyun
 */

/*
 * http://pettanr.sourceforge.jp/test/type.html
 */
	var Type = {
		isObject : function(v) {
			return v !== null && typeof v === 'object';
		},
		isFunction : function(v) {
			return typeof v === 'function';
		},
		isArray : function(v) {
			return Object.prototype.toString.call(v) === "[object Array]";
		},
		isBoolean : function(v) {
			return typeof v === 'boolean';
		},
		isString : function(v) {
			return typeof v === 'string';
		},
		isNumber : function(v) {
			return typeof v === 'number';
		},
		isFinite : function(v){
			return Type.isNumber(v) === true && isFinite(v);
		},
		isHTMLElement : function(v){
			if( 'HTMLElement' in window ){
				Type.isHTMLElement = function(v){
					return v instanceof HTMLElement;
				}
			} else {
				Type.isHTMLElement = function(v) {
					if( Type.isObject(v) === false ){
						return false;
					}
					var r;
					if(v && v.nodeType === 1){
						try{
							r = v.cloneNode(false);
						} catch(n) {
							return false;
						}
						if(r === v) return false;
						try{
							r.nodeType = 9;
							return r.nodeType === 1;
						} catch(n) {}
						return true;
					}
					return false;
				}
			}
			return Type.isHTMLElement(v);
		},
		/*
		isElementCollection : function(v) {
			return (Object.prototype.toString.call(v) === "[object HTMLCollection]");
		},
		*/
		isNull : function(v) {
			return v === null;
		},
		isUndefined : function(v) {
			return typeof v === 'undefined';
		}
	};


var pettanr = ( function(){
	var	FUNCTION_ARRAY = [],
		URL = document.location.href.split( '#')[ 0 ],
		IS_LOCAL = URL.indexOf( 'file:') === 0,
		URL_PARAMS = ( function(){
			var search = document.location.search,
				l = search.length;
		    if( 1 < l){
		        var	query = search.substring( 1),
					params = query.split( '&'),
					ret = {}, elm, name, v;
		        while( params.length > 0){
		            elm = params.shift().split( '=');
					name = decodeURIComponent( elm[ 0]);
					if( elm.length === 2){
						v = decodeURIComponent( elm[ 1]);
						if( '' + parseFloat( v) === v) v = parseFloat( v);
						if( '' + parseInt( v, 10 ) === '0' + v) v = parseInt( v, 10 );
						if( v === 'true') v = true;
						if( v === 'false') v = false;
						if( v === 'null') v = null;
						if( v === 'undefined') v = undefined;
			            ret[ name] = v;
					} else
					if( elm.length === 1){
						ret[ name] = true;
					}
		        }
		        return ret;
		    }
		    return {};
		})(),
		IS_DEBUG = Type.isBoolean( URL_PARAMS.debug ) ? URL_PARAMS.debug : IS_LOCAL === true,
		jqWindow , jqDocument , jqBody;
	return {
		version: '0.4.36',
		init: function(){
			jqWindow   = $( window );
			jqDocument = $( document );
			jqBody     = $( document.body );
			
			var l = FUNCTION_ARRAY.length,
				_fn;
			for( var i=0; i<l; i++){
				_fn = FUNCTION_ARRAY[ i];
				_fn.init && _fn.init( _fn === pettanr.view ? FUNCTION_ARRAY : undefined );
			}
			
			delete pettanr.init;
		},
		fn: function( _fn){
			FUNCTION_ARRAY.push( _fn);
			pettanr.init === undefined && _fn.init && _fn.init();
		},
		jqWindow: function(){
			return jqWindow;
		},
		jqDocument: function(){
			return jqDocument;
		},
		jqBody: function(){
			return jqBody;
		},
		URL_PARAMS: URL_PARAMS,
		ROOT_PATH: ( function(){
			// script と html の ドメインが一致
			var _h1 = document.getElementsByTagName( 'h1')[ 0],
				_a = _h1.getElementsByTagName( 'a')[ 0],
				_root = _a.href.split( '\/'),
				_current = document.location.href.split( '\/'),
				ret = '.\/';
			for( var i=0, l=_current.length - _root.length; i<l; ++i){
				ret = '.' + ret;
			}
			return ret;
			// script と html の ドメインが不一致
		})(),
		LOCAL: IS_LOCAL,
		DEBUG: IS_DEBUG,
		LINE_FEED_CODE_TEXTAREA: ( function(){
			var text = document.createElement('textarea');
			text.value = '\n';
			return text.value;
		})(),
		LINE_FEED_CODE_PRE: ( function(){
			var pre = document.createElement('pre');
			pre.appendChild( document.createTextNode('\n'));
			return pre.firstChild.data;
		})()
	}
})();

/*
 * pettanr.util
 * 
 *   extend( baseInstance, extend)
 *   cleanCommnetNode()
 *   cleanElement()
 *   getElementSize( _elm)
 *   getImageSize()
 *   getAbsolutePath()
 *   getGrobalObjectName()
 * 
 */
pettanr.util = ( function(){
	var ELM_SIZE_GETTER = ( function(){
			var ret = document.createElement( 'DIV'),
				style = ret.style;
			ret.id = 'elmSizeGetter';
			style.position = 'absolute';
			style.left = '0px';
			style.top = '-9999px';
			style.visibility = 'hidden';
			document.body.appendChild( ret);
			return ret;
		})(),
		IMG_SIZE_GETTER = ( function(){
			var ret = ELM_SIZE_GETTER.cloneNode( true);
			ret.id = 'imgSizeGetter';
			document.body.appendChild( ret);
			return ret;
		})(),
		CLEAN_TARGET_ELEMENT = 'script,style,object,applet,embed,iframe,frame,base,bgsound,frameset,listing'.split( ',');
	
	/* clean comment node */
	cleanCommnetNode();
	
	/* clean noscript */
	var nodeNoscript = document.getElementsByTagName( 'noscript'),
		noscript;
	for(var i=0; i<nodeNoscript.length; ++i){
		noscript = nodeNoscript[i];
		noscript.parentNode && noscript.parentNode.removeChild( noscript);
	}
	nodeNoscript = noscript = null;
	
	function cleanCommnetNode( _targetElm){
		search( _targetElm || document.body );
		
		function search( _elm){
			if( !_elm) return;
			if( _elm.nodeType === 8){
				_elm.parentNode.removeChild( _elm);
				return;
			}
			var i, l, _children = _elm.childNodes, _array = [];
			if( _children && typeof _children.length === 'number'){
				// liveNode > array
				for( i=0, l=_children.length; i<l; ++i){
					_array.push( _children[ i ] );
				}
				while( _array.length !== 0 ){
					search( _array.shift());
				}
			}
		}
	}
	return {
		extend: function( baseInstance, extend ){
			for( var key in extend ){
				if( Type.isUndefined( baseInstance[ key ] ) === true ){
					baseInstance[ key ] = extend[ key ];
				} else
				if( typeof baseInstance[ key ] === typeof extend[ key ] ){
					baseInstance[ key ] = extend[ key ];
				} else {
					alert( 'extend error' );
				}
			}
			return baseInstance;
		},	
		cleanCommnetNode: cleanCommnetNode,
		cleanElement: function( _targetElm){
			var _nodes, _elm, _array, j, m;
			for( var i=0, l=CLEAN_TARGET_ELEMENT.length; i<l; ++i){
				_nodes = _targetElm.getElementsByTagName( CLEAN_TARGET_ELEMENT[ i]);
				_array = [];
				for( j=0, m = _nodes.length; j<m; ++j){
					_array.push( _nodes[ j]);
				}
				for( j=0, m = _array.length; j<m; ++j){
					_elm = _nodes[ j];
					_elm.parentNode && _elm.parentNode.removeChild( _elm);
				}
			}
			cleanCommnetNode( _targetElm);
			if( pettanr.ua.isIE === false) return;
			_nodes = _targetElm.all || _targetElm.getElementsByName( '*');
			for( i=0, l = _nodes.length; i<l; ++i){
				_elm = _nodes[ i];
				_elm.style.filter = '';
				_elm.style.behavior = '';
			}
		},
		getElementSize: function( _elm ){
			if( Type.isHTMLElement( _elm ) === false ){
				return {
					width:	0,
					height:	0
				};
			};
			var	parentElm   = _elm.parentNode,
				prevElm     = _elm.previousSibling,
				nextElm     = _elm.nextSibling,
				displayNone = _elm.style.display === 'none';
			if( displayNone === true ) _elm.style.display = '';
			ELM_SIZE_GETTER.appendChild( _elm );
			var ret = {
				width:		_elm.offsetWidth,
				height:		_elm.offsetHeight
			}
			if( displayNone === true ) _elm.style.display = 'none';
			if( nextElm ){
				parentElm.insertBefore( _elm, nextElm );
			} else		
			if( prevElm && prevElm.nextSibling ){
				parentElm.insertBefore( _elm, prevElm.nextSibling );
			} else {
				parentElm && parentElm.appendChild( _elm );
			}			
			return ret;
		},
		getImageSize: function( img){
			var	parentElm = img.parentNode,
				prevElm = img.previousSibling,
				nextElm = img.nextSibling,
				displayNone = img.style.display === 'none';
			if( displayNone === true) img.style.display = '';
			IMG_SIZE_GETTER.appendChild( img);
			
			var size = getActualDimension( img);
			
			IMG_SIZE_GETTER.removeChild( img);
			if( displayNone === true) img.style.display = 'none';
			if( nextElm){
				parentElm.insertBefore( img, nextElm);
			} else		
			if( prevElm && prevElm.nextSibling){
				parentElm.insertBefore( img, prevElm.nextSibling);
			} else {
				parentElm && parentElm.appendChild( img);
			}
			
		/* LICENSE: MIT
		 * AUTHOR: uupaa.js@gmail.com
		 */
			function getActualDimension(image) {
				var run, mem, w, h, key = "actual";
			
			// for Firefox, Safari, Google Chrome
				if ("naturalWidth" in image) {
					return {
						width:	image.naturalWidth,
						height:	image.naturalHeight
					};
				}
			
				if ("src" in image) { // HTMLImageElement
					if (image[key] && image[key].src === image.src) {
						return image[key];
					}
					if (document.uniqueID) { // for IE
						run = image.runtimeStyle;
						mem = { w: run.width, h: run.height }; // keep runtimeStyle
						run.width  = "auto"; // override
						run.height = "auto";
						w = image.width;
						h = image.height;
						run.width  = mem.w; // restore
						run.height = mem.h;
					} else { // for Opera and Other
						mem = { w: image.width, h: image.height }; // keep current style
						image.removeAttribute("width");
						image.removeAttribute("height");
						w = image.width;
						h = image.height;
						image.width  = mem.w; // restore
						image.height = mem.h;
					}
					return image[key] = { width: w, height: h, src: image.src }; // bond
				}
				// HTMLCanvasElement
				return { width: image.width, height: image.height };
			}
			
			return size;
		},
		getAbsolutePath: function( path) {
			var e = document.createElement("div");
			e.innerHTML = '<a href=\"' + path + '\" />';
			return e.firstChild.href;
		},
		getAbsolutePosition: function( _elm){
			// Find the destination's position
			var	destx = _elm.offsetLeft,
				desty = _elm.offsetTop,
				thisNode = _elm,
				body = document.body;
			while (thisNode.offsetParent && thisNode.offsetParent !== body){
				thisNode = thisNode.offsetParent;
				destx += thisNode.offsetLeft;
				desty += thisNode.offsetTop;
			}
			return {
				x:	destx,
				y:	desty
			}
		},
		pullHtmlAsTemplete: function( IDorELM){
			if( typeof IDorELM === 'string'){
				IDorELM = document.getElementById( IDorELM);
			}
			if( !IDorELM) return;
			IDorELM.parentNode && IDorELM.parentNode.removeChild( IDorELM);
			if( IDorELM.id && IDorELM.id.indexOf( 'templete-') === 0){
				IDorELM.removeAttribute( 'id');
			}
			return IDorELM;
		},
		getElementsByClassName: function( _elm, _className, opt_tagName){
			var _all = !opt_tagName || opt_tagName === '*',
				_nodes = _all === true ? ( _elm.all || _elm.getElementsByTagName( '*')) : _elm.getElementsByTagName( opt_tagName),
				_node, _classes, ret = [];
			for( var i=0, l = _nodes.length; i<l; ++i){
				_node = _nodes[ i];
				_node.nodeType === 1 && this.hasClassName( _node, _className) === true && ret.push( _node);
			}
			return ret;
		},
		getChildIndex: function( _parent, _child){
			var _children = _parent.getElementsByTagName( _child.tagName ),
				l = _children.length;
			for(var i=0; i<l; ++i){
				if( _children[ i] === _child) return i;
			}
			return -1;
		},
		hasClassName: function( _elm, _className){
			var _classes = ( _elm.className || '').split( ' ');
			for( var i=0, l=_classes.length; i<l; ++i){
				if( _classes[ i] === _className) return true;
			}
			return false;
		},
		removeAllChildren: function ( _elm){
			while( _elm.firstChild){
				remove( _elm.firstChild);
			}
			function remove( _node){
				while( _node.firstChild){
					remove( _node.firstChild);
				}
				_node.parentNode && _node.parentNode.removeChild( _node);
			}
		},
		getIndex: function( _array, _element){
			if( Array.prototype.indexof ){
				pettanr.util.getIndex = function( _array, _element){
					return _array.indexof( _element);
				}
			} else {
				pettanr.util.getIndex = function( _array, _element){
					for( var i=0, l = _array.length; i<l; ++i){
						if( _array[ i] === _element) return i;
					}
					return -1;					
				}
			}
			return pettanr.util.getIndex( _array, _element);
		},
		copyArray: function( _array ){
			var ret = new Array( l );
			for(var i=0, l = _array.length; i<l; ++i){
				ret[ i ] = _array[ i ];
			}
			return ret;
		},
		/*
		 * 
		 */
		createGlobalFunction: function( _func) {
			var randomKey = null;
			while( true) {
				randomKey = '_glovalFunction_' + ( '' + Math.random()).replace( /\./,'');
				if( eval( 'typeof '+randomKey) === 'undefined') {
					break;
				}
			}
			window[ randomKey] = _func;
			return randomKey;
		},
		createGlobalFunc: function( func){
			var randomKey = null;
			while(true) {
				randomKey = 'hogeGlovalFunc_'+(''+Math.random()).replace(/\./,'');
				if(eval('typeof '+randomKey) == 'undefined') {
					break;
				}
			}
			eval(randomKey+'='+((typeof func=='string') ? func : func.toString()));
			return randomKey;
		},
		createGlobalVar: function( obj){
			var randomKey = null;
			while(true) {
				randomKey = 'hogeGlovalVar_'+(''+Math.random()).replace(/\./,'');
				if(eval('typeof '+randomKey+'') == 'undefined') {
					break;
				}
			}
			var globalObj = eval(randomKey+'={}');
			globalObj.value = obj;
			return randomKey;
		},
		createGlobalUniqueName: function(){
			var randomKey = null;
			while(true) {
				randomKey = '_uniqueName'+(''+Math.random()).replace(/\./,'');
				if( typeof window[randomKey] === 'undefined'){
					break;
				}
			}
			return randomKey;
		},
		createIframe: function( id, callback){
			var ua = pettanr.ua;
            var el = document.createElement( ua.isIE ? '<iframe name="' + id + '" frameborder="0" scrolling="no">' : 'iframe');

            if( ua.isIE){
				el.onreadystatechange = detect;
            } else {
            	// iron(chrome) の場合、append の前に onload を指定しないと onload が呼ばれない
            	el.onload = onLoad;
            	//setTimeout( asynkCallback, 0 );
			}

			document.body.appendChild( el);
            el.id = el.name = id;
            el.setAttribute( 'name', id);
            el.style.cssText = 'width:1px;height:1px;visibility:hidden;position:absolute;top:1px;left:1px;';
			// http://d.hatena.ne.jp/onozaty/20070830/p1
			// [JavaScript]IE6ではJavaScriptで動的に作成したiframeに対してsubmitできない(IE7は未確認) ->解決
			el.contentWindow.name = id;					
            
            window[id] = el;

            function detect(){
                if ( this.readyState === "complete") {
                    this.onreadystatechange = new Function();
                    this.onreadystatechange = null;
                    setTimeout( asynkCallback, 0 );
                }
            }
			function onLoad(){
				el.onload = null;
				setTimeout( asynkCallback, 0 );
			}
			function asynkCallback(){
				callback( el );
			}
		}
	}
})();

/*
 * pettanr.ua
 * 
 *   detect userAgent
 *   detect plug in
 */
pettanr.ua = ( function(){
	var ua = (function(){
			var acme = {};
			
			var n = navigator;
			var dua = n.userAgent;
			var dav = n.appVersion;
			var tv = parseFloat(dav);
			acme.isOpera = (dua.indexOf("Opera") >= 0) ? tv: undefined;
			acme.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : undefined;
			acme.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined;
			acme.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined;
			var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
			if(index && !acme.isChrome){
				acme.isSafari = parseFloat(dav.split("Version/")[1]);
				if(!acme.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3){
					acme.isSafari = 2;
				}
			}
			if(document.all && !acme.isOpera){
				acme.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
			}
			
			return acme;
		})(),
		isIE = navigator.userAgent.toLowerCase().indexOf( 'msie') !== -1,
		ieVersion = isIE === true ? parseInt( navigator.appVersion.toLowerCase().replace( /.*msie[ ]/, '').match( /^[0-9]+/)) : 0,
		ieRenderingVersion = ieVersion === 8 ? document.documentMode : ieVersion,
		isStanderdMode = document.compatMode === 'CSS1Compat',
		ActiveX = ( function(){
			if( isIE === false || ieVersion > 8) return false;
			var	b = document.body,
				c = b.className || '',
				x,
				ret = pettanr.URL_PARAMS.ActiveX,
				ns = 'pettanr-ActiveX-',
				enabled = 'enabled',
				disabled = 'disabled';
			if( ret !== true && ret !== false){
				if( pettanr.util.hasClassName( b, ns + enabled) === true) return true;
				if( pettanr.util.hasClassName( b, ns + disabled) === true) return false;
				x = document.createElement('div');
				b.appendChild(x);
				x.style.cssText = 'width:1px;height:1px;line-height:1px;filter:progid:DXImageTransform.Microsoft.Shadow()';
				ret = x.offsetHeight > 1;
				b.removeChild(x);
			}
			b.className += [ c !== '' ? ' ' : c, ns, ret === true ? enabled : disabled ].join( '');
			return ret;
		})(),
		VML = ( function(){
			if( ActiveX === false || isIE === false || ieVersion > 8) return false;
			var globalObjectName = pettanr.util.createGlobalUniqueName(),
				script,
				id = 'detectVML';
			document.write( [ '<!--[if gte vml 1]><script id="', id, '">window', '.', globalObjectName, '=1;<\/script><![endif]-->'].join( ''));
			if( window[globalObjectName] === 1){
				script = document.getElementById( id);
				script.parentNode.removeChild( script);
				window[globalObjectName] = null;
				return true;
			}
			return false;
		})(),
		isStandAloneMode = ( function(){
			if( isIE === false) return false;
			if( VML === true) return false;
			var globalObjectName = pettanr.util.createGlobalUniqueName(),
				script,
				id = 'detectStandAlone';
			document.write( [ '<!--[if IE ', Math.floor( ieVersion), ']><script id="', id, '">window', '.', globalObjectName, '=1;<\/script><![endif]-->'].join( ''));
			if( window[globalObjectName] === 1){
				script = document.getElementById( id);
				script.parentNode.removeChild( script);
				window[globalObjectName] = null;
				return false;
			}
			return true;
		})();
	return {
		IE:					ua.isIE,
		GECKO:				0,
		OPERA:				ua.isOpera,
		KHTML:				ua.isKhtml,
		WEBKIT:				ua.isWebKit,
		CHROME:				ua.isChrome,
		isIE:				isIE,
		ieVersion:			ieVersion,
		ieRenderingVersion:	ieRenderingVersion,
		isStanderdMode:		isStanderdMode,
		VENDER_PREFIX: ( function() {
			var ua = navigator.userAgent.toLowerCase();
			if ( ua.indexOf('opera') !== -1) {
				return 'O';
			} else if ( ua.indexOf('msie') !== -1) {
				return 'ms';
			} else if ( ua.indexOf('webkit') !== -1) {
				return 'webkit';
			} else if ( navigator.product === 'Gecko') {
				return 'Moz';
			}
			return '';
		})(),
		ACTIVEX: ActiveX,
		VML: VML,
		STANDALONE: isStandAloneMode,
		startVML: function(){
			delete this.startVML;
			if( pettanr.ua.VML !== true) return false;
			if (!document.namespaces["v"]) {
		        document.namespaces.add("v", "urn:schemas-microsoft-com:vml", "#default#VML");
		    }
		    document.createStyleSheet().cssText = "v\:shape,v\:image{behavior:url(#default#VML);display:block;};";
		}
	}
})();


pettanr.CONST = ( function(){
	var SERVER_SUPPORT    = !( 'has_server_support' in window && has_server_support === false ),
		PETTANR_ROOT_PATH = ( function(){
			if( SERVER_SUPPORT === false ){
				var h1 = document.getElementsByTagName( 'h1' )[ 0 ];
				if( h1 ){
					var a = h1.getElementsByTagName( 'a' )[ 0 ];
					return a ? a.href : '';
				}
				return '';
			}
			var loc = document.location;
			return [ loc.protocol, '\/\/', loc.host, '\/' ].join( '' );
		})(),
		RELATIVE = ( function(){
			var ret  = '',
				loc  = document.location,
				path = [ loc.protocol, '\/', loc.host, '\/', loc.pathname.split( '\\' ).join( '\/' ) ].join( '' ),
				l    = path.split( '\/' ).length - PETTANR_ROOT_PATH.split( '\/' ).length;
			for( var i=0; i<l; ++i ){
				ret += '..\/';
			}
			return ret;
		})();
		
	return {
		PETTANR_ROOT_PATH:			PETTANR_ROOT_PATH,
		URL_ORIGINAL_PICTURES_JSON: ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'original_pictures.json',
		URL_RESOURCE_PICTURES_JSON: ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'resource_pictures.json',
		URL_COMICS_JSON:			( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'comics.json',
		URL_PANELS_JSON:			( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'panels.json',
		NS_PETTANR_COMIC:			'pettanr-comic',
		RESOURCE_PICTURE_PATH:		( SERVER_SUPPORT === false ? RELATIVE : PETTANR_ROOT_PATH ) + 'resource_pictures\/',
		SYSTEM_PICTURE_PATH:		( SERVER_SUPPORT === false ? RELATIVE : PETTANR_ROOT_PATH ) + 'system_pictures\/',
		CREATE_COMIC_JS:			SERVER_SUPPORT === false ? 'js\/create_new_comic.js' : PETTANR_ROOT_PATH + 'comics\/new.js',
		CREATE_PANEL_JS:			SERVER_SUPPORT === false ? 'js\/create_new_panel.js' : PETTANR_ROOT_PATH + 'panels\/new.js',
		UPLOAD_PICTURE_JS:			SERVER_SUPPORT === false ? 'js\/upload_picture.js' : PETTANR_ROOT_PATH + 'original_pictures\/new.js',
		REGISTER_ARTIST_JS:			SERVER_SUPPORT === false ? 'js\/register_artist.js' : PETTANR_ROOT_PATH + 'artists\/new.js',
		JQUERY_URL:					SERVER_SUPPORT === false ? 'javascripts\/jquery-1.6.2.min.js' : PETTANR_ROOT_PATH + 'assets\/jquery-162_min.js',
		SERVER_SUPPORT:				SERVER_SUPPORT
	}
})();

pettanr.view = ( function(){
	/* create iframe overlay for user console */
	var LoginUserNavi = {
			show: function(){
				var i = pettanr.util.getChildIndex( this.parentNode, this );
				i !== -1 && bootApplication( i );
				return false;
			},
			hide: function(){}
		}

	/* debug info */
	// ua version, lang, os, plugin ( vml, svg), standerdmode, balloon, rimg

/*
 * window resize event, overlay と currentなviewに流す
 * view modeの保持
 * 	 editor, overlay, comic-viewer, image-explorer
 * fadeIn, faseOut
 */

	var jqWindow,
		APPLICATION_LIST = [],
		LUNCHER_APPLICATION_LIST = [],
		currentApplication = null;
	
	var AbstractBasicPane = function(){
		this.onPaneResize = function( _w, _h ){}
		this.resize = function( _w, _h ){
			if( this.MIN_WIDTH > _w || this.MIN_HEIGHT > _h ){
				if( Type.isHTMLElement( this.rootElement ) === true ){
					// 小さすぎる！、と表示
				};
				return;
			};
			this.onPaneResize( _w, _h );
		};
		this.MIN_WIDTH = 240;
		this.MIN_HEIGHT = 240;
	}
	
	var AbstractApplication = function(){
		var instance;
		this.displayName = 'app name';
		this.ID = 'app id';
		this.rootElement = null;
		this.parentElement = null;
		this.nextSibling = null;
		this.getUID = function(){
			return pettanr.util.getIndex( APPLICATION_LIST, instance );
		}
		this.open = function( _w, _h /*, _option */ ){
			instance = this;
			if( this.MIN_WIDTH > _w || this.MIN_HEIGHT > _h ){
				if( Type.isHTMLElement( this.rootElement ) === true ){
					// 小さすぎる！、と表示
				}
			}
			if( arguments.length > 2){
				// argumentsRellay( this.onOpen, arguments );
				this.onOpen.apply( this, arguments );
			} else {
				this.onOpen( _w, _h );
			}
		};
		this.close = function(){
			if( this.onClose() === false ){
				return false;
			}
		};
		this.onOpen = function( _w, _h /*, _option */ ){
			// overrride
		};
		this.onClose = function(){
			// overrride
			return true;
		}; // false の場合、close の拒否 
		this.addMouseEventListener = function( _element, _eventType, _handler ){
			 MouseEventManager.add( instance, _element, _eventType, _handler );
		};
	}
	AbstractApplication.prototype = new AbstractBasicPane();
	
	var ApplicationReference = function( application ){
		this.inOverlay = false;
		this.getUID = function(){
			return pettanr.util.getIndex( APPLICATION_LIST, application );
		}
		this.boot = function( /* _option */ ){
			if( arguments.length > 0 ){
				bootApplication( application, pettanr.util.copyArray( arguments ) );
			} else {
				bootApplication( application );
			}
		}
		this.bootInOverlay = function( /* _option */ ){
			this.inOverlay = true;
			pettanr.overlay.show( application, pettanr.util.copyArray( arguments ) );
		}
		this.shutdown = function(){
			if( this.inOverlay === true ){
				pettanr.overlay.hide();
				this.inOverlay = false;
			} else {
				bootApplication( 0 );
			}
		}
		this.addToLancher = function(){
			if( pettanr.util.getIndex( LUNCHER_APPLICATION_LIST, application ) !== -1 ) return;
			LUNCHER_APPLICATION_LIST.push( application );
	
			var navi = document.getElementById('global-navi'),
				item = document.createElement('a');
			navi.appendChild( item );
			navi.style.width = ( ( item.offsetWidth || 80 ) * LUNCHER_APPLICATION_LIST.length ) + 'px';
			item.href = '#';
			item.appendChild( document.createTextNode( application.displayName ));
			item.onclick = LoginUserNavi.show;
		}
	}

	function bootApplication( APPLICATIONorINDEX, _arguments ){
		var _application,
			i, j, l, 
			nodesA = document.getElementById('global-navi').getElementsByTagName( 'a') || [],
			_index = -1;
		if( typeof APPLICATIONorINDEX === 'number' && APPLICATIONorINDEX < LUNCHER_APPLICATION_LIST.length){
			_application = LUNCHER_APPLICATION_LIST[ APPLICATIONorINDEX ];
		} else
		if( typeof APPLICATIONorINDEX === 'string' ){
			for( i=0, l=LUNCHER_APPLICATION_LIST.length; i<l; ++i ){
				if( APPLICATIONorINDEX === APPLICATION_LIST[ i ].ID ){
					_application = APPLICATION_LIST[ i ];
					break;
				}
			}
		} else
		if( pettanr.view.isApplicationInstance( APPLICATIONorINDEX ) === true ){
			_application = APPLICATIONorINDEX;
		} else
		if( !currentApplication ){
			_application = LUNCHER_APPLICATION_LIST[ 0 ];
		} else {
			return;
		}
		
		if( !_application ) return;
		
		for( i=0, l=LUNCHER_APPLICATION_LIST.length; i<l; ++i ){
			if( _application === LUNCHER_APPLICATION_LIST[ i ] ){
				for( j=0, l=nodesA.length; j<l; ++j ){
					nodesA[ j ].className = i === j ? 'current' : '';
				}					
				break;
			}
		}
		
		if( currentApplication === _application ) return;
		if( currentApplication ){
			currentApplication.close();
			currentApplication.rootElement && currentApplication.rootElement.parentNode &&
				currentApplication.rootElement.parentNode.removeChild( currentApplication.rootElement );
		}
			
		currentApplication = _application;
		
		if( _application.nextSibling && _application.nextSibling.parentNode === _application.parentElement ){
			_application.parentElement.insertBefore( _application.rootElement, _application.nextSibling );
		} else
		if( _application.parentElement ){
			_application.parentElement.appendChild( _application.rootElement );
		} else {
			_application.rootElement && document.body.appendChild( _application.rootElement );
		}
			
		if( _arguments ){
			_arguments.unshift( jqWindow.width(), jqWindow.height() );
			_application.open.apply( _application, _arguments );
			// argumentsRellay( _application.open, _arguments );
		} else {
			_application.open( jqWindow.width(), jqWindow.height() );
		}
		pettanr.view.currentID = _application.ID;
	}
	
	function argumentsRellay( _method, _arguments ){
		alert( typeof _method )
		l = _arguments.length;
		if( l > 0 ){
			var _arg = [];
			for( i=0; i<l; ++i ){
				_arg.push( 'a[' + i + ']' );
			}
			window['_method'] = _method;
			//eval( '_method(' + _arg.join(',') + ')' );
			var f = new Function( 'a', '_method(' + _arg.join(',') + ')' );
			f( _arguments );
			window['_method'] = undefined;
		} else {
			_method();
		}		
	}
	
	function onWindowResize(){
		var w = jqWindow.width(),
			h = jqWindow.height();
		currentApplication && currentApplication.resize( w, h );
		pettanr.overlay.onWindowResize( w, h );
		pettanr.form.onWindowResize( w, h );
	}

	return {
		init: function( _funcArray ){
			jqWindow = pettanr.jqWindow();
			jqWindow.resize( onWindowResize );
			
			var _option = {}; // urlパラメータ
			
			onWindowResize();
			
			bootApplication( pettanr.URL_PARAMS.view || 0 );
			
			delete pettanr.view.init;
		},
		createBasicPane: function( _class, _options ){
			_class.prototype = new AbstractBasicPane();
			return new _class( _options );
		},
		_getAbstractApplication: function(){
			return new AbstractApplication();
		},
		registerApplication: function( _class, _options ){
			_class.prototype = new AbstractApplication();
			_application = new _class( _options );
			
			var elm = _application.rootElement;
			if( Type.isHTMLElement( elm ) === false ) return null;
			 
			_application.parentElement = elm.parentNode;
			_application.nextSibling = elm.nextSibling;
			
			if( elm.parentNode ){
				elm.parentNode.removeChild( elm );
			}
			APPLICATION_LIST.push( _application );
			return new ApplicationReference( _application );
		},
		isBasicPaneInstance: function( _basicPane ){
			return  _basicPane instanceof AbstractBasicPane;
		},
		isApplicationInstance: function( _application ){
			return _application instanceof AbstractApplication;
		},
		isApplicationReference: function( _reference ){
			return _reference instanceof ApplicationReference;
		},
		currentID:	null,
		EDITOR:		'editor',
		OVERLAY:	'overlay'
	}
})();

pettanr.overlay = ( function(){
	var SHADOW_OPACITY = 0.5,
		ELM_CONTAINER  = document.getElementById( 'overlay-container' ),
		currentOverlay = null,
		bootParams     = null,
		visible        = false,
		jqConteiner, jqShadow, jqCloseButton,// jqBody, 
		windowW, windowH;

	function asyncResize(){
		currentOverlay.resize( windowW, windowH );
	}
	function onCloseClick( e){
		pettanr.overlay.hide();
		e.preventDefault();
		return false;
	}
	function onFadeInComplete(){

	}
	function onFadeOutComplete(){
		currentOverlay.close();
		currentOverlay.rootElement.style.display = 'none';
		currentOverlay.rootElement.style.visibility = 'hidden';
		currentOverlay = null;	
	}
	return {
		init: function(){
			//jqBody = pettanr.jqBody();
			jqConteiner   = $( '#overlay-container');
			jqShadow      = $( '#overlay-shadow');
			jqCloseButton = $( '#overlay-close-button').click( onCloseClick );
			
			pettanr.key.addKeyDownEvent( pettanr.view.OVERLAY, 27, false, false, pettanr.overlay.hide ); // 27.esc
			
			delete pettanr.overlay.init;
		},
		show: function( _overlay, _bootParams ){
			if( visible === true && currentOverlay === _overlay ) return;
			if( pettanr.view.isApplicationInstance( _overlay ) === false ) return;
			
			document.body.style.overflow = 'hidden';
			document.body.appendChild( ELM_CONTAINER ); // ie6-8 で必要、なんで、、、？
			
			this.visible = visible = true;
			this.currentID = _overlay.ID;
			currentOverlay = _overlay;
			bootParams = _bootParams;

			jqConteiner.stop().css( {
				filter:		'',
				opacity:	'',
				top:		document.documentElement.scrollTop || document.body.scrollTop
			}).fadeIn( onFadeInComplete );
			
			currentOverlay.rootElement.style.display = '';
			currentOverlay.rootElement.style.visibility = 'visible';
			
			ELM_CONTAINER.insertBefore( currentOverlay.rootElement, document.getElementById( 'overlay-close-button' ));
	
			if( Type.isArray( bootParams ) === true ){
				bootParams.unshift( windowW, windowH )
				currentOverlay.open.apply( currentOverlay, bootParams );
			} else {
				currentOverlay.open( windowW, windowH, bootParams );
			}
		},
		hide: function(){
			if( visible === false) return;
			document.body.style.overflow = '';
			
			jqConteiner.stop().css( {
				filter:		'',
				opacity:	''
			}).fadeOut( onFadeOutComplete );
			this.visible = visible = false;
			this.currentID = null;
		},
		visible: visible,
		currentID: null,
		onWindowResize: function( _windowW, _windowH ){
			windowW = _windowW;
			windowH = _windowH;			
			
			if( currentOverlay === null ) return;
			
			jqConteiner.css({
				height:		_windowH,
				top:		document.documentElement.scrollTop || document.body.scrollTop
			});
			jqShadow.css( { height:	_windowH });
			// 先にeditorのcanvasを確定する。
			setTimeout( asyncResize, 0);
		}
	}
})();

/* ----------------------------------------
 * KEY
 * 
 *  - EDITABLE_TEXT_CONTROL
 * 
 *    .SHIFT_DOWN_EVENT:	'shiftDown',
 *    .SHIFT_UP_EVENT:		'shiftUp',
 *    .CTRL_DOWN_EVENT:		'ctrlDown',
 *    .CTRL_UP_EVENT:		'ctrlUp',
 *    .SPACE_DOWN_EVENT:	'spaceDown',
 *    .SPACE_UP_EVENT:		'spaceUp',
 *    .init:				function,
 *    .addKeyDownEvent:		function,
 *    .keyEventDispatcher:	function,
 * 
 * ショートカットキーの監視とテキスト入力(input, textarea)、チェックボックスを管理する。
 * キー入力はdocumentで受けて、テキスト編集中(input, textarea)はそちらにキーイベント流す。
 * 
 */
pettanr.key = ( function(){
	var log,
		jqWindow,
		keyOperationChatcher,
		KEYEVENT_ARRAY = [],
		shiftEnabled = false,
		ctrlEnabled = false;
	
	function keyHit( e){
		log.html( [ e.keyCode, e.shiftKey, e.ctrlKey, e.altKey, e.type].join( ','));
		//keyOperationChatcher.val( '');
		var cancel = false,
			type = e.type,
			key = e.keyCode,
			overlayEnabled = pettanr.overlay.visible === true,
			currentViewID = overlayEnabled === true ? pettanr.overlay.currentID : pettanr.view.currentID;
		if( type === 'keypress') type = 'keydown';
		if( pettanr.form.keyEventRellay( e ) === false ){
			var shift = e.shiftKey,
				ctrl = e.ctrlKey,
				l = KEYEVENT_ARRAY.length,
				d;
			if( key === 16 || e.shiftKey === true){
				shiftEnabled = type !== 'keyup';
			}
			if( key === 17 || e.ctrlKey === true){
				ctrlEnabled = type !== 'keyup';
			}

			for( var i=0; i<l; i++){
				d = KEYEVENT_ARRAY[ i];
				if( (
						d.viewID === currentViewID ||
							( overlayEnabled === true && d.viewID === pettanr.view.OVERLAY)
					) &&
					d.keyCode === key &&
					( d.shift === undefined || d.shift === shift) &&
					( d.ctrl === undefined || d.ctrl === ctrl)
				){
					Type.isFunction( d[ type ]) === true && new asyncCallback( d[ type ], e );
					cancel = true;
				}
			}
		}
		if( cancel === true || key === 18 || key === 9 || key === 27 || e.altKey === true){ // 13.enter 18.esc 9.tab 27.esc   || ( key === 13 && overlayEnabled === false)
			e.preventDefault();
	        e.keyCode      = 0;
	        e.cancelBubble = true;
	        e.returnValue  = false;
			return false;
		}
	}
	function asyncCallback( func, e ){
		window.setTimeout( _callback, 0 );
		function _callback(){
			func( e );
			func = e = null;
		}
	}	
	
	var keyPress = pettanr.ua.isIE === true && pettanr.ua.ieRenderingVersion < 8 ? ( function( e){
			var key = e.keyCode;
			if( key === 13 || key === 27){
				keyHit( e);
				return false;
			}
	}) : null;
	
	return {
		init: function(){
			log = $( '#key-event-log').html( 'ready');

			jqWindow = pettanr.jqWindow().focus();
			keyOperationChatcher = pettanr.jqDocument()
				.keydown( keyHit )
				.keyup( keyHit )
				.mouseenter( function(){
					jqWindow.focus();
				});
			keyPress !== null && keyOperationChatcher.keypress( keyPress );

			delete pettanr.key.init;
		},
		addKeyDownEvent: function( _viewID, _keyCode, _shift, _ctrl, _callbackFunction){
			KEYEVENT_ARRAY.push( {
				viewID:			_viewID,
				keyCode:		_keyCode,
				shift:			_shift,
				ctrl:			_ctrl,
				keydown:		_callbackFunction
			});
		},
		addKeyUpdateEvent: function( _viewID, _keyCode, _shift, _ctrl, _callbackFunction){
			KEYEVENT_ARRAY.push( {
				viewID:		_viewID,
				keyCode:	_keyCode,
				shift:		_shift,
				ctrl:		_ctrl,
				keydown:	_callbackFunction,
				keyup:		_callbackFunction
			});
		},
		addCursorEvent: function( _viewID, _shift, _ctrl, _callbackFunction){
			
		},
		keyEventDispatcher: function(){
			return keyOperationChatcher;
		},
		shiftEnabled: function(){
			return shiftEnabled;
		},
		ctrlEnabled: function(){
			return ctrlEnabled;
		}
	}
})();

/*
 * pettanr.form
 * 
 * keyEventRellay
 *  form -> overlay -> view
 * 
 */
pettanr.form = ( function(){
	var	FORM_GROUP_TABLE = {},
		currentID = null,
		currentItem = null,
		CLASSNAME_COMBOBOX_OPTION = 'combobox-option',
		windowW, windowH,
		ELM_A_ORIGIN = ( function(){
			var ret = document.createElement( 'a');
			ret.href = '#';
			return ret;
		})(),
		ELM_INPUT_TEXT = ( function(){
			var ret = document.createElement( 'input');
			ret.type = 'text';
			return ret;
		})(),
		ELM_COMBOBOX = ( function(){
			var ret = document.createElement( 'a'),
				elmToggle = document.createElement( 'span' ),
				elmValue = document.createElement( 'span' );
			ret.href = '#';
			ret.appendChild( elmToggle );
			ret.appendChild( elmValue );
			elmToggle.className = 'combobox-toggle';
			elmValue.className = 'combobox-value';
			
			elmToggle.appendChild( document.createTextNode( '▼' ));
			elmValue.appendChild( document.createTextNode( 'null' ));
			return ret;
		})();
		
	var InputTextClass = function( WRAPPER_ELM, ON_UPDATE_FUNCTION, GROUP_ID, validater ){
		validater = Type.isFunction( validater ) === true ? validater : null;
		
		var elmValue = pettanr.util.getElementsByClassName( WRAPPER_ELM, 'editable-value' )[ 0],
			value,
			instance = this,
			focus = false,
			visible = true,
			enabled = true,
			elmA = ELM_A_ORIGIN.cloneNode( true );
		
		if( elmValue === undefined ){
			alert( 'error!');
		}
		value = elmValue.innerHTML;
		elmValue.innerHTML = '';
		elmValue.className += ' editable-text';
		try {
			elmA.innerHTML = value;
		} catch(e){
			alert( value )
		}
		
		elmValue.appendChild( elmA );
		WRAPPER_ELM.onclick = onClick;
		
		function onClick(){
			focus = true;
			start( instance );
			elmA.style.display = 'none';
			elmValue.appendChild( ELM_INPUT_TEXT );
			ELM_INPUT_TEXT.value = value;
			ELM_INPUT_TEXT.focus();
			ELM_INPUT_TEXT.select();
			return false;
		}
		
		this.value = function( _value ){
			if( _value !== undefined){
				elmA.innerHTML = _value;
				value = _value;
				
				if( focus === true){
					ELM_INPUT_TEXT.value = value;
				}
			}
			currentItem === instance && instance.blur();
			return value;
		}
		this.focus = function(){
			onClick();
		}
		this.blur = function( keep ){
			var _newValue = ELM_INPUT_TEXT.value,
				_validated = validater !== null ? '' + validater( _newValue ) : _newValue;
			_newValue = keep !== 27 ? _validated : value; // 27:ESC

			elmValue.removeChild( ELM_INPUT_TEXT );
			
			elmA.innerHTML = _newValue;
			elmA.style.display = 'block';
			
			ON_UPDATE_FUNCTION && _newValue !== value && ON_UPDATE_FUNCTION( _newValue, value );
			
			value = _newValue;
			focus = false;
			
			currentItem = null;
		}
		this.enabled = function(){
			return enabled;
		}
		this.visible = function( _visible ){
			if( _visible === true){
				WRAPPER_ELM.style.display = '';
				visible = true;
			} else
			if( _visible === false){
				WRAPPER_ELM.style.display = 'none';
				visible = false;
			}
			return visible;
		}
		this.groupID = GROUP_ID;
	}
	
	var ButtonClass = function( WRAPPER_ELM, ON_CLICK_FUNCTION, GROUP_ID ){
		var className = WRAPPER_ELM.className || '',
			instance = this,
			focus = false,
			visible = true,
			enabled = true;
			
		WRAPPER_ELM.onclick = onClick;
		
		function onClick(){
			focus = true;
			ON_CLICK_FUNCTION();
			return false;
		}
		this.focus = function(){
			focus = true;
			WRAPPER_ELM.className = className + ' button-has-focus';
			start( instance );
		}
		this.blur = function( keyCode ){
			keyCode === 13 && ON_CLICK_FUNCTION();
			WRAPPER_ELM.className = className;
			focus = false;
			finish( instance );
		}
		this.enabled = function(){
			return enabled;
		}
		this.visible = function( _visible ){
			if( _visible === true){
				WRAPPER_ELM.style.display = '';
				visible = true;
			} else
			if( _visible === false){
				WRAPPER_ELM.style.display = 'none';
				visible = false;
			}
			return visible;
		}
		this.groupID = GROUP_ID;
	}

	var FileInputClass = function( WRAPPER_ELM, ON_UPDATE_FUNCTION, GROUP_ID, validater, elmFileInput ){
		validater = Type.isFunction( validater ) === true ? validater : null;
		
		var elmFilePath = pettanr.util.getElementsByClassName( WRAPPER_ELM, 'file-path')[ 0],
			value,
			index = GROUP_ID ? FORM_GROUP_TABLE[ GROUP_ID].length : -1,
			instance,
			focus = false,
			visible = true,
			enabled = true;
		elmFileInput = WRAPPER_ELM.getElementsByTagName('input')[0] || elmFileInput || document.createElement( 'input');
		elmFileInput.type = 'file';
		elmFileInput.style.visivility = 'hidden';

		WRAPPER_ELM.onclick = onClick;
		elmFileInput.onchenge = onChange;
		
		function onClick( e){
			focus = true;
			start( instance );
			elmFileInput.click();
			return false;
		}
		
		function onChange(){
			elmFilePath.innerHTML = elmFileInput.value;
		}
		return {
			init: function(){
				instance = this;
				delete this.init;
			},
			focus: function(){
				onClick();
			},
			blur: function( keep ){
				focus = false;
			},
			enabled: function(){
				return enabled;
			},
			visible: function( _visible){
				if( _visible === true){
					WRAPPER_ELM.style.display = '';
					visible = true;
				} else
				if( _visible === false){
					WRAPPER_ELM.style.display = 'none';
					visible = false;
				}
				return visible;
			},
			index : index,
			groupID: GROUP_ID
		}
	}

	var ComboBoxClass = function( WRAPPER_ELM, ON_UPDATE_FUNCTION, GROUP_ID ){
		var elmBox = pettanr.util.getElementsByClassName( WRAPPER_ELM, 'combobox' )[ 0 ],
			elmA = ELM_COMBOBOX.cloneNode( true ),
			elmToggle = pettanr.util.getElementsByClassName( elmA, 'combobox-toggle' )[ 0 ],
			elmValue = pettanr.util.getElementsByClassName( elmA, 'combobox-value' )[ 0 ].firstChild,
			value, index = 0,
			optionList = [],
			instance = this,
			oldBodyMouseupHandler,
			focus = false,
			visible = true,
			enabled = true;
			
		elmBox.appendChild( elmA );
		WRAPPER_ELM.onclick = onClick;
		
		function onClick(){
			WRAPPER_ELM.onclick = null;
			focus = true;
			elmA.className = 'combobox-has-focus';
			start( instance );
			OptionControl.show( instance, optionList );
			return false;
		}
		this.elm = elmBox;
		this.focus = function(){
			onClick();
		}
		this.blur = function( keyCode ){
			OptionControl.hide( instance );
			focus = false;
			elmA.className = '';
			finish( instance );
			WRAPPER_ELM.onclick = onClick;
		}
		this.enabled = function(){
			return enabled;
		}
		this.visible = function( _visible ){
			if( _visible === true){
				WRAPPER_ELM.style.display = '';
				visible = true;
			} else
			if( _visible === false){
				WRAPPER_ELM.style.display = 'none';
				visible = false;
			}
			return visible;
		}
		this.value = function( _value ){
			var i, j,
				l=optionList.length,
				_option;
			if( Type.isString( _value ) === true && value !== _value ){
				for( i=0; i<l; ++i ){
					_option = optionList[ i ];
					if( _value === _option.value ){
						value = _value;
						index = i;
						elmValue.data = _option.displayValue;
						if( focus === true ){
							OptionControl.update( instance, _value );
						}
						break;
					}
				}
			}
			return value;
		}
		this.selectIndex = function(){
			return index;
		}
		this.createOption = function( displayValue, _value, isSelected ){
			var exist = false,
				option = null, _option,
				_index;
			_value = _value || displayValue;
			for( var i = 0, l = optionList.length; i < l; ++i ){
				if( _value === optionList[ i ].value ){
					option = optionList[ i ];
					_index = i;
					break;
				}
			}
			if( option === null ){
				option = new OptionClass( instance, displayValue, _value );
				_index = optionList.length;
				optionList.push( option );
			}
			if( isSelected === true ){
				elmValue.data = option.displayValue;
				value = _value;
				index = _index;
				for( i = 0, l = optionList.length; i < l; ++i ){
					_option = optionList[ i ];
					_option.current( _option.value === _value );
				}
			}
			return option;
		}
		this.groupID = GROUP_ID;
	}
	
	var OptionControl = ( function(){
		var ELM_OPTION_WRAPPER = ( function(){
				var ret = document.createElement( 'ul' );
				ret.className = 'option-container';
				return ret;
			})();
		var currentCombobox = null,
			optionList,
			elm,
			value,
			currentOption,
			currentIndex;
		
		function updateCurrrentOption( _value, _updateCombobox ){
			var _option;
			for( var i=0, l=optionList.length; i<l; ++i ){
				_option = optionList[ i ]
				if( _value === _option.value ){
					currentOption && currentOption.current( false );
					_option.current( true );
					currentOption = _option;
					currentIndex = i;
					_updateCombobox === true && currentCombobox.value( _value );
				}
			}
		}
		function bodyMouseupHandler(){
			currentCombobox.blur();
			OptionControl.hide( currentCombobox );
		}
		function updateWrapperPosition(){
			var position = pettanr.util.getAbsolutePosition( elm );
			
			ELM_OPTION_WRAPPER.style.cssText = [
					'width:', elm.offsetWidth - 2, 'px;',
					'left:', position.x, 'px;',
					'top:', position.y + elm.offsetHeight, 'px;'
				].join('');			
		}
		return {
			show: function( _combobox, _optionList ){
				if( currentItem !== _combobox || currentCombobox === _combobox ) return;
				currentCombobox && currentCombobox.blur();
				
				currentCombobox = _combobox;
				optionList = _optionList;
				elm = _combobox.elm;
				
				updateCurrrentOption( _combobox.value(), false );
				
				for( var i=0, l=optionList.length; i<l; ++i ){
					ELM_OPTION_WRAPPER.appendChild( optionList[ i ].elm );
				}
				
				document.body.appendChild( ELM_OPTION_WRAPPER );
				oldBodyMouseupHandler = document.body.onmouseup;
				document.body.onmouseup = bodyMouseupHandler;
				
				updateWrapperPosition();
			},
			hide: function( _combobox ){
				if( currentCombobox !== _combobox ) return;

				ELM_OPTION_WRAPPER.parentNode && ELM_OPTION_WRAPPER.parentNode.removeChild( ELM_OPTION_WRAPPER );
				while( ELM_OPTION_WRAPPER.firstChild ){
					ELM_OPTION_WRAPPER.removeChild( ELM_OPTION_WRAPPER.firstChild );
				}
				currentCombobox = null;
				currentOption = null;
				currentIndex = 0;
				
				document.body.onmouseup = oldBodyMouseupHandler;
			},
			change: function( down ){
				var l = optionList.length,
					way = down === true ? 1 : -1;
					i = currentIndex + way
				if( currentCombobox === false || l < 2 ) return;
				i = i < 0 ?
						l - 1 :
						i < l ? i : 0;
				updateCurrrentOption( optionList[ i ].value, false );
			},
			update: function( _combobox, _value ){
				if( currentCombobox !== _combobox || currentItem !== _combobox ) return;
				if( currentOption.value === _value ) return;
				updateCurrrentOption( _value, true );
			},
			decide: function(){
				currentCombobox.value( currentOption.value );
				currentCombobox.blur();
				OptionControl.hide( currentCombobox );
			},
			onWindowResize: function( _w, _h ){
				setTimeout( updateWrapperPosition, 0 );
			}
		}
	})();
	
		var OptionClass = function( combobox, displayValue, value ){
			var elm = document.createElement( 'li' ),
				a = document.createElement( 'a' ),
				isCurrent = undefined;
			elm.appendChild( a );
			a.appendChild( document.createTextNode( displayValue ));
			elm.className = CLASSNAME_COMBOBOX_OPTION;
			a.href = '#';
			
			a.onmousedown = onClick; // onclick では 選択ボックス 隠すように body に設定した onmouseup が先に動いてしまう！
			function onClick(){
				OptionControl.update( combobox, value );
				OptionControl.hide( combobox );
				combobox.blur();
				return false;
			}
			this.elm = elm;
			this.displayValue = displayValue;
			this.value = value = value || displayValue;
			this.current = function( _isCurrent ){
				if( Type.isBoolean( _isCurrent ) === true && isCurrent !== _isCurrent ){
					elm.className = CLASSNAME_COMBOBOX_OPTION + ( _isCurrent === true ? ' current-option' : '' );
					isCurrent = _isCurrent;
				}
				return !!isCurrent;
			}
		}
	

	function start( _currentItem ){
		currentItem !== _currentItem && currentItem && currentItem.blur();
		currentItem = _currentItem;
	}
	function finish( _currentItem ){
		currentItem = currentItem === _currentItem ? null : currentItem;
	}

	function tabShift( _groupID, _index, _way ){
		// currentApplication の確認
		//if( _applicationID === ( pettanr.overlay.visible === true ? pettanr.overlay.currentID : pettanr.view.currentID )){
		//	return;
		//};
		var GROUP_ARRAY = FORM_GROUP_TABLE[ _groupID ] || [],
			l = GROUP_ARRAY.length,
			i = _index + _way,
			_item;
		if( l < 2 ) return;
		while( i !== _index ){
			i = i < 0 ?
				l - 1 :
				i < l ? i : 0; // 0 < i < l
			_item = GROUP_ARRAY[ i ];
			if( _item.enabled() === true && _item.visible() === true ){
				setTimeout( _item.focus, 0 );
				return;
			}
			i += _way;
		}
	}

	return {
		init: function(){},
		focus: function(){
			return currentItem !== null; 
		},
		keyEventRellay: function( e ){
			if( e.type === 'keyup' ) return false;
			if( currentItem === null ) return false;
			
			var keyCode = e.keyCode;
			var _groupID = currentItem.groupID,
				_index = pettanr.util.getIndex( FORM_GROUP_TABLE[ _groupID ], currentItem );
			if( currentItem instanceof ComboBoxClass ) {
				if( 37 <= keyCode && keyCode <= 40 ){ // ↑38 ←37 →39 ↓40
					OptionControl.change( keyCode === 40 );
					return true;
				} else
				keyCode === 13 && OptionControl.decide();
			}
			if( keyCode === 13 || keyCode === 27 || keyCode === 9 || keyCode === 18 || e.altKey === true ){ // 13.return 27.esc 9.tab 18.alt
				currentItem && currentItem.blur( keyCode );
				keyCode === 9 && _groupID && tabShift( _groupID, _index, e.shiftKey === true ? -1 : 1 );
				keyCode === 13 && _groupID && tabShift( _groupID, _index, 1 );
			}
			return true;
		},
		createUIGroup: function( _applicationReferance ){
			
		},
		createInputText: function( _elm, _onUpdate, _groupID, _validater ){
			if( typeof _groupID === 'string' && !FORM_GROUP_TABLE[ _groupID]){
				FORM_GROUP_TABLE[ _groupID] = [];
			}
			var ret = new InputTextClass( _elm, _onUpdate, _groupID, _validater );
			_groupID && FORM_GROUP_TABLE[ _groupID ].push( ret );
			return ret;
		},
		createButton: function( _elm, _onClick, _groupID ){
			if( typeof _groupID === 'string' && !FORM_GROUP_TABLE[ _groupID]){
				FORM_GROUP_TABLE[ _groupID ] = [];
			}
			var ret = new ButtonClass( _elm, _onClick, _groupID );
			_groupID && FORM_GROUP_TABLE[ _groupID ].push( ret );
			return ret;
		},
		createFileInput: function( _elm, _onUpdate, _groupID, _validater, _elmFileInput ){
			if( typeof _groupID === 'string' && !FORM_GROUP_TABLE[ _groupID]){
				FORM_GROUP_TABLE[ _groupID] = [];
			}
			var ret = FileInputClass( _elm, _onUpdate, _groupID, _validater, _elmFileInput );
			_groupID && FORM_GROUP_TABLE[ _groupID].push( ret);
			return ret;
		},
		createCombobox: function( _elm, _onUpdate, _groupID, _optionList ){
			if( typeof _groupID === 'string' && !FORM_GROUP_TABLE[ _groupID]){
				FORM_GROUP_TABLE[ _groupID ] = [];
			}
			var ret = new ComboBoxClass( _elm, _onUpdate, _groupID );
			_groupID && FORM_GROUP_TABLE[ _groupID ].push( ret );
			return ret;
		},
		createCheckBox: function(){
			
		},
		createRadio: function(){
			
		},
		createSlider: function(){
			
		},
		onWindowResize: function( w, h ){
			windowW = w;
			windowH = h;
			currentItem instanceof ComboBoxClass && OptionControl.onWindowResize( w, h );
		}
	}
})();


/* ----------------------------------------
 * Vector Support
 * 
 *              __________
 *             /          \
 *            /            \
 *            |,startX,Y    |
 * tailX,Y - <              |
 *            |'endX,Y      |
 *            \            /
 * 	           \__________/
 * 
 * SVG
 * -----------------------
 * ie9, other modern browser
 * 
 * XML
 * -----------------------
 * ie5.5-8
 * 
 * 内部の角度計算は radian で統一したい。
 * 当初 vectorEnabled = true で一度書いてみる。
 * 駄目なら、代替のイメージのsrcの用意もここで担当。
 * 閲覧と編集両方で使う。
 * 
 */
pettanr.balloon = ( function() {
	var MIN_BALLOON_WIDTH  = 30,
		MIN_BALLOON_HEIGHT = 30,
		NUM_BALLOON_IMAGE  = 24,
		TAIL_WIDTH         = 6,
		TAIL_HEIGHT        = 10,
		STROKE_WIDTH       = 1.2,
		PADDING_TOP        = TAIL_HEIGHT,
		PADDING_LEFT       = TAIL_HEIGHT,
		IS_VML             = pettanr.ua.isIE === true && pettanr.ua.ieVersion < 9,
		ELM_BALLOON_ORIGIN = ( function(){
			var ret;
			try {
				if( IS_VML === true){
					ret = document.createElement( 'DIV');
					var shape = document.createElement( 'v:shape');
					shape.coordorigin = "0,0";
					shape.strokecolor = "black";
					shape.strokeweight = STROKE_WIDTH;
					shape.fillcolor = "white";
					ret.appendChild( shape);
				} else {
					var kSVGNS = 'http://www.w3.org/2000/svg';
					ret = document.createElementNS( kSVGNS, 'svg');
					var path = document.createElementNS( kSVGNS, 'path');
					path.setAttribute( 'fill', "white");
					path.setAttribute( 'stroke', "black");
					path.setAttribute( 'strokeWidth', STROKE_WIDTH);
					ret.appendChild( path);
				}
				return ret;	
			} catch( e){
				return null;
			}
		})(),
		vectorEnabled = ELM_BALLOON_ORIGIN !== null &&
						pettanr.URL_PARAMS.vector !== false &&
						!( IS_VML === true && pettanr.ua.VML === false );

	var cos        = Math.cos,
		sin        = Math.sin,
		abs        = function(v){ return v >= 0 ? v : -1; },
		pow        = Math.pow,
		round      = Math.round,
		floor      = Math.floor,
		TARGET     = TAIL_WIDTH * TAIL_WIDTH,
		isFinit    = Type.isFinite,
		ACCURACY   = 1, // 有効少数桁	
		cround     = function ( v, r ){
						r = r || ACCURACY;
						return round( v * pow( 10.0, r )) / pow( 10.0, r );
					},
		DEG_TO_RAD = Math.PI / 180;

	var XBROWSER_BALLOON_CLASS = function( w, h, a ){
		var balloonElm = vectorEnabled === true ? ELM_BALLOON_ORIGIN.cloneNode( true ) : document.createElement( 'img' ), // pettanr.imageに変更
			path = balloonElm.getElementsByTagName( 'path' )[ 0 ],
			shape = balloonElm.getElementsByTagName( 'shape' )[ 0 ],
			instance = this,
			l = ',';
		
		function draw( _a ){
			var rx      = w / 2,
				ry      = h / 2,
				tailRad = _a * DEG_TO_RAD,
				tailX   = rx + ( rx + TAIL_HEIGHT ) * sin( tailRad ),
				tailY   = ry - ( ry + TAIL_HEIGHT ) * cos( tailRad ),
				startX, startY, endX, endY;
		/*
		 * tailの太さをTAIL_WIDTHに一致させるため、角度を絞りつつ計算
		 */
			var startRad, endRad,
				_startX, _startY, _endX, _endY,
				tailDeg = 0, d;
			
			for( var i = 45; i > 0.01; i /= 2){
				d = ( tailDeg + i ) /2;
				startRad = ( _a + d ) * DEG_TO_RAD;
				endRad   = ( _a - d ) * DEG_TO_RAD;
				
				_startX  = rx + sin( startRad ) * rx;
				_startY  = ry - cos( startRad ) * ry;
				_endX    = rx + sin( endRad ) * rx;
				_endY    = ry - cos( endRad ) * ry;	//円弧上のY位置＝円中心Y＋sin(角度×PI÷180)×円半径
					
				if( pow( ( _startX - _endX ), 2 ) + pow( ( _startY - _endY ), 2 ) < TARGET ){
					tailDeg += i;
					startX  = _startX;
					startY  = _startY;
					endX    = _endX;
					endY    = _endY;
				}
			}

		/*
		 * 
		 */			
			if( IS_VML === true ){
				var _tailX = tailX *10,
					_tailY = tailY *10,
					__w = w *10,
					__h = h *10;
				
				shape.style.width = w + 'px';
				shape.style.height = h + 'px';
				shape.coordsize = [ __w, __h ].join( l );
				shape.path = [
					' ar ', 0, l, 0, l, __w, l, __h, l,
					round( endX * 10 ), l, round( endY * 10 ), l,
					round( startX * 10 ), l, round( startY * 10 ),
					' l ', round( _tailX ), l, round( _tailY ),
					' x e'
				].join( '');

				balloonElm.style.marginTop =  _tailY < 0 ? floor( ( 60 + _tailY) / 10 ) : 10;
				balloonElm.style.marginLeft = _tailX < 0 ? floor( ( 60 + _tailX) / 10 ) : 10;
			} else {
				balloonElm.setAttribute( 'width', w + PADDING_LEFT *2 );
				balloonElm.setAttribute( 'height', h + PADDING_TOP *2 );
				path.setAttribute( 'd', [
					'M', cround( tailX + PADDING_LEFT ), l, cround( tailY + PADDING_TOP ),
					'L', cround( startX + PADDING_LEFT ), l, cround( startY + PADDING_TOP ),
					'A', rx, l, ry,
					'0 1 1',			// flag
					cround( endX + PADDING_LEFT ), l, cround( endY + PADDING_TOP ),
					'z'
				].join( ' '));
			}
		}
		
		this.elm = balloonElm;
		this.resize = function ( _a, _w, _h ){
			w  = isFinit( _w ) === true ? _w - PADDING_TOP * 2 : w;
			h  = isFinit( _h ) === true ? _h - PADDING_LEFT * 2 : h;
			// ie6 でリサイズが反応しない対策
			if( vectorEnabled === false && pettanr.ua.isIE === true && pettanr.ua.ieVersion < 7 ){
				var parent = balloonElm.parentNode;
				parent.removeChild( balloonElm );
				parent.insertBefore( balloonElm, parent.firstChild );
			}
			instance.angle( _a );
		};
		this.angle = function( _a ){
			if( isFinit( _a ) === true ){
				a = _a;
				if( vectorEnabled === false ){
					balloonElm.src = pettanr.balloon.getBalloonUrl( w, h, _a );
				} else {
					draw( _a );
				}
			}
			return a;
		}
		this.type = function( _type ){
			//draw( _a);
		}
		this.destroy = function(){
			delete instance.destroy;
			balloonElm.parentNode && balloonElm.parentNode.removeChild( balloonElm );
			balloonElm = path = shape = instance = null;
		}
		
		instance.resize( a, w, h );
	};
	
	IS_VML === false && vectorEnabled === true && ( function(){
		var detect = new XBROWSER_BALLOON_CLASS( 100, 100, 0 ),
			size = pettanr.util.getElementSize( detect.elm );
		vectorEnabled = size.width !== 0 && size.height !== 0;
		detect.destroy();
		detect = size = null;
	})();

	return {
	    createBalloon: function( _w, _h, _a ){
	    	return new XBROWSER_BALLOON_CLASS( _w, _h, _a );
	    },
	    isBalloonInstance: function( _ballon ){
	    	
	    },
	    getBalloonUrl: function( _w, _h, _a ){
			var d = 360 / NUM_BALLOON_IMAGE;
			_a = _a + d / 2;
			return [
				pettanr.CONST.SYSTEM_PICTURE_PATH, '_w',
				_a < 360 - d / 2 ? floor( _a / d ) : 0,
				_w <= 400 || _h <= 400 ? '_b1' : '',
				'.gif' ].join( '' );
	    },
		TYPE_NONE:				0,
		TYPE_SPEACH_BALLOON:	1,
		TYPE_THINKING:			2,
		TYPE_BOM:				3,
		TYPE_BLACK_BOX:			4,
		TYPE_BLUE_BOX:			5
	}
})();

/* ----------------------------------------
 *  pettanr.image
 *  
 *   xBackendな画像反転、画像描画機能。
 *   
 *   画像の反転
 *     - css3
 *     - ActiveX (ie)
 *     - VML (ie)
 *     - canvas ??
 *     - flash(lite)
 *     - silverlight
 *     - pettan server
 *   
 *   png画像の表示(アルファpngをサポートしないie6以下のため)
 *     - ActiveX
 *     - VML
 *     - flash(lite)
 *     - silverlight
 *     
 *     -moz-transform:scale( -1, -1);
 */
pettanr.image = ( function(){
	
	var FetchImageControl = ( function(){
		var TASK_LIST = [];

		/* 
		 * FetchClass original is
		 * 
		 * LICENSE: MIT?
		 *  URL: http://d.hatena.ne.jp/uupaa/20080413/1208067631
		 *  AUTHOR: uupaa.js@gmail.com
		 * 
		 */

		var FetchClass = function( abspath, onLoadCallback, onErrorCallback, delay, timeout ){
			var img,
				size,
				tick = 0,
				timer = null,
				finish = false;
				/*
			if( pettanr.ua.isIE === false && pettanr.ua.ieVersion < 8 ){
				var images = document.images,
					i=0, l= images.length;
				for( i=0; i<l; ++i ){
					img = images[ i ];
					if( img.src === abspath && img.complete ){
						finish = true;
						size = pettanr.util.getImageSize( img );
						timer = window.setTimeout( asyncCallback, 0 );
						break;
					}
				}
				images = null;
			}*/
			//if( finish === false ){
				img = document.createElement( 'img' ); //var img = new Image(); ではieでimgのsizeが取れない、、、removeChildも失敗し、imgSizeGetterにimgが残る
				img.onabort = img.onerror = onError;
				img.onload = onLoad;
				img.src = abspath;
				finish === false && timeout && detect();
			//}
			
			function onError(){
				if( finish === true ) return;
				finish = true;
				timer = window.setTimeout( asyncCallback, 10 );
			}			
			function onLoad(){
				// if( finish === true ) return; // これがあると firefox3.6 で駄目、、、
				// if( timer ) return; // これがあると safari3.2 で駄目、、、
				finish = true;
				timer !== null && window.clearTimeout( timer );
				if( window.opera && !img.complete ){
					timer = window.setTimeout( asyncCallback, 10 );
					return;
				}
				size = pettanr.util.getImageSize( img );
				timer = window.setTimeout( asyncCallback, 10 );
			}
			function detect(){
				if( finish === true ) return;
				if( img.complete ){
					finish = true;
					if( img.width ) return;
					timer = window.setTimeout( asyncCallback, 10 );
					return;
				}
				if( ( tick += delay ) > timeout ){
					finish = true;
					timer = window.setTimeout( asyncCallback, 10 );
					return;
				}
				timer = window.setTimeout( detect, delay );
			}
			
			function asyncCallback(){
				size ? onLoadCallback( abspath, size.width, size.height ) : onErrorCallback( abspath );
				destroy();
			}
			function destroy(){
				finish  = true;
				img.src = img.onload = img.onabort = img.onerror = '';
				img     = void 0;
				size    = onLoadCallback = onErrorCallback = timer = null;
			}
			this.stop = function(){
				timer !== null && window.clearTimeout( timer );
				destroy();			
			}
		}
		
		return {
			load: function( URLorELM, onLoad, onError, delay, opt_timeout ){
				var src, fetch;
				if( Type.isString( URLorELM ) === true ){
					src = URLorELM;
				} else
				if( Type.isHTMLElement( URLorELM ) === true && URLorELM.tagName.toLowerCase() === 'img' ){
					src = URLorELM.src;
				} else {
					return;
				}
				
				fetch = new FetchClass(
					pettanr.util.getAbsolutePath( src ),
					onLoad, onError,
					Type.isFinite( delay ) === true ? delay : 250,
					Type.isFinite( opt_timeout ) === true ? opt_timeout : undefined
				);
				// TASK_LIST.push( fetch );
				
				return fetch;
			}
		}
	})();
	
	var REG_PNG           = /\.png?/i,
		IS_CSS3           = 0,
		IS_VML            = 1,
		IS_ACTIVEX        = 2,
		IS_CANVAS         = 3,
		IS_FLASH          = 4,
		IS_SILVERLIGHT    = 5,
		IS_SERVER         = 6,
		IS_ACTIVEX_SERVER = 7,
		BACKEND = ( function(){
			if( pettanr.DEBUG === true && pettanr.URL_PARAMS.rimg ){
				var rimg = pettanr.URL_PARAMS.rimg.toLowerCase();
				if( rimg === 'css3' ) return IS_CSS3;
				if( rimg === 'activex' ) return IS_ACTIVEX;
				if( rimg === 'vml' ) return IS_VML;
			}
			if( pettanr.ua.isIE === false || pettanr.ua.ieVersion >= 9 ) return IS_CSS3; // 不十分！
			if( pettanr.ua.VML === true ) return IS_VML;
			if( pettanr.ua.ACTIVEX === true ) return IS_ACTIVEX;
			if( pettanr.FLASH === true ) return IS_FLASH;
			if( pettanr.SILVERLIGHT === true ) return IS_SILVERLIGHT;
			return IS_SERVER;
		})(),
		BACKEND_WHEN_PNG = ( function(){
			if( pettanr.ua.isIE === false || pettanr.ua.ieVersion > 6 ) return BACKEND;
			if( pettanr.ua.VML === true ) return IS_VML;
			if( pettanr.FLASH === true ) return IS_FLASH;
			if( pettanr.SILVERLIGHT === true ) return IS_SILVERLIGHT;
			if( pettanr.ua.ACTIVEX === true ) return IS_ACTIVEX_SERVER;
			return IS_SERVER;
		})(),
		CLASS_NAME         = 'reversible-image-container',
		CLASS_NAME_LOADING = CLASS_NAME + ' loading',
		CLASS_NAME_ERROR   = CLASS_NAME +' error',
		RETRY_DELAY        = 5000,
		NUM_RETRY          = 3,
		ReversibleImageClass,
		ReversibleImageClassWithPingfix;
	
	var css3Image = function( url, w, h, onLoadCallback ){
		var elmWrap    = document.createElement( 'div' ),
			elmImg     = null,
			retryTimer = null,
			fetch      = FetchImageControl.load( url, onLoad, onError, 100, 10000 ),
			instance   = this;
		elmWrap.className = CLASS_NAME_LOADING;

		function onLoad( _url, _actualW, _actualH ){
			if( elmWrap === null ) return;
			elmImg = new Image; // new Image でないと ie6,7 でクラッシュするかも、、、？
			/*
			 * createElement 直後に append しないと、ie(ActiveX)で img が正しく表示されない．
			 */
			elmWrap.appendChild( elmImg );
			elmImg.setAttribute( 'src', url );
			elmWrap.className = CLASS_NAME;
			onLoadCallback && onLoadCallback( _url, _actualW, _actualH );
			onLoadCallback = fetch = null;
			instance.resize( w, h );
		}
		function onError( _url ){
			if( elmWrap === null ) return;
			elmWrap.className = CLASS_NAME_ERROR;
			retryTimer = window.setTimeout( retry, RETRY_DELAY );
			fetch = null;
		}
		function retry(){
			elmWrap.className = CLASS_NAME_LOADING;
			fetch = FetchImageControl.load( url, onLoad, onError, 100, 10000 );
		}

		this.elm = elmWrap;
		this.resize = function( _w, _h ){
			w = _w !== undefined ? _w : w;
			h = _h !== undefined ? _h : h;
			if( elmImg === null ) return;
			elmImg.className = w < 0 || h < 0 ? ( 'img-flip-' + ( w < 0 && h < 0 ? 'vh' : ( w < 0 ? 'h' : 'v'))) : '';
		}
		this.destroy = function(){
			delete instance.destroy;
			
			elmImg !== null && elmWrap.removeChild( elmImg );
			retryTimer !== null && window.clearTimeout( retryTimer );
			fetch !== null && fetch.stop();
			elmWrap = elmImg = onLoadCallback = retryTimer = fetch = instance = null;
		}
	}
		
	var activexImage = css3Image;
	
	var vmlImage = function( url, w, h, onLoadCallback ){
		var elmWrap = document.createElement( 'div' ),
			vmlImg = null,
			retryTimer = null,
			fetch = FetchImageControl.load( url, onLoad, onError, 100, 10000 ),
			instance = this;
		elmWrap.className = CLASS_NAME_LOADING;
		function onLoad( _url, _actualW, _actualH ){
			if( elmWrap === null ) return;
			elmWrap.className = CLASS_NAME;
			vmlImg = document.createElement( 'v:image' );
			vmlImg.src = url;
			onLoadCallback && onLoadCallback( _url, _actualW, _actualH );
			onLoadCallback = fetch = null;
			instance.resize( w, h );
		}
		function onError( _url ){
			if( elmWrap === null ) return;
			elmWrap.className = CLASS_NAME_ERROR;
			retryTimer = window.setTimeout( retry, RETRY_DELAY );
			fetch = null;
		}
		function retry(){
			elmWrap.className = CLASS_NAME_LOADING;
			fetch = FetchImageControl.load( url, onLoad, onError, 100, 10000 );
		}
		
		this.elm = elmWrap;
		this.resize = function( _w, _h ){
			w = _w !== undefined ? _w : w;
			h = _h !== undefined ? _h : h;
			if( vmlImg === null ) return;
			vmlImg.style.width  = ( w < 0 ? -w : w ) + 'px';
			vmlImg.style.height = ( h < 0 ? -h : h ) + 'px';
			//if( flipH !== _flipH || flipV !== _flipV){
				vmlImg.parentNode === elmWrap && elmWrap.removeChild( vmlImg );
			//}
				vmlImg.className = w < 0 || h < 0 ? ( 'img-flip-' + ( w < 0 && h < 0 ? 'vh' : ( w < 0 ? 'h' : 'v'))) : '';
				elmWrap.appendChild( vmlImg );
		}
		this.destroy = function(){
			instance.destroy;
			
			vmlImg !== null && elmWrap.removeChild( vmlImg );
			retryTimer !== null && window.clearTimeout( retryTimer );
			fetch !== null && fetch.stop();
			elmWrap = vmlImg = onLoadCallback = retryTimer = fetch = instance = null;
		}
	}
	
	var serverImage = css3Image; // function( url, w, h, onLoadCallback ){}
	
	if( BACKEND === IS_CSS3 )    ReversibleImageClass = css3Image;
	if( BACKEND === IS_VML )     ReversibleImageClass = vmlImage;
	if( BACKEND === IS_ACTIVEX ) ReversibleImageClass = activexImage;
	if( BACKEND === IS_SERVER )  ReversibleImageClass = activexImage;
	
	css3Image = vmlImage = activexImage = activexImage = null;
	
	return {
		createReversibleImage: function( url, w, h, onLoadCallback){
			return new ReversibleImageClass( url, w, h, onLoadCallback );
		}
	}
})();

/*
 * bind : 製本
 */
pettanr.bind = ( function(){
	var BIND_WORKER_ARRAY = [],
		NAMESPACE_CLASSNAME = pettanr.CONST.NS_PETTANR_COMIC + '-',
		RESOURCE_PICTURE_PATH = pettanr.CONST.RESOURCE_PICTURE_PATH,
		ELM_DETECT_WIDTH = ( function(){
			var ret = document.createElement( 'div');
			ret.style.cssText = 'width: auto;height: 0;padding: 0;margin: 0;display: block;visibility: hidden;float: none;position: static;';
			return ret;
		})(),
		ELM_TITLE_ORIGN = ( function(){
			
		})();

	/*
	 * original
	 *   http://d.hatena.ne.jp/uupaa/20090720/1248097177
	 */
	var ResizeAgentClass = function( onResizeFunction, opt_elmCheck){
		var	_globalLock = 0,
			_size = { w: 0, h: 0 };
			_ie = !!document.all,
			_quirks = (document.compatMode || "") !== "CSS1Compat",
			_ieroot = _quirks ? "body" : "documentElement";
			_root = opt_elmCheck ? opt_elmCheck : ( _ie ? document[_ieroot] : window);

		function getInnerSize() {
			return {
				w: _root.innerWidth  || _root.clientWidth,
				h: _root.innerHeight || _root.clientHeight
			};
		}

		function loop() {
			if (!_globalLock++) {
				var size = getInnerSize();
				if (_size.w !== size.w || _size.h !== size.h) { // resized
					_size = size; // update
					onResizeFunction( _size );
				}
				setTimeout( unlock, 0); // delay unlock
			}
			setTimeout(loop, 500);
		}
		function unlock(){
			_globalLock = 0;
		}
		loop();
	}
	
	
	var ElementBuilderClass = function( elmTarget, noClassnameMode ){
		var RIMG_ARRAY     = [],
			BALLOON_ARRAY  = [];
		
		function buildComicElement(){
			
		}
		
		function buildPanelElement( json, zoom ){
			var _elmPanel = document.createElement( 'div' ),
				_style = {
						'border-width':		typeof json.border === 'number' ? json.border + 'px' : 0,
						width: 				json.width + 'px',
						height:				json.height + 'px'
				},
				_cssText = [],
				_comicElements = json.panel_elements || [],
				_comicElement, _elmImg, _rImg, _rPic,
				_balloon, _elmBalloonWrap, _elmText, _text, _speechesAttributes, _key;
			if( noClassnameMode === true ){
				
			} else {
				_elmPanel.className = NAMESPACE_CLASSNAME + 'panel';
			}
			for( var _key in _style ){
				_cssText.push( _key + ':' + _style[ _key ] );
			}
			_elmPanel.style.cssText = _cssText.join( ';');
			elmTarget.appendChild( _elmPanel );
			
			for( var i=0, l=_comicElements.length; i<l; ++i ){
				_comicElement = _comicElements[ i ];
				_rPic = _comicElement.resource_picture;
				if( _rPic ){
					_rImg = pettanr.image.createReversibleImage(
							[ RESOURCE_PICTURE_PATH, _rPic.id, '.', _rPic.ext ].join( ''),
							_comicElement.width, _comicElement.height
						);
					_elmImg = _rImg.elm;
					_elmPanel.appendChild( _elmImg );
					_elmImg.className = NAMESPACE_CLASSNAME + 'image';
					_elmImg.style.cssText = [
						'left:',   _comicElement.x, 'px;',
						'top:',    _comicElement.y, 'px;',
						'z-index:',_comicElement.z, ';'
					].join( '');					
					if( _elmImg.tagName === 'img' ){
						_elmImg.width        = Math.abs( _comicElement.width );
						_elmImg.height       = Math.abs( _comicElement.height );
					} else {
						_elmImg.style.width  = Math.abs( _comicElement.width ) + 'px';
						_elmImg.style.height = Math.abs( _comicElement.height ) + 'px';
					}
					
					RIMG_ARRAY.push( _rImg );
				} else {
					_elmBalloonWrap = document.createElement( 'div' );
					_elmPanel.appendChild( _elmBalloonWrap );
					_elmBalloonWrap.className = NAMESPACE_CLASSNAME + 'balloon';
					_elmBalloonWrap.style.cssText = [
						'width:',   _comicElement.width, 'px;',
						'height:',  _comicElement.height, 'px;',
						'left:',    _comicElement.x, 'px;',
						'top:',     _comicElement.y, 'px;',
						'z-index:', _comicElement.z, ';'
					].join( '');

					_balloon = pettanr.balloon.createBalloon( _comicElement.width, _comicElement.height, _comicElement.tail );
					_elmBalloonWrap.appendChild( _balloon.elm );
					
					_elmText = document.createElement( 'p' );
					_elmBalloonWrap.appendChild( _elmText );
					
					_elmText.appendChild( document.createElement( 'span' ) );
					
					_text = '';
					_speechesAttributes = _comicElement.speeches_attributes;
					if( _speechesAttributes ){
						for( _key in _speechesAttributes ){
							_text += _speechesAttributes[ _key ] && _speechesAttributes[ _key ].content ? _speechesAttributes[ _key ].content : '';
						}
					}
					_elmText.firstChild.appendChild( document.createTextNode( _text ));
					BALLOON_ARRAY.push( _balloon );
				}
			}
		}
		
		function clean(){
			// clean elmTarget
			while( RIMG_ARRAY.length > 0 ){
				RIMG_ARRAY.shift().destroy();
			}
			while( BALLOON_ARRAY.length > 0 ){
				BALLOON_ARRAY.shift().destroy();
			}
			pettanr.util.removeAllChildren( elmTarget );		
		}
		
		this.build = function( json, zoom ){
			clean();
			
			// json is Comic ? Panel ?
			var panels = json.panels;
			if( Type.isArray( panels ) === true ){
				// comic
				for( var i=0, l=panels.length; i<l; ++i ){
					buildPanelElement( panels[ i ], zoom );
				}
			} else
			if( json.panel_elements ){
				// panel
				buildPanelElement( json, zoom );
			} else {
				// invalid json
			}
		}
		this.zoom = function(){
			
		}
		this.destroy = function(){
			clean();
		}
	};
	
	var BindWorkerClass = function( elmTarget, json, zoomSelfEnabled, noClassnameMode ){
		var builder    = new ElementBuilderClass( elmTarget, noClassnameMode );
		var elmDetectW = ELM_DETECT_WIDTH.cloneNode( false );
		var resizer    = null;
		
		if( zoomSelfEnabled === true){
			elmTarget.parentNode.insertBefore( elmDetectW, elmTarget );
			resizer = new ResizeAgentClass( onResize, elmDetectW );
		}
		function onResize(){
			
		}
		json && typeof json === 'object' && builder.build( json );
		
		this.init = function(){
				
		}
		this.zoom = function(){
			builder.zoom();
		}
		this.json = function( _json ){
			json = _json;
			builder.build( _json );
		}
		this.targetElement = function(){
				
		}
		this.layout = function(){
				
		}
		this.destroy = function(){
			builder.destroy();
			elmTarget = json = builder = null;
		}
	}
	
	return {
		createBindWorker: function( elmTarget, opt_COMICJSONorPANELJSON, opt_zoomSelfEnabled, opt_noClassnameMode ){
			var ret = new BindWorkerClass( elmTarget, opt_COMICJSONorPANELJSON, !!opt_zoomSelfEnabled, !!opt_noClassnameMode);
			BIND_WORKER_ARRAY.push( ret );
			return ret;
		},
		isBindWorkerInstance: function( _bindWorker ){
			return _bindWorker instanceof BindWorkerClass;
		}
	}
})();

var VisualEffect = ( function(){
	
	var ANIMATION_TICKET_ARRAY = [],
		fpms = 50,
		TIMER = null,
		FILTER = 'filter',
		OPACITY = 'opacity',
		REG_ALPHA = /alpha\([^)]*\)/i,
		CORON = ':',
		EMPTY = '',
		SEMICORON = ';';
	
	function startAnimation( _elm, _cssObject, _onComplete, _onEnterFrame, _numFrames){
		var _ticket;
		for( var i=0, l=ANIMATION_TICKET_ARRAY.length; i<l; ++i){
			_ticket = ANIMATION_TICKET_ARRAY[ i];
			if( _ticket.elm === _elm) {
				_ticket.destroy();
				break;
			}
		}
		//  coputedStyle と _cssObject を比較して , 一致及び非数は削除しつつ コピー
		//  filter opacity の追加 REG_ALPHA.test( _value ) ? _value.replace( REG_ALPHA, opacity ) : _value + " " + opacity
		/*
		 * cssObject をまわす
		 * 非数は削除
		 * cssText と一致も削除
		 * coputedStyle と一致も削除
		 * updateTraget ととして記録
		 * 初期値を cssObject としてセット
		 * cssTest にセット zoom もセット
		 */
		
		//
		/*
			var style = elem.style,
				currentStyle = elem.currentStyle,
				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
				filter = currentStyle && currentStyle.filter || style.filter || "";

			// IE has trouble with opacity if it does not have layout
			// Force it by setting the zoom level
			style.zoom = 1;
		 */
		
		var _currentParameters = [],
			_offsetParameters = [],
			_endParameters = [],
			_targetAttributes = [];
		
		ANIMATION_TICKET_ARRAY.push( new AnimationTaskClass(
			_elm,
			_currentParameters, _offsetParameters, _endParameters, _targetAttributes,
			typeof _onComplete === 'function' ? _onComplete : null,
			typeof _onEnterFrame === 'function' ? _onEnterFrame : null,
			_numFrames
		));
		
		if( TIMER === null){
			TIMER = window.setInterval( onEnterFrame, fpms);
		}
	}
	function onEnterFrame(){
		var _ticket,
			i = 0;
		while( i<ANIMATION_TICKET_ARRAY.length){
			_ticket = ANIMATION_TICKET_ARRAY[ i];
			if( _ticket.onEnterFrame() === true){
				_ticket.destroy();
				ANIMATION_TICKET_ARRAY.splice( i, 1);
			} else {
				++i;
			}
		}
		if( ANIMATION_TICKET_ARRAY.length === 0){
			window.clearInterval( TIMER);
			TIMER = null;
		}
	}
	function updateCss( _elm, _updateParameters, _targetAttributes, _numAttributes){
		if( _numAttributes > 1){
			var _cssTexts = _elm.style.cssText.split( ';'), _css,
				_separate,
				_cssObject = {}, _target, _value, _number, _px,
				j;
			for(var i=0, l=_cssTexts.length; i<l; ++i){
				_css = _cssTexts[ i];
				_separate = _css.indexOf( ':');
				if( _separate >= 3){
					_target = _css.substr( 0, _separate +1);
					_value = _css.substr( _separate +1);
					/*
					 * ie filter
					 */
					if( _target === FILTER){
						for( j=0; j<_numAttributes; ++j){
							if( _targetAttributes[ j] === OPACITY){
								_cssTexts[ i] = [
										_target, ':',
										_value.replace( REG_ALPHA, "alpha(opacity=" + _updateParameters[ j] * 100 + ")")
									].join( '');
								break;
							}
						}
					/*
					 * other
					 */
					} else {
						_number = '' + parseFloat( _value);
						_px = _value.indexOf( _number);
						_px = _px > 0 ? _value.substr( _px + _number.length) : '';
						for( j=0; j<_numAttributes; ++j){
							if( _targetAttributes[ j] === _target){
								_cssTexts[ i] = [ _target, ':', _updateParameters[ j], _px].join( '');
								break;
							}
						}						
					}
				}
			}
			_elm.style.cssText = _cssTexts.join( ';');
			return;	
		}
		/*
		 * 一度に update する Attributes が少ない場合、cssText は使用しない.
		 */
	}
	
	var AnimationTaskClass = function( ELM, currentParameters, offsetParameters, endParameters, targetAttributes, onComplete, onEnterFrame, numFrames){
		var l = targetAttributes.length;
		return {
			elm:	ELM,
			onEnterFrame: function(){
				var _updateCss = {}, i;
				if( numFrames === 1){
					for( i=0; i<l; ++i){
						_updateCss[ targetAttributes[ i]] = endParameters[ i];
						++i;
					}
					updateCss( ELM, currentParameters, targetAttributes, l);
					onComplete !== null && onComplete();
				} else {
					for( i=0; i<l; ++i){
						_updateCss[ targetAttributes[ i]] = currentParameters[ i] = Math.floor( currentParameters[ i] + offsetParameters[ i]);
						++i;
					}
					updateCss( ELM, currentParameters, targetAttributes, l);
					onEnterFrame !== null && onEnterFrame( _updateCss);
				}
				--numFrames;
				return numFrames === 0;
			},
			destroy: function(){
				ELM = onComplete = onEnterFrame = null;
			}
		}
	}
	
	var VisualEffectClass = function( ELM){
		var isHtmlElement;
		
		function registerAnime( _cssObject, _onComplete, _onEnterFrame, _time){
			var _numFrames = Math.floor( _time / fpms);
			startAnimation( ELM, _cssObject, _onComplete, _onEnterFrame, _numFrames);
		}
		function startFadeIn(){
			
		}
		function startFadeOut(){
			
		}
		function update( _x, _y, _w, _h){
			var _cssText = ELM.style.cssText;
			
		}
		
		this.anime = registerAnime;
		this.fadeIn = startFadeIn;
		this.fadeOut = startFadeOut;
		this.update = update;
	}
	
	return {
		createVisualEffect: function( _elm){
			return new VisualEffectClass( _elm);
		},
		isInstanceOfVisualEffect: function( _instance){
			return _instance instanceof VisualEffectClass;
		}
	}
})();



/*
 *  Google Analytics
 */

if( pettanr.LOCAL === false){
	var _gaq = _gaq || [];
	_gaq.push(['_setAccount', 'UA-28023955-1']);
	_gaq.push(['_trackPageview']);
	
	(function() {
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
	})();	
}