/*
 * pettanR system.js
 *   version 0.4.37
 *   
 * author:
 *   itozyun
 * licence:
 *   3-clause BSD
 */

/*
 * 画像一覧は
 * 	お気に入り画像一覧 > tag:ペン次郎 > ペン次郎：笑う
 *  最近アップロードされた画像 > images
 *  最近使われた画像 > images
 *  キャラクター画像庫 > アニマル系 > tag:ペン次郎 > ペン次郎：笑う
 *  風景画像庫 >
 *  効果画像庫 >
 *  アイテム画像庫 >
 *  
 * 画像一覧を読み込むタイミング
 */
pettanr.file = ( function(){
	var FILE_TYPE_IS_FOLDER = 1,
		numFileType = FILE_TYPE_IS_FOLDER,
		FILEDATA_RESITER = [],			// store all of fileData( json object )
		FILEDATA_ACCESS = [],			// file operations for Kernel only ! hide from Out of pettanr.file
		FILE_OBJECT_POOL = [],
		EVENT_LISTENER_REGISTER = [],
		TREE_ARRAY = [],
		TREE_ACCESS_ARRAY = [];
	
	var REQUEST_CONTROLER = ( function(){
		var REQUEST_TICKET_RESISTER = [],
			currentTicket = null,
			currentData = null,
			DATA_TYPE_ARRAY = 'json,xml,html,text'.split( ','),
			DATA_IS_JSON = 0,
			DATA_IS_XML = 1,
			DATA_IS_HTML = 2,
			DATA_IS_TEXT = 3,
			numError = 0;
		
		var RequestTicketClass = function( _type, _data, _url, _onLoad, _onError){
			this.type = DATA_TYPE_ARRAY[ _type];
			this.data = _data;
			this.url = _url;
			this.onLoad = _onLoad;
			this.onError = _onError;
			this.state = 0;
		};
		
		function request(){
			if( currentTicket !== null ) return;
			currentTicket = REQUEST_TICKET_RESISTER.shift();
			$.ajax({
				url:		currentTicket.url,
				dataType:	currentTicket.type,
				success:	onSuccess,
				error: 		onError
			});
		}
		function onSuccess( _data ){
			currentData = _data;
			window.setTimeout( asyncSuccess, 0 );
		}
			function asyncSuccess(){
				currentTicket.onLoad( currentTicket.data, currentData );
				currentTicket = currentData = null;
				REQUEST_TICKET_RESISTER.length !== 0 && window.setTimeout( request, 0 );
			}
		
		function onError(){
			++numError;
			window.setTimeout( asyncError, 0 );
		}
			function asyncError(){
				currentTicket.onError( currentTicket.data );
				currentTicket = null;
				REQUEST_TICKET_RESISTER.length !== 0 && window.setTimeout( request, 0 );
			}
		return {
			getNumTask: function(){
				return REQUEST_TICKET_RESISTER.length;
			},
			getNumError: function(){
				return numError;
			},
			getJson: function( _data, _url, _onLoad, _onError ){
				REQUEST_TICKET_RESISTER.push( new RequestTicketClass( DATA_IS_JSON, _data, _url, _onLoad, _onError));
				currentTicket === null && request();
			}
		}
	})();



	var FILE_CONTROLER = {
		createTree: function( _rootFileData){
			var _tree = new TreeClass( _rootFileData);
			_tree.init();
			TREE_ARRAY.push( _tree);
			return _tree;
		},
		getFileUID: function( FILEDATAorFILE ){
			if( FILEDATAorFILE instanceof FileClass ){
				return FILEDATAorFILE.getUID();
			}
			
			var uid = pettanr.util.getIndex( FILEDATA_RESITER, FILEDATAorFILE );
			if( uid === -1){
				uid = FILEDATA_RESITER.length;
				FILEDATA_RESITER.push( FILEDATAorFILE );
			}
			return uid;
		},
		getFileDataAccess: function( UIDorFILEorFILEDATA){
			var _uid, _data, _access;
			
			if( typeof UIDorFILEorFILEDATA === 'number'){
				_data = FILEDATA_RESITER[ UIDorFILEorFILEDATA ] || null;
			} else
			if( UIDorFILEorFILEDATA instanceof FileClass){
				_uid = UIDorFILEorFILEDATA.getUID();
				_data = FILEDATA_RESITER[ _uid ] || null;
			} else {
				_data = UIDorFILEorFILEDATA || null;
			}
			
			if( _data === null || typeof _data !== 'object') return null;
			for( var i=0, l = FILEDATA_ACCESS.length; i<l; ++i){
				_access = FILEDATA_ACCESS[ i];
				if( _access.DATA === _data) return _access;
			}
			return null;
		},	
		getFileData: function( UIDorFILEorFILEDATA){
			var _access = FILE_CONTROLER.getFileDataAccess( UIDorFILEorFILEDATA);
			return _access !== null ? _access.DATA : null;
		},
		getChildren: function( UIDorFILEorFILEDATA){
			var _data = FILE_CONTROLER.getFileData( UIDorFILEorFILEDATA);
			return _data !== null ? _data.children || null : null;
		},
		getDriver: function( _file){
			var _data = FILE_CONTROLER.getFileData( _file);
			return _data !== null && _data.driver ? _data.driver : FileDriverBase;
		},
		getUpdateFlag: function( _file, _bit ){
			var _driver = FILE_CONTROLER.getDriver( _file ),
				_policy;
			if( typeof _driver.getUpdatePolicy === 'function'){
				_policy = _driver.getUpdatePolicy( _file );
				
			}
			if( typeof _policy !== 'number') {
				_policy = FileDriverBase.getUpdatePolicy( _file )
			}
			return _policy % ( _bit * 2) >= _bit;
		},
		move: function( _prentUID, _targetfile, _newFolder, _newIndex, _opt_callback){
			var _parentData = FILE_CONTROLER.getFileDataAccess( _prentUID),
				_parentType = _parentData.TYPE,
				_targetData = FILE_CONTROLER.getFileDataAccess( _targetfile),
				_targetType = _targetData.TYPE;
		},
		replace: function( _uid, _file, _newIndex){
			
		},
		addEventListener: function( FILEorNULL, _eventType, _callback ){
			var _uid = FILEorNULL instanceof FileClass ? FILEorNULL.getUID() : FILEorNULL;
			EVENT_LISTENER_REGISTER.push( new FileEventTicketClass( _uid, _eventType, _callback));
		},
		removeEventListener: function( FILEorNULL, _eventType, _callback ){
			var _uid = FILEorNULL instanceof FileClass ? FILEorNULL.getUID() : FILEorNULL,
				_ticket;
			for(var i=0, l = EVENT_LISTENER_REGISTER.length; i<l; ++i ){
				_ticket = EVENT_LISTENER_REGISTER[ i ];
				if( _ticket.fileUID === _uid && _ticket.eventType === _eventType && _ticket.callBack === _callback ){
					EVENT_LISTENER_REGISTER.splice( i, 1 );
					_ticket.destroy();
				}
			}
		},
		getTreeAccess: function(){
			
		},
		fileEventRellay: function( _uid, _event ){
			var _fileAccess = FILE_CONTROLER.getFileDataAccess( _uid );
			if( _fileAccess === null ) return;
			var _treeUID =  _fileAccess.TREE.getUID(),
				_treeAccess = TREE_ACCESS_ARRAY[ _treeUID ],
				_data = _fileAccess.DATA,
				_tree;
			if( !_treeAccess ) return;
			_treeAccess.dispatchFileEvent( _event );
			for( var i=0, l = TREE_ARRAY.length; i<l; ++i){
				if( i !== _treeUID ){
					_tree = TREE_ARRAY[ i ];
					if( FILE_CONTROLER.getFileData( _tree.getCurrentFile() ) === _data ){
						_treeAccess = TREE_ACCESS_ARRAY[ _tree.getUID() ];
						_treeAccess && _treeAccess.dispatchFileEvent( _event );
					}
				}
			}
		}
	}
	
	var AsyncEventDispatcher = ( function(){
		var STACK_LIST = [];
		
		function dispatch(){
			var _stack = STACK_LIST.shift();
			_stack[ 0 ]( _stack[ 1 ], _stack[ 2 ], _stack[ 3 ], _stack[ 4 ] );
			
			while( _stack.length > 0 ){
				_stack.shift();
			}
			if( STACK_LIST.length !== 0 ){
				window.setTimeout( dispatch, 0 );
			}
		}
		return {
			addEvent: function( _callback, _eventType, _targetFile, _key, _value ){
				if( STACK_LIST.length === 0 ){
					window.setTimeout( dispatch, 0 );
				}
				STACK_LIST.push( [ _callback, _eventType, _targetFile, _key, _value ] );
			}
		}
	})();
	
	var TreeClass = function( rootFileData ){
		var PARENT_FILE_RESITER = [],
			ACCESS = {
				dispatchFileEvent:	dispatchFileEvent
			},
			EVENT_LISTENER_ARRAY = [],
			rootFile,
			currentFile,
			instance;
			
		TREE_ACCESS_ARRAY.push( ACCESS );
		
		function dispatchFileEvent( e ){
			var _eventType = e.eventType,
				_targetFile = e.targetFile,
				_uid = _targetFile.getUID(),
				_ticket, _type, _callback;
			for( var i=0, l = EVENT_LISTENER_REGISTER.length; i<l; ++i ){
				_ticket = EVENT_LISTENER_REGISTER[ i ];
				_type = _ticket.eventType;
				_callback = _ticket.callBack;
				if( _eventType === _type && _uid === _ticket.fileUID ){
					AsyncEventDispatcher.addEvent( _callback, _eventType, _targetFile, e.key, e.value );
				} else
				if( _type === pettanr.file.TREE_EVENT.UPDATE && _eventType === pettanr.file.FILE_EVENT.GET_SEQENTIAL_FILES ){
					AsyncEventDispatcher.addEvent( _callback, _eventType, _targetFile );
				}
			}
		}
		
		return {
			init: function(){
				instance = this;
				currentFile = rootFile = new FileClass( instance, null, rootFileData );
				// rootFile.init();
				currentFile.getSeqentialFiles();
				delete this.init;
			},
			getUID: function(){
				return pettanr.util.getIndex( TREE_ACCESS_ARRAY, ACCESS );
			},
			getRootFile : function(){
				return rootFile;
			},
			getCurrentFile: function(){
				return currentFile;
			},
			hierarchy: function(){
				return PARENT_FILE_RESITER.length;
			},
			getParentFileAt: function( _index){
				var l = PARENT_FILE_RESITER.length;
				if( typeof _index !== 'number' || _index < 0 || _index >= l) return null;
				return PARENT_FILE_RESITER[ l -1 -_index];
			},
			down: function( _index){
				if( typeof _index !== 'number' || _index < 0 || _index >= currentFile.getChildFileLength()) return;
				PARENT_FILE_RESITER.unshift( currentFile );
				currentFile = currentFile.getChildFileByIndex( _index );
				currentFile.getSeqentialFiles();
				return currentFile;
			},
			up: function( _index){
				var l = PARENT_FILE_RESITER.length;
				if( l === 0) return null;
				
				if( currentFile ){
					var _currentFile = currentFile;
					currentFile = null;
					_currentFile.destroy();
				}
				if( typeof _index === 'number'){
					if( _index >= l) return null;
					currentFile = this.getParentFileAt( _index );
					PARENT_FILE_RESITER.splice( 0, l -_index);
				} else {
					currentFile = PARENT_FILE_RESITER.shift();
				}
				currentFile.getSeqentialFiles();
				return currentFile;	
			},
			addTreeEventListener: function( _eventType, _callback){
				FILE_CONTROLER.addEventListener( null, _eventType, _callback);
			},
			removeTreeEventListener: function( _eventType, _callback){
				FILE_CONTROLER.removeEventListener( null, _eventType, _callback);
			},
			destroy: function(){
				FILE_CONTROLER.destroyTree( instance.getUID() );
				// removeEvent
				var _currentFile = currentFile;
				currentFile = rootFile = rootFileData = null;
				// currentFile, rootFile を null にしないと .File.destroy() ができない.
				_currentFile.destroy();
				while( PARENT_FILE_RESITER.length > 0 ){
					_currentFile = PARENT_FILE_RESITER.shift();
					_currentFile.destroy();
				}
				instance = null;
			}
		}
	};

	var FileEventTicketClass = function( _uid, _eventType, _callback ){
		this.fileUID   = _uid;
		this.eventType = _eventType;
		this.callBack  = _callback;
		this.destroy   = function(){
			delete this.fileUID;
			delete this.eventType;
			delete this.destroy;
			delete this.callBack;
		}
		_uid = _eventType = _callback = undefined;
	}
	
	var FileEventClass = function( eventType, file, key, value){
		this.eventType = eventType;
		this.targetFile = file;
		this.updatedAttribute = key;
		this.updatedValue = value;
	}

/*
 * fileのdataはobjectで保持している。
 * pettanr.file.の外からファイルをみるときは、FileClassを通して操作する。
 * fileの変更、それに付随して追加されたイベントは、TreeClassで管理される。
 * treeがdestryされると、fileのイベントリスナーも全て削除される。
 * 他の tree も data の共通する currentFile に対してのみは、file の変更イベントを受け取って流す．
 * 
 * parentData のほうがいい！
 */
	
	var FileClass = function( tree, parentData, data ){
		var uid = FILE_CONTROLER.getFileUID( data ),
			instance = this;
		
		FILEDATA_ACCESS.push(
			{
				TREE:				tree,
				parentData:			parentData,
				DATA:				data,
				dispatchFileEvent:	dispatchEvent
			}
		);
		
		tree = parentData = data = null;
		
		function dispatchEvent( e ){
			FILE_CONTROLER.fileEventRellay( uid, e );
		}
		this.getUID = function(){
			return uid;
		}
	};
	
	FileClass.prototype = {
		isChildFile: function( _FILEorFILEDATA){
			return this.getChildFileIndex( _FILEorFILEDATA) !== -1;
		},
		getSeqentialFiles: function(){
			var _driver = FILE_CONTROLER.getDriver( this );
			if( _driver !== null && typeof _driver.getSeqentialFiles === 'function' ){
				_driver.getSeqentialFiles( this );
			}
		},
		addEventListener: function( _eventType, _callback ){
			FILE_CONTROLER.addEventListener( this, _eventType, _callback );
		},
		removeEventListener: function( _eventType, _callback ){
			FILE_CONTROLER.removeEventListener( this, _eventType, _callback );
		},
		getChildFileLength: function(){
			var children = FILE_CONTROLER.getChildren( this );
			return Type.isArray( children ) === true ? children.length : -1;
		},
		getChildFileIndex: function( _FILEorFILEDATA ){
			var children = FILE_CONTROLER.getChildren( this);
			if( Type.isArray( children ) === false ) return -1;
			var l = children.length,
				_fileData = FILE_CONTROLER.getFileData( _FILEorFILEDATA );
			if( _fileData === null ) return -1;
			for( var i=0; i<l; ++i ){
				if( children[ i ] === _fileData ) return i;
			}
			return -1;
		},
		getChildFileByIndex: function( _index ){
			var _access = FILE_CONTROLER.getFileDataAccess( this ),
				_children = FILE_CONTROLER.getChildren( this );
			if( typeof _index !== 'number' || _index < 0 || Type.isArray( _children ) === false || _index >= _children.length) return null;
			var _file = new FileClass( _access.TREE, _access.DATA, _children[ _index ]);
			// _file.init();
			return _file;
		},
		getName: function(){
			var driver = FILE_CONTROLER.getDriver( this );
			if( typeof driver.getName === 'function'){
				return driver.getName( this );
			}
			return FileDriverBase.getName( this);
		},
		getThumbnail: function(){
			var driver = FILE_CONTROLER.getDriver( this);
			if( typeof driver.getThumbnail === 'function'){
				return driver.getThumbnail( this);
			}
			return FileDriverBase.getThumbnail( this);
		},
		getType: function(){
			var _data = FILE_CONTROLER.getFileData( this);
			return typeof _data.type === 'number' ? _data.type : pettanr.file.FILE_TYPE.UNKNOWN;
		},
		getState: function(){
			var _data = FILE_CONTROLER.getFileData( this);
			return typeof _data.state === 'number' ? _data.state : pettanr.file.FILE_STATE.OK;
		},
		getSummary: function(){
			var driver = FILE_CONTROLER.getDriver( this );
			if( typeof driver.getSummary === 'function'){
				return driver.getSummary( this );
			}
			return FileDriverBase.getSummary( this);
		},
		isWritable: function(){
			return FILE_CONTROLER.getUpdateFlag( this, pettanr.file.FILE_UPDATE_POLICY.WRITE );
		},
		isSortable: function(){
			return FILE_CONTROLER.getUpdateFlag( this, pettanr.file.FILE_UPDATE_POLICY.SORT );
		},		
		isCreatable: function(){
			return FILE_CONTROLER.getUpdateFlag( this, pettanr.file.FILE_UPDATE_POLICY.CREATE );
		},
		isRenamable: function(){
			return FILE_CONTROLER.getUpdateFlag( this, pettanr.file.FILE_UPDATE_POLICY.RENAME );
		},
		isDeletable: function(){
			return FILE_CONTROLER.getUpdateFlag( this, pettanr.file.FILE_UPDATE_POLICY.DELETE );
		},
		read: function(){
			// simpleDeepCopy
			var driver = FILE_CONTROLER.getDriver( this ),
				data;
			if( typeof driver.read === 'function'){
				 data = driver.read( this );
			}
			return FileDriverBase.read( data || this );
		},
		write: function( _newData, _onUpdateFunction ){
			var driver = FILE_CONTROLER.getDriver( this );
			if( typeof driver.write === 'function'){
				return driver.write( this, _newData, _onUpdateFunction );
			}
			return FileDriverBase.write( this, _newData, _onUpdateFunction );
		},
		viewerApplicationList: function(){
			var driver = FILE_CONTROLER.getDriver( this );
			if( typeof driver.viewerApplicationList === 'function'){
				return driver.viewerApplicationList( this );
			}
			return FileDriverBase.viewerApplicationList( this );
		},
		editorApplicationList: function(){
			var driver = FILE_CONTROLER.getDriver( this );
			if( typeof driver.editorApplicationList === 'function'){
				return driver.editorApplicationList( this );
			}
			return FileDriverBase.viwerApps( this );
		},
		create: function(){
			
		},
		sort: function(){
			
		},
		onCopy: function(){
			
		},
		onDelete: function(){
			
		},
		move: function( _newFolder, _newIndex, opt_callback ){
			var _access = FILE_CONTROLER.getFileDataAccess( this );
			_access.TREE.move( _access.parentData, this.getUID(), _newFolder, _newIndex, opt_callback );
		},
		replace: function( _newIndex, opt_callback ){
			var _access = FILE_CONTROLER.getFileDataAccess( this );
			_access.TREE.replace( _access.parentData, this.getUID(), _newIndex, opt_callback);
		},
		/**
		 * サーチ
		 * 探しているファイルの属性と値を指定．一致する child の index を配列で返す．
		 */
		search: function( obj, rule ){
			var _children = FILE_CONTROLER.getChildren( this ),
				_child,
				ret = [], k, c;
			for( var i=0, l=_children.length; i<l; ++i ){
				_child = _children[ i ];
				c = true;
				for( k in obj ){
					if( obj[ k ] !== _child[ k ] ){
						c = false;
						break;
					}
				}
				c === true && ret.push( i );
			}
			return ret;
		},
		destroy: function(){
			var _access = FILE_CONTROLER.getFileDataAccess( this );
			var TREE = _access.TREE;
			if( TREE.getCurrentFile() === this ) return;
			if( TREE.getRootFile() === this ) return;
			for( var i=0, l = TREE.hierarchy(); i<l; ++i ){
				if( TREE.getParentFileAt( i ) === this ){
					return;
				}
			}
			var _index = pettanr.util.getIndex( FILEDATA_ACCESS, _access );
			if( _index === -1 || _access === null ) return;
			// event の 削除
			FILEDATA_ACCESS.splice( _index, 1 );
			delete _access.DATA;
			delete _access.TREE;
			delete _access.parentData;
			delete _access.dispatchFileEvent;
		}
	}

	/*
	 * FileDriverBase
	 */
	var FileDriverBase = {
		getSeqentialFiles: function( _file){
		},
		getName: function( _file){
			var _data = FILE_CONTROLER.getFileData( _file);
			return _data.name || 'No Name';
		},
		getThumbnail: function( _file){
			var _data = FILE_CONTROLER.getFileData( _file),
				_type = _data.type,
				_className = '';
			if( _type === pettanr.file.FILE_TYPE.FOLDER){
				_className = 'folder';
			} else
			if( _type === pettanr.file.FILE_TYPE.IMAGE){
				
			} else
			if( _type === pettanr.file.FILE_TYPE.TEXT){
				
			} else
			if( _type === pettanr.file.FILE_TYPE.HTML){
				
			} else
			if( _type === pettanr.file.FILE_TYPE.CSV){
				
			} else
			if( _type === pettanr.file.FILE_TYPE.JSON){
				
			} else
			if( _type === pettanr.file.FILE_TYPE.XML){
				
			}
			return {
				image:		null,
				className:	' file-type-' + _className
			}
		},
		getSummary: function( _file ){
			var _data = FILE_CONTROLER.getFileData( _file ),
				_type = _data.type;
			if( _type === pettanr.file.FILE_TYPE.FOLDER){
				return 'folder';
			} else
			if( _type === pettanr.file.FILE_TYPE.IMAGE){
				return 'image file';
			} else
			if( _type === pettanr.file.FILE_TYPE.TEXT){
				return 'text file';
			} else
			if( _type === pettanr.file.FILE_TYPE.HTML){
				return 'html document file';
			} else
			if( _type === pettanr.file.FILE_TYPE.CSV){
				return 'csv daat file';
			} else
			if( _type === pettanr.file.FILE_TYPE.JSON){
				return 'json data file';
			} else
			if( _type === pettanr.file.FILE_TYPE.XML){
				return 'xml data file';
			}
			return '';
		},
		getUpdatePolicy: function( _file ){
			// debug用 全てのメニューを許可
			return pettanr.file.FILE_UPDATE_POLICY.DSRWC;
		},
		read: function( _FILEorDATA ){
			var data,
				protects = pettanr.file.FILE_DATA_PROPERTY_RESERVED;			
			if( _FILEorDATA instanceof FileClass ){
				data = FILE_CONTROLER.getFileData( _FILEorDATA )
			} else {
				data = _FILEorDATA;
			}

			function clone( src ) {
				var ret;
				if( Type.isArray(src) === true ){
					ret = [];
				} else
				if( Type.isObject(src) === true ){
					ret = {};
				} else
				if( Type.isNumber(src) === true || Type.isString(src) === true || Type.isBoolean( src ) === true ){
					return src;
				} else {
					return null;
				}
				for( var key in src ){
					if( pettanr.util.getIndex( protects, key ) === -1 ){
						//alert( key )
						ret[ key ] = clone( src[ key ]);
					}
				}
				return ret;
			};
				
			return clone( data );
		},
		write: function( _file, _newData, _onUpdateFunction ){
			var _data = FILE_CONTROLER.getFileData( _file ),
				_type = _data.type;
			return false;
		},
		viewerApplicationList: function(){
			return [];
		},
		editorApplicationList: function(){
			return [];
		},
		onCreate: function(){
			
		},
		onSort: function(){
			
		},
		onCopy: function(){
			
		},
		onDelete: function(){
			
		}
	}

	var ROOT_FILEDATA = {
			name: 		'system root',
			type:		FILE_TYPE_IS_FOLDER,
			children:	[]
		},
		SYSTEM_TREE = FILE_CONTROLER.createTree( ROOT_FILEDATA),
		ROOT_FILE = SYSTEM_TREE.getRootFile();
	
	function createFolderUnderRoot( _fileData){
		ROOT_FILEDATA.children.push( _fileData);
		FILE_CONTROLER.getFileDataAccess( ROOT_FILE)
			.dispatchFileEvent( new FileEventClass( pettanr.file.FILE_EVENT.GET_SEQENTIAL_FILES, ROOT_FILE, 'children', null));
	}
	function createFileEvent( _eventType, _file, _key, _value){
		return new FileEventClass( _eventType, _file, _key, _value);
	}
	function createFileTypeID(){
		return ++numFileType;
	}
	
	return {
		init: function(){
			//REQUEST_CONTROLER.init();
			//FILE_CONTROLER.init();
			delete pettanr.file.init;
		},
		registerDriver: function( _driver ){
			_driver.prototype = FileDriverBase;
			/*
			 * File API
			 */
			return {
				createFolderUnderRoot:	createFolderUnderRoot,
				getFileDataAccess:		FILE_CONTROLER.getFileDataAccess,
				getFileData:			FILE_CONTROLER.getFileData,
				getJson:				REQUEST_CONTROLER.getJson,
				createFileEvent:		createFileEvent,
				createFileTypeID:		createFileTypeID
			}
		},
		createTree: function( _rootFile){
			return FILE_CONTROLER.createTree( _rootFile);
		},
		isTreeInstance: function( _tree){
			return _tree instanceof TreeClass;
		},
		isFileInstance: function( _file){
			return _file instanceof FileClass;
		},
		FILE_TYPE: {
			UNKNOWN:	0,
			FOLDER:		FILE_TYPE_IS_FOLDER,
			IMAGE:		createFileTypeID(),
			TEXT:		createFileTypeID(),
			HTML:		createFileTypeID(),
			CSV:		createFileTypeID(),
			JSON:		createFileTypeID(),
			XML:		createFileTypeID()
		},
		FILE_STATE: {
			UNKNOWN:	0,
			OK:			1,
			LOADING:	2,
			ERROR:		3,
			BROKEN:		4
		},
		FILE_UPDATE_POLICY: {
			_____:		parseInt( '00000', 2),
			____C:		parseInt( '00001', 2), // hasCreateMenu
			___W_:		parseInt( '00010', 2), // isWritable
			___WC:		parseInt( '00011', 2), // isWritable
			__R__:		parseInt( '00100', 2), // isRenamable
			__R_C:		parseInt( '00101', 2), // hasCreateMenu
			__RW_:		parseInt( '00110', 2), // isWritable
			__RWC:		parseInt( '00111', 2), // isWritable
			_S___:		parseInt( '01000', 2), // childrenIsSortable
			_S__C:		parseInt( '01001', 2),
			_S_W_:		parseInt( '01010', 2),
			_S_WC:		parseInt( '01011', 2),
			_SR__:		parseInt( '01100', 2),
			_SR_C:		parseInt( '01101', 2),
			_SRW_:		parseInt( '01110', 2),
			_SRWC:		parseInt( '01111', 2),
			D____:		parseInt( '10000', 2),
			D___C:		parseInt( '10001', 2), // hasCreateMenu
			D__W_:		parseInt( '10010', 2), // isWritable
			D__WC:		parseInt( '10011', 2), // isWritable
			D_R__:		parseInt( '10100', 2), // isRenamable
			D_R_C:		parseInt( '10101', 2), // hasCreateMenu
			D_RW_:		parseInt( '10110', 2), // isWritable
			D_RWC:		parseInt( '10111', 2), // isWritable
			DS___:		parseInt( '11000', 2), // childrenIsSortable
			DS__C:		parseInt( '11001', 2),
			DS_W_:		parseInt( '11010', 2),
			DS_WC:		parseInt( '11011', 2),
			DSR__:		parseInt( '11100', 2),
			DSR_C:		parseInt( '11101', 2),
			DSRW_:		parseInt( '11110', 2),
			DSRWC:		parseInt( '11111', 2),
			CREATE:		1,
			WRAITE:		2,
			RENAME:		4,
			SORT:		8,
			DELETE:		16
		},
		TREE_EVENT: {
			UPDATE:				'onTreeUpdate'
		},
		FILE_EVENT: {
			UPDATE_ATTRIVUTE:	'onFileUpdate',
			GET_SEQENTIAL_FILES:'gotSeqentilFiles'
		},
		FILE_DATA_PROPERTY_RESERVED: [
			'children', 'driver', 'state', 'type'
		]
	}
})();

