//cookies 文件
import inet.url;
namespace fsys;

class cookies{  
	@_meta;
}

namespace cookies{
    
	_meta = {
		_tostring = function(){
			return owner.stringify();
		};
	};
	_meta._get ={
		
    	mixin = function( lst ){
    		..table.assign(owner,lst);
    	}; 
    	push = function(cookie){  
    		
        	if(cookie.domain){
        		var domain = owner[cookie.domain]
        		if(!domain){
        			domain = { @{_readonly=false} };
        			owner[cookie.domain] = domain;
        		}
        		
        		if(!domain[cookie.name])domain[cookie.name] = cookie;
        		else {
        			..table.assign(domain[cookie.name],cookie);
        			return;
        		}
        	}
        	
        	..table.push(owner,cookie);
    	}; 
		parseLine = function(line){
			var httpOnly;
			if(line[1]=='#'# ){
				if( ..string.startWith(line,"#HttpOnly_") ){
            		line = ..string.slice(line,11);
            		httpOnly = true;
        		}
        		else {
        			if(!owner.header) owner.header = line;
        			else owner.header = owner.header + '\r\n' + line;
        			return;
        		} 
			} 
			
			var arr = ..string.split(line,'\t',7);
			if( #arr != 7 ) return;
			
        	var cookie ={
            	domain = arr[1];
            	flag  = arr[2] == "TRUE";
            	path = arr[3];
            	secure = arr[4] == "TRUE";
            	expires = arr[5] !="0" ? ..time.gmt( (tonumber(arr[5])) ) :null;
            	name = arr[6];
            	value = arr[7];
            	httpOnly = httpOnly;
        	}
        	
        	owner.push(cookie);
        	return cookie;
		};
		parse = function(str){
			owner.clear();
			for line in ..string.lines(str) { 
				owner.parseLine(line);
			}
			return owner;
		};
		clear = function(){
			for(i=#owner;1;-1){
				..table.remove(owner,i);
			}
			for(k,v in owner){
				if( type(v) != type.function ) owner[k] = null;
			};	
		};
		load = function(path){
			owner.clear();
			for(line in ..io.lines(path) ){
				owner.parseLine(line);
			} 
		};
		stringifySetCookieLine = function(i,head){
			var v = i;
			if( type(v) == type.number ) v = owner[i];
			if( ! (v && v.name) ) return "";
			
			if(!head) head =  "Set-Cookie: ";

			if( v.value === null ){
				return head + v.name + "=deleted; expires=" + tostring(  ..time.gmt(1) ) );  
			}
			
			v.value = tostring(v.value);
			if( ..string.find(v.value,":") ) v.value =  ..string.hex(v.value,"%",'\x80');
			var s = { v.value };
			
			if(v.expires && ..time.istime(v.expires)  ){ 
				..table.push(s,"expires=" + tostring( ..time.gmt(v.expires) ) );
			} 
			
			if(v.domain) ..table.push(s,"domain=" + v.domain );
			..table.push(s,"path=" + (v.path:"/") );
			if(v.httpOnly ) ..table.push(s,"HttpOnly");
			if(v.secure ) ..table.push(s,"Secure");
			
			return head + v.name + "=" + ..string.join(s,"; ");  
		};
		stringifyLine = function(i){
			var cookie = i;
			if( type(cookie) == type.number ) cookie = owner[i];
			if(!cookie) return;
			
			var s = {};
			if( cookie.httpOnly ) ..table.push(s,"#HttpOnly_");
			..table.push(s,cookie.domain,'\t');
			..table.push(s,cookie.flag?"TRUE":"FALSE",'\t');
			..table.push(s,cookie.path,'\t');
			..table.push(s,cookie.secure?"TRUE":"FALSE",'\t');
			..table.push(s,cookie.expires ? tostring(tonumber(cookie.expires)) : 0,'\t');
			..table.push(s,cookie.name,'\t');
			..table.push(s,cookie.value);
			return ..string.join(s);
		};
		stringify = function(){
			var s = {};
			for(i=1;#owner;1){
				..table.push( s,owner.stringifyLine(i) );
			}
			return ..string.join(s,'\r\n');
		};
		save = function(path){
			var file = ..io.open(path,"w+b");
			if(!owner.header)owner.header=/*
# Netscape HTTP Cookie File 
# This file was generated by aardio! Edit at your own risk.
*/
			file.write(owner.header,'\r\n\r\n');
			for(i=1;#owner;1){
				file.write( owner.stringifyLine(i),'\r\n' );
			} 
			file.close();
		};	
		getCookies = function(domain,path){
			if( type(domain)!= type.string ) error("请指定域名参数",2);
			
			var lst = owner.get(domain,path);
			var s  = {};
			for(k,v in lst){
				..table.push(s,k + "=" + v.value);
			} 
			
			if(#s) return ..string.join(s,"; ");
		};
		get = function(domain,path){
			if( type(domain)!= type.string ) error("请指定域名参数",2);
			
			if(!#path) {
				if(..inet.url.is(domain,0)){
					var uri = ..inet.url.split(domain);
					domain = uri.host;
					path = uri.path;
					if( type(domain)!= type.string ) error("无效的网址参数",2);
				}
				
				if(!#path) path = "/";
			}
			if(domain[1]!='.'#) domain = "." + domain;
			
			var s = {@{_readonly=false}};
			for(i=1;#owner;1){
				if( type(owner[i]) != type.table) continue;
				if(..string.endWith(domain,owner[i].domain,true)){
					if( ..string.startWith(path,owner[i].path,true) ){
						var pre =  s[owner[i].name];
						if(!pre || (#pre.path < #owner[i].path) ) s[owner[i].name] = owner[i];
					}
				}
			}
			return s;
			
		};	
	}
}

/**intellisense()
fsys.cookies = netscape/curl cookie文件格式解析器
fsys.cookies() = 创建netscape/curl cookie文件格式解析器\n此对象包含解析后的cookie数组,并包含以域名为键的cookie数组值,\n\n每个cookie的字段含义如下：\ndomain = 域名\nflag = 给定域的所有计算机是否可访问该值\npath = cookie路径\nsecure = cookie是否仅适用于https连接\nexpires = 过期时间,\n这是一个time.gmt对象,RFC1123格式的时间值\n会话cookie这个字段的值为null\nname = cookie名字\nvalue = cookie的值\n!stdfsyscookies.
end intellisense**/

/**intellisense(!stdfsyscookies)
header = cookie文件头描述,一般不用指定
parseLine(__) = 解析一行cookie文本,参数指定字符串\n此函数 不会 清空之前加载的cookie
push( =  更新或添加cookie,参数应当是一个表,\n如果指定域下已经存在同名cookie，则更新cookie\n否则添加cookie
push(cookie) = @.push( {\n    domain = domain;\n    flag  = flag;\n    path = path;\n    secure = secure;\n    expires = ..time.gmt() ;\n    name = name;\n    value = value;\n    httpOnly = httpOnly;\n})
parse(__) = 解析多行cookie文本,参数指定字符串\n此函数会清空之前加载的cookie
load(__) = 自文件加载cookie，参数指定类型\n此函数会清空之前加载的cookie
stringifySetCookieLine(__) = cookie转换为HTTP Set-Cookie响应头格式,\n参数指定索引,也可以直接传入一个cookie对象,\n可选使用参数指定前缀，不指定时默认为"Set-Cookie: ",\n成功返回非空字符串
stringifyLine(__) = cookie转换为字符串，参数指定索引\n也可以直接传入一个cookie对象
stringify() = 所有cooke转换为字符串
save(__) = 保存到文件,参数指定文件路径
getCookies(__) =  返回键值对组成的cookies字符串,可用于http请求头,失败返回null,\n可用参数@1指定网址,也可以用参数@1指定域名,参数@2指定网站路径\n不指定网站路径时默认为"/"
get(__) = 返回指定网址或域名的cookies,\n可用参数@1指定网址,也可以用参数@1指定域名,参数@2指定网站路径\n不指定网站路径时默认为"/"
mixin(_) = 混入兼容cookie数组
clear() = 清空已加载的cookie
end intellisense**/