/*
 * pettanR work.js
 *   version 0.4.37
 *   
 * author:
 *   itozyun
 * licence:
 *   3-clause BSD
 *
 * 
 * ----------------------------------------
 * naming rules
 * 
 *  Class
 *    ThisIsClass
 *  
 *  const
 *    THIS_IS_CONST = 'this is const';
 *  
 *  var
 *    thisIsVar
 *   
 *  value of jquery
 *    jqWrapper, JQ_WRAPPER
 *  
 *  value of dom element
 *    elmWrapper, ELM_WRAP
 * 
 * 	value of vml element
 *    vmlImg, VML_SHAPE
 * 
 */


/* ----------------------------------------
 *   pettanr.editor
 *    - MENU_BAR_CONTROL
 *    - HISTORY_CONTROL
 *    - SAVE_CONTROL
 *    - WINDOW_CONTROL
 *       - WindowClass
 *    - INFOMATION_WINDOW
 *    - TOOL_BOX_WINDOW
 *    - HELP_DOCUMENTS_WINDOW
 *    - PANEL_CONTROL
 *    - GRID_CONTROL
 *    - WHITE_GLASS_CONTROL
 *    - PANEL_CONTROL
 *    
 * 
 *    - PanelResizerClass
 *    - PANEL_RESIZER_TOP
 *    - PANEL_RESIZER_BOTTOM
 *    - CONSOLE_CONTROLER
 * 
 *    - TAIL_OPERATOR
 *    - RESIZE_OPERATOR
 *    - POSITION_OPERATOR
 *    - COMIC_ELEMENT_OPERATION_MANAGER
 *      
 *    - ImageElementClass
 *    - TextElementClass
 * 
 *    - COMIC_ELEMENT_CONTROL
 * 
 * 
 */
pettanr.editor = pettanr.view.registerApplication( function(){

	var PANEL_ELEMENT_TYPE_IMAGE = 0,
		PANEL_ELEMENT_TYPE_TEXT  = 1,
		MOUSE_LISTENER_ARRAY     = [],
		PANEL_ELEMENT_ARRAY      = [],
		ELM_MOUSE_EVENT_CHATCHER = document.getElementById( 'mouse-operation-catcher'),
		MIN_PANEL_HEIGHT         = 20,
		MIN_ELEMENT_SIZE         = 19,
		MOUSE_HIT_AREA           = 10,
		jqMouseEventChacher,
		jqEditor,
		windowW, windowH,
		currentListener          = null,
		currentCursor            = '',
		instance                 = this,
		option,
		comicID                  = -1,
		panelID                  = -1,
		panelTimming             = -1,
		phase                    = -1,
		log;

/* ----------------------------------------
 * MENU BAR
 *  - mouseEventListener
 *  - controler
 * 
 * div
 *   div.title
 *   ul
 *     li
 *        a
 *          span
 *          kbd shortcut
 */
	var MENU_BAR_CONTROL = ( function(){
		var ELM_BAR            = document.getElementById( 'menu-bar' ),
			ELM_ITEM_CLASSNAME = 'menu-bar-item',
			ELM_ITEM_ORIGN     = ( function(){
				var ret = document.createElement( 'div' ),
					div = document.createElement( 'div' ),
					ul  = document.createElement( 'ul' );
				ret.className = ELM_ITEM_CLASSNAME;
				ret.appendChild( div );
				ret.appendChild( ul );
				return ret;
			})(),
			ELM_SELECTION_ORIGN = ( function(){
				var ret  = document.createElement( 'li' ),
					a    = document.createElement( 'a' ),
					span = document.createElement( 'span' ),
					key  = document.createElement( 'kbd' );
				a.appendChild( span );
				a.appendChild( key );
				ret.appendChild( a );
				a.href = '#';
				return ret;
			})(),
			ITEM_ARRAY = [],
			barH       = pettanr.util.getElementSize( ELM_BAR ).height,
			itemW      = pettanr.util.getElementSize( ELM_ITEM_ORIGN ).width,
			selectionW = pettanr.util.getElementSize( ELM_ITEM_ORIGN.getElementsByTagName( 'ul' )[ 0 ] ).width,
			jqStage, jqBar;
		ELM_BAR.style.top = ( -barH ) +'px';

		var MenubarSelectionClass = function( container, title, shortcut, visible, separateAfter ){
			var ELM_WRAPPER = ELM_SELECTION_ORIGN.cloneNode( true ),
				ELM_TITLE   = ELM_WRAPPER.getElementsByTagName( 'span' )[ 0 ],
				elmShortcut = ELM_WRAPPER.getElementsByTagName( 'kbd' )[ 0 ];
				
			if( shortcut ){
				elmShortcut.innerHTML = shortcut;
			} else {
				elmShortcut.parentNode.removeChild( elmShortcut );
			}
			elmShortcut = null;
			
			container.appendChild( ELM_WRAPPER );

			this.elm   = ELM_WRAPPER;
			this.title = function( _title ){
				if( Type.isString( _title ) === true ){
					ELM_TITLE.innerHTML = title = _title;
				};
				return title;
			};
			this.visible = function( _visible ){
				if( Type.isBoolean( _visible ) === true && visible !== _visible ){
					visible = _visible;
					ELM_WRAPPER.className = visible === true ? '' : 'disabled';
				};
				return visible;
			};
			this.separateAfter = separateAfter;
			
			this.title( title );
			this.visible( visible );
		}

		var MenuBarItemClass = function( title ){
			var ELM_WRAPPER              = ELM_ITEM_ORIGN.cloneNode( true ),
				ELM_TITLE                = ELM_WRAPPER.getElementsByTagName( 'div' )[ 0 ],
				ELM_SELECTION            = ELM_WRAPPER.getElementsByTagName( 'ul' )[ 0 ],
				INDEX                    = ITEM_ARRAY.length,
				SELECTION_CALLBACK_ARRAY = [],
				numSelection             = 0,
				visible                  = false,
				instance                 = this;
			ELM_TITLE.innerHTML = title;
			
			ELM_WRAPPER.style.left = ( itemW * INDEX ) + 'px';
			ELM_BAR.appendChild( ELM_WRAPPER );
			
			this.elm     = ELM_WRAPPER;
			this.onClick = function( e ){
				var i = pettanr.util.getChildIndex( this.parentNode, this );
				i !== -1 && this.className !== 'disabled' && SELECTION_CALLBACK_ARRAY[ i ]( i );
				e.stopPropagation();
				return false;
			};
			this.init = function(){
				$( ELM_SELECTION ).children( 'li' ).click( instance.onClick );
				delete instance.init;
			};
			this.show = function(){
				if( visible === true ) return;
				jqStage.append( ELM_WRAPPER );
				ELM_WRAPPER.className = ELM_ITEM_CLASSNAME + '-focus';
				instance.onShow && setTimeout( instance.onShow, 0 );
				visible = true;
			};
			this.hide = function(){
				if( visible === false ) return;
				ELM_BAR.appendChild( ELM_WRAPPER );
				ELM_WRAPPER.className = ELM_ITEM_CLASSNAME;
				instance.onHide && setTimeout( instance.onHide, 0 );
				visible = false;
			};
			this.createSelection = function( title, shortcut, callback, visible, separateBefore, separateAfter ){
				var ret    = new MenubarSelectionClass( ELM_SELECTION, title, shortcut, visible, separateAfter ),
					before = SELECTION_CALLBACK_ARRAY.length > 0 ? SELECTION_CALLBACK_ARRAY[ SELECTION_CALLBACK_ARRAY.length -1 ] : null;
				SELECTION_CALLBACK_ARRAY.push( callback );
				if( before !== null && ( separateBefore === true || before.separateAfter === true )){
					ret.elm.style.borderTop = '1px solid #ccc';
				}
				return ret;
			};
		};

		
		function createMenubarItem( title ){
			var _item = new MenuBarItemClass( title );
			ITEM_ARRAY.push( _item );
			return _item;
		}
		return {
			init: function(){
				jqStage = jqEditor;
				jqBar = $( ELM_BAR).animate( { top: 0});

				var l = ITEM_ARRAY.length;
				for( var i=0; i<l; ++i){
					ITEM_ARRAY[ i].init();
				}

				delete MENU_BAR_CONTROL.init;
			},
			open: function(){
				MENU_BAR_CONTROL.init && MENU_BAR_CONTROL.init();
				// ELM_BAR.style.top = ( -barH) +'px';
				// anime
			},
			close: function(){
				var l = ITEM_ARRAY.length;
				for( var i=0; i<l; ++i){
					ITEM_ARRAY[ i].hide();
				}
			},
			h: barH,
			onMouseMove: function( _mouseX, _mouseY){
				if( barH >= _mouseY){
					return true;
				}
				var l = ITEM_ARRAY.length;
				for( var i=0; i<l; ++i){
					ITEM_ARRAY[ i].hide();
				}
				return false;
			},
			onMouseUp: function( _mouseX, _mouseY){
				return false;
			},
			onMouseDown: function( _mouseX, _mouseY){
				var l = ITEM_ARRAY.length;
				if( barH < _mouseY || itemW * l < _mouseX) return false;
				for( var i=0; i<l; ++i){
					if( i * itemW <= _mouseX && _mouseX < ( i +1) * itemW){
						ITEM_ARRAY[ i].show();
					} else {
						ITEM_ARRAY[ i].hide();
					}
				}
				return true;
			},
			busy: function( _busy ){
				return false;
			},
			onWindowResize: function( _windowW, _windowH ){
				
			},
			QUIT: createMenubarItem( 'Quit' ),
			EDIT: createMenubarItem( 'Edit' ),
			WINDOW: createMenubarItem( 'Window' ),
			HELP: pettanr.util.extend( createMenubarItem( 'Help' ), {
				createAjaxSelection: function( callback ){
					var elmLoading   = document.createElement( 'li' ),
						that         = this,
						elmSelection = this.elm.getElementsByTagName( 'ul' )[ 0 ];
					elmSelection.appendChild( elmLoading );
					elmLoading.className    = 'loading';
					elmLoading.style.height = '90px';							

					this.onShow = callback;
					callback    = null;
					
					delete this.createAjaxSelection;
					return function(){
						elmSelection.removeChild( elmLoading );
						$( elmSelection ).children( 'li' ).click( that.onClick );
						elmLoading = elmSelection = null;
						delete that.onShow;
						that = null;
					}
				}
			})
		}
	})();


/* ----------------------------------------
 * HISTORY_CONTROL
 *  - controler
 */
	var HISTORY_CONTROL = ( function() {
		var	STACK_BACK = [],
			STACK_FORWARD = [],
			MENUBAR_BACK = MENU_BAR_CONTROL.EDIT.createSelection( 'back', 'ctrl + z', back, false),
			MENUBAR_FORWARD = MENU_BAR_CONTROL.EDIT.createSelection( 'forward', 'ctrl + y', forward, false, false, true),
			log;
			
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 90, false, true, back);	// ctrl + Z
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 90, true, true, forward);	// ctrl + shift + Z
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 89, false, true, forward); // ctrl + Y

		function back(){
			/*
			 * currentを控えてSTACK_FORWARD.push(current)
			 * STACK_BACK.pop()を実行してcurrentに
			 */
			if( STACK_BACK.length === 0) return;

			var state = STACK_BACK.pop();
			state && state.fn( state.argBack);
			MENUBAR_BACK.visible( STACK_BACK.length !== 0);
			SAVE_CONTROL.panelUpdated( STACK_BACK.length !== 0);
			
			STACK_FORWARD.push( state);
			MENUBAR_FORWARD.visible( true);
		}
		function forward(){
			if( STACK_FORWARD.length === 0) return;
			
			var state = STACK_FORWARD.pop();
			state.fn( state.argForword);
			MENUBAR_FORWARD.visible( STACK_FORWARD.length !== 0);
			
			STACK_BACK.push( state);
			MENUBAR_BACK.visible( true);
			SAVE_CONTROL.panelUpdated( true);
		}
		function destroyStack( _stack, _destroy){
			_stack.fn = null;
			
			var	_argBack = _stack.argBack,
				_argForword = _stack.argForword,
				_value;
			if( Type.isArray( _argBack ) === true ){ // isArray
				while( _argBack.length > 0){
					_value = _argBack.shift();
					_destroy === true && Type.isFunction( _value.destroy ) === true && _value.destroy();
				}
			}
			if( Type.isArray( _argForword ) === true ){
				while( _argForword.length > 0){
					_value = _argForword.shift();
					_destroy === true && Type.isFunction( _value.destroy ) === true && _value.destroy();
				}						
			}			
		}
		return {
			init: function(){
				log = $( '#history-log');
				delete HISTORY_CONTROL.init;
			},
			open: function(){
				HISTORY_CONTROL.init && HISTORY_CONTROL.init();
			},
			close: function(){
				MENUBAR_BACK.visible( false);
				MENUBAR_FORWARD.visible( false);
		       	while( STACK_BACK.length > 0){
					destroyStack( STACK_BACK.shift(), true );
				}
		       	while( STACK_FORWARD.length > 0){
					destroyStack( STACK_FORWARD.shift(), true );
				}
			},
		    saveState: function( _function, _argBack, _argForword, _destroy) {
		        STACK_BACK.push( {
		        	fn:			_function,
		        	argBack:	_argBack,
					argForword:	_argForword,
					destroy:	_destroy
		        });
		        MENUBAR_BACK.visible( true);
				SAVE_CONTROL.panelUpdated( true);
				
				var _stack;
		       	while( STACK_FORWARD.length > 0){
					_stack = STACK_FORWARD.shift();
					destroyStack( _stack, _stack.destroy );
				}
				MENUBAR_FORWARD.visible( false);
		    }		
		}
	})();

/* ----------------------------------------
 * SAVE_CONTROL
 *  - controler
 */
	var SAVE_CONTROL = ( function(){
		var SAVE = MENU_BAR_CONTROL.QUIT.createSelection( 'save', 'ctrl + S', quit, false),
			SAVE_AND_QUIT = MENU_BAR_CONTROL.QUIT.createSelection( 'save & quit', null, quit, false, false, true),
			EXPORT = MENU_BAR_CONTROL.QUIT.createSelection( 'export', null, onExport, true, false, true),
			QUIT = MENU_BAR_CONTROL.QUIT.createSelection( 'quit', null, quit, true, true),
			updated = false;
		
		function quit(){
			pettanr.editor.shutdown();
		}
		
		function onExport(){
			pettanr.outputConsole.bootInOverlay(
				comicID, panelID, panelTimming,
				PANEL_CONTROL.w(), PANEL_CONTROL.h(),
				2, // border, BackgroundImage
				PANEL_ELEMENT_ARRAY
			);
		}
		return {
			open: function(){},
			close: function(){},
			quit: quit,
			panelUpdated: function( _updated){
				if( _updated !== undefined && updated !== _updated ){
					SAVE.visible( !!_updated );
					SAVE_AND_QUIT.visible( !!_updated );
					updated = !!_updated;
				}
				return updated;
			},
			save: function(){
				
			}
		}
	})();

