(function(){
	var DEV=LPCXpresso1769;
	var BCF=DEV._BCF;
	var EE=DEV._EE;
	var isUndef=MiMicLib.isUndef;

	/**
	 * 配列をMiMicDBへ変換する。
	 @throws
	 変換失敗時は例外
	 */
	function array2MimicDb(i_array)
	{
		try{
			var dt=["0000000","000000","00000","0000","000","00","0",""];
			var p="";
			for(var i=0;i<i_array.length;i++){
				var v=(i_array[i]>>>0);
				var s=v.toString(16).toLowerCase();
				if(s.length<1 || s.length>8){
					throw new MiMicException(EE.NG);
				}
				p+=dt[s.length-1]+s;
			}
			return p;
		}catch(e){
			throw MiMicException(e);
		}
	}
	
	/**
	 * PINの機能名を含むPin識別子を得る。
	 */
	function getPinByFuncName(i_name)
	{
		try{
			function getPinByFName(i_pintbl,i_name)
			{
				for(var i=0;i<i_pintbl.length;i++){
					if(i_pintbl[i]==null){
						continue;
					}
					if(DEV.hasPinFunctionName(i_pintbl[i],i_name)){
						return i_pintbl[i];
					}
				}
				return null;
			}
			var tbl=[DEV.P0,DEV.P1,DEV.P2,DEV.P3,DEV.P4];
			for(var i=0;i<tbl.length;i++){
				var pin=getPinByFName(tbl[i],i_name);
				if(pin!=null){
					return pin;
				}
			}
			throw new MiMicException("pin function '"+i_name+"' not found");
		}catch(e){
			throw new MiMicException(e);
		}
	}
	/**
	 * PIN機能名から使用するペリフェラルシンボルを推定する。
	 */
	function pinFuncName2PhyName(i_pinfuncname)
	{
		try{
			//Pin function nameプレフィクスとペリフェラル名の対比表
			var TBL={
				"GPIO":"GPIO",
				"AD":"ADC",
				"DA":"DAC"
			};
			for(var key in TBL){
				if(i_pinfuncname.indexOf(key)==0){
					return TBL[key];
				}
			}
			//見つからぬ。
			throw new MiMicException("Peripheral for "+i_pinfunction+" not found.");
		}catch(e){
			throw new MiMicException(e);
		}
	}
	
	/**
	 * @see API Manual
	 */
	DEV.Mcu=function Mcu(i_mimic_addr,i_is_activate)
	{
		try{
			//リモートインタフェイスの取得
			this._mif=new MiMicRemoteMcuInterface(i_mimic_addr);
			var ac=isUndef(i_is_activate)?true:i_is_activate;
			if(ac){
				this.activate();
			};
		}catch(e){
			throw new MiMicException(e);
		}
	};
	DEV.Mcu.prototype=
	{
		/**
		 * MiMicInterface
		 */
		_mif:null,
		/**
		 * @see API manual
		 */
		isActive:function isActive()
		{
			try{
				return this._mif.isConnected();
			}catch(e){
				throw new MiMicException(e);
			}
		},
		/**
		 * @see API manual
		 */
		events:{
			/**
			 * @see API manual
			 */
			onActivateChanged:null
		},
		/**
		 * ペリフェラルオブジェクトのホルダ。ペリフェラル名をキーにした、ペリフェラルオブジェクトの連想配列。
		 MCUが、自身のペリフェラルオブジェクトを管理する為に使う。
		 */
		_phy_holder:[],
		/**
		 * @see API manual
		 */
		activate:function activate()
		{
			try{
				var _t=this;
				//既にアクティブならエラー。
				if(this.isActive()){
					throw new MiMicException("Already activated!");
				}
				//接続
				this._mif.connect(
					function(b){
						if(!b){
							//非同期切断を検出。
							if(_t.events.onActivateChanged!=null){
								_t.events.onActivateChanged(false);
							}
						}
					}
				);
				if(this.events.onActivateChanged!=null){
					this.events.onActivateChanged(true);
				}
			}catch(e){
				throw new MiMicException(e);
			}
		},
		/**
		 * @see API manual
		 */
		deactivate:function deactivate()
		{
			try{
				if(!this.isActive()){
					throw new MiMicException("Already activated!");
				}
	
				this._mif.disconnect();
				if(this.events.onActivateChanged!=null){
					this.events.onActivateChanged(false);
				}
			}catch(e){
				throw new MiMicException(e);
			}
		},
		/**
		 * @see API manual
		 */
		callMiMic:function callMiMic(/**/)
		{
			try{
				var bc;
				switch(arguments.length){
				case 1:
					//mimicBC
					bc=arguments[0];
					break;
				case 2:
					//mimicBC:string,db:array[int]
					bc=arguments[0]+array2MimicDb(arguments[1]);
					break;
				default:
					throw new MiMicException(e);
				}
				return this._mif.execBc(bc);
			}catch(e){
				throw new MiMicException(e);
			}
		},
		/**
		 * @see API manual
		 */
		callMiMicWithCheck:function execBc2WithException(/**/)
		{
			try{
				var ret=this.callMiMic.apply(this,arguments);
				if(ret.result!=0x0){
					throw new MiMicException(EE.VM_RUNTIME,"Result="+ret.toString());
				}
				return ret;
			}catch(e){
				throw MiMicException(e);
			}
		},
		/**
		 * @see API manual
		 */
		getPin:function getPin(/*...*/)
		{
			switch(arguments.length){
			case 1://getPin:function getPin(i_pin_function)
				//pin_functionを持ってるPINを探す。
				var pin=getPinByFuncName(arguments[0]);
				//function名からペリフェラル名を得る。
				var phy_name=pinFuncName2PhyName(arguments[0]);
				//ピンコンストラクタとペリフェラルを使ってピンを生成。
				return this.getPeripheral(phy_name).getPin(pin);
			case 2://getPin:function getPin(i_pin,i_function_name)
				//function名からペリフェラル名を得る。(PINシンボル変換を流用)
				var phy_name=pinFuncName2PhyName(arguments[1]);
				return this.getPeripheral(phy_name).getPin(arguments[0]);
			default:
				throw new MiMicException();
			}
		},
		/**
		 * @see API manual
		 */
		getPort:function getPort(i_port_name)
		{
			throw new MiMicException("Not implemented.");
		},
		/**
		 * @see API manual
		 */
		getPeripheral:function getPeripheral(i_phy_symbol)
		{
			//ペリフェラルアイテムが生成済か確認
			if(isUndef(this._phy_holder[i_phy_symbol])){
				//存在しなければPhyを生成。
				var phy;
				switch(i_phy_symbol){
				case "GPIO":new DEV.Gpio(this);break;
				case "ADC":new DEV.Adc(this);break;
				default:
					throw new MiMicException("Unknown peripheral symbol "+i_phy_symbol);
				}
			}
			//phyからregisterのコールバックがかかるはず。
			return this._phy_holder[i_phy_symbol];
		},
		/**
		 * [forSystem]システム関数。MCU依存のペリフェラルオブジェクトを登録する。
		 */
		registerPhy:function registerPhy(i_phy,i_symbol)
		{
			try{
				//登録済みのシンボルは登録できない。
				if(!isUndef(this._phy_holder[i_symbol])){
					throw new MiMicException("Peripheral symbol "+i_symbol+" is already exist on mcu.");
				}
				this._phy_holder[i_symbol]=i_phy;
			}catch(e){
				throw new MiMicException(e);
			}
		}
	}
}());