/*
 * pettanR peta.common.js
 *   version 0.5.49
 * 
 *   author:
 *     itozyun
 *   licence:
 *     3-clause BSD
 */

var pettanr = ( function(){
	var	IS_LOCAL = document.location.href.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;
	return {
		version: '0.5.40',
		URL_PARAMS: URL_PARAMS,
		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.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(){
			if( PETTANR_ROOT_PATH === '' ) return '';
			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_MY_ORIGINAL_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'original_pictures.json',
		URL_MY_RESOURCE_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/resource_pictures.json',
		URL_RESOURCE_PICTURES_JSON    : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'resource_pictures.json',
		URL_MY_RESOURCE_PICTURES_JSON : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/resource_picture.json',
		URL_COMICS_JSON               :	( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'comics.json',
		URL_MY_COMICS_JSON            :	( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/comic.json',
		URL_PANELS_JSON               : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'panels.json',
		URL_MY_PANELS_JSON            : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'home\/panel.json',
		SPEECH_BALOON_TEMPLETE        : ( SERVER_SUPPORT === false ? 'json\/' : PETTANR_ROOT_PATH ) + 'speech_balloon_templates.json\/',
		NS_PETTANR_COMIC              : 'pettanr-comic',
		THUMBNAIL_PATH                : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/thumbnail\/' : PETTANR_ROOT_PATH + 'resource_pictures\/',
		RESOURCE_PICTURE_PATH         : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/' : PETTANR_ROOT_PATH + 'resource_pictures\/full\/',
		ORIGINAL_PICTURE_PATH         : SERVER_SUPPORT === false ? RELATIVE + 'resource_pictures\/' : PETTANR_ROOT_PATH + 'original_pictures\/',
		PICTURE_PATH                  : SERVER_SUPPORT === false ? RELATIVE + 'pictures\/' : PETTANR_ROOT_PATH + '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',
		SERVER_SUPPORT                : SERVER_SUPPORT,
		URL_PETA_APPS_CSS             : ( SERVER_SUPPORT === false ? 'stylesheets' : '\/assets' ) + '\/peta.apps.css'
	}
})();

/* ----------------------------------------
 * old balloon.
 * 
 */
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             = UA.isIE === true && 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';
					// http://modernizr.com/downloads/modernizr.js
					// Thanks to Erik Dahlstrom
					if( !document.createElementNS || !document.createElementNS(kSVGNS, 'svg').createSVGRect ){
						return null;
					};
					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 && 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 ){
		this.elm   = vectorEnabled === true ? ELM_BALLOON_ORIGIN.cloneNode( true ) : document.createElement( 'img' ); // pettanr.imageに変更
		this.path  = this.elm.getElementsByTagName( IS_VML === true ? 'shape' : 'path' )[ 0 ];
		this.resize( a, w, h );
	};
	XBROWSER_BALLOON_CLASS.prototype = {
		elm   : null,
		path  : null,
		w     : 0,
		h     : 0,
		a     : 0,
		resize : function ( _a, _w, _h ){
			this.w  = isFinit( _w ) === true ? _w - PADDING_TOP  * 2 : this.w;
			this.h  = isFinit( _h ) === true ? _h - PADDING_LEFT * 2 : this.h;
			// ie6 でリサイズが反応しない対策
			if( vectorEnabled === false && UA.isIE === true && UA.ieVersion < 7 ){
				var parent = this.elm.parentNode;
				parent.removeChild( this.elm );
				parent.insertBefore( this.elm, parent.firstChild );
			};
			this.angle( _a );
		},
		angle : function( _a ){
			if( isFinit( _a ) === true ){
				this.a = _a;
				if( vectorEnabled === false ){
					this.elm.src = pettanr.balloon.getBalloonUrl( this.w, this.h, _a );
				} else {
					this.draw( _a );
				};
			};
			return this.a;
		},
		type : function( _type ){
			//draw( _a);
		},
		destroy : function(){
			this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );
			delete this.elm;
			delete this.path;
		},
		draw : function( _a ){
			var rx      = this.w / 2,
				ry      = this.h / 2,
				l       = ',',
				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 = this.w *10,
					__h = this.h *10;
				
				this.path.style.width  = this.w + 'px';
				this.path.style.height = this.h + 'px';
				this.path.coordsize = [ __w, __h ].join( l );
				this.path.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( '' );

				this.elm.style.marginTop =  _tailY < 0 ? floor( ( 60 + _tailY) / 10 ) : 10;
				this.elm.style.marginLeft = _tailX < 0 ? floor( ( 60 + _tailX) / 10 ) : 10;
			} else {
				this.elm.setAttribute( 'width',  this.w + PADDING_LEFT *2 );
				this.elm.setAttribute( 'height', this.h + PADDING_TOP *2 );
				this.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( ' '));
			}
		}
	};
	
	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
	}
})();