/* ----------------------------------------
 * WINDOWS_CONTROL
 *  - contloler
 *  - mouseEventListener
 */	
	var WINDOWS_CONTROL = ( function(){
		/*
		 *  表示上手前にあるwindowは、WINDOW_ARRAYの先頭にあり、htmlでは後ろにある。
		 */
		var DEFAULT_MIN_WINDOW_WIDTH = 200,
			DEFAULT_MIN_WINDOW_HEIGHT = 200,
			WINDOW_ARRAY = [],
			WINDOW_BODY_BODER_SIZE = 1,
			jqContainer,
			currentWindow,
			currentWindowIndex = -1,
			log;

		var jqWindowOrigin,
			closeButtonWidth;
		var WindowClass = function( bodyTempleteID, title, x, y, w, h, visible, CLOSE_BUTTON_ENABLED, RESIZE_BUTTON_ENABLED, minWindowW, minWindowH ){
			var MOUSE_CURSOR = updateMouseCursor,
				MENUBAR_SELWCTION = MENU_BAR_CONTROL.WINDOW.createSelection( 
					( visible !== true ? 'show ' : 'hide ' ) + title,
					null, onMenuClick, true
				),
				jqStage,
				jqWrapper, jqHeader, jqFooter = null,
				elmBody, elmBodyStyle,
				startX, startY, startW, startH,
				offsetX, offsetY,
				headerH, bodyH, footerH = 0,
				isDragging = false,
				isResizing = false,
				bodyIsTachable = false,
				instance = this;

			function onMenuClick(){
				visible === true ? instance.close() : instance.open();
			}
			function update( _x, _y, _w, _h){
				_x = _x !== undefined ? _x : x;
				_y = _y !== undefined ? _y : y;
				_y = _y > MENU_BAR_CONTROL.h ? _y : MENU_BAR_CONTROL.h;
				_w = _w !== undefined ? _w : w;
				_h = _h !== undefined ? _h : h;
				jqWrapper.css( {
					left:		_x,
					top:		_y,
					width:		_w,
					height:		_h
				});
				bodyH = _h -headerH -footerH;
				elmBodyStyle.height = bodyH +'px';
				( w !== _w || h !== _h) && instance.onResize && instance.onResize( _w, bodyH);
				x = _x;
				y = _y;
				w = _w;
				h = _h;
			}
			function bodyBackOrForward( isBack ){
				if( !instance) return;
				if( bodyIsTachable === !isBack) return;
				elmBodyStyle.position =	isBack === true ? 'relative' : 'absolute';
				elmBodyStyle.left =		isBack === true ? 0  : x +'px';
				elmBodyStyle.top =		isBack === true ? 0  : y +headerH +'px';
				elmBodyStyle.width =	isBack === true ? '' : ( w -WINDOW_BODY_BODER_SIZE *2) +'px';
				bodyIsTachable === isBack && isBack === true ? jqHeader.after( elmBody) : jqStage.append( elmBody);
				bodyIsTachable = !isBack;
			}
			function onWindowResize( e){
				bodyBackOrForward( true);
				isResizing = true;
				startX = x;
				startY = y;
				startW = w;
				startH = h;
				offsetX = e.pageX;
				offsetY = e.pageY;
				MOUSE_CURSOR( 'nw-resize');
				e.stopPropagation();
				return false;
			}
			this.init = function( jqContainer ){
				jqWindowOrigin = jqWindowOrigin || ( function(){
					return $( $( '#windowTemplete').remove().html());
				})();
				closeButtonWidth = closeButtonWidth || ( function(){
					return pettanr.util.getElementSize( jqWindowOrigin.clone( true).find( '.window-close-button').get( 0)).width;
				})();
				
				jqStage = jqEditor;
				instance.$ = jqWrapper = jqWindowOrigin.clone( true);
				jqHeader = jqWrapper.children( '.window-header').eq( 0).html( title);
				headerH = pettanr.util.getElementSize( jqHeader.get( 0)).height;
				elmBody = jqWrapper.children( '.window-body').get( 0);
				elmBodyStyle = elmBody.style;
				
				if( bodyTempleteID) {
					jqWrapper.find( '.window-body-insert-position').replaceWith( $( $( '#' +bodyTempleteID).remove().html()));
				} else {
					jqWrapper.find( '.window-body-insert-position').remove();
				}
				CLOSE_BUTTON_ENABLED !== true && jqWrapper.find( '.window-close-button').remove();
				
				instance.onInit && instance.onInit();
				delete instance.init;
			};
			this.x = function(){ return x;};
			this.y = function(){ return y;};
			this.w = function(){ return w;};
			this.h = function(){ return h;};
			this.$ = null;
			this.title = function( _title ){
				if( Type.isString( _title ) === true ){
					jqHeader.html( _title );
					title = _title;
				}
				return title;
			};
			this.visible   = visible;
			this.firstOpen = function(){
				if( RESIZE_BUTTON_ENABLED === true){
					footerH = pettanr.util.getElementSize( jqWrapper.find( '.window-footer' ).get( 0 ) ).height;
				} else {
					jqWrapper.find( '.window-footer').remove();
				}
				instance.onFirstOpen && instance.onFirstOpen( w, h - headerH - footerH );
				
				update( x, y, w, h);
				
				delete instance.firstOpen;
			};
			this.open = function(){
				if( visible === true) return;
				instance.visible = visible = true;
				openWindow( instance);
				MENUBAR_SELWCTION.title( 'hide ' +title);
				
				for( var i=0, l = WINDOW_ARRAY.length; i<l; ++i){
					if( WINDOW_ARRAY[ i] === instance){
						WINDOW_ARRAY.splice( i, 1);
						WINDOW_ARRAY.unshift( instance);
						currentWindow = null;
						currentWindowIndex = -1;
					};
				};
			};
			this.onFadeIn = function(){
				instance.firstOpen && instance.firstOpen();
				instance.onOpen && setTimeout( callOnOpen, 0);
				function callOnOpen(){
					instance.onOpen( w, bodyH );
				};
			};
			this.onFadeOut = function(){
				var elmWrapper = jqWrapper.get(0);
				elmWrapper.parentNode.removeChild( elmWrapper);
				instance.onClose && setTimeout( instance.onClose, 0);
			};
			this.close = function(){
				if( visible === false) return;
				instance.visible = visible = false;
				jqWrapper.fadeOut( instance.onFadeOut);
				MENUBAR_SELWCTION.title( 'show ' +title);
			};
			this.bodyBackOrForward = bodyBackOrForward;
			this.onMouseDown = function( _mouseX, _mouseY ){
				if( RESIZE_BUTTON_ENABLED === true && x + w -20 <= _mouseX && _mouseX < x + w && y + headerH + bodyH < _mouseY && _mouseY <= y + h ){
					bodyBackOrForward( true);
					isResizing = true;
					startX = x;
					startY = y;
					startW = w;
					startH = h;
					offsetX = _mouseX;
					offsetY = _mouseY;
					MOUSE_CURSOR( 'nw-resize');
					return;
				}
				
				if( x > _mouseX || y > _mouseY || x + w < _mouseX || y + headerH < _mouseY ) return;
				if( CLOSE_BUTTON_ENABLED === true && x + w - closeButtonWidth < _mouseX){
					instance.close();
					return;
				}
				
				isDragging = true;
				MOUSE_CURSOR( 'move');				
				startX = x;
				startY = y;
				startW = w;
				startH = h;
				offsetX = _mouseX;
				offsetY = _mouseY;
			};
			this.onMouseUp = function( _mouseX, _mouseY ){
				isDragging = isResizing = false;
				MOUSE_CURSOR( '');
			};
			this.onMouseMove = function( _mouseX, _mouseY ){
				var _updateX = _mouseX - offsetX,
					_updateY = _mouseY - offsetY;
				
				if( isResizing === true){
					var _w = startW +_updateX,
						_h = startH +_updateY;
					update( startX, startY, _w < minWindowW ? minWindowW : _w, _h < minWindowH ? minWindowH : _h );
					return;
				} else
				if( isDragging === true) {
					update( startX + _updateX, startY + _updateY);
					return;
				} else
				if( x > _mouseX || x + w < _mouseX ) return;

				( y <= _mouseY && y +headerH >= _mouseY ) ?
					MOUSE_CURSOR( 'pointer') :	// hit to header
					MOUSE_CURSOR( '');
				bodyBackOrForward( y + headerH > _mouseY || y + headerH + bodyH < _mouseY);
			};
			this.onMouseOut = function( _mouseX, _mouseY ){
				bodyIsTachable === true && bodyBackOrForward( true );
				isDragging = false;
				MOUSE_CURSOR( '' );
			};
			this.busy = function(){
				return isDragging === true || isResizing === true;
			};
			this.bodyHeight = function(){
				return bodyH;
			};
		};
		
		function getCurrentIndex( _mouseX, _mouseY ){
			if( currentWindow && currentWindow.busy() === true ) return currentWindowIndex;
			var l = WINDOW_ARRAY.length,
				_currentWindow = null,
				_win, _x, _y;
			currentWindowIndex = -1;
			for( var i=0; i<l; i++){
				_win = WINDOW_ARRAY[ i];
				if( _win.visible !== true) continue;
				_x = _win.x();
				_y = _win.y();
				if( _x <= _mouseX && _y <= _mouseY && _x +_win.w() >= _mouseX && _y +_win.h() >= _mouseY){
					_currentWindow = _win;
					currentWindowIndex = i;
					break;
				}
			}
			currentWindow && currentWindow !== _currentWindow && currentWindow.onMouseOut( _mouseX, _mouseY);
			currentWindow = _currentWindow;
			return currentWindowIndex;
		}
		function openWindow( _window ){
			if( _window.visible !== true) return;
			var _jqWindow = _window.$;
			jqContainer.append( _jqWindow);// appendした後に fadeIn() しないと ie で filterが適用されない．
			_jqWindow.fadeIn( _window.onFadeIn);
			return;
		}
		
		return {
			init: function(){
				jqContainer = $( '#window-container');
				
				var l = WINDOW_ARRAY.length,
					_window;
				for( var i=l-1; i >= 0; --i){
					_window = WINDOW_ARRAY[ i];
					_window.init && _window.init( jqContainer);
					_window.visible === true && openWindow( _window);
				}
				log = $( '#window-log');
				
				delete WINDOWS_CONTROL.init;
			},
			open: function(){
				WINDOWS_CONTROL.init && WINDOWS_CONTROL.init();
			},
			close: function(){
				
			},
			onMouseMove: function( _mouseX, _mouseY){
				var _index = getCurrentIndex( _mouseX, _mouseY);
				if( _index === 0){
					currentWindow.onMouseMove( _mouseX, _mouseY);
					return true;
				} else
				if( _index > 0){ // 先頭のクリックでない場合
				// Array を前に
					WINDOW_ARRAY.splice( currentWindowIndex, 1);
					WINDOW_ARRAY.unshift( currentWindow);
				// Domを最後に
					jqContainer.append( currentWindow.$);
					currentWindowIndex = 0;
					return true;
				}
				return false;
			},
			onMouseUp: function( _mouseX, _mouseY){
				if( getCurrentIndex( _mouseX, _mouseY) === 0){
					currentWindow.onMouseUp( _mouseX, _mouseY);
					return true;
				}
				return false;
			},
			onMouseDown: function( _mouseX, _mouseY){
				if( getCurrentIndex( _mouseX, _mouseY) === 0){
					currentWindow.onMouseDown( _mouseX, _mouseY);
					return true;
				}
				return false;
			},
			busy: function(){
				return currentWindow !== null;
			},
			onWindowResize: function( _windowW, _windowH){
				/*
				 * 画面外に出るwindowの移動
				 */
			},
			createWindow: function( EXTENDS, bodyTempleteID, title, x, y, w, h, opt_visible, opt_closeButtonEnabled, opt_resizeButtonEnabled, opt_minWindowW, opt_minWindowH ){
				opt_visible = opt_visible !== false;
				opt_closeButtonEnabled = opt_closeButtonEnabled === true;
				opt_resizeButtonEnabled = opt_resizeButtonEnabled === true;
				opt_minWindowW = opt_minWindowW || ( w < DEFAULT_MIN_WINDOW_WIDTH ) ? w : DEFAULT_MIN_WINDOW_WIDTH;
				opt_minWindowH = opt_minWindowH || ( h < DEFAULT_MIN_WINDOW_HEIGHT ) ? h : DEFAULT_MIN_WINDOW_HEIGHT;
				
				var _window = new WindowClass( bodyTempleteID, title, x, y, w, h, opt_visible, opt_closeButtonEnabled, opt_resizeButtonEnabled, opt_minWindowW, opt_minWindowH );
				for( var key in EXTENDS ){
					_window[ key ] = EXTENDS[ key ];
				}
				WINDOW_ARRAY.unshift( _window );
				if( Type.isUndefined( WINDOWS_CONTROL.init ) === true ){
					_window.init( jqContainer );
					openWindow( _window );
				}
				return _window;
			}
		}
	})();

/* ----------------------------------------
 * TOOL_BOX_WINDOW
 * - window
 */
	var TOOL_BOX_WINDOW = ( function(){
		var addImageButton, addTextButton, editBgButton, switchGridButton, popupHelpButton, postButton,
			instance;
			
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 73, false, true, addImage);
		MENU_BAR_CONTROL.EDIT.createSelection( 'Add Image', 'ctrl + I', addImage, true, true, false);
		
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 84, false, true, addText);
		MENU_BAR_CONTROL.EDIT.createSelection( 'Add Text', 'ctrl + T', addText, true, false, true);

		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 71, false, true, switchGrid);
		MENU_BAR_CONTROL.EDIT.createSelection( 'show Grid', 'ctrl + G', switchGrid, true, true, true);

		function addImage( e){
			IMAGE_EXPLORER_WINDOW.open();// setTimeout( IMAGE_EXPLORER_WINDOW.open, 0);
			instance.bodyBackOrForward( true );
			e && e.preventDefault && e.preventDefault();
			return false;
		}
		function addText( e){
			setTimeout( COMIC_ELEMENT_CONTROL.createTextElement, 0);
			e && e.preventDefault && e.preventDefault();
			return false;
		}
		function switchGrid( e){
			setTimeout( GRID_CONTROL.update, 0);
			e && e.preventDefault && e.preventDefault();
			return false;
		}
		function popupHelp( e){
			instance.bodyBackOrForward( true);
			setTimeout( HELP_DOCUMENTS_WINDOW.open, 0);
			e && e.preventDefault && e.preventDefault();
			return false;
		}
		function editBG( e){
			instance.bodyBackOrForward( true);
			setTimeout( INFOMATION_WINDOW.open, 0);	
			e && e.preventDefault && e.preventDefault();
			return false;
		}
		
		return WINDOWS_CONTROL.createWindow(
			{
				onInit: function(){
					instance = this;
					delete this.onInit;
				},
				onFirstOpen: function(){
					addImageButton = $( '#toolbox-add-image-button').click( addImage);
					addTextButton = $( '#toolbox-add-text-button').click( addText);
					editBgButton = $( '#toolbox-edit-bg-button').click( editBG);
					switchGridButton = $( '#toolbox-switch-grid').click( switchGrid);
					popupHelpButton = $( '#toolbox-popup-help-button').click( popupHelp);
					
					postButton = $( '#toolbox-post-button');
					
					delete this.onFirstOpen;
				}
			},
			'toolbox-window', 'Tool box', 0, 215, 110, 290, true
		);
	})();
	
	
/* ----------------------------------------
 * IMAGE_EXPROLER
 *  - window
 */
	var IMAGE_EXPLORER_WINDOW = ( function(){
		var instance, finder;
		
		function onFileSelect( _file ){
			// 他の image ファイルも許可する？
			if( pettanr.driver.isPettanrFileInstance( _file ) === true ){
				if( _file.getType() === pettanr.driver.FILE_TYPE.PICTURE ){
					COMIC_ELEMENT_CONTROL.onImageSelect( pettanr.driver._getAPI().getFileData( _file ) );
				}
			}
		}
		
		return WINDOWS_CONTROL.createWindow(
			{
				onInit: function(){
					instance = this;
					delete this.onInit;
				},
				onOpen: function( _w, _h ){
					finder = finder || pettanr.finder.createFinder(
						pettanr.editor,
						document.getElementById( 'image-exproler-container'),
						pettanr.driver.createPictureTree(),
						null, null,
						onFileSelect,
						COMIC_ELEMENT_CONTROL.onImageSelect
					);

					finder.resize( _w, _h );
				},
				onResize: function( _w, _h ){
					finder.resize( _w, _h );
				}
			},
			'image-exproler', 'Album', 0, 215, 600, 350, false, true, true, 300, 300
		);
	})();
	
	
/* ----------------------------------------
 * INFOMATION_WINDOW
 *  - window
 */			
	var INFOMATION_WINDOW = ( function(){
		var FADE_EFFECT_ENABLED = true, //pettanr.ua.isIE === false || pettanr.ua.ieVersion >= 8,
			FADE_IN_EFFECT = FADE_EFFECT_ENABLED === true ? 'fadeIn' : 'show',
			FADE_OUT_EFFECT = FADE_EFFECT_ENABLED === true ? 'fadeOut' : 'hide',
			backgroundInfomationElm,
			jqComicElementInformation,
			inputX, inputY, inputZ, inputA, inputW, inputH, inputAspectRatio,
			inputPercentW, inputPercentH,
			currentComicElement = null,
			currentElementType = -1,
			currentLock = false;

		return WINDOWS_CONTROL.createWindow(
			{
				onFirstOpen: function( _w, _h){
					backgroundInfomationElm = $( '#panel-background-information');
					
					jqComicElementInformation = $( '#comic-element-infomation').hide().css( {
						height:		_h
					});
					var TAB_GROUP_ID = 'comic-element-attribute';
					var CREATER = pettanr.form.createInputText;//pettanr.key.createEditableText;
					inputX = CREATER( document.getElementById( 'comic-element-x'), null, TAB_GROUP_ID);
					inputY = CREATER( document.getElementById( 'comic-element-y'), null, TAB_GROUP_ID);
					inputZ = CREATER( document.getElementById( 'comic-element-z'), null, TAB_GROUP_ID);
					inputA = CREATER( document.getElementById( 'comic-element-a'), null, TAB_GROUP_ID);
					inputW = CREATER( document.getElementById( 'comic-element-w'), null, TAB_GROUP_ID);
					inputH = CREATER( document.getElementById( 'comic-element-h'), null, TAB_GROUP_ID);
					inputPercentW = CREATER( document.getElementById( 'comic-element-w-percent'), null, TAB_GROUP_ID);
					inputPercentH = CREATER( document.getElementById( 'comic-element-h-percent'), null, TAB_GROUP_ID);
					inputAspectRatio = $( '#comic-element-keep-aspect');
					delete INFOMATION_WINDOW.onFirstOpen;
				},
				onResize: function(  _w, _h){
					jqComicElementInformation.css( {
						height: _h
					});
				},
				update: function( currentElement ){
					
					if( currentLock === true && currentElement === null) return;
					
					var _elementType = currentElement === null ? -1 : currentElement.type,
						x = currentElement !== null ? currentElement.x : 0,
						y = currentElement !== null ? currentElement.y : 0,
						z = currentElement !== null ? currentElement.z : 0,
						a = _elementType === PANEL_ELEMENT_TYPE_TEXT ? Math.floor( currentElement.angle()) : 0,
						w = currentElement !== null ? currentElement.w : 0,
						h = currentElement !== null ? currentElement.h : 0,
						actualW = _elementType === PANEL_ELEMENT_TYPE_IMAGE ? currentElement.actualW() : 1,
						actualH = _elementType === PANEL_ELEMENT_TYPE_IMAGE ? currentElement.actualH() : 1,
						wPercent = _elementType === PANEL_ELEMENT_TYPE_IMAGE ? Math.floor( w / actualW *100) : 0,
						hPercent = _elementType === PANEL_ELEMENT_TYPE_IMAGE ? Math.floor( h / actualH *100) : 0,
						keepAspect = currentElement !== null && currentElement.keepAspect === true;
					
					if( currentElementType !== _elementType){
						if( _elementType !== -1){
							if( _elementType === 1){
								inputA.visible( true);
								inputPercentW.visible( false);
								inputPercentH.visible( false);
								inputAspectRatio.hide();
							} else {
								inputA.visible( false);
								inputPercentW.visible( true);
								inputPercentH.visible( true);
								inputAspectRatio.show();
							}
							currentElementType === -1 && jqComicElementInformation.stop().css( {
								filter:		'',
								opacity:	''
							})[ FADE_IN_EFFECT]();
						} else {
							currentElementType !== -1 && jqComicElementInformation.stop().css({
								filter:		'',
								opacity:	''
							})[ FADE_OUT_EFFECT]();
						}
						currentElementType = _elementType;
					}
					if( currentElementType !== -1){
						inputX.value( x);
						inputY.value( y);
						inputZ.value( z);
						_elementType === 1 && inputA.value( a);
						inputW.value( w);
						inputH.value( h);
						_elementType === 0 && inputPercentW.value( wPercent );
						_elementType === 0 && inputPercentH.value( hPercent );
					} else {
						
					}
				},
				lock: function( _currentLock ){
					currentLock = !!_currentLock;
					INFOMATION_WINDOW.bodyBackOrForward( !currentLock );
				}
			},
			'infomation-window', 'Infomation', 0, 30, 200, 180, true
		);
	})();

