//message 消息对象
namespace protobuf.parser

class field { 
	fieldIndex = fieldIndex ; 
	varName = varName; 
	fullTypeName = fullTypeName;
	default = defValue;   
}

class message{
	ctor( ){
		this.fields = {}
		this.subMessage = {}
		this.subEnum = {}
		this.parent = null; 
	};
	push = function( field ){ 
		..table.push( this.fields, field );
	} 
	nameSpace = "";
	
	findType = function(name,member){
		 
		if(!name)
			error("参数不能为null",2)
			
		var msg = this;
		do{ 
			if( msg.subMessage[name] || msg.subEnum[name] ){
				
				var t = combineNamespace( combineNamespace( msg.nameSpace,msg.name) ,name);
				if(member)
					t = combineNamespace( t,member)
					 
				return ".." + t;
			}
		
			msg = msg.parent
		}while(msg) 
		 
		error("Error message type:" + name,2)
		 
	} 
	
	serialize = function(indent=""){
		var clsNamespace = template.classNamespace;
		var clsDefine = template.classDefine;
		clsDefine = ..string.replace(clsDefine,"@<%CLASS_NAME%>",this.name );
		clsNamespace = ..string.replace(clsNamespace,"@<%CLASS_NAME%>",this.name );
		clsDefine = indent ++ ..string.replace(clsDefine,"\n",'\n'+indent);
		clsNamespace = indent ++ ..string.replace(clsNamespace,"\n",'\n'+indent);
		
		var tabSubMessage = {};
		for(k,message in this.subMessage){   
			..table.push(tabSubMessage,message.serialize( indent + "	" ) ); 
		} 
		
		var strSubMessage = "";
		if( #tabSubMessage ){
			strSubMessage =  ..string.join(tabSubMessage,'\r\n'); 
			
		}
		
		clsNamespace = ..string.replace(clsNamespace,"@<%INNER_CLASS%>",strSubMessage );
		
		
		var tabEnum = {};
		for(name,body in this.subEnum){
			var enum = template.enum;
			enum = ..string.replace(enum,"@<%ENUM_NAME%>",name );
			enum = ..string.replace(enum,"@<%ENUM_BODY%>",body ); 
			..table.push(tabEnum,enum ); 
		} 
		var strSubEnum = "";
		if( #tabEnum ){
			strSubEnum = ..string.join(tabEnum,'\r\n');
			strSubEnum = indent + "	" + ..string.replace(strSubEnum,"\n",'\n'+indent++"	"); 
		}
		clsNamespace = ..string.replace(clsNamespace,"@<%INNER_ENUM%>",strSubEnum );
		
		var tabField = {};
		var tabMetaField = {};
		for(i=1;#this.fields;1){
			 
			var field = this.fields[i]
			
			var strMeta
			var str = template.field;
			
			if(field.repeated){
				strMeta = template.fieldArrayMeta;
				str = ..string.replace(str,"@<%FIELD_VALUE%>","{ is_array = true; }");
			}
			elseif(..string.endWith(field.varName,"time",true) ){
				strMeta = template.fieldTimeMeta;
				str = ..string.replace(str,"@<%FIELD_VALUE%>",field.default===null?"null":field.default);
			}
			else{
				strMeta = template.fieldMeta;
				str = ..string.replace(str,"@<%FIELD_VALUE%>",field.default===null?"null":field.default);
			}
			
			str = ..string.replace(str,"@<%FIELD_IDX%>",field.fieldIndex );
			str = ..string.replace(str,"@<%FIELD_TYPE%>",field.fullTypeName );
			strMeta = ..string.replace(strMeta,"@<%FIELD_IDX%>",field.fieldIndex );
			strMeta = ..string.replace(strMeta,"@<%FIELD_NAME%>",field.varName );
			
			..table.push(tabField,str); 
			..table.push(tabMetaField,strMeta); 
		}
		
		if( #tabField ){
			var strTabField=  ..string.join(tabField,'\r\n'); 
			strTabField = indent + "	"+ ..string.replace(strTabField,"\n",'\n'+indent++"	"); 
			clsDefine = ..string.replace(clsDefine,"@<%FIELD_CTOR_TYPE_VALUE%>",strTabField );
			
			var strMetaField  = ..string.join(tabMetaField,'\r\n');
			strMetaField = indent ++ ..string.replace(strMetaField,"\n",'\n'+indent++"	") ; 
			clsNamespace = ..string.replace(clsNamespace,"@<%FIELD_FUNC%>",strMetaField ); 
		}
		
		intellisense = '/**intelli' + 'sense()\r\n'
		var intellPath = combineNamespace( this.nameSpace,this.name) 
		intellCls = ..string.replace( intellPath,"@.","_");
		var intellClsDot = "!" + intellCls + '.'
		intellisense ++= intellPath + " = " + 'protobuf消息对象\r\n'
		intellisense ++= intellPath + "() = " + '创建protobuf消息对象\r\n'
		intellisense ++= "?" + intellPath + " = " + intellClsDot + '\r\n' 
		intellisense ++= intellClsDot  + 'parseFromString(__/*字符串*/) = 二进制数据反序列化到消息对象\n此函数自动清空所有数组值,但不会重置其他非数组字段值.\n因此应对新创建的对象调用此函数.\r\n'
		intellisense ++= intellClsDot  + 'serializeToString() = 序列化消息对象,返回二进制字符串\r\n'
		for(i=1;#this.fields;1){ 
			var field = this.fields[i]
			var vtype = ..string.trim(field.fullTypeName,".")
			var scalarType = ..string.startWith(vtype,"protobuf.type.")
			var inellCustomType = ..string.replace( vtype,"@.","_")
			if(field.repeated){ 
				intellisense ++= intellClsDot ++ field.varName + "Length = " + '返回数组长度\r\n';
				intellisense ++= intellClsDot ++ field.varName + "Array = " + '返回原始数组\r\n';
				if( !scalarType ){
					intellisense ++= intellClsDot + field.varName + "() = " + "!" + inellCustomType + '.\r\n';  
				}
				intellisense = ..string.concat( intellisense ,  intellClsDot , field.varName 
						, "(1__/*索引*/) = "  , field.comment ,field.comment ? "\n" , vtype , '\r\n' );
			}
			else{ 
				intellisense = ..string.concat( intellisense ,  intellClsDot , field.varName 
						, " = "  , field.comment ,field.comment ? "\n" ,scalarType? vtype :  ("!" + inellCustomType + ".") , '\r\n' ); 
			}
		} 
		intellisense ++= "end intell" + "isense**/";
		
		return clsDefine + '\r\n' + clsNamespace + '\r\n' + intellisense;
		 
	}
	
}

