package
{
	import flash.desktop.NativeApplication;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.InvokeEvent;
	import flash.filesystem.File;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import mx.core.BitmapAsset;
	import mx.core.IFlexAsset;
	import mx.logging.Log;
	import mx.logging.LogEventLevel;
	import mx.logging.targets.TraceTarget;
	import org.libspark.thread.EnterFrameThreadExecutor;
	import org.libspark.thread.Thread;
	import vocaloplus.modules.IModelModule;
	import vocaloplus.modules.IMotionModule;
	import vocaloplus.modules.ISoundModule;

	/**
	 * ...
	 * @author Kazushi Tominaga (Seacolor)
	 */
	public class ModuleRegister extends Sprite
	{
		/**
		 * ビルド時に含めるクラスです。
		 */
		private const useClasses:Array = [ISoundModule, IModelModule, IMotionModule, BitmapAsset, IFlexAsset];
		/**
		 * 重複エラーの音声です。
		 */
		[Embed(source="/assets/voice/module_mei_ga_choufuku_v2.mp3")]
		[Bindable]
		private var sndDuplicatedError:Class;

		/**
		 * 除外するモジュールのファイル名です。
		 */
		protected const ignoreFiles:Array = ["register.swf", "vocaloplus.swf"];

		public function ModuleRegister()
		{
			var tt:TraceTarget = new TraceTarget();
			tt.includeDate = true;
			tt.includeTime = true;
			tt.includeLevel = true;
			tt.includeCategory = true;
			tt.level = LogEventLevel.DEBUG;
			Log.addTarget(tt);

			if (!Thread.isReady) Thread.initialize(new EnterFrameThreadExecutor());
			NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke);
		}

		protected function onInvoke(e:InvokeEvent):void
		{
			var binFiles:Array = File.applicationDirectory.resolvePath("bin").getDirectoryListing();
			var moduleFiles:Vector.<String> = new Vector.<String>();

			for each (var binFile:File in binFiles) {
				var filename:String = binFile.name;
				if (ignoreFiles.indexOf(filename) != -1) {
					continue;
				}
				moduleFiles.push(filename);
			}

			_register = new ModuleRegisterThread(moduleFiles);
			_register.addEventListener(Event.COMPLETE, destory);
			_register.start();
		}

		protected var _register:ModuleRegisterThread;

		protected function destory(event:Event = null):void {
			if (_register.duplicated) {
				var snd:Sound = new sndDuplicatedError() as Sound;
				var channel:SoundChannel = snd.play();
				channel.addEventListener(Event.SOUND_COMPLETE, function():void {
					NativeApplication.nativeApplication.exit();
				});
			} else {
				NativeApplication.nativeApplication.exit();
			}
		}

	}

}
import flash.events.IEventDispatcher;
import flash.filesystem.File;
import com.seacolorswind.dbi.AirDao;
import org.libspark.thread.utils.EventDispatcherThread;
import org.libspark.thread.Thread;
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
import mx.modules.IModuleInfo;
import vocaloplus.entities.ModuleDef;
import vocaloplus.modules.IContentModule;
import flash.events.Event;
class ModuleRegisterThread extends EventDispatcherThread {
	/**
	 * モジュールの定義情報を格納したデータベースです。
	 */
	protected const _moduleInfo:AirDao = new AirDao(File.applicationDirectory.resolvePath("modules.db"));
	/**
	 * 登録されるモジュールのファイル名です。
	 */
	protected var _moduleFiles:Vector.<String>;

	/**
	 * モジュール名が重複していたかどうかです。
	 */
	public var duplicated:Boolean = false;

	public function ModuleRegisterThread(moduleFiles:Vector.<String>) {
		_moduleFiles = moduleFiles;
	}

	override protected function run():void
	{
		super.run();
		load();
	}

	protected function load():void {
		if (isInterrupted) {
			return;
		} else if (_moduleFiles.length) {
			var _module:IModuleInfo = ModuleManager.getModule(_moduleFiles.shift());
			event(_module, ModuleEvent.READY, loaded);
			event(_module, ModuleEvent.ERROR, onError);
			_module.load();
		}
	}

	protected function loaded(e:ModuleEvent):void {
		var child:IContentModule = IContentModule(e.currentTarget.factory.create());
		var name:String = child.name;
		trace("module name: ", name);

		_moduleInfo.read(ModuleDef, function(result:Array):void {
			if (result.length) {
				if (result[0].url != e.currentTarget.url) {
					// モジュールニックネームが重複している場合は処理を中断
					duplicated = true;
					interrupt();
				}
				created();
				return;
			}

			var newModuleDef:ModuleDef = new ModuleDef();
			newModuleDef.name = name;
			newModuleDef.url = e.currentTarget.url;
			newModuleDef.type = child.type;
			_moduleInfo.create(newModuleDef, created);
		}, {name: name});

		next(load);
	}

	protected function created():void {
		if (!_moduleFiles.length) {
			if (!_moduleInfo.executing) {
				dispatchEvent(new Event(Event.COMPLETE));
			} else {
				new JoinThread(this, _moduleInfo).start();
			}
		}
	}

	protected function onError(e:ModuleEvent):void
	{
		trace("[Skip] " + (e.currentTarget as IModuleInfo).url + " is not module.");
		next(load);
	}

}

class JoinThread extends Thread {
	protected var _dispacher:IEventDispatcher;
	protected var _airDao:AirDao;

	public function JoinThread(dispacher:IEventDispatcher, airDao:AirDao) {
		_dispacher = dispacher;
		_airDao = airDao;
	}

	override protected function run():void
	{
		if (!_airDao.executing) {
			_dispacher.dispatchEvent(new Event(Event.COMPLETE));
		} else {
			next(run);
		}
	}
}