/* ----------------------------------------
 * HELP_WINDOW
 *  - window
 */
	var HELP_DOCUMENTS_WINDOW = ( function(){
		var visible = true,
			jqAjaxContents,
			jqNaviItems,
			jqPages,
			currentPageIndex = 0,
			numPage          = 0,
			HELP             = MENU_BAR_CONTROL.HELP,
			onLoadFunction   = HELP.createAjaxSelection( onAjaxStart );

		function onAjaxStart( _pageIndex ){
			currentPageIndex = _pageIndex || currentPageIndex;
			if( onHelpLoad !== null ){
				$.ajax({
					url:		'help/jp.xml',
					dataType:	'xml',
					success:	onHelpLoad
				});
				onHelpLoad = null;
			}
			onAjaxStart = new Function;
		}
		var onHelpLoad = function( _xml ){
			var jqXML          = $( _xml ),
				helpTitle      = jqXML.find( 'pages' ).eq( 0 ).attr( 'title' ),
				elmNavi        = document.createElement( 'div' ),
				elmItemOrigin  = document.createElement( 'a' ),
				elmPages       = document.createElement( 'div' ),
				elmPageOrigin  = document.createElement( 'div' ),
				elmTitleOrigin = document.createElement( 'h2' ),
				elmPage;
			elmNavi.className       = 'sidenavi';
			elmItemOrigin.className = 'sidenavi-item';
			elmItemOrigin.href      = '#';
			elmPages.className      = 'page-contents';
			elmPageOrigin.className = 'page-content main';
			elmPageOrigin.appendChild( elmTitleOrigin);
			
			jqXML.find( 'page' ).each( function(){
				var xmlPage = $( this ),
					title = xmlPage.attr( 'title' ),
					content = xmlPage.text();
				
				elmItemOrigin.innerHTML = title;
				elmNavi.appendChild( elmItemOrigin.cloneNode( true ));
				
				elmTitleOrigin.innerHTML = title;
				
				elmPage = elmPageOrigin.cloneNode( true );
				elmPage.innerHTML = content;
				
				pettanr.util.cleanElement( elmPage);
				
				if( elmPage.childNodes.length > 0 ){
					elmPage.insertBefore( elmTitleOrigin.cloneNode( true ), elmPage.childNodes[0]);
				} else {
					elmPage.appendChild( elmTitleOrigin.cloneNode( true ));
				}
				elmPages.appendChild( elmPage );
				
				HELP.createSelection( title, null, onSelectionClick, true );
				++numPage;
			});
			onLoadFunction();
			onLoadFunction = null;
			
			jqAjaxContents.removeClass( 'loading' ).append( elmNavi, elmPages );
			
			jqNaviItems = jqAjaxContents.find( 'a.' + elmItemOrigin.className ).click( onNaviClick );
			jqPages = jqAjaxContents.find( '.page-content' );
			jqPages.find( 'a').click( onInnerLinkClick );
			
			setTimeout( jumpPage, 0 );
		}
		function onSelectionClick( _pageIndex ){
			HELP_DOCUMENTS_WINDOW.open();
			jumpPage( _pageIndex );
		}
		function jumpPage( _index ){
			if( typeof _index === 'number' && 0 <= _index && _index < numPage && currentPageIndex !== _index ){
				currentPageIndex = _index;
			}
			jqNaviItems.removeClass( 'current' ).eq( currentPageIndex).addClass( 'current' );
			jqPages.hide().eq( currentPageIndex ).show();
		}
		function onNaviClick( e ){
			// this は <a>
			jumpPage( pettanr.util.getChildIndex( this.parentNode, this ));
			e.stopPropagation();
			return false;
		}
		function onInnerLinkClick( e ){
			var jump = ( this.href || '').split( '#jump' ),
				n = jump[1];
			if( !n) return;
			jumpPage( '' + parseFloat( n ) === n ? parseFloat( n ) : -1 );
			e.stopPropagation();
			return false;				
		}
		return WINDOWS_CONTROL.createWindow(
			{
				onInit: function(){
					jqAjaxContents = HELP_DOCUMENTS_WINDOW.$.find( '.window-body' ).addClass( 'loading' );
					delete HELP_DOCUMENTS_WINDOW.onInit;
				},
				onFirstOpen: function( _w, _h ){
					jqAjaxContents.css( { height: _h });
					onAjaxStart();
					delete HELP_DOCUMENTS_WINDOW.onFirstOpen;
				},
				onResize: function( _w, _h ){
					jqAjaxContents && jqAjaxContents.css( { height: _h });
				}
			},
			null, 'Help', 0, 215, 400, 350, false, true, true, 300, 300
		);
	})();

/* ----------------------------------------
 * GRID_CONTROL
 *  - control
 *  - panelResizeListener
 */
	var GRID_CONTROL = ( function(){
		var ELM_GRID = document.getElementById( 'grid' ),
			BG_URL = "url('images/grid.gif')",
			jqGrid,
			visible = false;

		return {
			init: function(){
				jqGrid = $( ELM_GRID );
				delete GRID_CONTROL.init;
			},
			open: function(){
				GRID_CONTROL.init && GRID_CONTROL.init();
			},
			close: function(){
				
			},
			onPanelResize: function( _panelX, _panelY ){
				ELM_GRID.style.backgroundPosition = [ _panelX % 10, 'px ', _panelY % 10, 'px' ].join( '' );
				ELM_GRID.style.height = windowH +'px';
			},
			enabled: function(){
				return visible;
			},
			update: function(){
				jqGrid.css( {
					opacity:	'',
					fliter:		''
				}).stop()[ visible === true ? 'fadeOut' : 'fadeIn' ]();
				
				visible = !visible;
				
				if( visible === true && BG_URL !== null){
					ELM_GRID.style.backgroundImage = BG_URL;
					BG_URL = null;
				}
				return visible;				
			}
		}
	})();
		
/* ----------------------------------------
 * WHITE_GLASS_CONTROL
 *  - panelResizeListener
 */
	var WHITE_GLASS_CONTROL = ( function(){
		var styleTop = document.getElementById( 'whiteGlass-top').style,
			styleLeft = document.getElementById( 'whiteGlass-left').style,
			styleRight = document.getElementById( 'whiteGlass-right').style,
			styleBottom = document.getElementById( 'whiteGlass-bottom').style;

		return {
			onPanelResize: function( _panelX, _panelY, _panelW, _panelH){
				var	_w = _panelW,
					_h = _panelH,
					marginTop = _panelY,
					marginBottom = windowH -_h -marginTop,
					marginX = _panelX,
					rightWidth = windowW -_w -marginX;
				
				styleTop.height = ( marginTop < 0 ? 0 : marginTop) +'px';
				
				styleLeft.top =	marginTop +'px';
				styleLeft.width = ( marginX < 0 ? 0 : marginX) +'px';
				styleLeft.height = ( _h + marginBottom) +'px';
				
				styleRight.top = marginTop +'px';
				styleRight.left = _w +marginX +'px';
				styleRight.width = ( rightWidth < 0 ? 0 : rightWidth) +'px';
				styleRight.height = ( _h + marginBottom) +'px';
				
				styleBottom.top = ( _h +marginTop) +'px';
				styleBottom.left = marginX +'px';
				styleBottom.width = _w +'px';
				styleBottom.height = ( marginBottom < 0 ? 0 : marginBottom) +'px';
			}
		}
	})();


/* ----------------------------------------
 * PANEL_CONTROL
 *  - controler
 *  - mouseEventListener
 * 
 * panel-border の表示と onPanelResize の通知．
 * panel drag.
 * 
 */
	var PANEL_CONTROL = ( function(){
		var ELM_PANEL = document.getElementById('panel-tools-container'),
			ELM_PANEL_STYLE = ELM_PANEL.style,
			DEFAULT_PANEL_WIDTH = 400,
			DEFAULT_PANEL_HEIGHT = 300,
			borderSize = 2,
			panelW, panelH, panelX, panelY,
			offsetX, offsetY, startX, startY,
			isDragging = false,
			isDraggable = false;
		
		pettanr.key.addKeyUpdateEvent( pettanr.view.EDITOR, 32, false, false, onSpaceUpdate);
		
		function onSpaceUpdate(e){
			if( e.type === 'keyup'){
				currentListener === null && updateMouseCursor( '');
				isDraggable = false;
			} else {
				currentListener === null && updateMouseCursor( 'move');
				isDraggable = true;
			}
		}
		
		return {
			open: function( _panelW, _panelH, _borderSize ){
				panelW = Type.isFinite( _panelW ) === true ? _panelW : DEFAULT_PANEL_WIDTH;
				panelH = Type.isFinite( _panelH ) === true ? _panelH : DEFAULT_PANEL_HEIGHT;
				//panelX = Math.floor( ( windowW -panelW) /2);
				//panelY = Math.floor( ( windowH -panelH) /2);
				borderSize = Type.isFinite( _borderSize ) === true ? _borderSize : borderSize;
				
				//setTimeout( PANEL_CONTROL.resize, 0);
			},
			close: function(){
				
			},
			x: function(){
				return panelX;
			},
			y: function(){
				return panelY;
			},
			w: function(){
				return panelW;
			},
			h: function(){
				return panelH;
			},
			resize: function( isResizerTopAction, _x, _y, _w, _h){
				panelX = _x !== undefined ? _x : panelX;
				panelY = _y !== undefined ? _y : panelY;
				panelW = _w !== undefined ? _w : panelW;
				panelH = _h !== undefined ? _h : panelH;
				
				ELM_PANEL_STYLE.left	= ( panelX -borderSize) +'px';
				ELM_PANEL_STYLE.top		= ( panelY -borderSize) +'px';
				ELM_PANEL_STYLE.width	= panelW +'px';
				ELM_PANEL_STYLE.height	= panelH +'px';
				
				PANEL_RESIZER_TOP.onPanelResize( panelX, panelY, panelW, panelH);
				PANEL_RESIZER_BOTTOM.onPanelResize( panelX, panelY, panelW, panelH);
				GRID_CONTROL.onPanelResize( panelX, panelY);
				WHITE_GLASS_CONTROL.onPanelResize( panelX, panelY, panelW, panelH);
				COMIC_ELEMENT_CONTROL.onPanelResize( panelX, panelY, panelW, panelH, isResizerTopAction === true);
			},
			onWindowResize: function( _windowW, _windowH){
				panelX = Math.floor(( _windowW - panelW) / 2);
				panelY = Math.floor(( _windowH - panelH) / 2);
				PANEL_CONTROL.resize();
			},
			onMouseMove: function( _mouseX, _mouseY){
				if( isDraggable === true && isDragging === true){
					PANEL_CONTROL.resize( false, startX +_mouseX -offsetX, startY +_mouseY -offsetY);
				}
			},
			onMouseUp: function( _mouseX, _mouseY){
				if( isDraggable === true){
					isDragging = false;
					updateMouseCursor( '');
				}
			},
			onMouseDown: function( _mouseX, _mouseY){
				if( isDraggable === true){
					offsetX = _mouseX;
					offsetY = _mouseY;
					startX = panelX;
					startY = panelY;
					isDragging = true;
					updateMouseCursor( 'move');
					return true;
				}
			},
			busy: function(){
				return isDragging === true;
			}				
		}
	})();

/* --------------------------------------------------------------------------------------------
 * PanelResizerClass
 *  - mouseEventListener
 */
	var PanelResizerClass = function( ID, isTop){
		var ELM = document.getElementById( ID),
			BORDER_WIDTH = 2,
			RESIZER_HEIGHT = 30,
			x = -BORDER_WIDTH /2,
			y = isTop === true ? ( -5 -RESIZER_HEIGHT -BORDER_WIDTH) : 0,
			w,
			h = RESIZER_HEIGHT,
			panelX, panelY, panelW, panelH,
			offsetY, startY, startH,
			isDragging = false,
			MOUSE_CURSOR = updateMouseCursor;
			
		function restoreState( arg){
			if( arg && arg.length > 3){
				PANEL_CONTROL.resize( isTop, arg[ 0] || panelX, arg[ 1] || panelY, arg[ 2] || panelW, arg[ 3] || panelH);
			}
		}
			
		this.onMouseDown = function( _mouseX, _mouseY){
			var _x = _mouseX -panelX,
				_y = _mouseY -panelY;
			if( _x < x || x + w < _x || _y < y || y + h < _y) return false;
			offsetY = _y;
			startY = panelY;
			startH = panelH;
			isDragging = true;
			MOUSE_CURSOR( 'n-resize');
			return true;
		}
		this.onMouseMove = function( _mouseX, _mouseY){
			var _x = _mouseX -panelX,
				_y = _mouseY -panelY;
			if( isDragging !== true){
				if( _x < x || x + w < _x || _y < y || y + h < _y) return false;
				COMIC_ELEMENT_OPERATION_MANAGER.hide();
				MOUSE_CURSOR( 'pointer');
				return true;
			} else {
				var move = _y -offsetY;
				if( isTop === true){
					if( panelH - move < MIN_PANEL_HEIGHT){
						move = panelH -MIN_PANEL_HEIGHT;
					}
					PANEL_CONTROL.resize( true, panelX, panelY + move, panelW, panelH - move);
				} else {
					var _h = startH +move;
					if( 0 < _h && _h < windowH -panelY -RESIZER_HEIGHT -5 -BORDER_WIDTH){
						PANEL_CONTROL.resize( false, panelX, panelY, panelW, _h < MIN_PANEL_HEIGHT ? MIN_PANEL_HEIGHT : _h);
					}
				}
			}
			return true;
		}
		this.onMouseUp = function( _mouseX, _mouseY){
			if( isDragging !== true) return;
			( startY !== panelY || startH !== panelH) && HISTORY_CONTROL.saveState( restoreState, [ NaN, startY, NaN, startH], [ NaN, panelY, NaN, panelH]);
			isDragging = false;
			MOUSE_CURSOR( '');
		}
		this.busy = function(){
			return isDragging
		}
		this.onPanelResize = function( _x, _y, _w, _h){
			panelX = _x;
			panelY = _y;
			if( panelW !== _w){
				ELM.style.width = ( _w +2) +'px';
				panelW = _w;
			}
			panelH = _h;
			y = isTop === true ? y : ( panelH +5 +BORDER_WIDTH);
			w = panelW +2;
		}
	};
	var	PANEL_RESIZER_TOP = new PanelResizerClass( 'panel-resizer-top', true ),
		PANEL_RESIZER_BOTTOM = new PanelResizerClass( 'panel-resizer-bottom', false );
		
	PanelResizerClass = undefined;