/* ----------------------------------------
 * New Balloon
 * 
 * Vector : SVG, Canvas, VML, Flash, None
 * 
 */
pettanr.newBalloon = ( function(){
	var TEMPLETES = {};
	
	var STROKE_WIDTH       = 1.2,
		IS_VML             = UA.isIE === true && 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';
					// http://modernizr.com/downloads/modernizr.js
					// Thanks to Erik Dahlstrom
					if( !document.createElementNS || !document.createElementNS(kSVGNS, 'svg' ).createSVGRect ){
						return null;
					};
					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 && UA.VML === false ),
		BalloonClass;
	
	if( vectorEnabled === true ){
		BalloonClass = function( templete ){
			this.elm     = ELM_BALLOON_ORIGIN.cloneNode( true );
			this.path    = this.elm.getElementsByTagName( IS_VML === true ? 'shape' : 'path' )[ 0 ];
			this.klass   = klass;
			this.getPath = klass.getPath;
		};
		BalloonClass.prototype = {
			elm     : null,
			path    : null,
			klass   : null,
			getPath : null,
			args    : null,
			update  : IS_VML === true ?
				function( /* w, h [, angle, ,,, ] */ ){
					var w = arguments[ 0 ],
						h = arguments[ 1 ];
					var path = this.getPath.call( this.klass, arguments );
					if( !path ) return false;
					path = /* SVG2VML */ path;
					this.path.style.width  = w + 'px';
					this.path.style.height = h + 'px';
					this.path.coordsize    = ( w * 10 ) + ',' + ( h * 10 );
					this.path.path         = path;
					// this.elm.style.marginTop =  _tailY < 0 ? floor( ( 60 + _tailY) / 10 ) : 10;
					// this.elm.style.marginLeft = _tailX < 0 ? floor( ( 60 + _tailX) / 10 ) : 10;
				} :
				function( /* w, h [, angle, ,,, ] */ ){
					var w = arguments[ 0 ],
						h = arguments[ 1 ],
						d = this.getPath.call( this.klass, arguments );
					if( !d ) return false;
					this.elm.width  = w + PADDING_LEFT * 2;
					this.elm.height = h + PADDING_TOP  * 2;
					this.path.setAttribute( 'd', d );
				},
			destroy : function(){
				this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );
				delete this.elm;
				delete this.path;
			}
		};
	} else {
		BalloonClass = function( klass ){
			// templete の vector の有無
			this.elm          = document.createElement( 'img' ); // pettanr.imageに変更
			this.klass        = klass;
			this.getPictureID = klass.getPictureID;
		};
		BalloonClass.prototype = {
			elm          : null,
			klass        : null,
			getPictureID : null,
			args         : null,
			update : function( /* w, h [, angle, ,,, ] */ ){
				var id = this.getPictureID.call( this.klass, arguments );
				if( id !== 0 && !id ) return false;
				this.elm.src = pettanr.CONST.SYSTEM_PICTURE_PATH + id + '.gif';
			},
			destroy : function(){
				this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );
			}
		};
	};
	
	/*
	 * http://sourceforge.jp/projects/pettanr/wiki/HowToMakeSpeechBalloon
	 */
	var NonVectorBalloonClass = function( templete ){
		this.elm       = document.createElement( 'img' ); // pettanr.imageに変更
		this.size      = this.elm.style;
		//this.templete  = templete;
		//this.speech    = templete.speech_template_attributes;
		//this.defaultW  = templete.default_width;
		//this.defaultH  = templete.default_height;
		//this.sizeCount = templete.size_count;
		this.wOffset   = templete.width_offset;
		this.hOffset   = templete.height_offset;
		this.wStep     = templete.width_step;
		this.hStep     = templete.height_step;
		// r_offset
		// r_steps
		
		var obj = templete.balloon_template_attributes, v, p;
		
		if( templete.size_count && 1 < templete.size_count ){
			this.picIDs = []; // system picture id list
			for( p in obj ){
				v = obj[ v ];
				this.picIDs[ v.size ] = v.system_picture_id;
			};			
		} else {
			for( p in obj ){
				v = obj[ v ];
				this.picID = v.system_picture_id;
			};
		};
	};
	NonVectorBalloonClass.prototype = {
		elm      : null,
		size     : null,
		templete : null,
		args     : null,
		picIDs   : null,
		picID    : 0,
		path     : pettanr.CONST.SYSTEM_PICTURE_PATH,
		update : function( w, h /* [, angle, ,,, ] */ ){
			var l, id, _w, _h;
			if( this.picIDs ){
				_w = ( w - this.wOffset ) / this.wStep;
				_h = ( h - this.hOffset ) / this.hStep;
				l  = this.picIDs.length - 1;
				_w = _w < 0 ? 0 : ( _w > l ? l : _w );
				_h = _h < 0 ? 0 : ( _h > l ? l : _h );
				id = this.picIDs[ _w > _h ? _w : _h ];			
			} else {
				id = this.picID;
			};
			
			this.elm.src     = this.path + id + '.gif';
			this.size.width  = w + 'px';
			this.size.height = h + 'px';
		},
		destory : function(){
			this.elm.parentNode && this.elm.parentNode.removeChild( this.elm );
		}
	};
	
	return {
		/**
		 * balloon_templetes.json 取得時に呼ばれる
		 * className は存在しない場合もある 
		 */
		register : function( templete ){
			templete = $.parseJSON( templete );
			if( templete.classname && !TEMPLETES[ templete.classname ] ){
				TEMPLETES[ templete.classname ] = templete;
				delete templete.classname;
			};
		},
		create : function( name ){
			if( Type.isString( name ) === true && name in window ){
				return new BalloonClass( window[ name ] );
			};
			return new NonVectorBalloonClass( TEMPLETES[ name ] );
		},
		isTemplete : function( templete ){
			
		},
		isInstance : function( balloon ){
			return balloon instanceof BalloonClass || balloon instanceof NonVectorBalloonClass;
		}
	}
})();