pettanr.finder = ( function(){
	var FINDER_ARRAY = [],
		ELM_ORIGIN_FINDER_LOCATION_ITEM = pettanr.util.pullHtmlAsTemplete( 'templete-finder-location-item'),
		ELM_ORIGIN_FINDER_ICON = ( function(){
				var forIE = pettanr.util.pullHtmlAsTemplete( 'templete-finder-icon-ie'),
					modern = pettanr.util.pullHtmlAsTemplete( 'templete-finder-icon');
				return pettanr.ua.isIE === true && pettanr.ua.ieVersion < 8 ? forIE : modern;
			})(),
		ELM_ORIGIN_CONTAINER = pettanr.util.pullHtmlAsTemplete( 'templete-finder-container'),
		ICON_HEIGHT = pettanr.util.getElementSize( ELM_ORIGIN_FINDER_ICON).height,
		ICON_CLASSNAME = 'finder-icon-thumbnail',
		FINDER_ICON_POOL = [],
		BREAD_OBJECT_POOL = [];
	
	var FinderIconClass = function(){
		var elmContainer,
			ELM_WRAPPER = ELM_ORIGIN_FINDER_ICON.cloneNode( true),
			ELM_THUMBNAIL = pettanr.util.getElementsByClassName( ELM_WRAPPER, ICON_CLASSNAME )[0],
			ELM_FILENAME = pettanr.util.getElementsByClassName( ELM_WRAPPER, 'finder-icon-filename' )[0],
			ELM_DESCRIPTION = pettanr.util.getElementsByClassName( ELM_WRAPPER, 'finder-icon-summary' )[0],
			ELM_EDITOR_BUTTON = pettanr.util.getElementsByClassName( ELM_WRAPPER, 'finder-icon-console-editor-apps' )[0],
			ELM_VIEWER_BUTTON = pettanr.util.getElementsByClassName( ELM_WRAPPER, 'finder-icon-console-viewer-apps' )[0],
			ELM_ACTION_BUTTON = pettanr.util.getElementsByClassName( ELM_WRAPPER, 'finder-icon-console-action' )[0],
			file, w, index, style, instansce,
			onDownCallback, onEditorCallback, onViewerCallback, onActionCallback,
			viewerList, editorList;
		
		ELM_WRAPPER.onclick = onDownClick;
		function onDownClick(){
			onDownCallback( index);
			return false;
		}
		ELM_EDITOR_BUTTON.onclick = onEditorClick;
		function onEditorClick(){
			onEditorCallback( file, editorList[ 0 ] );
			return false;
		}
		ELM_VIEWER_BUTTON.onclick = onViwerClick;
		function onViwerClick(){
			onViewerCallback( file, viewerList[ 0 ] );
			return false;
		}
		ELM_ACTION_BUTTON.onclick = onActionClick;
		function onActionClick(){
			onActionCallback( file );
			return false;
		}
		function draw(){
			var _thumb = file.getThumbnail();
			if( _thumb.image ){
				ELM_THUMBNAIL.className = ICON_CLASSNAME + ' has-thumbnail';
				ELM_THUMBNAIL.style.backgroundImage = [ 'url(', _thumb.image, ')'].join( '');
			} else {
				ELM_THUMBNAIL.className = ICON_CLASSNAME + ' ' + _thumb.className;
				ELM_THUMBNAIL.style.backgroundImage = '';
			}
			ELM_FILENAME.firstChild.data = file.getName();
			ELM_DESCRIPTION.firstChild.data = file.getSummary();
			
			if( Type.isArray( viewerList ) === true && viewerList.length > 0 ){
				ELM_VIEWER_BUTTON.style.display = '';
			} else {
				ELM_VIEWER_BUTTON.style.display = 'none';
			};
			if( Type.isArray( editorList ) === true && editorList.length > 0 ){
				ELM_EDITOR_BUTTON.style.display = '';
			} else {
				ELM_EDITOR_BUTTON.style.display = 'none';
			};
		}
		function resize(){
			// ELM_WRAPPER.style.top = (index * ICON_HEIGHT) +'px';
		}
		function onCollect(){
			elmContainer.removeChild( ELM_WRAPPER );
			elmContainer = null;
			FINDER_ICON_POOL.push( instansce );
		}
		
		return {
			init: function( _file, _elmContainer, _w, _index, _style, _onDownCallback, _onEditorCallback, _onViewerCallback, _onActionCallback ){
				instansce = this;
				if( elmContainer !== _elmContainer){
					_elmContainer.appendChild( ELM_WRAPPER);
					elmContainer = _elmContainer;
				}
				if( file !== _file){
					file && file.destroy();
					file = _file;
					viewerList = file.viewerApplicationList();
					editorList = file.editorApplicationList();
					draw();
				}
				if( index !== _index){
					index = _index;
					resize();
				}
				onDownCallback = _onDownCallback;
				onEditorCallback = _onEditorCallback;
				onViewerCallback = _onViewerCallback;
				onActionCallback = _onActionCallback;
			},
			elm: ELM_WRAPPER,
			index: function( _index){
				
				return index;
			},
			style: function( _style){
				
				return style;
			},
			onResize: function( w ){
				
			},
			destroy: function(){
				elmContainer.removeChild( ELM_WRAPPER );
				file && file.destroy();
				file = elmContainer = onDownCallback = onEditorCallback = onViewerCallback = onActionCallback = viewerList = editorList = null;
				FINDER_ICON_POOL.push( instansce);
			}
		}
	}
	function updateIconPosition( _style, _w, _index, _elm){
		
	}
	var BreadcrumbClass = function(){
		var elmContainer,
			ELM_WRAPPER = ELM_ORIGIN_FINDER_LOCATION_ITEM.cloneNode( true ),
			ELM_FILENAME = ELM_WRAPPER.getElementsByTagName( 'a')[0],
			file, w, index, instansce,
			callback;
		ELM_WRAPPER.onclick = onClick;
		function draw(){
			ELM_FILENAME.className = 'file-icon-' + file.getType();
			ELM_FILENAME.innerHTML = file.getName();
		}
		function resize( index){
			ELM_WRAPPER.style.left = (index * 90) +'px';
		}
		function onClick(){
			callback( index);
			return false;
		}

		return {
			init: function( _file, _elmContainer, _index, _callback ){
				instansce = this;
				if( elmContainer !== _elmContainer ){
					_elmContainer.appendChild( ELM_WRAPPER);
					elmContainer = _elmContainer;
				}
				if( file !== _file){
					file = _file;
					draw();
				}
				if( index !== _index){
					index = _index;
					resize( index);
				}
				callback = _callback;
			},
			elm: ELM_WRAPPER,
			index: function( _index){
				
				return index;
			},
			onResize: function( w){
				
			},
			destroy: function(){
				elmContainer.removeChild( ELM_WRAPPER);
				file = elmContainer = null;
				BREAD_OBJECT_POOL.push( this );
			}
		}
	}
	
	var FinderClass = function( ELM_CONTAINER, tree, header, footer, onSelect, viewerOption, editorOption ){
		var ICON_ARRAY = [],
			BREAD_ARRAY = [],
			elmContainer = ELM_ORIGIN_CONTAINER.cloneNode( true ),
			elmLocation = elmContainer.getElementsByTagName( 'ul' )[0],
			nodesDiv = elmContainer.getElementsByTagName( 'div' ),
			elmSidebarButton = nodesDiv[1],
			elmStyleButton = nodesDiv[2],
			elmActionButton = nodesDiv[3],
			elmBody = nodesDiv[ nodesDiv.length -1 ],
			//tree = pettanr.file.createTree( TREE_TYPE),
			headX,
			headY,
			headH = pettanr.util.getElementSize( nodesDiv[0] ).height,
			bodyY,
			currentFile = null,
			breadW = 90,
			size = pettanr.util.getElementSize( ELM_ORIGIN_FINDER_ICON ),
			iconW = size.width,
			iconH = size.height,
			style = 0,
			w, h, bodyH,
			instance = this;
			
		tree.addTreeEventListener( pettanr.file.TREE_EVENT.UPDATE, draw );
		ELM_CONTAINER.appendChild( elmContainer );
		
		function draw( _w, _h ){
			w = Type.isFinite( _w ) === true ? _w : w;
			h = Type.isFinite( _h ) === true ? _h : h;
			bodyH = h - headH;
			var	l = tree.hierarchy() +1,
				m = BREAD_ARRAY.length,
				_file, _bread;
			for(var i=0; i<l; ++i){
				_file = i !== l-1 ? tree.getParentFileAt( i) : tree.getCurrentFile();
				if( i < m){
					BREAD_ARRAY[ i].init( _file, elmLocation, i, onHeadClick);
				} else {
					BREAD_ARRAY.push( getBreadcrumb( _file, elmLocation, i, onHeadClick ));
				}
			}
			while( l < BREAD_ARRAY.length){
				BREAD_ARRAY.pop().destroy();
			}
			
			l = _file.getChildFileLength();
			m = ICON_ARRAY.length;

			for( i=0; i<l; ++i){
				if( i < m){
					ICON_ARRAY[ i ].init( _file.getChildFileByIndex( i), elmBody, w, i, style, onDown, onEditor, onViwer, onAction );
				} else {
					ICON_ARRAY.push( getFinderIcon( _file.getChildFileByIndex( i), elmBody, _w, i, style, onDown, onEditor, onViwer, onAction ));
				}
			}
			if( _file.getState() === pettanr.file.FILE_STATE.LOADING ){
				elmBody.className = 'finder-body loading';
			} else {
				elmBody.className = 'finder-body';
			}
			
			elmBody.style.height = bodyH + 'px';
			
			while( l < ICON_ARRAY.length){
				ICON_ARRAY.pop().destroy();
			}
		}
		
		function onHeadClick( i){
			var l = BREAD_ARRAY.length -1;
			if( i < l){
				var _file = tree.getParentFileAt( i);
				if( _file !== null){
					tree.up( i);
					draw( w, h );
				}
			}
		}
		function onDown( i ){
			if( i < ICON_ARRAY.length ){
				var _file = tree.getCurrentFile().getChildFileByIndex( i );
				if( _file !== null && ( _file.getChildFileLength() !== -1 || _file.getType() === pettanr.file.FILE_TYPE.FOLDER)){
					tree.down( i );
					draw( w, h );
				} else {
					Type.isFunction( onSelect ) === true && onSelect( _file  );
				}
			}
		}
		function onEditor( _file, _app, editorOption ){
			_app.boot( _file, editorOption );
		}
		function onViwer( _file, _app ){
			_app.bootInOverlay( _file, viewerOption );
		}
		function onAction( _file ){

		}
		this.rootElement   = elmContainer;
		this.parentElement = ELM_CONTAINER;
		this.displayName   = 'finder';
		this.ID            = 'finder';
		this.MIN_WIDTH     = 240;
		this.MIN_HEIGHT    = 240;
		this.init = function(){
			//$( elmLocation).click( onHeadClick);
			//$( elmContainer).click( onBodyClick);
			var position = pettanr.util.getAbsolutePosition( elmLocation );
			headX = position.x;
			headY = position.y;
			bodyY = pettanr.util.getAbsolutePosition( elmBody ).y;
			delete instance.init;
		}
		this.onPaneResize = function( _w, _h ){
			instance.init && instance.init();
			draw( _w, _h );			
			
			w = _w;
			h = _h;
			elmBody.style.height = ( _h - headH ) + 'px';
			
			for(var i=0, l=ICON_ARRAY.length; i<l; ++i){
				ICON_ARRAY[ i].onResize( _w );
			}
		}
	}
	FinderClass.prototype = pettanr.view._getAbstractApplication();
	
	function getFinderIcon( _file, _elmContainer, w, index, style, onDown, onEditor, onViwer, onAction){
		var _icon;
		if( FINDER_ICON_POOL.length > 0){
			_icon = FINDER_ICON_POOL.shift();
		} else {
			_icon = new FinderIconClass();
		}
		_icon.init( _file, _elmContainer, w, index, style, onDown, onEditor, onViwer, onAction );
		return _icon;
	}
	
	function getBreadcrumb( _file, _elmContainer, index, callback){
		var _bread;
		if( BREAD_OBJECT_POOL.length > 0){
			_bread = BREAD_OBJECT_POOL.shift();
		} else {
			_bread = new BreadcrumbClass();
		}
		_bread.init( _file, _elmContainer, index, callback);
		return _bread;
	}

	return {
		init: function(){
			
		},
		createFinder: function( _applicationReference, _elmTarget, _tree, _header, _footer, _onSelect, _viewerOption, _editorOption ){
			if( pettanr.view.isApplicationReference( _applicationReference ) === false ) return;
			
			var _finder = new FinderClass( _elmTarget, _tree, _header, _footer, _onSelect, _viewerOption, _editorOption );
			FINDER_ARRAY.push( _finder );
			return _finder;
		},
		registerFinderHead: function(){
			
		},
		registerFinderPane: function( _finderPane){
			
		},
		isFinderInstance: function( _finder){
			return _finder instanceof FinderClass;
		},
		isFinderPaneInstance: function(){
			
		},
		isFinderHeadInstance: function(){
		}
	}
})();


