import util.metaProperty
namespace fsys;

class file{
	//构造参数与API函数CreateFile基本一致,请参考API手册
	ctor( path
		,mode = "r"
		,access = 0x80000000/*_GENERIC_READ*/ 
		,sharemode = 0x1/*_FILE_SHARE_READ*/ | 0x2/*_FILE_SHARE_WRITE*/ 
		,creation = 0
		,attrib = 0x80/*_FILE_ATTRIBUTE_NORMAL*/
		,secAttrib
		,template
		){ 
		if(type(path)==type.pointer){
			this.hfile =  path
		}
		else{
			path = ..io.fullpath(path); 
			var access = 0;
			var seekend;
			if( type(mode) == type.string ){
				var f=mode[1];
				if( f='r'# ) {
					creation |= 0x3/*_OPEN_EXISTING*/  
					access |= 0x80000000/*_GENERIC_READ*/;
				}
				else {  
					access |= 0x40000000/*_GENERIC_WRITE*/
					if( f='w'#  ) 
						creation |= 0x2/*_CREATE_ALWAYS*/
					else{
						creation |= 0x4/*_OPEN_ALWAYS*/
						seekend = true;
					}
				}
				
				if(..string.indexAny(mode,"+") )
					access |= 0x10000000/*_GENERIC_ALL*/ 
			}
			else {
				access = mode;
			} 
			
			this.hfile = CreateFile(path,access,sharemode,secAttrib : {} ,creation,attrib ) 
			if( this.hfile == INVALID_HANDLE )
				return null,..lasterr()
				
			if(seekend)
			 	llseek( this.hfile,0 ,0x2/*_SEEK_END*/);
		}
			
		this._gc = ..gcdata(
			_gc = function(){
				this.close();
			} 
		)
	}; 
	@metaProperty
}
 
var push = ..table.push;
namespace file{	
	metaProperty = ..util.metaProperty(
		close = function(){
			if(owner.hfile)
				..raw.closehandle(owner.hfile)
			owner.hfile = null;
		}
		
		seek = function(mode,off=0){
			if(owner.hfile){
				return llseek( owner.hfile,off,seekmode[mode]:0);
			}
		}
		read = function(len){
			if(owner.hfile){ 
				if( type(len)!=type.number){ 
					var bytes = {} 
					var ok,byte = ReadByte(owner.hfile,0,1,0)
					if(!ok)return; 
					while(ok && byte && (byte!='\n'#) ){  
						if(byte!='\r'#)
							push(bytes,byte);  
						ok,byte = ReadByte(owner.hfile,0,1,0)
					}
					return ..string.pack(bytes)
				}
				 
				if(len<0) 
					len = owner.size -len + 1; 
					
				var ok,str,numBytes = ReadFile( owner.hfile,len,len,0);
				if(ok)
					return ..string.left(str,numBytes); 
				
			}
		}
		write = function(str){
			if(owner.hfile){
				str = tostring(str);
				var ok,str,numBytes = WriteFile( owner.hfile,str,#str,0);
				if(ok)
					return numBytes;
			}
		}
		flush = function(){
			if(owner.hfile){
				return FlushFileBuffers( owner.hfile );
			}
		}
		
		setFileTimes = function(tm){
			if(! owner.hfile)
				return;
			var creation,access,write = tm.creation,tm.access,tm.write
			if( !(..time.istime(creation) 
				&&  ..time.istime(access)
				&&  ..time.istime(write)
				) ){
				error('参数必须是一个table对象\n并且creation,access,write成员必须是合法的time对象',2)
			}
			var ok;
			ok,creation = SystemTimeToFileTime(creation,0)
			ok,access = SystemTimeToFileTime(access,0)
			ok,write = SystemTimeToFileTime(write,0)
			var ok = SetFileTime( owner.hfile,creation,access,write)
			return ok;
			
		}
		getFileTimes = function(){
			if(! owner.hfile)
				return;
				
			var ok,creation,access,write = GetFileTime(owner.hfile,0,0,0) 
			ok,,creation = FileTimeToSystemTime(creation,..time() )
			ok,,access = FileTimeToSystemTime(access,..time() )
			ok,,write = FileTimeToSystemTime(write,..time() )
			return  {creation=creation;access=access;write=write};
			
		}
		
		size ={
			_get = function(){
				if(owner.hfile){
					var len,high = GetFileSize(owner.hfile,0) 
					return len;
				}
			} 
		}
		handle = {
			_get = function(){
				return owner.hfile;
			} 
		}
		
		
	)
	INVALID_HANDLE = topointer(0xFFFFFFFF)
	CreateFile = ::Kernel32.api("CreateFileA","pointer(string path,int access,int sharemode,
	struct secAttrib,int creationDisposition,int attrib,pointer template)")
	llseek = ::Kernel32.api("_llseek","int(pointer file,int off,int mode)") 
	ReadByte = ::Kernel32.api("ReadFile","int(pointer file,BYTE& buffer,INT bufferSize,INT& numBytes,pointer overlapped)") 
	ReadFile = ::Kernel32.api("ReadFile","int(pointer file,string& buffer,INT bufferSize,INT& numBytes,pointer overlapped)") 
	WriteFile = ::Kernel32.api("WriteFile","int(pointer file,string buffer,INT bufferSize,INT& numBytes,pointer lpOverlapped)")
	GetFileSize = ::Kernel32.api("GetFileSize","int(pointer file,int& high)")
	FlushFileBuffers = ::Kernel32.api("FlushFileBuffers","int(pointer file)")
	
	GetFileTime = ::Kernel32.api("GetFileTime","int(pointer file,long& creation,long& access,long& write)")
	SetFileTime = ::Kernel32.api("SetFileTime","int(pointer file,long& creation,long& access,long& write)")
	FileTimeToSystemTime = ::Kernel32.api("FileTimeToSystemTime","int(long &filetime,struct& time)")
	SystemTimeToFileTime = ::Kernel32.api("SystemTimeToFileTime","int(struct time,long& filetime)") 
	//GetFileType = ::Kernel32.api("GetFileType","int(int hFile)")
	
	seekmode = {
	 	["cur"] = 0x1/*_FILE_CURRENT*/;
	 	["end"] = 0x2/*_FILE_END*/;
	 	["set"] = 0x0/*_FILE_BEGIN*/;
	}
}
 

/**intellisense() 
fsys.file(__/*文件句柄*/) = 可以指定文件、管道等句柄
fsys.file("__/*文件路径*/") = 只读模式打开,文件必须存在\n更多参数参考源码
fsys.file("__/*文件路径*/","r+") = 读写模式打开,文件必须存在\n更多参数参考源码
fsys.file("__/*文件路径*/","w") = 只写模式打开,创建新文件清空原文件\n更多参数参考源码
fsys.file("__/*文件路径*/","w+") = 读写模式打开,创建新文件清空原文件\n更多参数参考源码
fsys.file("__/*文件路径*/","a") = 只写追加模式打开,创建新文件保留原文件\n更多参数参考源码
fsys.file("__/*文件路径*/","a+") = 读写追加模式打开,创建新文件保留原文件\n更多参数参考源码
!fsysfile.read(__/*字节数*/) = 读取指定长度的字节 
!fsysfile.read() = 读取一行文本\n返回文本不包含回车换行符
!fsysfile.read(-1) = 读取所有内容到文件尾部
!fsysfile.write(__/*字符串*/) = 写入字符串
!fsysfile.setFileTimes(__) = 修改创建时间、最后修改时间、最后访问时间\n参数必须请使用getFileTimes()函数返回的对象
!fsysfile.getFileTimes() = 返回创建时间、最后修改时间、最后访问时间
!fsysfile.seek("end") = 移动指针至结束处
!fsysfile.seek("end",__) = 移动至相对结束处的指定偏移量
!fsysfile.seek() = 得到当前位置
!fsysfile.seek("cur",__) = 移动至相对当前位置的指定偏移量
!fsysfile.seek("set") = 移动指针到开始
!fsysfile.seek("set",__) = 移动至相对开始处的指定偏移量
!fsysfile.path = 返回文件路径
!fsysfile.flush() = 刷新缓冲区
!fsysfile.close() = 关闭文件句柄
!fsysfile.size = 返回文件大小
!fsysfile.handle = 返回文件句柄
?fsys.file = !fsysfile.
!filetimes.creation = !time.
!filetimes.access = !time.
!filetimes.write = !time.
?.getFileTimes = !filetimes.
end intellisense**/
