function EventTarget(){
  //事件处理程序数组集合
  this.handlers = {};
}
//自定义事件的原型对象
EventTarget.prototype = {
  //设置原型构造函数链
  constructor: EventTarget,
  //注册给定类型的事件处理程序，
  //type -> 自定义事件类型， handler -> 自定义事件回调函数
  addEvent: function(type, handler){
    //判断事件处理数组是否有该类型事件
    if(typeof this.handlers[type] == 'undefined'){
      this.handlers[type] = [];
    }
    //将处理事件push到事件处理数组里面
    this.handlers[type].push(handler);
  },
  //触发一个事件
  //event -> 为一个js对象，属性中至少包含type属性，
  //因为类型是必须的，其次可以传一些处理函数需要的其他变量参数。（这也是为什么要传js对象的原因）
  fireEvent: function(event){
    //模拟真实事件的event
    if(!event.target){
      event.target = this;
    }
    //判断是否存在该事件类型
    if(this.handlers[event.type] instanceof Array){
      var handlers = this.handlers[event.type];
      //在同一个事件类型下的可能存在多种处理事件，找出本次需要处理的事件
      for(var i = 0; i < handlers.length; i++){
        //执行触发
        handlers[i](event);
      }
    }
  },
  //注销事件
  //type -> 自定义事件类型， handler -> 自定义事件回调函数
  removeEvent: function(type, handler){
    //判断是否存在该事件类型
    if(this.handlers[type] instanceof Array){
      var handlers = this.handlers[type];
      //在同一个事件类型下的可能存在多种处理事件
      for(var i = 0; i < handlers.length; i++){
        //找出本次需要处理的事件下标
        if(handlers[i] == handler){
          break;
        }
      }
      //从事件处理数组里面删除
      handlers.splice(i, 1);
    }
  }
};

function ArrayList(){ 
  this.arr=[], 
  this.size=function(){ 
     return this.arr.length; 
      }, 
   this.add=function(){ 
        if(arguments.length==1){ 
           this.arr.push(arguments[0]); 
           }else if(arguments.length>=2){ 
              var deleteItem=this.arr[arguments[0]]; 
              this.arr.splice(arguments[0],1,arguments[1],deleteItem) 
            } 
    return this; 
   }, 
   this.get=function(index){ 
     return this.arr[index]; 
    }, 
   this.removeIndex=function(index){ 
        this.arr.splice(index,1); 
    }, 
   this.removeObj=function(obj){ 
   this.removeIndex(this.indexOf(obj)); 
   }, 
   this.indexOf=function(obj){ 
      for(var i=0;i<this.arr.length;i++){ 
      if (this.arr[i]===obj) { 
        return i; 
      }; 
    } 
    return -1; 
    }, 
this.isEmpty=function(){ 
return this.arr.length==0; 
}, 
this.clear=function(){ 
this.arr=[]; 
}, 
this.contains=function(obj){ 
return this.indexOf(obj)!=-1; 
} 

}; 

var YOWORFIDReader=
{
	
	createNew:function()
	{
		var yw={};
		yw.Version="";
		yw.ReaderID=1;
		yw.UID=0;
		yw.RequestActive=1;
		yw.KeyMode=0;
		yw.KeyString="FFFFFFFFFFFF";
		yw.KeyStringMode=0;
		yw.Repeat=0;
		yw.BeepOnSuccess=1;
		yw.BeepOnFail=0;
		yw.HaltAfterSuccess=0;
		yw.DesDir=0;
		yw.DesMode=0;
		yw.DesKey="";
		yw.DesKeyMode=0;

		yw.onResult=function(func)
		{
			target.addEvent("Result", func);
		};
		
		var FuncID=0;
		var ws=null;
		var target=null;
		var SocketOpen=false;
		var bExitFromWait=false;
		var SplitChar=String.fromCharCode(65530);
		var Timer;
		var CList;
		var STimer;
		
		var WSonOpen=function(){SocketOpen=true;yw.Ver();};
		var WSonMessage=function(evt)
		{
			
			var t = evt.data.split(SplitChar);
			var resultData = {
				type:"Result",
				FunctionID:parseInt(t[0]),
				Result:parseInt(t[1]),
				UID:parseInt(t[2]),
				ReaderID:parseInt(t[3]),
				CardNo:t[4],
				strData:t[5],
				ValData:parseInt(t[6])
			};
			if(resultData.FunctionID==14)
			{
				if(resultData.Result>=0)yw.Version = resultData.strData;
			}
			if(resultData.FunctionID==15)return;
			if(target!=null)
			{	//alert("Trans");
				target.fireEvent(resultData);
			}
		};
		var WSonClose=function(){SocketOpen=false;};
		var WSonError=function(){SocketOpen=false;};
		var Wait=function(ms)
		{
		   	var now = new Date();
    		var exitTime = now.getTime() + ms;
    		while (true) 
			{
        		if(ws.readyState==1)return true;
				now = new Date();
        		if (now.getTime() > exitTime)return false;
			}
    	};
		var TickOn=function(){yw.Tick();};
		var st=function()
		{
			if(CList.size()>0)
			{
				try
				{
					
					if(!SocketOpen){CList.removeIndex(0);yw.TryConnect();return;}
					ws.send(CList.get(0));
				}
				catch(ex)
				{
					
					
					return;
				}
				CList.removeIndex(0);
			}
		};
		yw.TryConnect=function()
		{
            try 
			{
				
                if ("WebSocket" in window) 
				{
					
					ws = new WebSocket("ws://127.0.0.1:15232/YOWOReaderManage");
                }
                else if("MozWebSocket" in window) 
				{
                    
					ws = new MozWebSocket("ws://127.0.0.1:15232/YOWOReaderManage");
                }
				else
				{	
					return false;}
				
                ws.onopen= WSonOpen;
                ws.onmessage= WSonMessage;
                ws.onclose= WSonClose;
                ws.onerror= WSonError;	
		        if(target==null)target = new EventTarget(); 
				if(Timer==null)Timer =setInterval(TickOn,20000); 
				
				if(CList==null)CList = new ArrayList(); 
				
				if(STimer==null)STimer =setInterval(st,100);  
				     
                return true;
            } 
			catch (ex) 
			{
                 return false;
            }
	  
		};
		
		yw.Disconnect=function(){clearInterval(Timer);clearInterval(STimer);if(ws!=null)ws.close();};
		var s=function(FuncName, FunctionID, ParamStr)
		{
			var PrixStr;

			PrixStr=yw.ReaderID+SplitChar
			      +yw.UID+SplitChar
				  +yw.RequestActive+SplitChar
				  +yw.KeyMode+SplitChar
				  +yw.KeyString+SplitChar
				  +yw.KeyStringMode+SplitChar
				  +yw.Repeat+SplitChar
				  +yw.BeepOnSuccess+SplitChar
				  +yw.BeepOnFail+SplitChar 
				  +yw.HaltAfterSuccess+SplitChar
				  +yw.DesDir+SplitChar
				  +yw.DesMode+SplitChar
				  +yw.DesKey+SplitChar
				  +yw.DesKeyMode+SplitChar
				  +FunctionID+ SplitChar;
			//ws.send(FuncName+":"+PrixStr+ParamStr);
			CList.add(FuncName+":"+PrixStr+ParamStr);
			
		};
		
		
		yw.Connected=function(){return SocketOpen;};

		
		yw.RequestTypeACardNo=function(FormatID, OrderID){s("RequestTypeACardNo",0,FormatID+SplitChar+ OrderID);};
		yw.Ver=function(){s("Ver",14,"");};
		yw.Tick=function(){s("Tick",15,"");};
		return yw;
	}
};