pettanr.driver = ( function(){
	var MyAuthorID = 'current_author' in window ? current_author.id : ( pettanr.CONST.SERVER_SUPPORT === false ? 1 : -1 ),
		MyArtistID = 'current_artist' in window ? current_artist.id : ( pettanr.CONST.SERVER_SUPPORT === false ? 1 : -1 ),
		Driver = {
			getSeqentialFiles: function( _file){
				var _data = FileAPI.getFileData( _file),
					_json = _data !== null ? _data.json : null;
				if( _json === true && _data.type === pettanr.driver.FILE_TYPE.COMIC ){
					if( pettanr.CONST.SERVER_SUPPORT === false ){
						_json = [ 'json\/comics_', _data.id, '.json' ].join( '' );
					} else {
						_json = [ pettanr.CONST.PETTANR_ROOT_PATH, 'comics\/', _data.id, '.json\/play\/' ].join( '' );
					}
				}
				if( typeof _json === 'string'){
					FileAPI.getJson( _file, _json, onLoadJson, onErrorJson);
					_data.state = pettanr.file.FILE_STATE.LOADING;
					_data.json = null;
					return;
				}
			},
			getName: function( _file){
				var _data = FileAPI.getFileData( _file),
					_type = _data !== null ? _data.type : null;
				if( _type === pettanr.driver.FILE_TYPE.PICTURE ){
					return [ _data.id, _data.ext ].join( '.');
				} else
				if( _type === pettanr.driver.FILE_TYPE.PANEL ){
					return [ _data.t, ':', _data.comic.title ].join( '');
				} else
				if( _type === pettanr.driver.FILE_TYPE.COMIC ){
					return _data.title;
				} else
				if( _type === pettanr.driver.FILE_TYPE.ARTIST ){
					return [ _data.name, '画伯' ].join( '');
				} else
				if( _type === pettanr.driver.FILE_TYPE.AUTHOR ){
					return [ _data.name, '先生' ].join( '');
				}
				return _data.name;
			},
			getThumbnail: function( _file){
				var _data = FileAPI.getFileData( _file),
					_type = _data !== null ? _data.type : null;
				if( _type === pettanr.driver.FILE_TYPE.PICTURE){
					return { image: [ pettanr.CONST.RESOURCE_PICTURE_PATH, 'thumbnail/', _data.id, '.', _data.ext ].join( '')};
				}
				if( _data === FILE_DATA_COMICS_ROOT){
					return { className: 'file-type-cabinet'};
				}
				if( _type === pettanr.driver.FILE_TYPE.COMIC){
					return { className: 'file-type-comic'};
				}
				if( _type === pettanr.driver.FILE_TYPE.PANEL){
					return { className: 'file-type-panel'};
				}
				if( _type === pettanr.driver.FILE_TYPE.AUTHOR){
					return { className: 'file-type-author'};
				}
				if( _type === pettanr.driver.FILE_TYPE.ARTIST){
					return { className: 'file-type-artist'};
				}
				if( _type === pettanr.file.FILE_TYPE.FOLDER){
					return { className: 'file-type-folder'};
				}
				return { className: 'file-type-broken'};
			},
			getSummary: function( _file ){
				var _data = FileAPI.getFileData( _file ),
					_type = _data !== null ? _data.type : null;
				if( _type === pettanr.driver.FILE_TYPE.PICTURE){
					return [ _data.width, 'x', _data.height, ', filesize:', _data.filesize, ', lisence:', _data.license ].join( '' );
				}
				if( _data === FILE_DATA_COMICS_ROOT){
					return 'cabinet file';
				}
				if( _type === pettanr.driver.FILE_TYPE.COMIC){
					return 'comic file, id:' + _data.id;
				}
				if( _type === pettanr.driver.FILE_TYPE.PANEL){
					return [ _data.width, 'x', _data.height ].join( '' );
				}
				if( _type === pettanr.driver.FILE_TYPE.AUTHOR){
					return 'author file, id:' + _data.id;
				}
				if( _type === pettanr.driver.FILE_TYPE.ARTIST){
					return [ 'id:', _data.id, ' Email:', _data.email || 'empty' , ', HP:', _data.homepage_url || 'empty' ].join( '' );
				}
				if( _type === pettanr.file.FILE_TYPE.FOLDER){
					return 'pettanR folder';
				}
				return 'pettanR unknown file';
			},
			read: function( _file ){
				var _data = FileAPI.getFileData( _file ),
					_type = _data !== null ? _data.type : null,
					ret;
				if( _type === pettanr.driver.FILE_TYPE.COMIC ){
					// children を panels に deepcopy
					ret = {};
					for( var key in _data ){
						ret[ key ] = _data[ key ]
					}
					ret.panels = _data.children;
					return ret;
				}
				if( _type === pettanr.driver.FILE_TYPE.PANEL ){
				}
				if( _type === pettanr.driver.FILE_TYPE.PANEL_PICTURE ){
					
				}
				if( _type === pettanr.driver.FILE_TYPE.BALLOON ){
				}
				if( _type === pettanr.driver.FILE_TYPE.PICTURE ){
				}
			},
			write: function( _file, _newData, _onUpdateFunction ){
				var _data = FileAPI.getFileData( _file ),
					_type = _data !== null ? _data.type : null;
				if( _type === pettanr.driver.FILE_TYPE.COMIC ){
				}
				if( _type === pettanr.driver.FILE_TYPE.PANEL ){
				}
				if( _type === pettanr.driver.FILE_TYPE.PANEL_PICTURE ){
					
				}
				if( _type === pettanr.driver.FILE_TYPE.BALLOON ){
				}
				if( _type === pettanr.driver.FILE_TYPE.PICTURE ){
				}				
			},
			viewerApplicationList: function( _file ){
				var _data = FileAPI.getFileData( _file ),
					_type = _data !== null ? _data.type : null;
				if( _type === pettanr.driver.FILE_TYPE.PANEL ){
					return [ pettanr.reader ];
				}
				if( _type === pettanr.driver.FILE_TYPE.COMIC ){
					return [ pettanr.reader ];
				}	
				if( _data === FILE_DATA_MY_PICTURES_ROOT ){
					return [ pettanr.premiumSatge ];
				}
				if( _type === pettanr.driver.FILE_TYPE.ARTIST ){
					return [ pettanr.premiumSatge ];
				}
				return [];
			},
			editorApplicationList: function( _file ){
				var _data = FileAPI.getFileData( _file ),
					_type = _data !== null ? _data.type : null;
				if( _type === pettanr.driver.FILE_TYPE.PANEL ){
					return [ pettanr.editor ];
				}
				if( _type === pettanr.driver.FILE_TYPE.COMIC ){
					return [ pettanr.editor, pettanr.comicConsole ];
				}
				return [];
			}
		},
		FileAPI = pettanr.file.registerDriver( Driver ),
		FILE_DATA_SERVICE_ROOT = {
			name:		'PettanR root',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[]
		},
		FILE_DATA_COMICS_ROOT = {
			name:		'Comics',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[],
			driver:		Driver,
			json:		pettanr.CONST.URL_COMICS_JSON
		},
		FILE_DATA_PANELS_ROOT = {
			name:		'Panels',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[],
			driver:		Driver,
			json:		pettanr.CONST.URL_PANELS_JSON
		},
		FILE_DATA_PICTURE_ROOT = {
			name:		'Picutures',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[],
			driver:		Driver,
			json:		pettanr.CONST.URL_RESOURCE_PICTURES_JSON
		},
		FILE_DATA_MY_COMICS_ROOT = {
			name:		'My Comics',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[],
			driver:		Driver,
			id:			MyAuthorID
		},
		FILE_DATA_LATEST_COMICS = {
			name:		'Latest Comics',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[]
		},
		FILE_DATA_MY_PICTURES_ROOT = {
			name:		'My Pictures',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[],
			driver:		Driver,
			json:		pettanr.CONST.URL_ORIGINAL_PICTURES_JSON,
			id:			MyArtistID
		},
		FILE_DATA_AUTHOR_ROOT = {
			name:		'Authors',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[]
		},
		FILE_DATA_ARTIST_ROOT = {
			name:		'Artists',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[]
		},
		FILE_DATA_LISENCE_ROOT = {
			name:		'Original Lisences',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[]
		},
		FILE_DATA_BALLOON_ROOT = {
			name:		'Balloon templetes',
			type:		pettanr.file.FILE_TYPE.FOLDER,
			children:	[]
		},
		AUTHOR_ARRAY = [],
		ARTIST_ARRAY = [],
		PANEL_ARRAY = [],
		COMIC_ARRAY = [],
		RESOURCE_PICTURE_ARRAY = [],
		BALLOON_TEMPLETE_ARRAY = [],
		ORIGINAL_LICENSE_ARRAY = [],
		BASIC_LICENSES = 'cc_by,cc_nc,cc_nd,cc_sa,keep_aspect_ratio,no_convert,no_flip,no_resize'.split( ',');
	FILE_DATA_SERVICE_ROOT.children.push( FILE_DATA_COMICS_ROOT, FILE_DATA_PICTURE_ROOT, FILE_DATA_PANELS_ROOT, FILE_DATA_LISENCE_ROOT, FILE_DATA_BALLOON_ROOT);
	FILE_DATA_COMICS_ROOT.children.push( FILE_DATA_MY_COMICS_ROOT, FILE_DATA_LATEST_COMICS, FILE_DATA_AUTHOR_ROOT);
	FILE_DATA_PICTURE_ROOT.children.push( FILE_DATA_MY_PICTURES_ROOT, FILE_DATA_ARTIST_ROOT);
	
	FileAPI.createFolderUnderRoot( FILE_DATA_SERVICE_ROOT);

	function onLoadJson( _file, _json ){
		var _access = FileAPI.getFileDataAccess( _file),
			_data = _access !== null ? _access.DATA : null,
			l;
		if( _data === null){
			onErrorJson( _file);
			return;
		}
		_data.state = pettanr.file.FILE_STATE.OK;
		
		if( Type.isArray( _json ) === true ){
			l = _json.length;
			if( l === 0) return;
			for( var i=0; i<l; ++i ){
				buildFileData( _json[ i], _data);
			}			
		} else
		if( _json.id ){
			buildFileData( _json, _data );
		}
		_access.dispatchFileEvent( FileAPI.createFileEvent( pettanr.file.FILE_EVENT.GET_SEQENTIAL_FILES, _file, 'children', null));
	}
	function onErrorJson( _file ){ 
		var _data = FileAPI.getFileData( _file);
		if( _data !== null){
			_data.state = pettanr.file.FILE_STATE.ERROR;
		}
	}
	function buildFileData( _data, _parent ){
		var _array, i, l;
		// Panel
		if( _parent === FILE_DATA_PANELS_ROOT ){
			_data.type = pettanr.driver.FILE_TYPE.PANEL;
			_array = PANEL_ARRAY;
		} else
		// Comic
		if( _parent === FILE_DATA_COMICS_ROOT ){
			_data.type = pettanr.driver.FILE_TYPE.COMIC;
			_array = COMIC_ARRAY;
		} else
		if( _parent.type === pettanr.driver.FILE_TYPE.COMIC ){
			_array = COMIC_ARRAY;
		} else
		// Lisence
		if( _parent === FILE_DATA_LISENCE_ROOT ){
			_data.type = pettanr.driver.FILE_TYPE.LICENSE;
			_array = ORIGINAL_LICENSE_ARRAY;
		} else
		// Author
		if( _parent === FILE_DATA_AUTHOR_ROOT ){
			_data.type = pettanr.driver.FILE_TYPE.AUTHOR;
			_array = AUTHOR_ARRAY;
		} else
		// Artist
		if( _parent === FILE_DATA_ARTIST_ROOT ){
			_data.type = pettanr.driver.FILE_TYPE.ARTIST;
			_array = ARTIST_ARRAY;
		} else		
		// Picture
		if( _parent === FILE_DATA_PICTURE_ROOT || _parent === FILE_DATA_MY_PICTURES_ROOT ){
			_data.type = pettanr.driver.FILE_TYPE.PICTURE;
			_array = RESOURCE_PICTURE_ARRAY;
			// original_license を含まなければ、license object を削除して ビットデータ で保持
			// original_license なら ファイルを作る buildFileData( _license, FILE_DATA_LISENCE_ROOT)
			var _license = _data.license,
				_rule,
				_Math_pow = Math.pow,
				_bits = 0;
			if( typeof _license === 'object'){
				for( i=0, l=BASIC_LICENSES.length; i<l; ++i){
					_rule = _license[ BASIC_LICENSES[ i]]
					if( typeof _rule === 'number' && _rule === 1 ){
						_bits += _Math_pow( 2, i);
					}
				}
				_data.license = _bits;
			}
		} else {
			alert( 'error' );
		}
		
		_data.driver = Driver;
		
		// _array に _data を格納 または 上書き
		if( typeof _data.id === 'number' && _data.id > 0 ){
			var _id = _data.id - 1,
				__data = _array[ _id ],
				_reserved = pettanr.file.FILE_DATA_PROPERTY_RESERVED.join( ', ' );
			if( __data ){
				for( var key in _data){
					if( _reserved.indexOf( key ) === -1 ){
						__data[ key ] = _data[ key ];
					}
				}
				_data = __data; // このタイミングで参照が切れるので注意！！
			} else {
				_array[ _id ] = _data;
			}
		} else {
			alert( 'error' );
		}

		// Author
		// Artist
		if( _parent === FILE_DATA_AUTHOR_ROOT || _parent === FILE_DATA_ARTIST_ROOT ){
			addChildData( _parent, _data );
		} else
		// Comic + Panels
		if( _parent.type === pettanr.driver.FILE_TYPE.COMIC || _parent === FILE_DATA_COMICS_ROOT ){
			var _panels = _data.panels,
				_panel;
			if( _panels && Type.isArray( _panels ) === true ){
				
				for( i=0, l=_panels.length; i<l; ++i){
					_panel = buildFileData( _panels[ i ], FILE_DATA_PANELS_ROOT );
					/*
					 * 間違い！ t 順に格納
					 */
					addChildData( _data, _panel );
				}
				delete _data.panels;
			} else {
				if( _data.json !== null ){
					_data.json = true;
				}
				if( Type.isArray( _data.children ) === false ){
					_data.children = [];
				}				
			}
			var _author = _data.author || getResource( AUTHOR_ARRAY, _data.author_id );
			if( _author ){
				_data.author = _author = buildFileData( _author, FILE_DATA_AUTHOR_ROOT );
				addChildData( _author, _data );
				_author.id === MyAuthorID && addChildData( FILE_DATA_MY_COMICS_ROOT, _data );
			}
			if( _parent === FILE_DATA_COMICS_ROOT ){
				addChildData( FILE_DATA_LATEST_COMICS, _data);
			}
		} else
		// Panel
		if( _parent === FILE_DATA_PANELS_ROOT ){
			_data.comic = getResource( COMIC_ARRAY, _data.comic_id );
			_data.author = getResource( AUTHOR_ARRAY, _data.author_id );

			// picture data をファイルに取り出し
			var _elements = _data.panel_elements,
				_elm;
			if( Type.isArray( _elements ) === true ){
				for( i=0, l=_elements.length; i<l; ++i){
					_elm = _elements[ i];
					if( _elm.resource_picture ){
						_elm.resource_picture = buildFileData( _elm.resource_picture, FILE_DATA_PICTURE_ROOT ); // 上記参照切れに備えてここで上書き
					} else {
						_elm.resource_picture = getResource( RESOURCE_PICTURE_ARRAY, _elm.resource_picture_id );
					}
				}				
			}
		} else
		// Picture
		if( _data.type == pettanr.driver.FILE_TYPE.PICTURE ){
			var _artist = _data.artist || getResource( ARTIST_ARRAY, _data.artist_id );
			if( _artist){
				_data.artist = _artist = buildFileData( _artist, FILE_DATA_ARTIST_ROOT );
				addChildData( _artist, _data );
				if( _artist.id === MyArtistID ){
					addChildData( FILE_DATA_MY_PICTURES_ROOT, _data );
					//FILE_DATA_MY_PICTURES_ROOT.type = pettanr.driver.FILE_TYPE.ARTIST;
					//FILE_DATA_MY_PICTURES_ROOT.id = MyArtistID;
				}
			}
		}
		return _data;
	}
	function addChildData( _parent, _child ){
		if( Type.isArray( _parent.children ) === false){
			_parent.children = [];
		}
		pettanr.util.getIndex( _parent.children, _child ) === -1 && _parent.children.push( _child );
	}
	function getResource( _array, _id ){
		if( Type.isArray( _array ) === false || Type.isNumber( _id ) === false || _id < 1 ) return null;
		var _data = _array[ _id - 1 ];
		if( !_data ){
			_data = _array[ _id - 1 ] = {};
		}
		return _data;
	}

	return {
		createComicTree: function(){
			return pettanr.file.createTree( FILE_DATA_SERVICE_ROOT ); //FILE_DATA_COMICS_ROOT);
		},
		createPictureTree: function(){
			var _tree  = pettanr.file.createTree( FILE_DATA_PICTURE_ROOT );
				_root  = _tree.getRootFile();
				_myPic = _root.getChildFileByIndex( 0 );
				_pic   = _root.getChildFileByIndex( 1 );
			_myPic.getSeqentialFiles();
			_pic.getSeqentialFiles();
			_myPic.destroy();
			_pic.destroy();
			return _tree;
		},
		createArtistTree: function(){
			return pettanr.file.createTree( FILE_DATA_ARTIST_ROOT );
		},
		createServiceTree: function(){
			return pettanr.file.createTree( FILE_DATA_SERVICE_ROOT );
		},
		isPettanrFileInstance: function( _file ){
			if( pettanr.file.isFileInstance( _file ) === true){
				var _data = FileAPI.getFileData( _file);
				return _data !== null && _data.driver === Driver;
			}
			return false;
		},
		_getAPI: function(){
			return FileAPI;
		},
		_getPictureRootData: function(){
			return FILE_DATA_PICTURE_ROOT;
		},
		_getMyPicturesData: function(){
			return FILE_DATA_MY_PICTURES_ROOT;
		},
		FILE_TYPE: {
			COMIC:				FileAPI.createFileTypeID(),
			PANEL:				FileAPI.createFileTypeID(),
			PICTURE:			FileAPI.createFileTypeID(),
			PANEL_PICTURE:		FileAPI.createFileTypeID(),
			BALLOON:			FileAPI.createFileTypeID(),
			AUTHOR:				FileAPI.createFileTypeID(),
			ARTIST:				FileAPI.createFileTypeID(),
			LICENSE:			FileAPI.createFileTypeID()
		}
	}
})();