/* --------------------------------------------------------------------------------------------
 * CONSOLE_CONTROLER
 */
	var CONSOLE_CONTROLER = ( function(){
		var LAYER_BACK_BUTTON = MENU_BAR_CONTROL.EDIT.createSelection( 'layer back', 'ctrl + B', layerBack, false, true, false),
			LAYER_FORWARD_BUTTON = MENU_BAR_CONTROL.EDIT.createSelection( 'layer forward', 'ctrl + F', layerForward, false, false, false),
			DELETE_BUTTON = MENU_BAR_CONTROL.EDIT.createSelection( 'delete', 'ctrl + D', del, false, true, true),
			EDIT_BUTTON = MENU_BAR_CONTROL.EDIT.createSelection( 'Edit Text', 'ctrl + E', edit, false, true, false),
			CHANGE_BUTTON = MENU_BAR_CONTROL.EDIT.createSelection( 'change', 'ctrl + U', change, false, false, true),
			SAVE = HISTORY_CONTROL.saveState,
			jqStage,
			jqConsoleParent,
			jqConsoleWrapper,
			jqConsoleTail,
			jqImgConsole, jqTextConsole,
			currentElement = null,
			currentType = -1,
			visible = false,
			imgConsoleWidth, imgConsoleHeight,
			textConsoleWidth, textConsoleHeight,
			consoleWidth, consoleHeight,
			consoleX, consoleY,
			tailSize = 10,
			buttonClickable = false;
		
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 66, false, true, layerBack);
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 70, false, true, layerForward);
		
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 68, false, true, del);
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 69, false, true, edit);
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 85, false, true, change);
		
		function buttonBackOrForward( isBack){
			var	offest = jqConsoleWrapper.offset();
			jqConsoleWrapper.css( {
				position:	isBack === true ? '' : 'absolute',
				left:		isBack === true ? consoleX  : offest.left,
				top:		isBack === true ? consoleY  : offest.top
			});
			buttonClickable === isBack && ( isBack === true ? jqConsoleParent : jqStage).append( jqConsoleWrapper);
			buttonClickable = !isBack;
		}
		function layerBack(){
			if( currentElement === null) return;
			if( COMIC_ELEMENT_CONTROL.replace( currentElement, false) === false) return;
			INFOMATION_WINDOW.update( currentElement);
			SAVE( COMIC_ELEMENT_CONTROL.restoreReplace, [ currentElement, true], [ currentElement, false]);
			var _z = currentElement.z;
			LAYER_BACK_BUTTON.visible( _z > 0);
			LAYER_FORWARD_BUTTON.visible( _z < PANEL_ELEMENT_ARRAY.length -1);
		}
		function layerForward(){
			if( currentElement === null) return;
			if( COMIC_ELEMENT_CONTROL.replace( currentElement, true) === false) return;
			INFOMATION_WINDOW.update( currentElement);
			SAVE( COMIC_ELEMENT_CONTROL.restoreReplace, [ currentElement, false], [ currentElement, true]);
			var _z = currentElement.z;
			LAYER_BACK_BUTTON.visible( _z > 0);
			LAYER_FORWARD_BUTTON.visible( _z < PANEL_ELEMENT_ARRAY.length -1);
		}
		function del(){
			if( currentElement === null) return;
			buttonBackOrForward( true);
			COMIC_ELEMENT_CONTROL.remove( currentElement);
			SAVE( COMIC_ELEMENT_CONTROL.restore, [ true, currentElement], [ false, currentElement], true);
			COMIC_ELEMENT_OPERATION_MANAGER.hide();
		}
		function edit(){
			if( currentElement === null || currentElement.type !== PANEL_ELEMENT_TYPE_TEXT) return;
			pettanr.textEditor.bootInOverlay( PANEL_CONTROL.x(), PANEL_CONTROL.y(), currentElement );
			buttonBackOrForward( true );
		}
		function change(){
			if( currentElement === null) return;
			buttonBackOrForward( true);
			pettanr.premiumSatge.bootInOverlay( currentElement.getArtistID(), currentElement.resourcePicture );
		}
		function onImageSelect( resourcePicture ){
			currentElement.resourcePicture( resourcePicture );
		}
		return {
			init: function(){
				jqStage = jqEditor;
				jqConsoleTail = $( '#comic-element-consol-tail');
				jqImgConsole = $( '#image-element-consol').hide();
				var imgConsoleSize = pettanr.util.getElementSize( jqImgConsole.get( 0));
				imgConsoleWidth = imgConsoleSize.width;
				imgConsoleHeight = imgConsoleSize.height;
				
				jqTextConsole = $( '#text-element-consol').hide();
				var textConsoleSize = pettanr.util.getElementSize( jqTextConsole.get( 0));
				textConsoleWidth = textConsoleSize.width;
				textConsoleHeight = textConsoleSize.height;
				
				jqConsoleWrapper = $( '#comic-element-consol-wrapper').hide();
				jqConsoleParent = jqConsoleWrapper.parent();
				
				$( '#edit-text-button').click( edit);
				$( '#delete-image-button, #delete-text-button').click( del);
				$( '#change-image-button').click( change);
				$( '#layer-forward-button, #forward-text-button').click( layerForward);
				$( '#layer-back-button, #back-text-button').click( layerBack);
											
				delete CONSOLE_CONTROLER.init;
			},
			show: function( _currentElement, _w, _h ){
				CONSOLE_CONTROLER.init && CONSOLE_CONTROLER.init();
				
				visible === false && jqConsoleWrapper.show();
				visible = true;
				currentElement = _currentElement;
				var _currentType = _currentElement.type,
					_z = _currentElement.z;
				if( currentType !== _currentType){
					currentType = _currentType;
					jqImgConsole.toggle( _currentType === PANEL_ELEMENT_TYPE_IMAGE);
					jqTextConsole.toggle( _currentType === PANEL_ELEMENT_TYPE_TEXT);
					consoleWidth = _currentType === PANEL_ELEMENT_TYPE_IMAGE ? imgConsoleWidth : textConsoleWidth;
					consoleHeight = _currentType === PANEL_ELEMENT_TYPE_IMAGE ? imgConsoleHeight : textConsoleHeight;
				}
				consoleX = Math.floor( ( _w -consoleWidth) /2);
				
				LAYER_BACK_BUTTON.visible( _z > 0);
				LAYER_FORWARD_BUTTON.visible( _z < PANEL_ELEMENT_ARRAY.length -1);
				DELETE_BUTTON.visible( true);
				EDIT_BUTTON.visible( _currentType === PANEL_ELEMENT_TYPE_TEXT);
				CHANGE_BUTTON.visible( false);
				
				if( _w > consoleWidth * 1.5 && _h > consoleHeight * 1.5){
					consoleY = Math.floor( ( _h -consoleHeight) /2);
					jqConsoleWrapper.css( {
						left:			consoleX,
						top:			consoleY
					}).removeClass( 'console-out');
				} else {
					consoleY = _h +tailSize;
					jqConsoleWrapper.css( {
						left:			consoleX,
						top:			consoleY
					}).addClass( 'console-out');
				}
			},
			hide: function (){
				visible === true && jqConsoleWrapper.hide();
				visible = false;
				currentElement = null;
				LAYER_BACK_BUTTON.visible( false);
				LAYER_FORWARD_BUTTON.visible( false);
				DELETE_BUTTON.visible( false);
				EDIT_BUTTON.visible( false);
				CHANGE_BUTTON.visible( false);
			},
			x: function(){ return consoleX;},
			y: function(){ return consoleY;},
			w: function(){ return consoleWidth;},
			h: function(){ return consoleHeight;},
			onMouseMove: function( _mouseX, _mouseY){
				if( consoleX > _mouseX || consoleY > _mouseY || consoleX +consoleWidth < _mouseX || consoleY +consoleHeight < _mouseY){
					buttonClickable === true && buttonBackOrForward( true);
					return false;
				}
				buttonClickable === false && buttonBackOrForward( false);
				return true;
			},
			onMouseOut: function( _mouseX, _mouseY){
				buttonClickable === true && buttonBackOrForward( true);
			}
		}
	})();

/* --------------------------------------------------------------------------------------------
 * TAIL_OPERATOR
 *  - comicElementOperator
 */
	var TAIL_OPERATOR = ( function(){
		var	MOUSE_CURSOR = updateMouseCursor,
			ELM_MOVER    = document.getElementById( 'balloon-tail-mover'),
			SIZE         = pettanr.util.getElementSize( ELM_MOVER).width,
			SIN          = Math.sin,
			COS          = Math.cos,
			ATAN         = Math.atan,
			FLOOR        = Math.floor,
			DEG_TO_RAD   = Math.PI / 180,
			RAD_TO_DEG   = 1 / DEG_TO_RAD,
			currentText  = null,
			tailX, tailY,
			x, y, w, h,
			balloonW, balloonH, balloonA, radA,
			visible = false,
			startA;
		
		return {
			update: function ( _w, _h, _a ){
				balloonW = _w !== undefined ? _w : balloonW;
				balloonH = _h !== undefined ? _h : balloonH;
				balloonA = _a !== undefined ? _a : balloonA;
				radA = ( balloonA - 90 ) * DEG_TO_RAD;
				tailX = FLOOR( ( ( COS( radA ) / 2 + 0.5 ) * ( balloonW + SIZE )) - SIZE / 2);
				tailY = FLOOR( ( ( SIN( radA ) / 2 + 0.5 ) * ( balloonH + SIZE )) - SIZE / 2);
				ELM_MOVER.style.left = tailX +'px';
				ELM_MOVER.style.top = tailY +'px';
				//log.html( [ balloonW, balloonH, balloonA].join());
			},
			show: function( _currentText){
				/*
				 * visibilityのほうがいい, display:none だと ie で描画が狂う
				 */
				ELM_MOVER.style.visibility = '';
				TAIL_OPERATOR.update( _currentText.w, _currentText.h, _currentText.angle() );
				currentText = _currentText;
			},
			hitTest: function( _mouseX, _mouseY){
				var _x = tailX -SIZE / 2,
					_y = tailY -SIZE / 2;
					ret = _x <= _mouseX && _y <= _mouseY && _x +SIZE >= _mouseX && _y +SIZE >= _mouseY;
				ret === true && MOUSE_CURSOR( 'move');
				return ret;
			},
			hide: function(){
				ELM_MOVER.style.visibility = 'hidden';
				currentText = null;
			},
			onStart: function( _currentText, _mouseX, _mouseY){
				if( _currentText.type !== PANEL_ELEMENT_TYPE_TEXT ) return false;
				x = _currentText.x;
				y = _currentText.y;
				if( TAIL_OPERATOR.hitTest( _mouseX -x, _mouseY -y ) === true){
					w = _currentText.w;
					h = _currentText.h;
					currentText = _currentText;
					startA = _currentText.angle();
					return true;
				}
				return false;
			},
			onDrag: function( _mouseX, _mouseY){
				_mouseX = _mouseX - x - w / 2;
				_mouseY = _mouseY - y - h / 2; //Balloonの中心を0,0とする座標系に変換
				TAIL_OPERATOR.update( w, h,
					_mouseX !== 0 ?
						ATAN( _mouseY / _mouseX ) * RAD_TO_DEG + ( _mouseX > 0 ? 90 : 270 ) :
						_mouseY > 0 ? 180 : 0
				);
				currentText && currentText.angle( FLOOR( balloonA + 0.5 ));
				INFOMATION_WINDOW.update( currentText );
			},
			onFinish: function(){
				startA !== currentText.angle() && COMIC_ELEMENT_OPERATION_MANAGER.saveStatus( x, y, w, h, startA);
				startA !== currentText.angle() && COMIC_ELEMENT_OPERATION_MANAGER.resize( x, y, w, h, currentText.angle());
				currentText = null;
			},
			onCancel: function(){
				currentText.angle( startA);
				COMIC_ELEMENT_OPERATION_MANAGER.resize( x, y, w, h, startA);
				currentText = null;
			}
		}
	})();

/* --------------------------------------------------------------------------------------------
 * RESIZE_OPERATOR
 *  - comicElementOperator
 */
	var RESIZE_OPERATOR = ( function(){
		var	MOUSE_CURSOR = updateMouseCursor,
			GRID_ENABLED = GRID_CONTROL.enabled;
		
		var	HIT_AREA = MOUSE_HIT_AREA,
			POSITION_ARRAY = [],
			FLOOR = Math.floor,
			CURSOR_AND_FLIP = [
				{ cursor:	'n-resize',		v: 3},
				{ cursor:	'e-resize',		h: 2},
				{ cursor:	'e-resize',		h: 1},
				{ cursor:	'n-resize',		v: 0},
				{ cursor:	'nw-resize',	h: 5, v: 6, vh: 7},
				{ cursor:	'ne-resize',	h: 4, v: 7, vh: 6},
				{ cursor:	'ne-resize',	h: 7, v: 4, vh: 5},
				{ cursor:	'nw-resize',	h: 6, v: 5, vh: 4}
			],
			elmResizerContainer = document.getElementById( 'comic-element-resizer-container'),
			elmResizerContainerStyle = elmResizerContainer.style,
			elmResizerTopStyle = document.getElementById( 'comic-element-resizer-top').style,
			elmResizerLeftStyle = document.getElementById( 'comic-element-resizer-left').style,
			elmResizerRightStyle = document.getElementById( 'comic-element-resizer-right').style,
			elmResizerBottomStyle = document.getElementById( 'comic-element-resizer-bottom').style,
			x, y, w, h,
			currentIndex = -1,
			currentElement,
			currentIsTextElement = false;
		
		elmResizerContainerStyle.display = 'none';
		
		var RESIZE_WORK_ARRAY = [
				{ x:	0, w:	 0, y:	1, h:	-1}, //top
				{ x:	1, w:	-1, y:	0, h:	 0}, //left
				{ x:	0, w:	 1, y:	0, h:	 0}, //right
				{ x:	0, w:	 0, y:	0, h:	 1}, //bottom
				{ x:	1, w:	-1, y:	1, h:	-1}, //top-left
				{ x:	0, w:	 1, y:	1, h:	-1}, //top-right
				{ x:	1, w:	-1, y:	0, h:	 1}, //bottom-left
				{ x:	0, w:	 1, y:	0, h:	 1}  //bottom-right
			],
			startX, startY, startW, startH, startFilpV, startFilpH, startAspect,
			baseX, baseY, baseW, baseH,
			currentX, currentY, currentW, currentH,
			offsetX, offsetY,
			lock = false,
			error = 0;
		
		function draw( _x, _y, _w, _h){
			x = _x !== undefined ? _x : x;
			y = _y !== undefined ? _y : y;
			w = _w !== undefined ? _w : w;
			h = _h !== undefined ? _h : h;
			try {
				elmResizerContainerStyle.left = x +'px';
				elmResizerContainerStyle.top = y +'px';
				elmResizerContainerStyle.width = w +'px';
				elmResizerContainerStyle.height = h +'px';
				elmResizerTopStyle.left = FLOOR( w /2 -10 /2) +'px';
				elmResizerLeftStyle.top = FLOOR( h /2 -10 /2) +'px';
				elmResizerRightStyle.top = FLOOR( h /2 -10 /2) +'px';
				elmResizerBottomStyle.left = FLOOR( w /2 -10 /2) +'px';				
			} catch(e){
				alert( [x, y, w, h].join( ','));
				return;
			}

			
			POSITION_ARRAY.splice( 0, POSITION_ARRAY.length);
			POSITION_ARRAY.push(
				{x:	x +5,					y:	y -HIT_AREA,		w:	w -5 *2,		h:	HIT_AREA +5},
				{x: x -HIT_AREA,			y:	y +HIT_AREA +5,		w:	HIT_AREA +5,	h:	h -5 *2},
				{x: x +w -5,				y:	y +HIT_AREA +5,		w:	HIT_AREA +5,	h:	h -5 *2},
				{x:	x +5,					y:	y +h -5,			w:	w -5 *2,		h:	HIT_AREA +5},
				{x:	x -HIT_AREA,			y:	y -HIT_AREA,		w:	HIT_AREA +5,	h:	HIT_AREA +5},
				{x: x +w -HIT_AREA,			y:	y -HIT_AREA,		w:	HIT_AREA +5,	h:	HIT_AREA +5},
				{x:	x -HIT_AREA,			y:	y +h -5,			w:	HIT_AREA +5,	h:	HIT_AREA +5},
				{x:	x +w -5,				y:	y +h -5,			w:	HIT_AREA +5,	h:	HIT_AREA +5}
			);
		}
		
		function update( _x, _y, _w, _h){
			x = _x !== undefined ? _x : currentX;
			y = _y !== undefined ? _y : currentY;
			w = _w !== undefined ? _w : currentW;
			h = _h !== undefined ? _h : currentH;
			
			if( currentIsTextElement === false && currentIndex > 3 && pettanr.key.shiftEnabled() === true){
				if( startAspect >= 1){
					_w = w;
					w = Math.floor( startAspect * h);
					x = x +( currentIndex % 2 === 0 ? _w -w : 0);
				} else {
					_h = h;
					h = Math.floor( w / startAspect);
					y = y + ( currentIndex <= 5 ? _h -h : 0);
				}
			}
			draw( x, y, w, h);
			currentElement.resize( x, y, w, h);
			currentIsTextElement === true && TAIL_OPERATOR.update( w, h);
			CONSOLE_CONTROLER.show( currentElement, w, h);
			INFOMATION_WINDOW.update( currentElement);
		}
		
		function flip( _flipH, _flipV){
			var p = CURSOR_AND_FLIP[ currentIndex];
			currentIndex = _flipH === true || _flipV === true ? p[
					_flipH === true && _flipV === true ? 'vh' : ( _flipH === true ? 'h' : 'v')
				] : currentIndex;
			MOUSE_CURSOR( CURSOR_AND_FLIP[ currentIndex].cursor);
			elmResizerContainer.className = 'current-resizer-is-' +currentIndex;
			currentElement.flip( _flipH, _flipV);
		}
		return {
			update: draw,
			index: function( _mouseX, _mouseY){
				var	p, i;
				for( i=4; i<8; i++){
					p = POSITION_ARRAY[ i];
					if( p.x <= _mouseX && p.y <= _mouseY && p.x + p.w >= _mouseX && p.y +p.h >= _mouseY){
						MOUSE_CURSOR( CURSOR_AND_FLIP[ i].cursor);
						elmResizerContainer.className = 'current-resizer-is-' +i;
						return currentIndex = i;
					}
				}
				for( i=0; i<4; i++){
					p = POSITION_ARRAY[ i];
					if( p.x <= _mouseX && p.y <= _mouseY && p.x + p.w >= _mouseX && p.y +p.h >= _mouseY){
						MOUSE_CURSOR( CURSOR_AND_FLIP[ i].cursor);
						elmResizerContainer.className = 'current-resizer-is-' +i;
						return currentIndex = i;
					}
				}
				MOUSE_CURSOR( '');
				elmResizerContainer.className = '';
				return -1;
			},
			show: function( _currentElement){
				currentElement = _currentElement;
				currentIsTextElement = _currentElement.type === PANEL_ELEMENT_TYPE_TEXT;
				elmResizerContainerStyle.display = '';
			},
			hide: function(){
				currentElement = null;
				elmResizerContainerStyle.display = 'none';
			},
			onStart: function( _currentElement, _mouseX, _mouseY){
				currentElement = _currentElement;
				currentIsTextElement = _currentElement.type === PANEL_ELEMENT_TYPE_TEXT;
				if( _currentElement.keepSize === true) return false;
				currentIndex = this.index( _mouseX, _mouseY);
				if( currentIndex === -1) return false;
				offsetX = _mouseX;
				offsetY = _mouseY;
				startX = baseX = _currentElement.x;
				startY = baseY = _currentElement.y;
				startW = baseW = _currentElement.w;
				startH = baseH = _currentElement.h;
				if( _currentElement.type === PANEL_ELEMENT_TYPE_IMAGE){
					startFilpV = _currentElement.flipV();
					startFilpH = _currentElement.flipH();							
				}
				startAspect = startW /startH;
				return true;
			},
			onDrag: function( _mouseX, _mouseY){
				var com = RESIZE_WORK_ARRAY[ currentIndex],
					moveX = _mouseX -offsetX,
					moveY = _mouseY -offsetY,
					_updated = moveX !== 0 || moveY !== 0,
					_x, _y, _w, _h,
					_thisError = 0;
					
				var _memoryX = 0,
					_memoryY = 0,
					_momoryW = 0,
					_momoryH = 0;
				/*
				 * Opera 11+ often forget values, why ??
				 */
				while( _x === undefined || _y === undefined || _w === undefined || _h === undefined){
					_x = _x !== undefined ? _x : baseX +moveX *com.x;
					_y = _y !== undefined ? _y : baseY +moveY *com.y;
					_w = _w !== undefined ? _w : baseW +moveX *com.w;
					_h = _h !== undefined ? _h : baseH +moveY *com.h;
					error += _thisError === 0 ? 0 : 1;
					++_thisError;
					if( _thisError > 9999){
						++error
						//alert( 'opera error' +error);
						this.onCancel;
						return;
					}
				}
				
				if( _w >= MIN_ELEMENT_SIZE && _h >= MIN_ELEMENT_SIZE){
					
				} else 
				if( _w >= -MIN_ELEMENT_SIZE && _h >= -MIN_ELEMENT_SIZE){
					//return;
					if( _w < MIN_ELEMENT_SIZE){
						//_x += Math.abs( MIN_ELEMENT_SIZE -_w);
						_x = currentX;
						_w = MIN_ELEMENT_SIZE;
					}
					if( _h < MIN_ELEMENT_SIZE){
						//_y += Math.abs( MIN_ELEMENT_SIZE -_h);
						_y = currentY;
						_h = MIN_ELEMENT_SIZE;
					}
				} else 
				if( currentElement.type === PANEL_ELEMENT_TYPE_TEXT){
					return;
				} else 
				if( _w < -MIN_ELEMENT_SIZE || _h < -MIN_ELEMENT_SIZE){

					if( _w < -MIN_ELEMENT_SIZE && _h > MIN_ELEMENT_SIZE){
					// flipH
						_memoryX = _x;
						baseX = _x = _x +_w;
						baseY = _y;
						baseW = _w = _memoryX -_x;
						baseH = _h;
						flip( true, false);
						flipV = currentElement.flipV();
					} else 
					if( _w > MIN_ELEMENT_SIZE && _h < -MIN_ELEMENT_SIZE){
					// flipV
						_memoryY = _y;
						baseX = _x;
						baseY = _y = _y +_h;
						baseW = _w;
						baseH = _h = _memoryY -_y;
						flip( false, true);
						flipH = currentElement.flipH();
					} else {
					// flipVH
						_memoryX = _x;
						_memoryY = _y;
						baseX = _x = _x +_w;
						baseY = _y = _y +_h;
						baseW = _w = _memoryX -_x;
						baseH = _h = _memoryY -_y;
						flip( true, true);
						flipV = currentElement.flipV();
						flipH = currentElement.flipH();
					}
					_updated = true;
					offsetX = _mouseX;
					offsetY = _mouseY;	
				}
				currentX = _x;
				currentY = _y;
				currentW = _w;
				currentH = _h;
				_updated === true && update( _x, _y, _w, _h);
				
				log.html( [
						'currentIndex:', currentIndex, 
						'baseW', baseW, 'baseH', baseH,'<br>',
						'mouse', _mouseX, _mouseY,'<br>',
						'move', moveX, moveY,'<br>',
						'xy', _x, _y, 'wh',_w, _h,'<br>',
						'com.w', com.w, 'com.h', com.h,'<br>',
						'current',currentW, currentH,'<br>',
						'result', y, h,
						'err', error
				].join( ' , '));
			},
			onFinish: function(){
				MOUSE_CURSOR( '');
				if( w === startW && h === startH && x === startX && y === startY) return;
				COMIC_ELEMENT_OPERATION_MANAGER.resize( x, y, w, h);
				currentElement.resize( x, y, w, h);
				COMIC_ELEMENT_OPERATION_MANAGER.saveStatus( startX, startY, startW, startH, undefined, startFilpV, startFilpH);
			},
			onCancel: function(){
				MOUSE_CURSOR( '');
				COMIC_ELEMENT_OPERATION_MANAGER.resize( startX, startY, startW, startH);
				currentElement.type === PANEL_ELEMENT_TYPE_IMAGE ?
					currentElement.animate( startX, startY, startW, startH, startFilpV, startFilpH) :
					currentElement.animate( startX, startY, startW, startH, angle);
			},
			lock: function( _lock){
				if( _lock !== undefined){
					elmResizerContainerStyle.borderColor = _lock === true ? 'blue' : '';
					lock = _lock;
				}
				return lock;
			},
			onShiftUpdate: update,
			onCtrlUpdate: update
		}
	})();

