

/**
 * MiMic関数ライブラリ
 */
var MiMicLib=
{
	isUndef:function isUndef(a){return typeof a==="undefined"}
}



/**
 * @see API manual
 */
var MiMicError=
{
	OK:[0x00000000,"OK"],
	NG:[0x40000000,"NG"],	//汎用NG
	/**
	 * エラーコードがOKか調べる。
	 */
	isOK:function(v){
		return (0x40000000 & v)==0x00000000;
	},
	/**
	 * 定数定義
	 */
	MID_MiMic:0x00390000,
	CAID_RemoteMCU     :0x0100,	//
	CAID_LPCXPresso1769:0x0200	//リモートAPI
	
}

/**
 * @see API manual
 */
function MiMicException(/*...*/)
{
	var pfx;
	if(typeof arguments.callee.caller=="function"){
		 if(arguments.callee.caller.name.toString().length>0){
			pfx="function '"+arguments.callee.caller.name+'.';
		 }else{
		 	var s=arguments.callee.caller.toString();
			pfx="closure '"+s.substring(0,s.indexOf("{"))+"...'";
		 }
	}else{
		pfx="root document";
	}
	var sfx="";
	switch(arguments.length){
	case 0:
		//とりあえずexceptiion
		this.code=MiMicError.NG[0];
		this.message=pfx+" code(0x"+this.code.toString(16)+")"+MiMicError.NG[1];
		return;
	case 1:
		var v=arguments[0];
		if(v instanceof MiMicException){
			//exception継承
			this.code=v.code;
			sfx="  \nfrom "+v.message;
		}else if(typeof v=="object" && v.length==2){
			//Errorコードテーブル
			this.code=v[0];
			sfx=v[1];
		}else{
			//文字列やオブジェクト
			this.code=MiMicError.NG[0];
			sfx=MiMicError.NG[1]+(((typeof v)!='undefined')?v.toString():"v==undefined");
		}
		this.message=pfx+" code(0x"+this.code.toString(16)+")"+sfx;
		return;
	case 2:
		var v=arguments[0];
		if(v instanceof MiMicException){
			//Exception+メッセージ
			this.code=v.code;
			this.message=pfx+" code(0x"+this.code.toString(16)+")"+"\nfrom "+v.message+":"+arguments[1];
			return;
		}else if(typeof v!="string" && v.length==2){
			//Errorコードテーブル+メッセージ
			this.code=v[0];
			this.message=pfx+" code(0x"+this.code.toString(16)+")"+v[1]+":"+arguments[1];
		}else{
			break;
		}
		return;
	default:
		break;
	}
	throw new MiMicException("Invalid MiMicException argument.");
}
MiMicException.prototype={
	code:MiMicError.OK,
	message:"",
	alert:function(){
		alert(this.message);
	},
	toString:function()
	{
		return "MiMicException:"+this.message;
	}	
}






/*
 * MiMicRemoteMCU
 */
var MiMicRemoteMcuInterface;