pettanr.entrance = pettanr.view.registerApplication( function(){
	var wrap = document.getElementById('inner-wrapper'),
		pageHeaderH = pettanr.util.getElementSize( document.getElementById( 'header' ) ).height,
		instance = this;
	this.displayName = 'Home';
	this.ID          = 'Home';
	this.rootElement = document.getElementById('entrance');
	this.onOpen = function( _w, _h, _option ){
		wrap.style.display = '';
		wrap.style.height = ( _h - pageHeaderH ) + 'px';
	}
	this.onClose = function(){
		wrap.style.display = 'none';
	}
	this.onPaneResize = function( _w, _h){
		instance.onOpen( _w, _h );
	}
});
pettanr.entrance.addToLancher();

pettanr.cabinet = pettanr.view.registerApplication( function(){
	var finder,
		elmContainer = document.getElementById( 'cabinet'),
		option,
		pageHeaderH = pettanr.util.getElementSize( document.getElementById( 'header' ) ).height;
		
	this.displayName = 'Comic list';
	this.ID          = 'Comiclist';
	this.rootElement = elmContainer;
	this.onOpen = function( _w, _h ){
		finder = finder || pettanr.finder.createFinder( pettanr.cabinet, elmContainer, pettanr.driver.createComicTree() );
		finder.resize( _w, _h - pageHeaderH );
	}
	this.onClose = function(){
		// finder.close();
	}
	this.onPaneResize = function( _w, _h){
		finder.resize( _w, _h - pageHeaderH );
	}
});
pettanr.cabinet.addToLancher();