/* --------------------------------------------------------------------------------------------
 * POSITION_OPERATOR
 *  - comicElementOperator
 */
	var POSITION_OPERATOR = ( function(){
		var	MOUSE_CURSOR = updateMouseCursor,
			GRID_ENABLED = GRID_CONTROL.enabled;
		
		var currentElement,
			startX, startY,
			x, y,
			offsetX, offsetY,
			isCopy = false;
		
		function update( _x, _y){
			x = _x !== undefined ? _x : x;
			y = _y !== undefined ? _y : y;
			RESIZE_OPERATOR.update( x, y);
			currentElement.resize( x, y);
			INFOMATION_WINDOW.update( currentElement);
		}
		
		return {
			onStart: function( _currentElement, _mouseX, _mouseY){
				currentElement = _currentElement;
				offsetX = _mouseX;
				offsetY = _mouseY;
				startX = x = _currentElement.x;
				startY = y = _currentElement.y;
				MOUSE_CURSOR( 'move');
			},
			onDrag: function( _mouseX, _mouseY){
				var moveX = _mouseX -offsetX,
					moveY = _mouseY -offsetY,
					_x = startX +moveX,
					_y = startY +moveY;
				if( GRID_ENABLED() === true){
					_x = Math.floor( _x / 10) * 10;
					_y = Math.floor( _y / 10) * 10;
				}
				update( _x, _y);
			},
			onFinish: function(){
				MOUSE_CURSOR( '');
				if( x === startX && y === startY) return;
				COMIC_ELEMENT_OPERATION_MANAGER.resize( x, y);
				currentElement.resize( x, y);
				COMIC_ELEMENT_OPERATION_MANAGER.saveStatus( startX, startY);
			},
			onCancel: function(){
				MOUSE_CURSOR( '');
				COMIC_ELEMENT_OPERATION_MANAGER.resize( startX, startY);
				currentElement.animate( startX, startY);
			},
			onShiftUpdate: update,
			onCtrlUpdate: update
		}
	})();


/* --------------------------------------------------------------------------------------------
 * COMIC_ELEMENT_OPERATION_MANAGER
 */
	var COMIC_ELEMENT_OPERATION_MANAGER = ( function(){
		var	MOUSE_CURSOR = updateMouseCursor,
			SAVE = HISTORY_CONTROL.saveState,
			GRID_ENABLED = GRID_CONTROL.enabled,
			HIT_AREA = MOUSE_HIT_AREA,
			currentIsTextElement = false,
			currentOperator = null,
			currentElement = null,
			currentx, currenty, currentw, currenth, angle, flipV, flipH;

			function resize( _x, _y, _w, _h, _angle){
				currentx = _x !== undefined ? _x : currentx;
				currenty = _y !== undefined ? _y : currenty;
				currentw = _w !== undefined ? _w : currentw;
				currenth = _h !== undefined ? _h : currenth;
				angle = _angle !== undefined ? _angle : angle;

				RESIZE_OPERATOR.update( currentx, currenty, currentw, currenth);
				currentIsTextElement === true && TAIL_OPERATOR.update( currentw, currenth, angle);
				CONSOLE_CONTROLER.show( currentElement, currentw, currenth);
				INFOMATION_WINDOW.update( currentElement);
			}
			function show( _currentElement){
				currentElement === null && RESIZE_OPERATOR.show( _currentElement);
				if( currentElement !== _currentElement){
					currentElement = _currentElement;
					
					currentIsTextElement = ( _currentElement.type === PANEL_ELEMENT_TYPE_TEXT);
					currentIsTextElement === true ? TAIL_OPERATOR.show( _currentElement) : TAIL_OPERATOR.hide();
					
					flipV = currentIsTextElement === false ? _currentElement.flipV() : 0;
					flipH = currentIsTextElement === false ? _currentElement.flipH() : 0;
					
					resize(
						_currentElement.x, _currentElement.y, _currentElement.w, _currentElement.h,
						currentIsTextElement === true ? _currentElement.angle() : 0
					);
				}
			}

			pettanr.key.addKeyUpdateEvent( pettanr.view.EDITOR, 16, undefined, undefined, function( e){
				currentOperator !== null && currentOperator.onShiftUpdate && currentOperator.onShiftUpdate();
			});
			pettanr.key.addKeyUpdateEvent( pettanr.view.EDITOR, 17, undefined, undefined, function( e){
				currentOperator !== null && currentOperator.onCtrlUpdate && currentOperator.onCtrlUpdate();
			});
			pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 27, false, false, function( e){
				currentOperator !== null && currentOperator.onCancel && currentOperator.onCancel();
				currentOperator = null;
			});
		return {
			open: function(){
				this.hide();
			},
			close: function(){
				
			},
			hide: function(){
				currentElement !== null && RESIZE_OPERATOR.hide();
				currentElement = null;
				MOUSE_CURSOR( '');
				TAIL_OPERATOR.hide();
				CONSOLE_CONTROLER.hide();
				INFOMATION_WINDOW.update( null);
			},
			resize: resize,
			restoreState: function( arg){
				if( arg && arg.length !== 8) return;
				var _currentElement = arg[ 0],
					_x = arg[ 1], _y = arg[ 2], _w = arg[ 3], _h = arg[ 4],
					_a = arg[ 5],
					_flipV = arg[ 6], _flipH = arg[ 7];
				if( !_currentElement && !currentOperator) return;
				_currentElement.type === PANEL_ELEMENT_TYPE_IMAGE ?
					_currentElement.animate( _x, _y, _w, _h, _flipV, _flipH) :
					_currentElement.animate( _x, _y, _w, _h, _a);
				currentOperator !== null && currentOperator.onCancel && currentOperator.onCancel();
				currentOperator = null;
				currentElement === _currentElement ? resize( _x, _y, _w, _h, _a) : show( _currentElement);
			},
			saveStatus: function( startX, startY, startW, startH, startA, startFilpV, startFilpH){
				startX = startX !== undefined ? startX : currentx;
				startY = startY !== undefined ? startY : currenty;
				startW = startW !== undefined ? startW : currentw;
				startH = startH !== undefined ? startH : currenth;
				startA = startA !== undefined ? startA : angle;
				startFilpV = startFilpV !== undefined ? startFilpV : flipV;
				startFilpH = startFilpH !== undefined ? startFilpH : flipH;
				currentElement && SAVE( COMIC_ELEMENT_OPERATION_MANAGER.restoreState,
					[ currentElement, startX, startY, startW, startH, startA, startFilpV, startFilpH],
					[ currentElement, currentx, currenty, currentw, currenth, angle, flipV, flipH]
				);
			},
			busy: function(){
				return currentOperator !== null;
			},
			hitTest: function( _mouseX, _mouseY, _panelElement ){
				var _x, _y, _w, _h;
				if( _panelElement === currentElement){
					var _consoleX = CONSOLE_CONTROLER.x();
					_x = currentx +( _consoleX < 0 ? _consoleX : 0) -HIT_AREA;
					_y = currenty -HIT_AREA;
					var _consoleW = CONSOLE_CONTROLER.w();
					_w = ( _consoleW < currentw ? currentw : _consoleW) +HIT_AREA *2;
					var _consoleY = CONSOLE_CONTROLER.y();
					_h = ( _consoleY < currenth ? currenth : _consoleY +CONSOLE_CONTROLER.h()) +HIT_AREA *2;
				} else {
					_x = _panelElement.x -HIT_AREA;
					_y = _panelElement.y -HIT_AREA;
					_w = _panelElement.w +HIT_AREA *2;
					_h = _panelElement.h +HIT_AREA *2;
				}
				log.html( [ _x, _y, _w, _h ].join( ' ') );
				return _x <= _mouseX && _mouseX <= _x + _w && _y <= _mouseY && _mouseY <= _y + _h;
			},
			onMouseDown: function( _currentElement, _mouseX, _mouseY){
				//show( _currentElement);
				if( currentIsTextElement === true && TAIL_OPERATOR.onStart( _currentElement, _mouseX, _mouseY) === true){
					currentOperator = TAIL_OPERATOR;
				} else
				if( RESIZE_OPERATOR.onStart( _currentElement, _mouseX, _mouseY) === true){
					currentOperator = RESIZE_OPERATOR;
				} else {
					POSITION_OPERATOR.onStart( _currentElement, _mouseX, _mouseY)
					currentOperator = POSITION_OPERATOR;
				}
			},
			onMouseMove: function( _currentElement, _mouseX, _mouseY){
				show( _currentElement);
				if( currentOperator !== null){
					currentOperator.onDrag( _mouseX, _mouseY);						
				} else
				if( currentElement !== null){
					CONSOLE_CONTROLER.onMouseMove( _mouseX -currentx, _mouseY -currenty);
					if( currentIsTextElement === false || TAIL_OPERATOR.hitTest( _mouseX -currentx, _mouseY -currenty) === false){
						RESIZE_OPERATOR.index( _mouseX, _mouseY);
					}
				}
			},
			onMouseUp: function( _currentElement, _mouseX, _mouseY){
				currentOperator !== null && currentOperator.onFinish();
				currentOperator = null;
			}
		}
	})();
	/*
	 *  // COMIC_ELEMENT_OPERATION_MANAGER
	 */

	var AbstractComicElement = function( COMIC_ELM_TYPE ){
		this.type = COMIC_ELM_TYPE;
		this.hitTest = function( _mouseX, _mouseY ){
			return COMIC_ELEMENT_OPERATION_MANAGER.hitTest( _mouseX, _mouseY, this );
		}
		this.shift = function( _shiftX, _shiftY ){
			this.resize( this.x + _shiftX, this.y + _shiftY);
		}
		this.busy = function(){
			return COMIC_ELEMENT_OPERATION_MANAGER.busy();
		}
		this.onMouseMove = function( _mouseX, _mouseY ){
			COMIC_ELEMENT_OPERATION_MANAGER.onMouseMove( this, _mouseX, _mouseY );
		}
		this.onMouseUp = function( _mouseX, _mouseY ){
			COMIC_ELEMENT_OPERATION_MANAGER.onMouseUp( this, _mouseX, _mouseY );
		}
		this.onMouseDown = function( _mouseX, _mouseY ){
			COMIC_ELEMENT_OPERATION_MANAGER.onMouseDown( this, _mouseX, _mouseY );
		}
	};

/* --------------------------------------------------------------------------------------------
 * ImageElementClass
 */
	var	jqImageElementOrigin;
	var ImageElementClass = function( data ){
		jqImageElementOrigin = jqImageElementOrigin || $( $( '#imgElementTemplete' ).remove().html() );
		
		var jqWrap          = jqImageElementOrigin.clone( true ),
			flipH           = data.width  < 0 ? -1 : 1,
			flipV           = data.height < 0 ? -1 : 1,
			resourcePicture = data.resource_picture,
			actualW         = data.resource_picture.width,
			actualH         = data.resource_picture.height,
			reversibleImage = null,
			instance        = this,
			x, y, z, w, h;
		function flipReversibleImage(){
			reversibleImage && reversibleImage.resize( flipH * w, flipV * h );
		}
		function updateResourcePicture( _resourcePicture ){
			resourcePicture = _resourcePicture;
			
			actualW = _resourcePicture.width;
			actualH = _resourcePicture.height;
			
			var _reversibleImage = pettanr.image.createReversibleImage( 
					[ pettanr.CONST.RESOURCE_PICTURE_PATH, _resourcePicture.id, '.', _resourcePicture.ext ].join(''),
					flipH * w, flipV * h
				);
			if( reversibleImage !== null ){
				jqWrap.children( reversibleImage.elm ).replaceWith( _reversibleImage.elm );
				reversibleImage.destroy();
			} else {
				jqWrap.append( _reversibleImage.elm );
			}
			reversibleImage = _reversibleImage;
		}
		/* global methods */
		this.$ = jqWrap;
		//this.x = x;
		//this.y = y;
		//this.w = w;
		//this.h = h;					
		this.z = data.z;
		this.timing = data.t || PANEL_ELEMENT_ARRAY.length + 1;
		this.keepSize = false;
		this.init = function(){
			updateResourcePicture( data.resource_picture );
			instance.resize( data.x, data.y, Math.abs( data.width ), Math.abs( data.height ) );
			delete instance.init;
		}
		this.flip = function( _updateH, _updateV ){
			if( _updateH !== true && _updateV !== true ) return;
			flipH = _updateH === true ? -flipH : flipH;
			flipV = _updateV === true ? -flipV : flipV;
			reversibleImage.resize( flipH * w, flipV * h );
		}
		this.flipV = function(){ return flipV;}
		this.flipH = function(){ return flipH;}
		this.resourcePicture = function( _resourcePicture ){
			if( _resourcePicture && _resourcePicture !== resourcePicture ){
				HISTORY_CONTROL.saveState( updateResourcePicture, resourcePicture, _resourcePicture );
				updateResourcePicture( _resourcePicture );
			}
			return resourcePicture;
		}
		this.getArtistID = function(){
			return resourcePicture.artist_id || resourcePicture.artist.id || -1;
		}
		this.actualW = function(){ return actualW;}
		this.actualH = function(){ return actualH;}
		this.resize = function( _x, _y, _w, _h, animate ){
			instance.x = x = Type.isFinite( _x ) === true ? _x : x;
			instance.y = y = Type.isFinite( _y ) === true ? _y : y;
			instance.w = w = Type.isFinite( _w ) === true ? _w : w;
			instance.h = h = Type.isFinite( _h ) === true ? _h : h;
			jqWrap[ animate === true ? 'animate' : 'css' ]( { 
				left:	x,
				top:	y,
				width:	w,
				height:	h
			}, 250,  flipReversibleImage );
			animate !== true && flipReversibleImage();
		}
		this.animate = function ( _x, _y, _w, _h, _flipH, _flipV ){
			flipH = _flipH !== undefined ? _flipH : flipH;
			flipV = _flipV !== undefined ? _flipV : flipV;
			instance.resize( _x, _y, _w, _h, true );
		}
		this.destroy = function(){
			delete instance.destroy;
			
			reversibleImage.destroy();
			jqWrap.stop().remove();
			jqWrap = reversibleImage = resourcePicture = data = instance = null;
		}
	}
	ImageElementClass.prototype = new AbstractComicElement( PANEL_ELEMENT_TYPE_IMAGE );
