namespace labs.httpdown;

import inet;
import string;

::Kernel32 := ..raw.loadDll("kernel32.dll");
::GetTickCount = Kernel32.api("GetTickCount", "INT()");
::CreateFile = Kernel32.api("CreateFileA", "int(string, INT, INT, int, INT, INT, int)");
::WriteFile = Kernel32.api("WriteFile", "int(int, string, int, int&, int)" );
::CloseHandle = Kernel32.api("CloseHandle", "int(int)");

::Wininet := ..raw.loadDll("wininet.dll");
::InternetGetConnectedState = Wininet.api("InternetGetConnectedState", "int(int&, int)");

::Shlwapi := ..raw.loadDll("Shlwapi.dll");
//::StrFormatByteSize = Shlwapi.api("StrFormatByteSizeA", "string(int, string&, INT)" );

_INTERNET_CONNECTION_PROXY		= 0x00000004;
_INTERNET_OPEN_TYPE_DIRECT		= 0x00000001;
_INTERNET_FLAG_NO_CACHE_WRITE	= 0x04000000;
_INTERNET_FLAG_PRAGMA_NOCACHE	= 0x00000100;
_INTERNET_FLAG_RELOAD			= 0x80000000;
_HTTP_QUERY_CONTENT_DESCRIPTION = 0x00000004;
_HTTP_QUERY_CONTENT_LENGTH		= 0x00000005;

down = class {
	ctor (url, saveTo)
	{
		if (url && saveTo)
		{
			this.url = url;
			this.saveTo = saveTo;
		}
	}
	start = function (callback)
	{
		if (type(callback) != type.function)
			return false, "回调函数错误";
		
		var re, dwFlag = ::InternetGetConnectedState(0, 0);
		var strAgent = "Agent" + tostring(::GetTickCount());
		var hOpen;
		if (dwFlag & _INTERNET_CONNECTION_PROXY == 0)
			hOpen = ::InternetOpen(strAgent, _INTERNET_OPEN_TYPE_DIRECT, , , 0);
		else
			hOpen = ::InternetOpen(strAgent, 0x0/*_INTERNET_OPEN_TYPE_PRECONFIG*/, , , 0);
		if (!hOpen)
			return false, "无法建立 Internet 连接";
		var szHead = 'Accept: */*\r\nAccept-Language: zh-cn\r\nAccept-Encoding: gzip, deflate\r\n';
		szHead += 'User-Agent: Mozilla/4.0(compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322)';
		var hConnect = ::InternetOpenUrl(hOpen, 
										 this.url, 
										 szHead, 
										 #szHead, 
										 _INTERNET_FLAG_NO_CACHE_WRITE | _INTERNET_FLAG_PRAGMA_NOCACHE | _INTERNET_FLAG_RELOAD, 
										 0);
		if (!hConnect)
			return false, "无法打开网址";
		var hFile = ::CreateFile(this.saveTo, 0x40000000/*_GENERIC_WRITE*/, 0x1/*_FILE_SHARE_READ*/, 0, 0x2/*_CREATE_ALWAYS*/, 0x80/*_FILE_ATTRIBUTE_NORMAL*/, 0);
		if (hFile == -1)
			return false, "无法打开文件";
		var dwBytesReaded, dwBytesTotal, dwSizeOfRq = 0, 0, 4;
		re, dwBytesTotal = ::HttpQueryInfoNumber(hConnect, 0x20000005, dwBytesReaded, dwSizeOfRq, 0);
		if (re = 0)
			dwBytesReaded = 0;
		var tStart = ::GetTickCount();
		var dwSize = 0;
		var szTemp;
		do
		{
			re, szTemp, dwSize = ::InternetReadFile(hConnect, 15 * 1024, 10 * 1024, dwSize); /* 一次读取 15kb */
			if (!re)
				return false, "读取数据失败";
			if (dwSize)
			{
				szTemp = ..string.left(szTemp, dwSize);
				::WriteFile(hFile, szTemp, dwSize, 0, 0);
				dwBytesReaded += dwSize;
				callback(dwBytesReaded, dwBytesTotal, ::GetTickCount() - tStart);
			}
		} while(dwSize)
		::CloseHandle(hFile);
		::InternetCloseHandle(hOpen);
		return true, null; 
	}
	formatSize = function (bytes)
	{
		var re, sSize;
		re, sSize = ::StrFormatByteSize(bytes, 128, 128);
		return ..string.str(sSize);
	}
}

/**intellisense()
down("下载网址", "保存路径") = 进度下载网络上的文件
start(function (br, bt, nTime)) = 开始下载文件，回调函数有三个参数，第一个为已下载的字节数，第二个为文件总字节数，第三个为已下载时间（毫秒）
formatSize(字节) = 格式化字节，并带上单位、转化为文本型
end intellisense**/