pettanr.gallery = pettanr.view.registerApplication( function(){
	var finder,
		elmContainer = document.getElementById( 'gallery' ),
		option,
		pageHeaderH = pettanr.util.getElementSize( document.getElementById( 'header' ) ).height;
		
	this.displayName = 'Pictures';
	this.ID          = 'pictures';
	this.rootElement = elmContainer;
	this.onOpen = function( _w, _h ){
		finder = finder || pettanr.finder.createFinder( pettanr.gallery, elmContainer, pettanr.driver.createPictureTree() );
		finder.resize( _w, _h - pageHeaderH );
	}
	this.onClose = function(){
		// finder.close();
	}
	this.onPaneResize = function( _w, _h){
		finder.resize( _w, _h - pageHeaderH );
	}
});
pettanr.gallery.addToLancher();

pettanr.backyard = pettanr.view.registerApplication( function(){
	this.displayName = 'Settings';
	this.ID          = 'Settinds';
	this.rootElement = document.getElementById( 'backyard' );
	this.onOpen = function( _w, _h, _option ){
	}
	this.onClose = function(){
	}
	this.onPaneResize = function( _w, _h){
	}
});
pettanr.backyard.addToLancher();

if( pettanr.DEBUG === true){
	pettanr.debug = pettanr.view.registerApplication( function(){
		var elmDl = document.getElementById( 'useragent'),
			elmDt, elmDd,
			data = {
				pettanR:	pettanr.version,
				ua:			navigator.userAgent,
				platform:	navigator.platform,
				appVersion:	navigator.appVersion,
				appCodeName:navigator.appCodeName,
				appName:	navigator.appName,
				language:	navigator.browserLanguage || navigator.language,
				ActiveX:	pettanr.ua.ACTIVEX
			},
			ua = pettanr.ua;
		if( ua.IE){
			//data.ua = 'Internet Explorer';
			data.version = ua.IE;
			if( ua.ieVersion >= 8) data.RenderingVersion = ua.ieRenderingVersion;
			data.browserType = ua.STANDALONE === true ? 'Standalone' : 'bundle';
			if( ua.ieVersion < 9) {
				data.vml = ua.VML;
			} else {
				data.svg = ua.SVG;
			}
		}
		data.RenderingMode = ua.isStanderdMode === true ? 'Standerd' : 'Quirks';
		
		for( var key in data){
			elmDt = document.createElement( 'dt');
			elmDt.innerHTML = key;
			elmDd = document.createElement( 'dd');
			elmDd.innerHTML = '' + data[ key];
			if( !data[ key]) elmDd.style.color = 'red';
			elmDl.appendChild( elmDt);
			elmDl.appendChild( elmDd);
		}
		
		var wrap = document.getElementById('inner-wrapper'),
			pageHeaderH = pettanr.util.getElementSize( document.getElementById( 'header' )).height,
			instance = this;
		
		this.displayName = 'Debug';
		this.ID          = 'debug';
		this.rootElement = document.getElementById( 'debug' );
		this.onOpen = function( _w, _h, _option ){
			wrap.style.display = '';
			wrap.style.height = ( _h - pageHeaderH ) + 'px';
		}
		this.onClose = function(){
			wrap.style.display = 'none';
		}
		this.onPaneResize = function( _w, _h ){
			instance.onOpen( _w, _h );
		}
	});
	pettanr.debug.addToLancher();
	
} else {
	var _debug = document.getElementById( 'debug');
	if( _debug){
		pettanr.util.removeAllChildren( _debug);
		_debug.parentNode.removeChild( _debug);
		_debug = null;
	}
}