/*
 * / ImageElementClass
 * --------------------------------------------------------------------------------------------
 */


/* --------------------------------------------------------------------------------------------
 * TextElementClass
 * 
 * type
 * 0.none
 * 1.speach balloon
 * 2.think
 * 3.bom
 * 4.black-box( dq style)
 * 5.blue-box( ff style)
 * 
 */
	var jqTextElementOrigin;
	var TextElementClass = function( data ){
		jqTextElementOrigin = jqTextElementOrigin || ( function(){
			var _OLD_IE = $( $( '#textElementTempleteForOldIE').remove().html()),
				_MODERN = $( $( '#textElementTemplete').remove().html());
			return pettanr.ua.isIE === true && pettanr.ua.ieRenderingVersion < 8 ? _OLD_IE : _MODERN;
		})();
		
		var JQ_WRAPPER = jqTextElementOrigin.clone( true ),
			elmText = JQ_WRAPPER.find( 'td,.speach-inner' ).get( 0 ),
			type     = data.balloon_template_id,
			text     = ( function(){
				var _speachs = data.speeches_attributes;
				for( var k in _speachs ){
					return _speachs[ k ].content || '';
				}
				return '';
			})(),
			balloon = pettanr.balloon.createBalloon( data.width, data.height, data.tail, type ),
			x, y, w, h, a,
			instance = this;
		
		JQ_WRAPPER.find( 'img' ).eq( 0 ).replaceWith( balloon.elm );
		
		function updateType( _type ){
			if( type !== _type ){
				type = _type || type;
				balloon.type( type );
			}
		}
		function updateAngle( _a ){
			if( _a !== undefined && a !== _a ){
				a = _a !== undefined ? _a : a;
				balloon.angle( a );
			}
		}
		function updateText( _text ){
			text = _text || text || '';
			elmText.firstChild.data = text;
		}
		function resizeBalloon(){
			balloon && balloon.resize( a, w, h );
		}
		
		/* global methods */
		this.$ = JQ_WRAPPER;
		//this.x = x;
		//this.y = y;
		//this.w = w;
		//this.h = h;
		this.z = data.z;
		this.timing = data.t || PANEL_ELEMENT_ARRAY.length + 1;
		this.init = function(){
			updateText();
			instance.resize( data.x, data.y, data.width, data.height, data.tail );
			delete instance.init;
		};
		this.angle = function( _a ){
			_a !== undefined && instance.resize( x, y, w, h, _a );
			return a;
		};
		this.text = function( _text ){
			if( _text && text !== _text) {
				HISTORY_CONTROL.saveState( updateText, text || '', _text );
				updateText( _text );
			}
			return text;
		};
		this.resize = function( _x, _y, _w, _h, _a, animate ){
			instance.x = x = _x !== undefined ? _x : x;
			instance.y = y = _y !== undefined ? _y : y;
			instance.w = w = _w !== undefined ? _w : w;
			instance.h = h = _h !== undefined ? _h : h;
			a = _a !== undefined ? _a : a;
			
			JQ_WRAPPER[ animate === true ? 'animate' : 'css']( {
					left:		x,
					top:		y,
					width:		w,
					height:		h
				}, 250, resizeBalloon
			);		
			animate !== true && resizeBalloon();
		};
		this.animate = function ( _x, _y, _w, _h, _a ){
			instance.resize( _x, _y, _w, _h, _a, true );
		};
		this.destroy = function(){
			delete instance.destroy;
			
			JQ_WRAPPER.stop().remove();
			balloon.destroy();
			JQ_WRAPPER = elmText = data = balloon = instance = null;
		};
	}
	TextElementClass.prototype = new AbstractComicElement( PANEL_ELEMENT_TYPE_TEXT );

/* --------------------------------------------------------------------------------------------
 * COMIC_ELEMENT_CONTROL
 *  - mouseEventListener
 */
	var COMIC_ELEMENT_CONTROL = ( function(){
		var	SAVE = HISTORY_CONTROL.saveState,
			ELM_CONTAINER = document.getElementById( 'comic-element-container'),
			currentElement = null,
			currentLockTest = false,
			currentLock = false,
			panelX, panelY, panelW, panelH,
			startX, startY;
	/*
	 * append, remove, replace
	 * 
	 * comicElement には、z-position と dom-index がある。
	 *   z-position は 表示上の位置。大きいほど前に表示される（ z-index）
	 *   dom-index は 意味上の順番。htmlタグの登場順で、検索結果や音声読み上げブラウザで正しく意味が取れる順番。
	 * 
	 * editerでは、実際には z-index は使わず、htmlの順序で前後を表現する。
	 * dom-index は、数値のみ保持して、投稿時にcomicElementを適宜に並び替える。
	 * 
	 * append comicElement
	 * 1. 新しい comicElement の z-position を得る
	 * 2. ｚ の同じ comicElementを見つけ、その前に加える。または一番先頭へ。（PANEL_ELEMENT_ARRAY）
	 *    zが大きいほど、PANEL_ELEMENT_ARRAYの先頭へ。
	 * 3. dom位置は、PANEL_ELEMENT_ARRAY とは反対に、前のものほど後ろへ。
	 * 
	 * 
	 * remove comicElement
	 * 1. remove
	 * 2. renumber z
	 */
		function appendComicElement( _panelElement ) {
			var z = Type.isFinite( _panelElement.z ) === true ? _panelElement.z : -1,
				l = PANEL_ELEMENT_ARRAY.length,
				_jqElm = _panelElement.$.stop().css( {
					filter:		'',
					opacity:	''
				});
			if( z < 0 ){
				PANEL_ELEMENT_ARRAY.unshift( _panelElement );
				// ELM_CONTAINER.appendChild( _jqElm.get( 0 ));
				renumber();
				_jqElm.fadeIn();
			} else {
				for( var i = 0; i < l; ++i ){
					if( PANEL_ELEMENT_ARRAY[ i ].z < z ) break;
				}
				if( i === l ){
					PANEL_ELEMENT_ARRAY.push( _panelElement );
					//ELM_CONTAINER.appendChild( _jqElm.get( 0 ));
				} else {
					PANEL_ELEMENT_ARRAY.splice( i, 0, _panelElement );
					//PANEL_ELEMENT_ARRAY[ insertIndex ].$.before( _jqElm );
				}
				renumber();
				_jqElm.fadeIn();
			}
		}
		function removeComicElement( _panelElement ) {
			var l = PANEL_ELEMENT_ARRAY.length;
			for( var i=0; i<l; ++i ){
				if( PANEL_ELEMENT_ARRAY[ i ] === _panelElement ){
					PANEL_ELEMENT_ARRAY.splice( i, 1 );
					renumber();
					_panelElement.$.stop().css( {
						filter:		'',
						opacity:	''
					}).fadeOut( onFadeOut );
					currentElement = currentElement === _panelElement ? null : currentElement;
					return;
				}
			}
		}
		function onFadeOut(){
			this.parentNode.removeChild( this );
		}		
		function restoreComicElement( arg ){
			var isAppend = arg[ 0 ],
				comicElement = arg[ 1 ];
			isAppend === true ? appendComicElement( comicElement ) : removeComicElement( comicElement );
		}
		/*
		 * PANEL_ELEMENT_ARRAY の順番を基準に、zの再計算
		 * jqElmの並び替え。
		 */
		function renumber(){
			var l = PANEL_ELEMENT_ARRAY.length,
				_panelElement, jqElm, jqNext;
			for( var i=0; i < l; ++i){
				_panelElement = PANEL_ELEMENT_ARRAY[ i ];
				jqElm = _panelElement.$;
				i === 0 && ELM_CONTAINER.appendChild( jqElm.get( 0 ));
				jqNext && jqNext.before( jqElm );
				if( phase === 1 ) _panelElement.z = l - i - 1;
				jqNext = jqElm;
			}
		}
		function replaceComicElement( _panelElement, goForward ){
			// PANEL_ELEMENT_ARRAYの再構築
			var l = PANEL_ELEMENT_ARRAY.length,
				i = -1;
			for( var j = 0; j < l; ++j ){
				if( PANEL_ELEMENT_ARRAY[ j ] === _panelElement ){
					i = j;
					break;
				};
			}
			if( i === -1) return false;
			if( goForward === true ){
				if( i === 0 ) return false;
				PANEL_ELEMENT_ARRAY.splice( i, 1 );
				PANEL_ELEMENT_ARRAY.splice( i - 1, 0, _panelElement );
			} else {
				if( i === l - 1 ) return false;
				PANEL_ELEMENT_ARRAY.splice( i, 1 );
				PANEL_ELEMENT_ARRAY.splice( i + 1, 0, _panelElement );
			}
			renumber( true );
			return true;
		}
		function restoreReplaceElement( arg ){
			replaceComicElement( arg[ 0], arg[ 1]);
		}
		function onTextInput( _panelElement ){
			appendComicElement( _panelElement );
			SAVE( restoreComicElement, [ false, _panelElement ], [ true, _panelElement ], true );
		}
	
		return {
			init: function(){
				log = $( '#operation-catcher-log');
				
				delete COMIC_ELEMENT_CONTROL.init;
			},
			open: function(){
				COMIC_ELEMENT_CONTROL.init && COMIC_ELEMENT_CONTROL.init();
			},
			close: function(){
				var _comicElm;
				while( PANEL_ELEMENT_ARRAY.length > 0){
					_comicElm = PANEL_ELEMENT_ARRAY.shift();
					_comicElm.destroy && _comicElm.destroy();
				}
			},
			remove: removeComicElement,
			restore: restoreComicElement,
			replace: replaceComicElement,
			restoreReplace: restoreReplaceElement,
			onPanelResize : function ( _panelX, _panelY, _panelW, _panelH, isResizerTopAction ){
			/*
			 * リサイズが、ResizerTopによって行われた場合、comicElementのyを動かして見かけ上動かないようにする。
			 */					
				if( isResizerTopAction === true){
					var	_shiftX = _panelW -panelW,
						_shiftY = _panelH -panelH,
						l = PANEL_ELEMENT_ARRAY.length;
					for( var i = 0; i < l; i++){
						PANEL_ELEMENT_ARRAY[ i].shift( _shiftX, _shiftY);
					}
				}
				panelX = _panelX;
				panelY = _panelY;
				panelW = _panelW;
				panelH = _panelH;
				
				ELM_CONTAINER.style.width	= _panelW +'px';
				ELM_CONTAINER.style.height	= _panelH +'px';
				ELM_CONTAINER.style.left	= _panelX +'px';
				ELM_CONTAINER.style.top		= _panelY +'px';
			},
			onMouseMove: function( _mouseX, _mouseY ){
				var l = PANEL_ELEMENT_ARRAY.length,
					_x = _mouseX -panelX,
					_y = _mouseY -panelY,
					_elm = currentElement;
					
				if( _elm !== null){
					currentLockTest = currentLockTest === true && _x === 0 && _y === 0;
					if( _elm.busy() === true ){
						_elm.onMouseMove( _x, _y);
						return true;
					}
					if( _elm.hitTest( _x, _y) === true ){
						_elm.onMouseMove( _x, _y ); // cursor
						return true;
					}
					if( currentLock === true){
						currentLockTest = true;
						return true;
					}
				}
				for( var i=0; i<l; i++){
					_elm = PANEL_ELEMENT_ARRAY[ i ];
					// hitTest
					if( _elm.hitTest( _x, _y ) === true ){
						_elm.onMouseMove( _x, _y ); // cursor
						log.html( [ _x, _y, i].join( ','));
						currentElement = _elm;
						return true;
					} else {
						log.html( [ _elm.x, _elm.y, i].join( ','));
					}
				}
				currentElement = null;							
				COMIC_ELEMENT_OPERATION_MANAGER.hide();
				return false;
			},
			onMouseUp: function( _mouseX, _mouseY){
				var ret = currentElement !== null && currentElement.busy() === true;
				ret === true && currentElement.onMouseUp( _mouseX -startX || panelX, _mouseY -startY || panelY);
				currentLock = currentLockTest === true && currentElement.hitTest( _mouseX -panelX, _mouseY -panelY) === true;
				RESIZE_OPERATOR.lock( currentLock);
				INFOMATION_WINDOW.lock( currentLock);
				return ret;
			},
			onMouseDown: function( _mouseX, _mouseY){
				startX = panelX;
				startY = panelY;
				if( currentElement === null) return false
				currentElement.onMouseDown( _mouseX -startX, _mouseY -startY);
				currentLockTest = true;
				return true;
			},
			busy: function(){
				return currentElement !== null;
			},
			createImageElement: function( data ){
				if( Type.isObject( data ) === false ){
					pettanr.premiumSatge.bootInOverlay( 1, COMIC_ELEMENT_CONTROL.onImageSelect );
				} else {
					COMIC_ELEMENT_CONTROL.onImageSelect( data, true );
				}
			},
			onImageSelect: function( data, isPanelPictureData ){
				var _panelElement;
				if( isPanelPictureData !== true ){
					_panelElement = new ImageElementClass( {
						resource_picture:data,
						x:               Math.floor( panelW / 2 - data.width / 2 ),
						y:               Math.floor( panelH / 2 - data.height / 2 ),
						z:               -1,
						t:               PANEL_ELEMENT_ARRAY.length + 1,
						width:           1,
						height:          1
					});
					_panelElement.init && _panelElement.init();
					appendComicElement( _panelElement );
					_panelElement.animate( undefined, undefined, Math.abs( data.width ), Math.abs( data.height ) );
				} else {
					_panelElement = new ImageElementClass( data );
					_panelElement.init && _panelElement.init();
					appendComicElement( _panelElement );
				}
				SAVE( restoreComicElement, [ false, _panelElement], [ true, _panelElement ], true );
			},
			createTextElement: function( data ){
				var _panelElement;
				if( Type.isObject( data ) === false ){
					data = {
						balloon_template_id:1,
						size:               1,
						tail:               90,
						x:					Math.floor( panelW /2 - 100 +Math.random() *10 ),
						y:                  Math.floor( panelH /2 - 100 +Math.random() *10 ),
						z:                  -1,
						t:                  PANEL_ELEMENT_ARRAY.length + 1,
						width:              200,
						height:             200,
						speeches_attributes: {
							text1: {
								content:    'Hello'
							}
						}
					}
					_panelElement = new TextElementClass( data );
					_panelElement.init();
					pettanr.textEditor.bootInOverlay( PANEL_CONTROL.x(), PANEL_CONTROL.y(), _panelElement, onTextInput );
				} else {
					_panelElement = new TextElementClass( data );
					_panelElement.init();
					onTextInput( _panelElement );
				}
			}
		}
	})();

	/*
	 * end of COMIC_ELEMENT_CONTROL
	 */



	function updateMouseCursor( _cursor){
		if( currentCursor !== _cursor){
			currentCursor = _cursor;
			setTimeout( update, 0);
		}
		function update(){
			ELM_MOUSE_EVENT_CHATCHER.style.cursor = currentCursor;
		}
	}
	function centering(){
		instance.onPaneResize( windowW, windowH);
	}	
	function mouseEventRellay( e){
		var _mouseX = e.pageX,
			_mouseY = e.pageY,
			rellayMethod = e.type === 'mousedown' ?
					'onMouseDown' :
					( e.type === 'mousemove' ? 'onMouseMove' : 'onMouseUp');
		if( currentListener !== null && currentListener.busy() === true){
			currentListener[ rellayMethod]( _mouseX, _mouseY);
		} else {
			currentListener = null;
			var l = MOUSE_LISTENER_ARRAY.length,
				_listener;
			for( var i=0; i<l; ++i){
				_listener = MOUSE_LISTENER_ARRAY[ i];
				if( _listener[ rellayMethod]( _mouseX, _mouseY) === true){
					currentListener = _listener;
					break;
				}
			}
		}
		// 文字選択の禁止
		//!document.selection && window.getSelection().removeAllRanges();
		e.stopPropagation();
		return false;
	}

	/* grobal method */
	this.rootElement = document.getElementById( 'editor' );
	this.displayName = pettanr.view.EDITOR;
	this.ID          = pettanr.view.EDITOR;
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.firstOpen = function(){
	/*
	 * MOUSE_LISTENER_ARRAY は、表示順に格納．手前の要素が最初
	 * MENU_BAR_CONTROL,
	 * WINDOW_CONTROL,
	 * COMIC_ELEMENT_CONTROL,
	 * PANEL_CONTROL
	 * .busy() === true なら、そのままonMouseMove()にイベントを流す．
	 * onMouseMove()に流してみて、false が帰れば、次にリスナーにも流す．
	 */
		MOUSE_LISTENER_ARRAY.push( MENU_BAR_CONTROL, WINDOWS_CONTROL, PANEL_RESIZER_TOP, PANEL_RESIZER_BOTTOM, COMIC_ELEMENT_CONTROL, PANEL_CONTROL);
	/*
	 * centering
	 */
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 96, false, true, centering);	// ctrl + 0
		pettanr.key.addKeyDownEvent( pettanr.view.EDITOR, 48, false, true, centering);	// ctrl + 0
		MENU_BAR_CONTROL.EDIT.createSelection( 'centering', 'ctrl + 0', centering, true, true, true);
	/*
	 * jqMouseEventChacher は透明な要素で、
	 * マウスイベントをcurrentElement(currentElement)に伝えるのが仕事
	 * このような実装になるのは、ここの表示オブジェクトにイベントを設定した場合、表示が追いつかずマウスカーソルが外れたタイミングでイベントが終わってしまうため。
	 */			
		jqMouseEventChacher = $( ELM_MOUSE_EVENT_CHATCHER)
			.mousemove( mouseEventRellay)
			.mousedown( mouseEventRellay)
			.mouseup( mouseEventRellay)
			.mouseout( mouseEventRellay);
		
		delete instance.firstOpen;
	}
	this.onOpen = function( _w, _h, _file ){
		comicID      = -1;
		panelID      = -1;
		panelTimming = -1;
		phase        = 0;
		
		var panelW, panelH,
			borderSize,
			fileData, panelElements, panelElm;
		
		if( pettanr.file.isFileInstance( _file ) === true ){
			if( pettanr.driver.isPettanrFileInstance( _file ) === true ){
				if( _file.getType() === pettanr.driver.FILE_TYPE.COMIC ){
					fileData = _file.read();
					panelW = fileData.width;
					panelH = fileData.height;
					comicID = fileData.id || -1;
				} else
				if( _file.getType() === pettanr.driver.FILE_TYPE.PANEL ){
					fileData = _file.read();
					panelW = fileData.width;
					panelH = fileData.height;
					borderSize = fileData.border;
					panelElements = fileData.panel_elements;
					comicID = fileData.comic ? fileData.comic.id || -1 : -1;
					panelID = fileData.id || -1;
					panelTimming = fileData.t || -1;
					if( Type.isArray( panelElements ) === true ){
						for( var i=0; i<panelElements.length; ++i){
							panelElm = panelElements[ i ];
							if( panelElm.resource_picture ){
								COMIC_ELEMENT_CONTROL.createImageElement( panelElm );
							} else
							if( panelElm.balloon_template_id ){
								COMIC_ELEMENT_CONTROL.createTextElement( panelElm );
							}
						}						
					}
				}
			} else {
				
			}
		}
		jqEditor = jqEditor || $( '#editor');
		
		HISTORY_CONTROL.open();
		
		WINDOWS_CONTROL.open();
		
		GRID_CONTROL.open();
		PANEL_CONTROL.open( panelW, panelH, borderSize );
		
		COMIC_ELEMENT_OPERATION_MANAGER.open();
		COMIC_ELEMENT_CONTROL.open();
		
		instance.firstOpen !== undefined && instance.firstOpen();
		
		// last
		MENU_BAR_CONTROL.open();
		
		windowW = _w;
		windowH = _h;
		instance.onPaneResize( _w, _h );
		
		phase   = 1;
	}
	this.onClose = function(){
		phase   = 2;
		HISTORY_CONTROL.close();
		
		WINDOWS_CONTROL.close();
		
		GRID_CONTROL.close();
		PANEL_CONTROL.close();
		
		COMIC_ELEMENT_OPERATION_MANAGER.close();
		COMIC_ELEMENT_CONTROL.close();
		
		// last
		MENU_BAR_CONTROL.open();
		
		phase = -1;
	}
	this.onPaneResize = function( _windowW, _windowH){
		windowW = _windowW || windowW;
		windowH = _windowH || windowH;
		/*
		 * ieは +'px'が不要みたい
		 */
		jqEditor.get( 0).style.height = _windowH +'px';
		ELM_MOUSE_EVENT_CHATCHER.style.height = _windowH +'px';
		
		WINDOWS_CONTROL.onWindowResize( _windowW, _windowH);
		MENU_BAR_CONTROL.onWindowResize( _windowW, _windowH);
		PANEL_CONTROL.onWindowResize( _windowW, _windowH);
	}
});