namespace message{
    scalar_types = {
    	double = '..protobuf.type.int';
    	float = '..protobuf.type.int';
    	int32 = '..protobuf.type.int';
    	int64 = '..protobuf.type.int';
        uint32 = '..protobuf.type.signedInt';
        uint64 = '..protobuf.type.signedInt';
        sint32 = '..protobuf.type.signedInt';
        sint64 = '..protobuf.type.signedInt';
        fixed32 = '..protobuf.type.int'; 
        fixed64 = '..protobuf.type.int';
        sfixed32 = '..protobuf.type.signedInt';
        sfixed64 = '..protobuf.type.signedInt';
        bool = '..protobuf.type.bool';
        string = '..protobuf.type.string';
        bytes =  '..protobuf.type.bytes'
    };
    
    combineNamespace = function(path,name){
    	if(!name)
    		error("name 不能为空",2)
    	return ..string.trim(
    		..string.format("%s.%s",path,name )
    		,"."
    	)
    }
    
    namespace template{
    	
    	classDefine = /*
class <%CLASS_NAME%> {
	ctor(reader){
		this = ..protobuf.message(reader) 
		
<%FIELD_CTOR_TYPE_VALUE%>  
	} 
	@_metaProperty ;
}
*/
    	classNamespace = /*
namespace <%CLASS_NAME%> {
<%INNER_CLASS%>  
<%INNER_ENUM%>   
	_metaProperty  = ..util.metaProperty( 
		_tostring = function(){
			return owner.serializeToString();
		};
		
<%FIELD_FUNC%>   
	)
}
*/

		enum = /*
class <%ENUM_NAME%>  {
	ctor(...){
		this = ..protobuf.type.enum(...)
	}
}   
namespace <%ENUM_NAME%> <%ENUM_BODY%>
*/	

		field = /*
	this.fields[<%FIELD_IDX%>] = "<%FIELD_TYPE%>";
	this.values[<%FIELD_IDX%>] = <%FIELD_VALUE%>;
 */
  
  		fieldMeta = /*
	<%FIELD_NAME%> = {
		_get = function(){ 
			return owner._get_value(<%FIELD_IDX%>);
		}
		_set = function( value ){
			return owner._set_value(<%FIELD_IDX%>, value);
		} 	
	}; 
 */
 
   		fieldTimeMeta = /*
	<%FIELD_NAME%> = {
		_get = function(){ 
			return owner._get_time_value(<%FIELD_IDX%>,"%Y-%m-%d %H:%M:%S");
		}
		_set = function( value ){
			return owner._set_time_value(<%FIELD_IDX%>, value,"%Y-%m-%d %H:%M:%S");
		} 	
	}; 
 */
   		fieldArrayMeta = /*
	<%FIELD_NAME%> =  function(index){ 
		return owner._get_arr_value(<%FIELD_IDX%>,index); 
	};
	<%FIELD_NAME%>Length = {
		_get = function(){ 
				return owner._get_arr_size(<%FIELD_IDX%>);
		} 	
	}; 
	<%FIELD_NAME%>Array = {
		_get = function(){ 
				return owner._get_arr(<%FIELD_IDX%>);
		} 	
	};  
 */
    }
}
 

/**intellisense()
?protobuf.parser.field = !protobufparserfield.
!protobufparserfield.index = 字段索引
!protobufparserfield.varName = 字段名称
!protobufparserfield.fullTypeName = 字段类型名
!protobufparserfield.defValue = 字段默认值
!protobufparserfield.isArray =  是否数组
!protobufparserfield.isOptional = 是否可选
?protobuf.parser.field = !protobufparserfield.
end intellisense**/