/* ----------------------------------------
 * Image Group Exproler
 *  - overlay
 */
pettanr.premiumSatge = pettanr.view.registerApplication( function(){
	var ICON_ARRAY = [],
		WHEEL_DELTA = 64,
		ARTIST_TREE = pettanr.driver.createArtistTree(),
		ARTIST_ROOT_FILE = ARTIST_TREE.getRootFile(),
		instance = this,
		winW, winH,
		wrapX,
		elmWrap = document.getElementById( 'image-group-wrapper' ),
		elmContainer = document.getElementById( 'image-group-icon-container' ),
		containerW,
		containerH = pettanr.util.getElementSize( elmContainer ).height,		
		elmIconOrigin = ( function(){
			var ret = document.createElement( 'div' ),
				data = document.createElement( 'div' );
			ret.appendChild( data );
			ret.className = 'image-group-item';
			data.className = 'image-group-item-title';
			return ret;
		})(),
		jqContainer,
		size = pettanr.util.getElementSize( elmIconOrigin ),
		itemW = size.width,
		itemH = size.height,
		elmName = document.getElementById( 'image-group-name' ),
		elmButton = document.getElementById( 'image-group-button' ),
		buttonW = pettanr.util.getElementSize( elmButton ).width,
		//onUpdateFunction,
		onUpdateFunction = null,
		onUpdateData = null,
		artistID = -1,
		onEnterInterval = null;

	elmButton.onclick = clickOK;
	
	var BASE_PATH = pettanr.CONST.RESOURCE_PICTURE_PATH,
		THUMB_PATH = BASE_PATH, // + 'thumbnail/',
		LIMIT_FILESIZE = 1024 * 10; // 10KB

	var ImageGroupIconClass = function( INDEX, data ){
		var elmIconWrap     = elmIconOrigin.cloneNode( true ),
			elmIconTitle    = pettanr.util.getElementsByClassName( elmIconWrap, 'image-group-item-title' )[ 0 ],
			SRC             = [ BASE_PATH, data.id, '.', data.ext ].join( ''),
			LOW_SRC         = data.filesize && data.filesize > LIMIT_FILESIZE ? [ THUMB_PATH, data.id, '.', data.ext ].join( '') : null,
			reversibleImage = null,
			timer           = null,
			onEnterFlag     = false,
			instance        = this;
		elmContainer.appendChild( elmIconWrap );
		elmIconWrap.style.left = ( INDEX * itemW ) + 'px';
		elmIconTitle.appendChild( document.createTextNode( data.filesize + 'bytes' ) );
		
		function onImageLoad( url, _imgW, _imgH ){
			data.width = _imgW = _imgW || data.width || 64;
			data.height = _imgH = _imgH || data.height || 64;
			elmIconTitle.firstChild.data = _imgW + 'x' + _imgH;
			var zoom = 128 /( _imgW > _imgH ? _imgW : _imgH ),
				MATH_FLOOR = Math.floor,
				h = MATH_FLOOR( _imgH * zoom ),
				w = MATH_FLOOR( _imgW * zoom );
			reversibleImage.elm.style.cssText = [
				'width:',  w, 'px;',
				'height:', h, 'px;',
				'margin:', MATH_FLOOR( itemH / 2 - h / 2 ), 'px ', MATH_FLOOR( itemW / 2 - w / 2 ), 'px 0'
			].join('');
			reversibleImage.resize( w, h );
			elmIconWrap.onclick = onClick;
		}
		
		function onClick(){
			onUpdateData = data;
			pettanr.premiumSatge.shutdown();
		}
		
		function asyncDraw(){
			reversibleImage = pettanr.image.createReversibleImage( LOW_SRC || SRC, itemW, itemH, onImageLoad );
			elmIconWrap.appendChild( reversibleImage.elm );
			onEnterFlag = true;
			timer = null;
		}
		
		this.onEnter = function( delay ){
			timer = window.setTimeout( asyncDraw, delay );
			delete instance.onEnter;
		}
		this.destroy = function(){
			delete instance.destroy;
			timer && window.clearTimeout( timer );
			reversibleImage && reversibleImage.destroy();
			pettanr.util.removeAllChildren( elmIconWrap );
			elmContainer.removeChild( elmIconWrap );
			elmIconWrap.onclick = '';
			reversibleImage = elmIconWrap = elmIconTitle = data = timer = null;
		}
	}
	
	function onEnterShowImage(){
		var l = ICON_ARRAY.length,
			_start = -wrapX /itemW -1,
			_end = _start + winW /itemW +1,
			_icon;
		for( var i=0, c = 0; i<l; ++i){
			_icon = ICON_ARRAY[ i ];
			if( _start < i && i < _end && _icon.onEnter ){
				_icon.onEnter( c * 100 );
				c++;
			}
		}
		onEnterInterval !== null && window.clearTimeout( onEnterInterval );
		onEnterInterval = null;
	}
	function clickOK(){
		pettanr.premiumSatge.shutdown();
	}
	function onMouseWheel( e, delta ){
		if( winW < containerW){
			wrapX += delta * WHEEL_DELTA;
			wrapX = wrapX > 0 ? 0 : wrapX < winW -containerW ? winW -containerW : wrapX;
			jqContainer.css( { left: wrapX});
			
			onEnterInterval !== null && window.clearTimeout( onEnterInterval );
			onEnterInterval = window.setTimeout( onEnterShowImage, 500 );
		}
		//e.stopPropagation();
		return false;			
	}
	
	function drawIcons(){
		while( ICON_ARRAY.length > 0 ){
			ICON_ARRAY.shift().destroy();
		}
		
		var _index = ARTIST_ROOT_FILE.search( {
				id:   artistID,
				type: pettanr.driver.FILE_TYPE.ARTIST
			})[ 0 ],
			_artistFile = ARTIST_ROOT_FILE.getChildFileByIndex( _index ),
			_file;
		if( _artistFile !== null ){
			for(var i=0, l=_artistFile.getChildFileLength(); i<l; ++i ){
				_file = _artistFile.getChildFileByIndex( i );
				ICON_ARRAY.push( new ImageGroupIconClass( i, pettanr.driver._getAPI().getFileData( _file ) ));
				_file.destroy();
			}
			elmName.firstChild.data = _artistFile.getName();
			_artistFile.destroy();
		}
	}
	
	function onFadeout(){
		while( ICON_ARRAY.length > 0 ){
			ICON_ARRAY.shift().destroy();
		}
		onUpdateFunction !== null && onUpdateData !== null && onUpdateFunction( onUpdateData );
		onUpdateFunction = onUpdateData = null;
	}
	
	/* grobal method */
	// this.rootElement = elmWrap;
	this.displayName = 'premiumStage';
	this.ID          = 'premiumStage';
	this.rootElement = elmWrap;
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.init = function(){
		jqContainer = $( elmContainer ).mousewheel( onMouseWheel );
		
		// よくない！ 一時的な処理,,,
		//var tree = pettanr.driver.createPictureTree();
		//tree.addTreeEventListener( pettanr.file.TREE_EVENT.UPDATE, drawIcons );
		// pettanr.file.FILE_EVENT.GET_SEQENTIAL_FILES
		delete instance.init;
	}
	this.onOpen = function( _windowW, _windowH, _ARTISTIDorFILE, _onUpdateFunction ){
		instance.init && instance.init();
		
		if( pettanr.driver.isPettanrFileInstance( _ARTISTIDorFILE ) === true ){
			var _data = pettanr.driver._getAPI().getFileData( _ARTISTIDorFILE );
			if( _ARTISTIDorFILE.getType() === pettanr.driver.FILE_TYPE.ARTIST || pettanr.driver._getMyPicturesData() === _data ){
				artistID = _data.id || -1;
			}
		} else
		if( Type.isNumber( _ARTISTIDorFILE ) === true ){
			artistID = _ARTISTIDorFILE;
		}
		
		onUpdateFunction = _onUpdateFunction || null;
		onUpdateData = null;
		
		drawIcons();
		
		wrapX = 0;
		containerW = ICON_ARRAY.length * itemW;
		
		winW = _windowW;
		winH = _windowH;
		var w = winW > containerW ? winW : containerW,
			h = _windowH > containerH ? containerH : _windowH,
			MATH_FLOOR = Math.floor;
		
		jqContainer.css( {
			width:		w,
			height:		0,
			left:		0,
			top:		MATH_FLOOR( _windowH /2)
		}).stop().animate( {
			height: 	h,
			top:		MATH_FLOOR( _windowH /2 -h /2)
		}, onEnterShowImage );
		
		elmButton.style.cssText = [
			'left:', MATH_FLOOR( winW /2 - buttonW /2), 'px;',
			'top:', MATH_FLOOR( _windowH /2 + containerH /2 +10), 'px'
		].join('');
	}
	this.onPaneResize = function( _windowW, _windowH ){
		var w = _windowW > containerW ? _windowW : containerW,
			h = _windowH > containerH ? containerH : _windowH,
			MATH_FLOOR = Math.floor,
			offsetW = MATH_FLOOR( _windowW /2 -winW /2);
			
		winW = _windowW;
		winH = _windowH;
		if( offsetW <= 0){ // smaller
			jqContainer.css( {
				left:				offsetW,
				width:				w
			}).animate( {
				left:				0,
				top:				MATH_FLOOR( _windowH /2 -h /2)
			});					
		} else {
			jqContainer.css( { // bigger
				left:				0,
				width:				w,
				borderLeftWidth:	offsetW
			}).animate( {
				top:				MATH_FLOOR( _windowH /2 -h /2),
				borderLeftWidth:	0
			});
		}
		elmButton.style.cssText = [
			'left:', MATH_FLOOR( _windowW /2 -buttonW /2), 'px;',
			'top:', MATH_FLOOR( _windowH /2 +containerH /2 +10), 'px'
		].join('');
		onEnterShowImage();
	}
	this.onClose = function(){
		jqContainer.stop().animate( {
				height:	0,
				top:	Math.floor( winH /2 )
			}, onFadeout );
		onEnterInterval !== null && window.clearTimeout( onEnterInterval );
		onEnterInterval = null;
	}
});