/* ----------------------------------------
 *  pettanr.image
 *  
 *   xBackendな画像反転、画像描画機能。
 *   
 *   画像の反転
 *     - css3
 *     - ActiveX (ie)
 *     - VML (ie)
 *     - canvas ??
 *     - flash(lite)
 *     - silverlight
 *     - pettan server
 *   
 *   png画像の表示(アルファpngをサポートしないie6以下のため)
 *     - ActiveX
 *     - VML
 *     - flash(lite)
 *     - silverlight
 *     - pettan server
 * 
 *     -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( UA.isIE === false && 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 = 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 = 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(
					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( UA.isIE === false || UA.ieVersion >= 9 ) return IS_CSS3; // 不十分！
			if( UA.VML === true ) return IS_VML;
			if( 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( UA.isIE === false || UA.ieVersion > 6 ) return BACKEND;
			if( UA.VML === true ) return IS_VML;
			if( pettanr.FLASH === true ) return IS_FLASH;
			if( pettanr.SILVERLIGHT === true ) return IS_SILVERLIGHT;
			if( 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(){
			delete 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 + '-',
		PICTURE_PATH        = pettanr.CONST.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 ElementBuilder = function( elmTarget, noClassname ){
		this.imageList    = [];
		this.balloonList  = [];
		this.elmTarget    = elmTarget;
		this.noClassname  = noClassname;
	};
	ElementBuilder.prototype = {
		build : function( json, zoom ){
			this.clean();
			
			// json is Comic ? Panel ?
			var stories = json.children || json.stories,
				i, l;
			if( Type.isArray( stories ) === true ){
				// comic
				for( i = 0, l = stories.length; i<l; ++i ){
					this.buildPanelElement( stories[ i ], zoom );
				};
			} else
			if( json.elements ){
				// panel
				this.buildPanelElement( json, zoom );
			} else {
				// invalid json
			};
		},
		buildFromFile : function( file, zoom ){
			this.clean();
			
			var l    = file.getChildFileLength(),
				data = file.read(),
				i, story;
			if( data.title ){
				// comic
				for( i = 0; i<l; ++i ){
					story = file.getChildFileAt( i ).read();
					this.buildPanelElement( story.panel, zoom );
				};
			} else
			if( data.panel ){
				// story
				this.buildPanelElement( data.panel, zoom );
			} else
			if( data.border ){
				// panel
				this.buildPanelElement( data, zoom );
			} else {
				// invalid json
			};
		},
		buildComicElement : function(){
			
		},
		buildPanelElement : function( 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  = [],
				elements = json.elements,
				realPic,
				p, i, l, data;
			this.elmTarget.appendChild( elmPanel );
			
			if( this.noClassname === true ){
				
			} else {
				elmPanel.className = NAMESPACE_CLASSNAME + 'panel';
			};
			for( p in style ){
				cssText.push( p + ':' + style[ p ] );
			};
			elmPanel.style.cssText = cssText.join( ';' );
			
			if( !elements ) return;
			for( i = 0, l = elements.length; i < l; ++i ){
				data    = elements[ i ];
				realPic = data.picture;
				if( realPic ){
					this.buildImage( elmPanel, data, realPic );
				} else {
					this.buildBalloon( elmPanel, data );
				};
			};
		},
		buildImage : function( elmPanel, data, realPic ){
			var rImg = pettanr.image.createReversibleImage(
					[ PICTURE_PATH, realPic.id, '.', realPic.ext ].join( '' ),
					data.width, data.height
				),
				elmImg = rImg.elm;
			elmPanel.appendChild( elmImg );
			elmImg.className = NAMESPACE_CLASSNAME + 'image';
			elmImg.style.cssText = [
				'left:',    data.x, 'px;',
				'top:',     data.y, 'px;',
				'z-index:', data.z, ';'
			].join( '');					
			if( elmImg.tagName === 'img' ){
				elmImg.width        = Math.abs( data.width );
				elmImg.height       = Math.abs( data.height );
			} else {
				elmImg.style.width  = Math.abs( data.width ) + 'px';
				elmImg.style.height = Math.abs( data.height ) + 'px';
			};
			
			this.imageList.push( rImg );			
		},
		buildBalloon : function( elmPanel, data ){
			var elmBalloonWrap = document.createElement( 'div' ),
				elmText        = document.createElement( 'p' ),
				content        = '',
				speechesAttr   = data.speeches_attributes,
				balloon, p;
			elmPanel.appendChild( elmBalloonWrap );
			elmBalloonWrap.className = NAMESPACE_CLASSNAME + 'balloon';
			elmBalloonWrap.style.cssText = [
				'width:',   data.width, 'px;',
				'height:',  data.height, 'px;',
				'left:',    data.x, 'px;',
				'top:',     data.y, 'px;',
				'z-index:', data.z, ';'
			].join( '' );

			balloon = pettanr.balloon.createBalloon( data.width, data.height, data.tail );
			elmBalloonWrap.appendChild( balloon.elm );
			
			elmBalloonWrap.appendChild( elmText );
			
			elmText.appendChild( document.createElement( 'span' ) );
			
			if( speechesAttr ){
				for( p in speechesAttr ){
					content += speechesAttr[ p ] && speechesAttr[ p ].content ? speechesAttr[ p ].content : '';
				};
			};
			elmText.firstChild.appendChild( document.createTextNode( content ));
			this.balloonList.push( balloon );
		},
		clean : function(){
			// clean elmTarget
			while( this.imageList.length > 0 ){
				this.imageList.shift().destroy();
			};
			while( this.balloonList.length > 0 ){
				this.balloonList.shift().destroy();
			};
			Util.removeAllChildren( this.elmTarget );
		},
		zoom : function(){},
		destroy : function(){
			this.clean();
		}			
	};
	
	var BindWorker = function( elmTarget, json, zoomSelfEnabled, noClassname ){
		this.builder     = new ElementBuilder( elmTarget, noClassname );
		this.elmDetectW  = ELM_DETECT_WIDTH.cloneNode( false );
		this._json        = json;
		this.noClassname = noClassname;
		if( zoomSelfEnabled === true ){
			elmTarget.parentNode.insertBefore( this.elmDetectW, elmTarget );
			this.resizer = new ResizeAgentClass( onResize, this.elmDetectW );
		};
		function onResize(){
			
		};
		json && typeof json === 'object' && this.builder.build( json );
	};
	BindWorker.prototype = {
		init : function(){
				
		},
		zoom : function(){
			this.builder.zoom();
		},
		json : function( json ){
			this._json = json;
			this.builder.build( json, this.noClassname );
		},
		file : function( file ){
			this.builder.buildFromFile( file, this.noClassname );
		},
		targetElement : function(){
				
		},
		layout : function(){
				
		},
		destroy : function(){
			this.builder.destroy();
			delete this.json;
			delete this.builder;
		}		
	};
	return {
		createBindWorker: function( elmTarget, opt_COMICJSONorPANELJSON, opt_zoomSelfEnabled, opt_noClassnameMode ){
			var ret = new BindWorker( elmTarget, opt_COMICJSONorPANELJSON, !!opt_zoomSelfEnabled, !!opt_noClassnameMode );
			BIND_WORKER_ARRAY.push( ret );
			return ret;
		},
		isBindWorkerInstance: function( _bindWorker ){
			return _bindWorker instanceof BindWorkerClass;
		}
	}
})();


/*
 *  Google Analytics
 */

if( pettanr.LOCAL === false || document.location.href.indexOf( 'localhost:' ) === -1 ){
	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);
	})();	
};