//默认库源代码
import raw.struct;
namespace zeromq
var dll = ..raw.loadDll( $"\.res\libzmq.dll","zeromq.dll")

errno = dll.api("zmq_errno","int()" ,"cdecl" ) 
strerror = dll.api("zmq_strerror","string(int errnum)","cdecl") 
lasterr = function(){
	var e = errno(); 
	if(e)
		return strerror(e),e
}
var lasterr = lasterr;

class pollitem{
    pointer socket; 
    pointer fd; 
    word events;
    word revents;
}  
zmq_poll = dll.api("zmq_poll","int(struct &items, int nitems, int timeout)","cdecl"  ) 
//zmq_device = dll.api("zmq_device","int(int device, pointer insocket,pointer outsocket)" ,"cdecl"  ) 
  
//-------------------------------------------------------------
message = class {
	ctor( data,size,zmq_free_fn,hint){
		this.zmq_msg = zmq_msg_t();
		var dataType = type(data);
		
		//可转换为字符串的数据
		if( data@[["_tostring"]] || (dataType == type.number) ){
			data = tostring(data)
			dataType = type.string;
		}
		
		if( !data || (dataType==type.string) ){
			if( zmq_msg_init(this.zmq_msg._struct_cdata) != 0 )
				error( (lasterr()),2)
			
			if( dataType==type.string ){
				zmq_msg_init_size(this.zmq_msg._struct_cdata,#data)
				::CopyMemory(zmq_msg_data(this.zmq_msg._struct_cdata),data,#data); 
				
			}
			elseif(size){	
				zmq_msg_init_size(this.zmq_msg._struct_cdata,size);
			}
		}
		else {  
			if(zmq_free_fn){ 
				this.zmq_free_fn = zmq_free_fn;
				this.zmq_free_fn_c = ..raw.tocdecl(zmq_free_fn,"void(pointer data,pointer hint )")
			}
			
			if( !( dataType == type.cdata || dataType == type.pointer ) ){
			
				if( data[["_struct"]] ){
					this.zmq_data = ..raw.malloc(data,0)
				}
				else {
					error("缓冲区参数必须是一个字符串,或指针",2)
				}
			}
			else {
				this.zmq_data = data;
			} 
			
			if(size === null){
				size = #(this.zmq_data)
			}
			this.zmq_data_hint = hint;//void gc;
			zmq_msg_init_data(this.zmq_msg._struct_cdata,this.zmq_data,size,this.zmq_free_fn_c ,this.zmq_data_hint)
		} 
		..table.add_gc( this,"close" );
	}; 
	close = function(){
		zmq_msg_close(this.zmq_msg._struct_cdata)
	}
	getData = function(){
		return zmq_msg_data(this.zmq_msg._struct_cdata)
	}
	getSize = function(){
		return zmq_msg_size(this.zmq_msg._struct_cdata)
	} 
	getString = function(){
		return ..raw.tostring( this.getData(),1,this.getSize())
	} 
	copy = function(msg){
		zmq_msg_copy(this.zmq_msg._struct_cdata,msg.zmq_msg._struct_cdata)
		this.zmq_data = msg.zmq_data
		this.zmq_data_hint = msg.zmq_data_hint
		this.zmq_free_fn = msg.zmq_free_fn
	} 
	move = function(msg){
		zmq_msg_move(this.zmq_msg._struct_cdata,msg.zmq_msg._struct_cdata)
		this.zmq_data = msg.zmq_data
		this.zmq_data_hint = msg.zmq_data_hint
		this.zmq_free_fn = msg.zmq_free_fn
	} 
} 
namespace message {  
	zmq_msg_t = ..raw.struct( { 
    	pointer context;
    	BYTE flags;
    	BYTE vsm_size;
    	BYTE vsm_data [0x1E/*_ZMQ_MAX_VSM_SIZE*/];
	} )
	
	zmq_msg_init = dll.api("zmq_msg_init","int(pointer msg)","cdecl"  ) 
	zmq_msg_init_size = dll.api("zmq_msg_init_size","int(pointer msg,int size)","cdecl"  ) 
	zmq_msg_init_data = dll.api("zmq_msg_init_data","int(pointer msg, pointer data, int size, pointer ffn, pointer hint)","cdecl"  ) 
	zmq_msg_close = dll.api("zmq_msg_close","int(pointer msg)","cdecl"  ) 
	
	zmq_msg_move = dll.api("zmq_msg_move","int(pointer dest,pointer src)","cdecl"  )
	zmq_msg_copy = dll.api("zmq_msg_copy","int(pointer dest,pointer src)","cdecl"  )
	zmq_msg_data = dll.api("zmq_msg_data","pointer(pointer msg)","cdecl"  )  
	zmq_msg_size = dll.api("zmq_msg_size","INT(pointer msg)","cdecl"  )  
}

//-------------------------------------------------------------
class socket{
	ctor(handle){
		this.handle = handle;
	}
	setsockopt = function( opt,v ){ 
		return zmq_setsockopt( this.handle,opt,v,..raw.sizeof(v) ) == 0;
	}
	getsockopt = function( opt,v){
		var len = ..raw.sizeof(v)
		var r,len = zmq_getsockopt( this.handle,opt,v,len );
		if(r==0)
			return v,len;
	}
	close = function(){
		var ret = zmq_close( this.handle );
		this.handle = false;
	} 
	bind = function(addr){
		return zmq_bind( this.handle,addr ) == 0; 
	} 
	connect = function(addr){
		return zmq_connect( this.handle,addr ) == 0; 
	}
	sendMsg = function(v,flags=0){
		if(!v[["zmq_msg"]] ){
			var msg = ..zeromq.message(v);
			var ret = zmq_sendmsg( this.handle,msg.zmq_msg._struct_cdata,flags )
			msg.close();
			return 0 == ret;
		}
		else{ 
			return 0 == zmq_sendmsg( this.handle,v.zmq_msg._struct_cdata,flags ); 
		}
	}
	recvMsg = function(v,flags=0){
		if(!v[["zmq_msg"]] ){
			var msg = ..zeromq.message();
			
			if( 0 == zmq_recvmsg( this.handle,msg.zmq_msg._struct_cdata,flags ) ){
				if(! msg.getSize())
					return "";
				var str = ..raw.tostring( msg.getData(),1,msg.getSize())
				msg.close();
				return str;
			}
			else {
				error((..zeromq.lasterr()),2)
			}
			
		}
		else{ 
			return 0 == zmq_recvmsg( this.handle,v.zmq_msg._struct_cdata,flags ); 
		} 
	} 
	send = function(s,len,flags=0){
		if(!len) len = #s;
		if(zmq_send){
			//for 3.0
			return zmq_send(this.handle,s,len,flags) == 0;
		}
		return this.sendMsg(s,flag); //for 3.0
	}
	recv = function(s,len,flags=0){
		if(s){ 
			var t = type(s)
			if( type.pointer == t ){
				if(!len)
					error("请使用第二个参数指定指针指向内存长度",2)
			}
			elseif( type.cdata == t ){
				if(!len) len = #s;
			}
			else{
				error("参数一必须是指针对象",2)
			} 
			
			if(zmq_recv){
				return 0 == zmq_recv(this.handle,s,len,flags) ////for 3.0
			}
			else {
				error("当前使用zeromq2.0,此函数不支持自定义缓冲区",2) 
			}
		}
		else {
			return this.recvMsg( ,flags); 
		} 
	} 
} 
zmq_version = dll.api("zmq_version","void(int &major, int &minor, int &patch)","cdecl"  )
var ver_major,ver_minor,ver_patch = zmq_version(0,0,0)
 
namespace socket{
	zmq_close = dll.api("zmq_close","pointer(pointer s)","cdecl"  ) 
	zmq_setsockopt = dll.api("zmq_setsockopt","int(pointer s, int option, struct optval, int optvallen)","cdecl"  ) 
	zmq_getsockopt = dll.api("zmq_getsockopt","int(pointer s, int option, struct &optval, int &optvallen)","cdecl"  ) 
	
	zmq_bind = dll.api("zmq_bind","int(pointer s, string addr)","cdecl"  ) 
	zmq_connect = dll.api("zmq_connect","int(pointer s, string addr)","cdecl"  ) 
	
	//for 3.0
	if( ver_major > 2 ){
		zmq_sendmsg = dll.api("zmq_sendmsg","int(pointer s, pointer msg, int flags)","cdecl"  ) 
		zmq_recvmsg = dll.api("zmq_recvmsg","int(pointer s, pointer msg, int flags)","cdecl"  ) 
		zmq_send = dll.api("zmq_send","int(pointer s, pointer buf,INT len,int flags)","cdecl"  ) 
		zmq_recv = dll.api("zmq_recv","int(pointer s, pointer buf,INT len,int flags)","cdecl"  ) 
	}
	else {
		zmq_sendmsg = dll.api("zmq_send","int(pointer s, pointer msg, int flags)","cdecl"  ) 
		zmq_recvmsg = dll.api("zmq_recv","int(pointer s, pointer msg, int flags)","cdecl"  ) 
	}
	
   
}
var socket = socket; 
class context {
	ctor(io_threads=1,shareName){ 
		if( shareName ){
			shareName += "{BB61BDEC-97CF-43C0-93BB-96499D9D264F}"
			this.handle = thread.shareHandle.create( shareName,zmq_init,io_threads ) 
		}
		else{
			this.handle = zmq_init(io_threads);
		}
		..table.add_gc( this,"term" ); 
	}
	zmq_socket = function( t = 0/*_ZMQ_PAIR*/ ){
		return socket( zmq_socket( this.handle,t ) );
	}
	zmq_socket_pub = function(){
		return this.zmq_socket(1)
	}
	zmq_socket_sub = function(){
		return this.zmq_socket(2)
	}
	zmq_socket_request = function(){
		return this.zmq_socket(3)
	}
	zmq_socket_reply = function(){
		return this.zmq_socket(4/*_ZMQ_REP*/)
	}
	zmq_socket_dealer = function(){
		return this.zmq_socket(5)
	}
	zmq_socket_router = function(){
		return this.zmq_socket(6)
	}
	zmq_socket_pull = function(){
		return this.zmq_socket(7)
	}
	zmq_socket_push = function(){
		return this.zmq_socket(8)
	}
	zmq_socket_xpub = function(){
		return this.zmq_socket(9)
	}
	zmq_socket_xsub = function(){
		return this.zmq_socket(10)
	}
	term = function(){
		if( this.handle ) {
			var ret;
			if( shareName ){ 
				ret = ( thread.shareHandle.delete( shareName,zmq_term ) == 0 )
			}
			else{
				ret = ( zmq_term( this.handle ) == 0 )  
			}
			this.handle = null;
			return ret;
		}
	}
}
namespace context{
	import thread.shareHandle;
	
	zmq_init = dll.api("zmq_init","pointer(int threads)" ,"cdecl") 
	zmq_term = dll.api("zmq_term","int(pointer context)" ,"cdecl")
	zmq_socket = dll.api("zmq_socket","pointer(pointer context,int type)"  ,"cdecl" ) 
}
content = context;

/**intellisense(zeromq)
lasterr() = 检测最后调用API发生的错误\n如果存在错误则返回两个值:\n错误信息,错误代码
end intellisense**/

 
/**intellisense()
zeromq = 消息支持库\n建议结合protobuf库使用
zeromq.context(__/*IO线程数*/) = 参数可选,默认值为1
?zeromq.context = !zeromq_context.
!zeromq_context.term() = 释放对象\n该函数在线程结束时会作为析构函数自动调用.
!zeromq_context.zmq_socket(__/*协议类型*/) = 创建pair模式socket,可自行配对,\n任何一方都可以做为服务端
!zeromq_context.zmq_socket_pub() = 创建socket,与pub模式配对\n任何一方都可以做为服务端\n!zmq_socket.
!zeromq_context.zmq_socket_sub() = 创建socket,与sub模式配对\n任何一方都可以做为服务端\n!zmq_socket.
!zeromq_context.zmq_socket_request() = 创建socket,与reply模式配对\n任何一方都可以做为服务端\n!zmq_socket.
!zeromq_context.zmq_socket_reply() = 创建socket,与request模式配对\n任何一方都可以做为服务端\n!zmq_socket.
!zeromq_context.zmq_socket_dealer() = 创建socket\n!zmq_socket.
!zeromq_context.zmq_socket_router() = 创建socket\n!zmq_socket.
!zeromq_context.zmq_socket_pull() = 创建socket,与push模式配对\n任何一方都可以做为服务端\n!zmq_socket.
!zeromq_context.zmq_socket_push() = 创建socket,与pull模式配对\n任何一方都可以做为服务端\n!zmq_socket.
!zeromq_context.zmq_socket_xpub() = 创建socket\n!zmq_socket.
!zeromq_context.zmq_socket_xsub() = 创建socket\n!zmq_socket.  
?.zmq_socket = !zmq_socket.
?.zmq_socket_pub = !zmq_socket.
?.zmq_socket_sub = !zmq_socket.
?.zmq_socket_request = !zmq_socket.
?.zmq_socket_reply = !zmq_socket.
?.zmq_socket_dealer = !zmq_socket.
?.zmq_socket_router = !zmq_socket.
?.zmq_socket_pull = !zmq_socket.
?.zmq_socket_push = !zmq_socket.
?.zmq_socket_xpub = !zmq_socket.
?.zmq_socket_xsub = !zmq_socket.

!zmq_socket.setsockopt(.(选项,结构体) = 值必须是一个结构体对象\n成功返回true
!zmq_socket.getsockopt(.(选项,结构体) = 值必须是一个结构体对象\n成功返回更新的结构体对象.
!zmq_socket.close() = 关闭socket 
!zmq_socket.bind("tcp://*:26666__/*地址*/") = 绑定
!zmq_socket.connect("tcp://localhost:26666__/*地址*/") = 连接 
!zmq_socket.sendMsg(.(消息对象,选项) = 发送消息\n如果参数一不是一个消息对象,\n则可转换为字符串的对象,或结构体、CDATA指针等参数可自动转换为临时消息对象发送,\n成功返回true
!zmq_socket.recvMsg(.(消息对象,选项) = 接收消息\n成功返回true,失败返回false.\n如果参数一不是一个消息对象,则创建临时消息对象并尝试返回接收的字符串.
!zmq_socket.send(.(缓冲区,长度,选项) = 发送消息\参数一可以是字符串或指针.\n其他参数可选
!zmq_socket.recv(.(缓冲区,长度,选项) = 接收消息\n参数一可选指定缓冲区指针.\n所有参数可选
zeromq.message(.(缓冲区,缓冲区大小,析构函数,附加指针) = 创建消息对象,所有参数可选\n缓冲区如果是字符串或可转换为字符串的对象,则忽略后续所有参数,\n缓冲区如果为空,则可选使用第二个参数指定长度,其他参数忽略,\n缓冲区如果为pointer指针,则必须使用第二个参数指定长度,\n缓冲区如果是cdata对象,则忽略第二个参数\n缓冲区如果是结构体或数值,则调用raw.malloc转换为cdata对象\n如果指定析构函数,当不再需要消息缓冲区时回调该函数,\n缓冲区指针,附加指针参数将作为回调的实参.
zeromq.message() = 创建消息对象,初始化默认缓冲区\n!zmq_message.
?zeromq.message = !zmq_message.
!zmq_message.close() = 释放消息对象
!zmq_message.getData() = 返回缓冲区指针
!zmq_message.getSize() = 返回缓冲区长度 
!zmq_message.getString() = 以字符串形式返回缓冲区内容
!zmq_message.copy(__/*消息对象*/) = 复制消息缓冲区
!zmq_message.move(__/*消息对象*/) = 移动消息缓冲区
!zmq_message.zmq_msg.context = context
!zmq_message.zmq_msg.flags = flags
!zmq_message.zmq_msg.vsm_size = vsm_size
!zmq_message.zmq_msg.vsm_data = vsm_data
end intellisense**/


 /**intellisense()
_ZMQ_MAX_VSM_SIZE=@0x1E/*_ZMQ_MAX_VSM_SIZE*/
_ZMQ_DELIMITER=@0x1F/*_ZMQ_DELIMITER*/
_ZMQ_VSM=@0x20/*_ZMQ_VSM*/
_ZMQ_MSG_MORE=@1/*_ZMQ_MSG_MORE*/
_ZMQ_MSG_SHARED=@0x80/*_ZMQ_MSG_SHARED*/
_ZMQ_MSG_MASK=@0x81/*_ZMQ_MSG_MASK*/
 
_ZMQ_PAIR=@0/*_ZMQ_PAIR*/
_ZMQ_PUB=@1/*_ZMQ_PUB*/
_ZMQ_SUB=@2/*_ZMQ_SUB*/
_ZMQ_REQ=@3/*_ZMQ_REQ*/
_ZMQ_REP=@4/*_ZMQ_REP*/
_ZMQ_DEALER=@5/*_ZMQ_DEALER*/
_ZMQ_ROUTER=@6/*_ZMQ_ROUTER*/
_ZMQ_PULL=@7/*_ZMQ_PULL*/
_ZMQ_PUSH=@8/*_ZMQ_PUSH*/
_ZMQ_XPUB=@9/*_ZMQ_XPUB*/
_ZMQ_XSUB=@0xA/*_ZMQ_XSUB*/
_ZMQ_HWM=@1/*_ZMQ_HWM*/
_ZMQ_SWAP=@3/*_ZMQ_SWAP*/
_ZMQ_AFFINITY=@4/*_ZMQ_AFFINITY*/
_ZMQ_IDENTITY=@5/*_ZMQ_IDENTITY*/
_ZMQ_SUBSCRIBE=@6/*_ZMQ_SUBSCRIBE*/
_ZMQ_UNSUBSCRIBE=@7/*_ZMQ_UNSUBSCRIBE*/
_ZMQ_RATE=@8/*_ZMQ_RATE*/
_ZMQ_RECOVERY_IVL=@9/*_ZMQ_RECOVERY_IVL*/
_ZMQ_MCAST_LOOP=@0xA/*_ZMQ_MCAST_LOOP*/
_ZMQ_SNDBUF=@0xB/*_ZMQ_SNDBUF*/
_ZMQ_RCVBUF=@0xC/*_ZMQ_RCVBUF*/
_ZMQ_RCVMORE=@0xD/*_ZMQ_RCVMORE*/
_ZMQ_FD=@0xE/*_ZMQ_FD*/
_ZMQ_EVENTS=@0xF/*_ZMQ_EVENTS*/
_ZMQ_TYPE=@0x10/*_ZMQ_TYPE*/
_ZMQ_LINGER=@0x11/*_ZMQ_LINGER*/
_ZMQ_RECONNECT_IVL=@0x12/*_ZMQ_RECONNECT_IVL*/
_ZMQ_BACKLOG=@0x13/*_ZMQ_BACKLOG*/
_ZMQ_RECONNECT_IVL_MAX=@0x15/*_ZMQ_RECONNECT_IVL_MAX*/
_ZMQ_NOBLOCK=@1/*_ZMQ_NOBLOCK*/
_ZMQ_SNDMORE=@2/*_ZMQ_SNDMORE*/
_ZMQ_POLLIN=@1/*_ZMQ_POLLIN*/
_ZMQ_POLLOUT=@2/*_ZMQ_POLLOUT*/
_ZMQ_POLLERR=@4/*_ZMQ_POLLERR*/
_ZMQ_STREAMER=@1/*_ZMQ_STREAMER*/
_ZMQ_FORWARDER=@2/*_ZMQ_FORWARDER*/
_ZMQ_QUEUE=@3/*_ZMQ_QUEUE*/
end intellisense**/

STUDIO_BUILD = /*
import raw.struct;
import thread.shareHandle;
*/