/* ----------------------------------------
 * Text Editor
 *  - overlay
 */
pettanr.textEditor = pettanr.view.registerApplication( function(){
	var jqWrap, jqTextarea, jqButton,
		textElement, onUpdateFunction,
		ID = 'textEditor',
		panelX, panelY,
		instance = this;
	//pettanr.key.addKeyDownEvent( ID, 69, false, false, clickOK);
	
	function clickOK(){
		textElement && textElement.text( jqTextarea.val() );
		window.setTimeout( asyncCallback, 0 );
	}
	
	function asyncCallback(){
		onUpdateFunction && onUpdateFunction( textElement );
		onUpdateFunction = textElement = null;
		pettanr.textEditor.shutdown();
	}
	
	function keyCancel( e ){
		if( e.keyCode === 69 && e.shiftKey === false && e.ctrlKey === true){
			clickOK();
			e.preventDefault();
	        e.keyCode = 0;
	        e.cancelBubble = true;
	        e.returnValue = false;
			return false;
		}	
	}
	function textareaFitHeight(){
		var rows = 0;
		while( jqTextarea.height() < textElement.h ){
			rows++;
			jqTextarea.attr( 'rows', rows );
		}
		rows > 1 && jqTextarea.attr( 'rows', --rows );
	}
	
	/* grobal method */
	// this.rootElement = elmWrap;
	this.displayName = 'textEditor';
	this.ID          = 'textEditor';
	this.rootElement = document.getElementById( 'speach-editor-wrapper' );
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.init = function(){
		jqWrap     = $( '#speach-editor-wrapper' ).hide();
		jqTextarea = $( '#speach-editor' ).keydown( keyCancel );
		jqButton   = $( '#speach-edit-complete-button').click( clickOK );
		delete instance.init;
	}
	this.onOpen = function( _w, _h, _panelX, _panelY, _textElement, _onUpdateFunction ){
		instance.init && instance.init();
		
		panelX = _panelX;
		panelY = _panelY;
		textElement = _textElement;
		onUpdateFunction = _onUpdateFunction || null;
		
		jqWrap.show();
		instance.onPaneResize( _w, _h );
		jqTextarea.val( _textElement.text() ).focus();
		
		/*
		 * ie6,7は、textarea { width:100%}でも高さが変わらない。rowsを設定。
		 */
		pettanr.ua.isIE === true && pettanr.ua.ieVersion <= 7 && setTimeout( textareaFitHeight, 0);
	}
	this.onPaneResize = function( _w, _h ){
		jqWrap.css( {
			left:			textElement.x + panelX,
			top:			textElement.y + panelY,
			width:			textElement.w,
			height:			textElement.h
		});
	}
	this.onClose = function(){
		jqWrap.hide();
	}
});