pettanr.comicConsole = pettanr.view.registerApplication( function(){
	var jqWrap,
		ID = 'comicConsole',
		elmWrap = document.getElementById( 'comic-console-wrapper' ),
		elmHeader = document.getElementById( 'comic-console-header' ),
		elmProgress = document.getElementById( 'comic-console-progress' ),
		inputTitle, inputW, inputH,
		comboboxVisible, comboboxEditable,
		buttonSubmit, buttonCancel,
		elmUploader = null,
		elmScript = null,
		elmIframe = null,
		elmForm = null,
		timer = null,
		isUploading = false,
		instance = this;
	//pettanr.key.addKeyDownEvent( ID, 69, false, false, clickOK);
	
	function clickOK(){
		if( !elmForm || !elmIframe || isUploading === true ) return false;
		// validate
		isUploading = true;
		elmProgress.innerHTML = '■';
		copyAndSubmit();
	}

		function copyAndSubmit(){
			var _inputList = elmForm.getElementsByTagName( 'input' ),
				_input, _name;
			for( var i=0, l= _inputList.length; i<l; ++i){
				_input = _inputList[ i ];
				_name = _input.name;
				if( _name === 'comic[title]'){
					_input.value = inputTitle.value();
				} else
				if( _name === 'comic[width]'){
					_input.value = inputW.value();
				} else
				if( _name === 'comic[height]'){
					_input.value = inputH.value();
				}
			}
			var _selectList = elmForm.getElementsByTagName( 'select' ),
				_select, _optionList;
			for( i=0, l= _selectList.length; i<l; ++i){
				_select = _selectList[ i ];
				_name = _select.name;
				_optionList = _select.getElementsByTagName( 'option' )
				if( _name === 'comic[visible]'){
					_select.selectedIndex = comboboxVisible.selectIndex();
				} else
				if( _name === 'comic[editable]'){
					_select.selectedIndex = comboboxEditable.selectIndex();
				}
			}
			try {
				elmForm.submit();
			} catch( e){
				elmProgress.innerHTML = 'submit() err..';
				isUploading = false;
				setTimeout( clickCancel , 3000);
				return;
			}
			if( pettanr.ua.isIE){
				elmIframe.onreadystatechange = detectIframe;
			} else {
				elmIframe.onload = onIframeUpdate;
			}
			elmProgress.innerHTML = 'uploading..';
		}
	/*
	 * ie の 場合、readyState をチェック．
	 */
			function detectIframe(){
	            if ( elmIframe.readyState === 'complete') {
	                elmIframe.onreadystatechange = new Function();
	                elmIframe.onreadystatechange = null;
	                onIframeUpdate();
	            }
			}
				function onIframeUpdate(){
					elmIframe.onload = null;
					( elmIframe.contentWindow || elmIframe.contentDocument.parentWindow ).close();
					elmIframe = null;
					elmProgress.innerHTML = 'success!';
					setTimeout( clickCancel , 1000);
					isUploading = false;
				}
			
	function clickCancel(){
		if( isUploading === true) return false;
		pettanr.comicConsole.shutdown();
	}
	function detectForm(){
		elmForm = elmUploader.getElementsByTagName( 'form' )[ 0 ];
		if( elmForm ){
			var selectList = elmForm.getElementsByTagName( 'select' ),
				select,
				j, m,
				optionList, option;
			for( var i=0, l=selectList.length; i<l; ++i ){
				select = selectList[ i ];
				optionList = select.getElementsByTagName( 'option' );
				for( j=0, m=optionList.length; j<m; ++j ){
					option = optionList[ j ];
					if( select.name === 'comic[visible]' ){
						comboboxVisible.createOption( option.innerHTML, option.value, option.selected );
					} else
					if( select.name === 'comic[editable]' ){
						comboboxEditable.createOption( option.innerHTML, option.value, option.selected );
					}
				}
			}
			
			window.clearInterval( timer);
			timer = null;
			pettanr.util.createIframe( 'targetFrameCreateComic', onCreateIframe );
			elmProgress.innerHTML = 'create iframe';
		}
	}
	function onCreateIframe( _iframe ){
		elmUploader.appendChild( _iframe );
		elmIframe = _iframe;
		elmForm.target = _iframe.name;
		elmProgress.innerHTML = '';
	}

	/* grobal method */
	this.rootElement = document.getElementById( 'comic-console-wrapper' );
	this.displayName = ID;
	this.ID          = ID;
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.init = function(){
		jqWrap = $( '#comic-console-wrapper').hide();
		
		inputTitle       = pettanr.form.createInputText( document.getElementById( 'comic-console-title'), null, ID);
		inputW           = pettanr.form.createInputText( document.getElementById( 'comic-console-width'), null, ID);
		inputH           = pettanr.form.createInputText( document.getElementById( 'comic-console-height'), null, ID);
		comboboxVisible  = pettanr.form.createCombobox( document.getElementById( 'comic-console-visible'), null, ID);
		comboboxEditable = pettanr.form.createCombobox( document.getElementById( 'comic-console-editable'), null, ID);
		buttonSubmit     = pettanr.form.createButton( document.getElementById( 'comic-console-post-button'), clickOK, ID);
		buttonCancel     = pettanr.form.createButton( document.getElementById( 'comic-console-cancel-button'), clickCancel, ID);
		
		delete instance.init;
	}
	this.onOpen = function( w, h ){
		instance.init && instance.init();
		
		jqWrap.show();
		
		inputTitle.focus();
		
		elmUploader = document.createElement( 'div' );
		elmUploader.id = 'newcomic';
		elmUploader.style.cssText = 'height:1px;line-height:1px;visibility:hidden;overflow:hidden;';
		elmWrap.appendChild( elmUploader);
		
		var elmScript = document.createElement( 'script');
		elmScript.type = 'text\/javascript';
		elmScript.src = pettanr.CONST.CREATE_COMIC_JS;
		elmWrap.appendChild( elmScript );
		
		elmProgress.innerHTML = 'loading form.';
		
		if( timer === null){
			timer = window.setInterval( detectForm, 250);
		}
		
		instance.onPaneResize( w, h );
	}
	this.onPaneResize = function( _windowW, _windowH){
		jqWrap.css(
			{
				left:	Math.floor( ( _windowW - jqWrap.width()) /2),
				top:	Math.floor( ( _windowH - jqWrap.height()) /2)
			}
		);
	}
	this.onClose = function(){
		elmForm !== null && $( elmUploader ).remove();
		elmForm  = null;
		isUploading = false;
		
		if( elmScript !== null ){
			document.body.removeChild( elmScript);
			elmScript = null;					
		}
		if( timer !== null){
			window.clearInterval( timer);
			timer = null;
		}
		
		jqWrap.hide();
	}
});

pettanr.uploadConsole = pettanr.view.registerApplication( function(){
	var jqWrap, windowW, windowH,
		ID = 'uploadConsole',
		TARGET_FRAME_NAME = 'targetFrame',
		elmContainer = document.getElementById( 'uploader'),
		elmProgress = document.getElementById( 'upload-console-progress'),
		timer = null,
		elmScript = null,
		elmForm = null,
		elmFile = null,
		elmIframe = null,
		isUploading = false,
		instance = this;
	/*
	 * upload ボタンが押されたらまず iframe をつくる．
	 */
	function clickOK(){
		if( !elmForm || !elmIframe || isUploading === true ) return false;
		if( elmFile.value.length === 0) return false;
		elmProgress.innerHTML = 'uploading.';
		isUploading = true;
		submit();
		return false;
	}
	/*
	 * form の target に iframe を指定したのち submit();
	 */
		function submit(){
			try {
				elmForm.submit();
			} catch( e){
				elmProgress.innerHTML = 'submit() err..';
				isUploading = false;
				setTimeout( clickCancel , 3000);
				return;
			}
			
			if( pettanr.ua.isIE){
				elmIframe.onreadystatechange = detectIframe;
			} else {
				elmIframe.onload = onLoad;
			}
			elmProgress.innerHTML = 'uploading..';
		}
	/*
	 * ie の 場合、readyState をチェック．
	 */
			function detectIframe(){
	            if ( elmIframe.readyState === 'complete') {
	                elmIframe.onreadystatechange = new Function();
	                elmIframe.onreadystatechange = null;
	                onLoad();
	            }
			}
				function onLoad(){
					elmIframe.onload = null;
					( elmIframe.contentWindow || elmIframe.contentDocument.parentWindow ).close();
					elmProgress.innerHTML = 'success!';
					setTimeout( clickCancel , 1000);
					isUploading = false;
				}
	
	function detectForm(){
		elmForm = elmContainer.getElementsByTagName( 'form' )[ 0 ];
		if( elmForm){
			var _inputList = elmForm.getElementsByTagName( 'input' ),
				_input;
			for( var i=0, l= _inputList.length; i<l; ++i){
				_input = _inputList[ i ];
				if( _input.type === 'file'){
					elmFile = _input;
				}
				if( _input.type === 'submit'){
					_input.style.display = 'none';
				}
			}
			window.clearInterval( timer);
			timer = null;
			pettanr.util.createIframe( TARGET_FRAME_NAME, onCreateIframe);
			elmProgress.innerHTML = 'create iframe';
		}
	}
	function onCreateIframe( _iframe ){
		elmContainer.appendChild( _iframe );
		elmIframe = _iframe;
		elmForm.target = _iframe.name;
		elmProgress.innerHTML = '';
		instance.onPaneResize( windowW, windowH );
	}
	/*
	 * 
	 */
	function clickCancel(){
		if( isUploading === true) return false;
		pettanr.uploadConsole.shutdown();
		return false;
	}

	/* grobal method */
	this.rootElement = document.getElementById( 'upload-console-wrapper' );
	this.displayName = ID;
	this.ID          = ID;
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.init = function(){
		jqWrap = $( '#upload-console-wrapper').hide();
		$( '#upload-console-post-button').click( clickOK );
		$( '#upload-console-cancel-button').click( clickCancel );

		delete instance.init;
	}
	this.onOpen = function( w, h){
		instance.init && instance.init();
		/*
		 * ie 6, 7 で fadeIn 中の要素に appendChild すると クラッシュするので、document.body に追加．
		 */				
		elmScript = document.createElement( 'script');
		elmScript.type = 'text\/javascript';
		elmScript.src = pettanr.CONST.UPLOAD_PICTURE_JS;
		document.body.appendChild( elmScript);
		
		jqWrap.show();

		if( timer === null){
			timer = window.setInterval( detectForm, 250);
		}
		
		elmProgress.innerHTML = 'loading form.';
		
		instance.onPaneResize( w, h);
	}
	this.onPaneResize = function( _windowW, _windowH){
		windowW = _windowW;
		windowH = _windowH;
		jqWrap.css(
			{
				left:	Math.floor( ( _windowW -jqWrap.width()) /2),
				top:	Math.floor( ( _windowH -jqWrap.height()) /2)
			}
		);
	}
	this.onClose = function(){
		elmForm !== null && $( elmContainer.children ).remove();
		elmForm = elmFile = elmIframe = null;
		isUploading = false;
		
		if( elmScript !== null ){
			document.body.removeChild( elmScript);
			elmScript = null;					
		}
		if( timer !== null){
			window.clearInterval( timer);
			timer = null;
		}
		jqWrap.hide();
	}
});

pettanr.panelConsole = pettanr.view.registerApplication( function(){
	var jqWrap, windowW, windowH,
		ID = 'panelConsole',
		TARGET_FRAME_NAME = 'targetFrameCreateNewPanel',
		elmContainer = document.getElementById( 'newpanel'),
		elmProgress = document.getElementById( 'panel-console-progress'),
		timer = null,
		elmScript = null,
		elmForm = null,
		elmIframe = null,
		isUploading = false,
		instance = this;
	/*
	 * upload ボタンが押されたらまず iframe をつくる．
	 */
	function clickOK(){
		if( !elmForm || !elmIframe || isUploading === true ) return false;
		elmProgress.innerHTML = 'uploading.';
		isUploading = true;
		submit();
		return false;
	}
	/*
	 * form の target に iframe を指定したのち submit();
	 */
		function submit(){
			try {
				elmForm.submit();
			} catch( e){
				elmProgress.innerHTML = 'submit() err..';
				isUploading = false;
				setTimeout( clickCancel , 3000);
				return;
			}
			
			if( pettanr.ua.isIE){
				elmIframe.onreadystatechange = detectIframe;
			} else {
				elmIframe.onload = onLoad;
			}
			elmProgress.innerHTML = 'uploading..';
		}
	/*
	 * ie の 場合、readyState をチェック．
	 */
			function detectIframe(){
	            if ( elmIframe.readyState === 'complete') {
	                elmIframe.onreadystatechange = new Function();
	                elmIframe.onreadystatechange = null;
	                onLoad();
	            }
			}
				function onLoad(){
					elmIframe.onload = null;
					( elmIframe.contentWindow || elmIframe.contentDocument.parentWindow ).close();
					elmProgress.innerHTML = 'success!';
					setTimeout( clickCancel , 1000);
					isUploading = false;
				}
	
	function detectForm(){
		elmForm = elmContainer.getElementsByTagName( 'form' )[ 0 ];
		if( elmForm){
			var _inputList = elmForm.getElementsByTagName( 'input' ),
				_input;
			for( var i=0, l= _inputList.length; i<l; ++i){
				_input = _inputList[ i ];
				if( _input.type === 'submit'){
					_input.style.display = 'none';
				}
			}
			window.clearInterval( timer);
			timer = null;
			pettanr.util.createIframe( TARGET_FRAME_NAME, onCreateIframe);
			elmProgress.innerHTML = 'create iframe';
		}
	}
	function onCreateIframe( _iframe ){
		elmContainer.appendChild( _iframe );
		elmIframe = _iframe;
		elmForm.target = _iframe.name;
		elmProgress.innerHTML = '';
		instance.onPaneResize( windowW, windowH );
	}
	/*
	 * 
	 */
	function clickCancel(){
		if( isUploading === true) return false;
		pettanr.panelConsole.shutdown();
		return false;
	}

	/* grobal method */
	this.rootElement = document.getElementById( 'panel-console-wrapper' );
	this.displayName = ID;
	this.ID          = ID;
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.init = function(){
		jqWrap = $( '#panel-console-wrapper').hide();
		$( '#panel-console-post-button').click( clickOK );
		$( '#panel-console-cancel-button').click( clickCancel );

		delete instance.init;
	}
	this.onOpen = function( w, h ){
		instance.init && instance.init();
		/*
		 * ie 6, 7 で fadeIn 中の要素に appendChild すると クラッシュするので、document.body に追加．
		 */				
		elmScript = document.createElement( 'script');
		elmScript.type = 'text\/javascript';
		elmScript.src = pettanr.CONST.CREATE_PANEL_JS;
		document.body.appendChild( elmScript);
		
		jqWrap.show();

		if( timer === null){
			timer = window.setInterval( detectForm, 250 );
		}
		
		elmProgress.innerHTML = 'loading form.';
		
		instance.onPaneResize( w, h );
	}
	this.onPaneResize = function( _windowW, _windowH ){
		windowW = _windowW;
		windowH = _windowH;
		jqWrap.css(
			{
				left:	Math.floor( ( _windowW -jqWrap.width()) /2),
				top:	Math.floor( ( _windowH -jqWrap.height()) /2)
			}
		);
	}
	this.onClose = function(){
		elmForm !== null && $( elmContainer.children ).remove();
		elmForm = elmIframe = null;
		isUploading = false;
		
		if( elmScript !== null ){
			document.body.removeChild( elmScript);
			elmScript = null;					
		}
		if( timer !== null){
			window.clearInterval( timer);
			timer = null;
		}
		jqWrap.hide();
	}
});