(function(){
	/**
	 * エラーID定義
	 */
	var EE=function(i_base)
	{
		return {
		NG:[i_base|0x00,"Unknown exception in MiMicRemoteMcuInterface"],
		TCP_CONNECT:[i_base|0x01,"TCP CONNECT FAILED"],//接続エラー
		HTTP   	   :[i_base|0x02,"HTTP FAILED"]}//HTTPエラー
	}(MiMicError.NG[0]|MiMicError.MID_MiMic|MiMicError.CAID_RemoteMCU);

	MiMicRemoteMcuInterface=function MiMicRemoteMcuInterface(server)
	{
		this._mimic_host=server;
	}

	MiMicRemoteMcuInterface.prototype=
	{
		_mimic_host:null,
		_keep_alive:null,	
		/**
		 * XmlHttpRequestを実行する。
		 @return
		 取得したデータ。
		 @throws
		 取得失敗時(例外発生の場合)
		 */
		_xhrGet:function(i_url,i_async,i_callback)
		{
		    var xhr = window.XDomainRequest ? new XDomainRequest() : new XMLHttpRequest();
		    var prog=0;
		    try{
		    	if(i_async){
		    		xhr.onreadystatechange = function(){
						if (xhr.readyState == 4){
							i_callback(xhr);	
						}
					}
				}
		        xhr.open("GET",i_url,i_async);
		        prog=1;
		        xhr.send(null);	
		        prog=2;
		    } catch (e){
		    	throw new MiMicException(
		    		function(){
		    			switch(prog){
		    			case 1:return EE.HTTP;
		    			}
						return EE.TCP_CONNECT;
					}(),"url="+i_url);
		    }
		    return xhr;
		},
		/**
		 * MiMicの応答から、オンラインチェックを実行します。
		 @param res
		 レスポンスを格納済みのXHRオブジェクト
		 @return
		 オンラインならtrue
		 入力文章から状態が判定できなかった場合、false
		 */
		_isOnline_parseResponse: function(res)
		{
			try{
				if(res.status!=200){
					return false;
				}
				var ret=eval("("+res.responseText+")");
				if(ret.application.split(";")[0]!="MiMicRemoteMCU/1.0a"){
					return false;
				}
			}catch(e){
				return false;
			}
			return true;
		},
		/**
		 * MvmのレスポンスをJSOにする。
		 @return
		 成功時はjson
		 @throws
		 JSONが得られない場合
		 */
		_parseMvmResult:function(i_mvmresult)
		{
			var ret=eval("("+i_mvmresult+")");
			if(ret.version=="MiMicVM/1.0a;Json/1.0"){
				if(ret.result!=undefined){
					if(ret.result!=0x0 || ret.stream!=undefined){
						return ret;
					}
				}
			}
			//なんかうまくいかない。
			throw new MiMicException(EE.NG);
		},
		/**
		 * @see API manual
		 */
		isConnected:function isConnected()
		{
			return this._keep_alive!=null;
		},
		/**
		 * MiMicBCを実行する。
		 実行中は、関数はブロックします。
		 @return
		 Response JSONを返します。
		 {version：JSONバージョン文字列,result:実行結果,stream:[]}
		 Appendix 1. MiMicVM HTTP Interfaceを参照してください。
		 @throws
		 Response Jsonが得られないとき.
		 */
		execBc:function execBc(i_bc)
		{
			try{
				var res=this._xhrGet("http://"+this._mimic_host+"/mvm.api?v=1&bc="+i_bc,false);
				if(res.status!=200){
					throw new MiMicException(EE.HTTP,"i_bc="+i_bc+",XHR.status="+res.status);
				}
				return this._parseMvmResult(res.responseText,false);
			}catch(e){
				throw new MiMicException(e);
			}
		},

		/**
		 * RemoteMCUに接続します。
		 既に接続済みの場合はなにもしません。
		 @param i_callback
		 コールバック関数 f(b)を指定します。非同期
		 @throws
		 接続処理に失敗した場合
		 */
		connect:function connect(i_callback)
		{
			try{
				var _t=this;
				//接続中ならおわり
				if(this._keep_alive!=null){
					return;
				}
				var res=this._xhrGet("http://"+this._mimic_host+"/status.api",false,null);
				function startCheck()
				{
					function checkProc(res)
					{
						//結果の確認
						if(!_t._isOnline_parseResponse(res)){
							if(_t._keep_alive!=null){
								_t._keep_alive=null;
								i_callback(false);
							}
						}else{
							i_callback(true);
							startCheck();
						}
						return;
					}
					_t._keep_alive={
						tid:setTimeout(function(){_t._keep_alive.xhr=_t._xhrGet("http://"+_t._mimic_host+"/status.api",true,checkProc);},5000),
						xhr:null};
				};
				//非同期監視の開始
				startCheck();
			}catch(e){
				throw new MiMicException(e);
			}
			return;
		},
		/**
		 * RemoteMCUから切断します。
		 既に切断済みなら何もしません。この関数は、非同期チェックをキャンセルします。
		 */
		disconnect:function disconnect()
		{
			try{
				if(this._keep_alive!=null){
					clearTimeout(this._keep_alive.tid);
					var xhr=this._keep_alive.xhr;
					this._keep_alive=null;//abortによるコールバックを抑制
					if(xhr!=null){
						xhr.abort();
					}
				}
			}catch(e){
				throw new MiMicException(e);
			}
		}
	}
	
	
	
	
	
}());