pettanr.reader = pettanr.view.registerApplication( function(){
	var jqWrap, jqPanelContainer,
		windowW, windowH,
		headerH       = pettanr.util.getElementSize( document.getElementById( 'comic-reader-header' ) ).height,
		consoleH      = pettanr.util.getElementSize( document.getElementById( 'comic-reader-console' ) ).height,
		panelMargin,
		elmContainer  = document.getElementById( 'comic-reader-panel-container' ),
		elmTitle      = document.getElementById( 'comic-reader-title' ).firstChild,
		elmAuthor     = document.getElementById( 'comic-reader-author' ).firstChild,
		elmBackButton = document.getElementById( 'comic-reader-back-button' ),
		elmNextButton = document.getElementById( 'comic-reader-forward-button' ),
		ID            = 'comicReader',
		bindWorker    = null,
		currentFile   = null;
		comicData     = null,
		currentPanel  = null,
		currentIndex  = 0,
		numPanel      = 0,
		instance      = this;

	function onBackClick(){
		currentIndex -= ( currentIndex > 0 ? 1 : 0 );
		slide();
		return false;
	}
	function onNextClick(){
		currentIndex += ( currentIndex < numPanel - 1 ? 1 : 0 );
		slide();
		return false;
	}
	function slide(){
		var elm    = elmContainer.childNodes[ currentIndex ],
			h      = windowH - headerH - consoleH,
			top    = headerH;
		if( elm ){
			top =  headerH - elm.offsetTop + Math.floor( ( h - elm.offsetHeight ) / 2 );
		}
		
		jqPanelContainer.stop().animate( {
			top:	top
		});
	}
	function getCurrentTopPosition(){

	}
	function draw(){
		var fileData, title, author;
		
		if( pettanr.driver.isPettanrFileInstance( currentFile ) === true ){
			if( currentFile.getType() === pettanr.driver.FILE_TYPE.COMIC ){
				fileData    = currentFile.read();
				title       = fileData.title;
				author      = fileData.author.name;
				comicData   = fileData;
				numPanel    = currentFile.getChildFileLength();
			} else
			if( currentFile.getType() === pettanr.driver.FILE_TYPE.PANEL ){
				fileData    = currentFile.read();
				title       = fileData.comic.title;
				author      = fileData.comic.author.name;
				comicData   = fileData;
				numPanel    = 1;
			}
		} else {
			
		}

		if( comicData !== null ){
			elmTitle.data  = title;
			elmAuthor.data = author;
			bindWorker.json( comicData );
			window.setTimeout( asyncResize, 0 );
		}
	}
	function asyncResize(){
		instance.onPaneResize( windowW, windowH );
	}
	
	/* grobal method */
	// this.rootElement = elmWrap;
	this.displayName = ID;
	this.ID          = ID;
	this.rootElement = document.getElementById( 'comic-reader-wrapper' );
	this.MIN_WIDTH   = 320;
	this.MIN_HEIGHT  = 320;
	this.init = function(){
		jqWrap           = $( instance.rootElement );
		jqPanelContainer = $( elmContainer );
		
		elmBackButton.onclick = onBackClick;
		elmNextButton.onclick = onNextClick;
		
		bindWorker = pettanr.bind.createBindWorker( elmContainer, null, false, false );
		
		delete instance.init;
	}
	this.onOpen = function( _w, _h, _file ){
		instance.init && instance.init();
		numPanel = currentIndex = 0;
		
		jqWrap.show();
		jqPanelContainer.css({
			left:	_w / 2,
			top:	_h
		});
		windowW = _w;
		windowH = _h;
		if( pettanr.file.isFileInstance( _file ) === true ){
			currentFile = _file;
			_file.addEventListener( pettanr.file.FILE_EVENT.GET_SEQENTIAL_FILES, draw );
			draw();
		}
	}
	this.onPaneResize = function( _windowW, _windowH ){
		windowW = _windowW;
		windowH = _windowH;
		var panelH = elmContainer.offsetHeight,
			panelW = elmContainer.offsetWidth,
			h      = _windowH - headerH - consoleH;
		jqPanelContainer.stop().animate(
			{
				left:	Math.floor( ( _windowW - panelW ) / 2 ),
				top:	headerH + ( panelH < h ? Math.floor( ( h - panelH ) / 2 ) : 0 )
			}
		);
	}
	this.onClose = function(){
		jqWrap.hide();
		currentFile.addEventListener( pettanr.file.FILE_EVENT.GET_SEQENTIAL_FILES, draw );
		currentFile = comicData = currentPanel = null;
	}
});

// i18n
// login
// lib

pettanr.fn( pettanr.view);
pettanr.fn( pettanr.overlay);
pettanr.fn( pettanr.key);
pettanr.fn( pettanr.balloon);

pettanr.fn( pettanr.editor);

pettanr.fn( pettanr.file);
pettanr.fn( pettanr.finder);
pettanr.fn( pettanr.gallery);
pettanr.fn( pettanr.cabinet);

$(window).ready( pettanr.init);