pettanr.artistConsole = pettanr.view.registerApplication( function(){
	var jqWrap, windowW, windowH,
		ID = 'artistConsole',
		TARGET_FRAME_NAME = 'targetFrameRegisterArtist',
		elmContainer = document.getElementById( 'register'),
		elmProgress = document.getElementById( 'artist-console-progress'),
		timer = null,
		elmScript = null,
		elmForm = null,
		elmIframe = null,
		isUploading = false,
		instance = this;
	/*
	 * upload ボタンが押されたらまず iframe をつくる．
	 */
	function clickOK(){
		if( !elmForm || !elmIframe || isUploading === true ) return false;
		elmProgress.innerHTML = 'uploading.';
		isUploading = true;
		submit();
		return false;
	}
	/*
	 * form の target に iframe を指定したのち submit();
	 */
		function submit(){
			try {
				elmForm.submit();
			} catch( e){
				elmProgress.innerHTML = 'submit() err..';
				isUploading = false;
				setTimeout( clickCancel , 3000);
				return;
			}
			
			if( pettanr.ua.isIE){
				elmIframe.onreadystatechange = detectIframe;
			} else {
				elmIframe.onload = onLoad;
			}
			elmProgress.innerHTML = 'uploading..';
		}
	/*
	 * ie の 場合、readyState をチェック．
	 */
			function detectIframe(){
	            if ( elmIframe.readyState === 'complete') {
	                elmIframe.onreadystatechange = new Function();
	                elmIframe.onreadystatechange = null;
	                onLoad();
	            }
			}
				function onLoad(){
					elmIframe.onload = null;
					( elmIframe.contentWindow || elmIframe.contentDocument.parentWindow ).close();
					elmProgress.innerHTML = 'success!';
					setTimeout( clickCancel , 1000);
					isUploading = false;
				}
	
	function detectForm(){
		elmForm = elmContainer.getElementsByTagName( 'form' )[ 0 ];
		if( elmForm){
			var _inputList = elmForm.getElementsByTagName( 'input' ),
				_input;
			for( var i=0, l= _inputList.length; i<l; ++i){
				_input = _inputList[ i ];
				if( _input.type === 'submit'){
					_input.style.display = 'none';
				}
			}
			window.clearInterval( timer);
			timer = null;
			pettanr.util.createIframe( TARGET_FRAME_NAME, onCreateIframe);
			elmProgress.innerHTML = 'create iframe';
		}
	}
	function onCreateIframe( _iframe ){
		elmContainer.appendChild( _iframe );
		elmIframe = _iframe;
		elmForm.target = _iframe.name;
		elmProgress.innerHTML = '';
		instance.onPaneResize( windowW, windowH );
	}
	/*
	 * 
	 */
	function clickCancel(){
		if( isUploading === true) return false;
		pettanr.artistConsole.shutdown();
		return false;
	}

	/* grobal method */
	this.rootElement = document.getElementById( 'artist-console-wrapper' );
	this.displayName = ID;
	this.ID          = ID;
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.init = function(){
		jqWrap = $( '#artist-console-wrapper').hide();
		$( '#artist-console-post-button').click( clickOK );
		$( '#artist-console-cancel-button').click( clickCancel );

		delete instance.init;
	}
	this.onOpen = function( w, h ){
		instance.init && instance.init();
		/*
		 * ie 6, 7 で fadeIn 中の要素に appendChild すると クラッシュするので、document.body に追加．
		 */				
		elmScript = document.createElement( 'script' );
		elmScript.type = 'text\/javascript';
		elmScript.src = pettanr.CONST.REGISTER_ARTIST_JS;
		document.body.appendChild( elmScript );
		
		jqWrap.show();

		if( timer === null){
			timer = window.setInterval( detectForm, 250 );
		}
		
		elmProgress.innerHTML = 'loading form.';
		
		instance.onPaneResize( w, h );
	}
	this.onPaneResize = function( _windowW, _windowH ){
		windowW = _windowW;
		windowH = _windowH;
		jqWrap.css(
			{
				left:	Math.floor( ( _windowW -jqWrap.width()) /2),
				top:	Math.floor( ( _windowH -jqWrap.height()) /2)
			}
		);
	}
	this.onClose = function(){
		elmForm !== null && $( elmContainer.children ).remove();
		elmForm = elmIframe = null;
		isUploading = false;
		
		if( elmScript !== null ){
			document.body.removeChild( elmScript);
			elmScript = null;					
		}
		if( timer !== null){
			window.clearInterval( timer);
			timer = null;
		}
		jqWrap.hide();
	}
});

pettanr.outputConsole = pettanr.view.registerApplication( function(){
	var FORMAT_LIST = [ 'json[POST]', 'json[GET]', 'XML', 'HTML', 'XHTML', 'MT export', 'Blogger ATOM' ];
	var jqWrap, jqOutputArea,
		comboboxFormat, inputOption,
		buttonGenerate, buttonClose,
		ID = 'outputConsole',
		timing = 0,
		comicID, panelID, panelTimming, panelW, panelH, borderSize, panelElementArray,
		instance = this;
	//pettanr.key.addKeyDownEvent( ID, 69, false, false, clickOK);
	
	function clickOK(){
		pettanr.outputConsole.shutdown();
	}

	function getPanelElementByTiming(){
		var i, l = panelElementArray.length;
		while( timing < l * 2){
			for( i=0; i<l; ++i ){
				if( timing === panelElementArray[ i ].timing ){
					++timing;
					return panelElementArray[ i ];
				}
			}
			++timing;
		}
		return null;
	}

	function getAsHtmlString( isAbsoluteUrl, isXHTML ){
		timing = 0;
		
		var HTML_ARRAY = [],
			l = panelElementArray.length,
			_panelElement;

		while( HTML_ARRAY.length < l ){
			_panelElement = getPanelElementByTiming();
			if( _panelElement === null) break;
			HTML_ARRAY.push( panelElementToHtml( _panelElement, isAbsoluteUrl, isXHTML ));
		}

		HTML_ARRAY.unshift(
			[
				'<div class="panel" ',
					'style="',
						'height:', panelH, 'px;',
						'background-color:', ';',
					'"',
				'>'
			].join( '')
		);		
		HTML_ARRAY.push( '</div>');
		
		return HTML_ARRAY.join( pettanr.LINE_FEED_CODE_TEXTAREA);
	}

		function panelElementToHtml( _panelElement, isAbsoluteUrl, isXHTML ){
			var url;
			if( _panelElement.type === 0 ){
				url = [ pettanr.CONST.RESOURCE_PICTURE_PATH, _panelElement.resourcePicture().id, '.', _panelElement.resourcePicture().ext ].join( '' );
				return [
					'<img ',
						'src="',        isAbsoluteUrl !== true ? url : pettanr.util.getAbsolutePath( url ), '" ',
						'width="',      _panelElement.w, '" ',
						'height="',     _panelElement.h, '" ',
						'style="',
							'left:',    _panelElement.x, 'px;',
							'top:',     _panelElement.y, 'px;',
							'z-index:', _panelElement.z, ';',
						'"',
					isXHTML !== true ? '>' : ' \/>'
				].join( '');				
			} else {
				url = pettanr.balloon.getBalloonUrl( _panelElement.w, _panelElement.h, _panelElement.angle() );
				return [
					'<img ',
						'src="',        isAbsoluteUrl !== true ? url : pettanr.util.getAbsolutePath( url ), '" ',
						'width="',      _panelElement.w, '" ',
						'height="',     _panelElement.h, '" ',
						'style="',									
							'left:',    _panelElement.x, 'px;',
							'top:',     _panelElement.y, 'px;',
							'z-index:', _panelElement.z, ';',
						'"',
					isXHTML !== true ? '>' : ' \/>',
					pettanr.LINE_FEED_CODE_TEXTAREA,
					'<div class="balloon" style="',
						'left:',        _panelElement.x, 'px;',
						'top:',         _panelElement.y, 'px;',
						'width:',       _panelElement.w, 'px;',
						'height:',      _panelElement.h, 'px;',
						'z-index:',     _panelElement.z,
					'"><span>', _panelElement.text(), '<\/span>', '<\/div>'
						
				].join( '');				
			}
		}
	
	function getJsonGetString(){
		timing = 0;
		
		var JSON_STRING_ARRAY = [],
			ELEMENT_ARRAY     = [],
			l                 = panelElementArray.length,
			cr                = pettanr.LINE_FEED_CODE_TEXTAREA,
			_panelElement;

		while( ELEMENT_ARRAY.length <= l){
			_panelElement = getPanelElementByTiming();
			if( _panelElement === null ) break;
			 
			ELEMENT_ARRAY.push( _panelElement.type === 0 ? getImageJsonGET( _panelElement ) : balloonToJson( _panelElement ));
		}
		return [
			'{', cr,
				'"panel": {', cr,
					'"id": ',               panelID, ',', cr,
				    '"border": ',           borderSize, ',', cr,
				    '"comic_id": ',         comicID, ',', cr,
				    '"resource_picture_id": 1,', cr,
					'"x": ',                0, ',', cr,
					'"y": ',                0, ',', cr,
					'"z": ',                0, ',', cr,
					panelTimming !== -1 ? ( '"t": ' + panelTimming + ',' + cr ) : '',
				    '"width": ',            panelW, ',', cr,
				    '"height": ',           panelH, ',', cr,
				    '"panel_elements": [', cr,
				    	ELEMENT_ARRAY.join( ',' + cr ), cr,
				    ']', cr,
				'}', cr,
			'}'
		].join( '' );
	}
		function getImageJsonGET( _imageElement ){
			var cr = pettanr.LINE_FEED_CODE_TEXTAREA;
			return [
				'{', cr,
					'"resource_picture": {', cr,
						'"id": ',              _imageElement.resourcePicture().id, ',', cr,
						'"ext": ',             '"',_imageElement.resourcePicture().ext, '"', cr,
					'},', cr,
					'"x": ',                   _imageElement.x, ',', cr,
					'"y": ',                   _imageElement.y, ',', cr,
					'"z": ',                   _imageElement.z, ',', cr,
					'"width": ',               _imageElement.flipH() * _imageElement.w, ',', cr,
					'"height": ',              _imageElement.flipV() * _imageElement.h, ',', cr,
					'"t": ',                   timing, cr,
				'}'
			].join( '');
		}
	
	function getJsonPostString(){
		timing = 0;
		
		var JSON_STRING_ARRAY = [],
			IMAGE_ARRAY = [],
			BALLOON_ARRAY = [],
			l = panelElementArray.length,
			_panelElement,
			cr = pettanr.LINE_FEED_CODE_TEXTAREA;

		while( IMAGE_ARRAY.length + BALLOON_ARRAY.length <= l){
			_panelElement = getPanelElementByTiming();
			if( _panelElement === null) break;
			_panelElement.type === 0 ? 
				IMAGE_ARRAY.push( [ '"new', timing, '": ', imageToJson( _panelElement ) ].join( '' )) :
				BALLOON_ARRAY.push( [ '"new', timing, '": ', balloonToJson( _panelElement ) ].join( '' ) );
		}
		return [
			'{', cr,
				'"panel": {', cr,
					'"id": ',               panelID, ',', cr,
				    '"border": ',           borderSize, ',', cr,
				    '"comic_id": ',         comicID, ',', cr,
				    '"resource_picture_id": 1,', cr,
					'"x": ',                0, ',', cr,
					'"y": ',                0, ',', cr,
					'"z": ',                0, ',', cr,
					'"t": ',				panelTimming, ',', cr,
				    '"width": ',            panelW, ',', cr,
				    '"height": ',           panelH, ',', cr,
				    '"panel_pictures_attributes": {', cr,
				    	IMAGE_ARRAY.join( ',' + cr ), cr,
				    '},', cr,
				    '"balloons_attributes": {', cr,
				    	BALLOON_ARRAY.join( ',' + cr ), cr,
				    '}', cr,
				'}', cr,
			'}'
		].join( '' );
	}
		function imageToJson( _imageElement ){
			var cr = pettanr.LINE_FEED_CODE_TEXTAREA;
			return [
				'{', cr,
					'"resource_picture_id": ', _imageElement.resourcePicture().id, ',', cr,
					'"x": ',                   _imageElement.x, ',', cr,
					'"y": ',                   _imageElement.y, ',', cr,
					'"z": ',                   _imageElement.z, ',', cr,
					'"width": ',               _imageElement.flipH() * _imageElement.w, ',', cr,
					'"height": ',              _imageElement.flipV() * _imageElement.h, ',', cr,
					'"t": ',                   timing, cr,
				'}'
			].join( '');
		}

		function balloonToJson( _textElement ){
			var cr = pettanr.LINE_FEED_CODE_TEXTAREA;
			return [
				'{', cr,
					'"balloon_template_id": ', 1, ',', cr,
					'"system_picture_id": ',   1, ',', cr,
					'"size": ',                1, ',', cr,
					'"tail": ',                _textElement.angle(), ',', cr,
					'"x": ',                   _textElement.x, ',', cr,
					'"y": ',                   _textElement.y, ',', cr,
					'"z": ',                   _textElement.z, ',', cr,
					'"t": ',                   timing, ',', cr,
					'"width": ',               _textElement.w, ',', cr,
					'"height": ',              _textElement.h, ',', cr,
					'"speeches_attributes": {', cr,
						'"newf', timing, '": {', cr,
    						'"content": "', _textElement.text(), '",', cr,
							'"x": ',        _textElement.x, ',', cr,
							'"y": ',        _textElement.y, ',', cr,
							'"t": ',        timing, ',', cr,
							'"width": ',    _textElement.w, ',', cr,
							'"height": ',   _textElement.h, cr,
						'}', cr,
					'}', cr,
				'}'
			].join( '');
		}
	
	function clickGenerate(){
		var i = comboboxFormat.selectIndex(),
			text = 'sorry...';
		if( i === 0 ){
			text = getJsonPostString();
		} else
		if( i === 1 ){
			text = getJsonGetString();
		} else
		if( i === 3 ){
			text = getAsHtmlString( false, false );
		} else {
			
		}
		jqOutputArea.val( text );
	}
	function clickClose(){
		pettanr.outputConsole.shutdown();
		return false;
	}
	
	/* grobal method */
	this.rootElement = document.getElementById( 'output-console-wrapper' );
	this.displayName = ID;
	this.ID          = ID;
	
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.init = function(){
		jqWrap = $( '#output-console-wrapper').hide();
		jqOutputArea = $( '#output-area');
		
		comboboxFormat = pettanr.form.createCombobox( document.getElementById( 'output-console-format' ), null, ID );
		for( var i=0, l = FORMAT_LIST.length; i<l; ++i ){
			comboboxFormat.createOption( FORMAT_LIST[ i ], null, i === 0 );
		}
		inputOption    = pettanr.form.createInputText( document.getElementById( 'output-console-option' ), null, ID );
		buttonGenerate = pettanr.form.createButton( document.getElementById( 'output-console-generate-button' ), clickGenerate, ID );
		buttonClose    = pettanr.form.createButton( document.getElementById( 'output-console-close-button' ), clickClose, ID );
		delete instance.init;
	}
	this.onOpen = function( _w, _h, _comicID, _panelID, _panelTimming, _panelW, _panelH, _borderSize, _panelElementArray ){
		instance.init && instance.init();
		
		jqWrap.show();
		instance.onPaneResize( _w, _h );
		var text;
		
		comicID           = _comicID;
		panelID           = _panelID;
		panelTimming      = _panelTimming;
		panelW            = _panelW;
		panelH            = _panelH;
		borderSize        = _borderSize;
		panelElementArray = _panelElementArray;
		
		clickGenerate();
	}
	this.onPaneResize = function( _w, _h){
		jqWrap.css(
			{
				left:	Math.floor( ( _w -jqWrap.width()) /2),
				top:	Math.floor( ( _h -jqWrap.height()) /2)
			}
		);
	}
	this.onClose = function(){
		jqWrap.hide();
		jqOutputArea.val('');
	}
});
