#include-once
#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <InetConstants.au3>
#include <StaticConstants.au3>
#include <WinAPIMisc.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>

; #INDEX# ======================================================================
; Title .........: _DownloadWithProgress
; AutoIt Version : 3.3.12.0 oder höher
; Date ..........: 19.09.2021
; Language ......: Deutsch/English
; Description ...: Download einer Datei aus dem Internet mit Progressbar und zusätzlichen Infos
; Author(s) .....: Oscar + UEZ (www.autoit.de)
;===============================================================================

;===============================================================================
; Function Name:   _DownloadWithProgress($sURL[, $sDownloadDir][, $sTitle][, $iLeft][, $iTop][, $hParent])
; Description:     Download einer Datei aus dem Internet mit Progressbar und zusätzlichen Infos
; Parameter(s):    $sURL = die komplette URL zu der Datei
;                  $sDownloadDir = das Verzeichnis, in das die Datei heruntergeladen werden soll (muss existieren!)
;                  $iLanguage = Language-Code (1031 = deutsch, 1033 = english)
;                  $sTitle = Fenstertitel
;                  $iLeft und $iTop = Position für das Fenster
;                  $hParent = Handle zum Parentfenster
; Requirement(s):  includes (siehe oben) und AutoIt-Version v3.3.12.0 oder höher
; Return Value(s): im Fehlerfall wird @error gesetzt:
;                  @error = 1 -> $sURL ist ein Leerstring
;                  @error = 2 -> das Downloadverzeichnis existiert nicht
;                  @error = 3 -> der Download wurde vom Benutzer abgebrochen
;                  @error = 4 -> während des Downloads ist ein Fehler aufgetreten
;                  @error = 5 -> der Speicherplatz auf dem Datenträger reicht nicht
;                  @error = 6 -> die Dateigröße konnte nicht ermittelt werden
; Author(s):       Oscar + UEZ (www.autoit.de)
;===============================================================================
Func _DownloadWithProgress($sURL, $sDownloadDir = @ScriptDir, $iLanguage = Default, $sTitle = 'AutoIt-Download-Tool', $iLeft = -1, $iTop = -1, $hParent = 0)
	If $sURL = '' Then Return SetError(1, 0, 0)
	If StringRight($sDownloadDir, 1) <> '\' Then $sDownloadDir &= '\'
	If Not FileExists($sDownloadDir) Then Return SetError(2, 0, 0)
	Local $sPrevUserAgent = HttpSetUserAgent('Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0;  rv:11.0) like Gecko')
	Local $iOldEventMode = Opt('GUIOnEventMode', 0)
	_GDIPlus_Startup()
	If IsHWnd($hParent) Then
		GUISetState(@SW_DISABLE, $hParent)
	Else
		TraySetState(2) ; TrayIcon verstecken, wenn kein Parent angegeben wurde
	EndIf
	Local $iDownloadSize = 0, $aDownloadData, $iTimer = TimerInit(), $iError = 0, $iPercent = 0, $hDownload
	Local $iDownSpeedTimer = TimerInit(), $iDownSpeed = 0, $iRestTime = 0, $iOldTime = 0, $sDownloadFile = ''
	If $iLanguage = Default Or $iLanguage = -1 Then $iLanguage = Dec(@OSLang)
	Local $aLanguage = _DWP_GetLanguage($iLanguage)
	Local $hGui = GUICreate($sTitle, 400, 240, $iLeft, $iTop, -1, -1, $hParent)
	GUISetIcon('shell32.dll', 18, $hGui)
	GUISetFont(10, 400, 0, 'Arial', $hGui, 5)
	GUISetBkColor(0xCCCCCC, $hGui)
	GUICtrlCreateGroup('', 10, 5, 380, 165)
	GUICtrlCreateLabel(StringFormat('%s "%s"', $aLanguage[0], StringRegExpReplace($sURL, '.+\/(.+)', '$1')), 25, 22, 350, 20)
	GUICtrlCreateLabel($aLanguage[1], 25, 50, 170, 16)
	Local $idDownloadSize = GUICtrlCreateLabel('', 200, 50, 170, 16)
	GUICtrlCreateLabel($aLanguage[2], 25, 70, 170, 16)
	Local $idDownloadSpeed = GUICtrlCreateLabel('', 200, 70, 170, 16)
	GUICtrlCreateLabel($aLanguage[3], 25, 90, 170, 16)
	Local $idDownloadTime = GUICtrlCreateLabel('', 200, 90, 170, 16)
	GUICtrlCreateLabel($aLanguage[4], 25, 110, 170, 16)
	Local $idRestTime = GUICtrlCreateLabel('', 200, 110, 170, 16)
	Local $iW = 360, $iH = 24, $iBGColor = 0xFEFEFE, $hHBmp_BG, $hB, $iSleep = TimerInit()
	Local $idProgress = GUICtrlCreatePic('', 20, 138, $iW, $iH)
	Local $aColors[7][2] = [ _
			[0xFFEE5F5B, 0xFFF07673], _
			[0xFFABCC04, 0xFFBBD636], _
			[0xFF78CCEE, 0xFF93D6F1], _
			[0xFFFFBB58, 0xFFFFC97A], _
			[0xFFFF6677, 0xFFFF8795], _
			[0xFF78CCEE, 0xFFFFC97A], _
			[0xFF78CCEE, 0xFFE8E5D9]]
	$hHBmp_BG = _GDIPlus_StripProgressbar($iPercent, $iW, $iH, 0xFF000000 + $iBGColor, $aColors[1][0], $aColors[1][1], '')
	$hB = GUICtrlSendMsg($idProgress, 0x0172, $IMAGE_BITMAP, $hHBmp_BG)
	If $hB Then _WinAPI_DeleteObject($hB)
	_WinAPI_DeleteObject($hHBmp_BG)
	GUICtrlCreateGroup('', -99, -99, 1, 1)
	Local $idCancelButton = GUICtrlCreateButton($aLanguage[5], 100, 180, 180, 28)
	Local $hStatus = _GUICtrlStatusBar_Create($hGui)
	Local $hAttentionIcon = _WinAPI_LoadShell32Icon(77)
	Local $hOkIcon = _WinAPI_LoadShell32Icon(144)
	Local $hInfoIcon = _WinAPI_LoadShell32Icon(277)
	_GUICtrlStatusBar_SetIcon($hStatus, 0, $hInfoIcon)
	_GUICtrlStatusBar_SetText($hStatus, $aLanguage[6])
	GUISetState(@SW_SHOW, $hGui)
	Local $iDriveSpaceFree = DriveSpaceFree($sDownloadDir) * 2 ^ 20 ; in Bytes umrechnen
	Local $iFileSize = InetGetSize($sURL) ; Rueckgabe in Bytes
	If $iFileSize > 0 Then
		If $iDriveSpaceFree > $iFileSize Then
			_GUICtrlStatusBar_SetText($hStatus, $aLanguage[7])
			$iDownSpeedTimer = TimerInit()
			GUICtrlSetData($idDownloadSize, StringFormat('%s / %s', _WinAPI_StrFormatByteSize($iDownloadSize), _WinAPI_StrFormatByteSize($iFileSize)))
			GUICtrlSetData($idDownloadSpeed, StringFormat('%s/s', $iDownSpeed))
			$sDownloadFile = $sDownloadDir & StringRegExpReplace($sURL, '.+\/(.+)', '$1')
			$hDownload = InetGet($sURL, $sDownloadFile, 1, 1)
			$iSleep = TimerInit()
			Do
				Switch GUIGetMsg()
					Case $idCancelButton
						$iError = 3
						ExitLoop
					Case $GUI_EVENT_CLOSE
						InetClose($hDownload)
						If FileExists($sDownloadFile) Then FileDelete($sDownloadFile)
						_WinAPI_DestroyIcon($hAttentionIcon)
						_WinAPI_DestroyIcon($hOkIcon)
						_WinAPI_DestroyIcon($hInfoIcon)
						HttpSetUserAgent($sPrevUserAgent)
						If $hParent Then GUISetState(@SW_ENABLE, $hParent)
						Opt('GUIOnEventMode', $iOldEventMode)
						GUIDelete($hGui)
						_GDIPlus_Shutdown()
						Return SetError(3, 0, 0)
				EndSwitch
				$aDownloadData = InetGetInfo($hDownload)
				If $aDownloadData[$INET_DOWNLOADERROR] Then
					$iError = 4
					ExitLoop
				EndIf
				$iDownloadSize = $aDownloadData[$INET_DOWNLOADREAD]
				If TimerDiff($iTimer) > 250 Then
					$iDownSpeed = _WinAPI_StrFormatByteSize($iDownloadSize / TimerDiff($iDownSpeedTimer) * 1000)
					$iTimer = TimerInit()
					$iPercent = Int(100 / $iFileSize * $iDownloadSize)
					GUICtrlSetData($idDownloadSize, StringFormat('%s / %s', _WinAPI_StrFormatByteSize($iDownloadSize), _WinAPI_StrFormatByteSize($iFileSize)))
					GUICtrlSetData($idDownloadSpeed, StringFormat('%s/s', $iDownSpeed))
					GUICtrlSetData($idDownloadTime, StringFormat('%s', _WinAPI_StrFromTimeInterval(TimerDiff($iDownSpeedTimer))))
					$iRestTime = ($iFileSize - $iDownloadSize) / ($iDownloadSize / TimerDiff($iDownSpeedTimer))
					If $iRestTime <> $iOldTime Then
						$iOldTime = $iRestTime
						GUICtrlSetData($idRestTime, StringFormat('%s', _WinAPI_StrFromTimeInterval($iRestTime)))
					EndIf
				EndIf
				If TimerDiff($iSleep) > 50 Then
					$hHBmp_BG = _GDIPlus_StripProgressbar($iPercent, $iW, $iH, 0xFF000000 + $iBGColor, $aColors[1][0], $aColors[1][1], $iPercent & '%')
					$hB = GUICtrlSendMsg($idProgress, 0x0172, $IMAGE_BITMAP, $hHBmp_BG)
					If $hB Then _WinAPI_DeleteObject($hB)
					_WinAPI_DeleteObject($hHBmp_BG)
					$iSleep = TimerInit()
				EndIf
			Until $aDownloadData[$INET_DOWNLOADCOMPLETE]
			InetClose($hDownload)
			If $iError Then
				If FileExists($sDownloadFile) Then FileDelete($sDownloadFile)
				$hHBmp_BG = _GDIPlus_StripProgressbar($iPercent, $iW, $iH, 0xFF000000 + $iBGColor, $aColors[0][0], $aColors[0][1], $iPercent & '%')
				_GUICtrlStatusBar_SetIcon($hStatus, 0, $hAttentionIcon)
				_GUICtrlStatusBar_SetText($hStatus, $aLanguage[8])
			Else
				$hHBmp_BG = _GDIPlus_StripProgressbar(100, $iW, $iH, 0xFF000000 + $iBGColor, $aColors[1][0], $aColors[1][1], '100%')
				GUICtrlSetData($idDownloadSize, StringFormat('%s / %s', _WinAPI_StrFormatByteSize($iDownloadSize), _WinAPI_StrFormatByteSize($iFileSize)))
				GUICtrlSetData($idDownloadSpeed, StringFormat('%s/s', $iDownSpeed))
				_GUICtrlStatusBar_SetIcon($hStatus, 0, $hOkIcon)
				_GUICtrlStatusBar_SetText($hStatus, $aLanguage[9])
			EndIf
			$hB = GUICtrlSendMsg($idProgress, 0x0172, $IMAGE_BITMAP, $hHBmp_BG)
			If $hB Then _WinAPI_DeleteObject($hB)
			_WinAPI_DeleteObject($hHBmp_BG)
		Else
			$iError = 5
			_GUICtrlStatusBar_SetIcon($hStatus, 0, $hAttentionIcon)
			_GUICtrlStatusBar_SetText($hStatus, $aLanguage[10])
		EndIf
	Else
		$iError = 6
		_GUICtrlStatusBar_SetIcon($hStatus, 0, $hAttentionIcon)
		_GUICtrlStatusBar_SetText($hStatus, $aLanguage[11])
	EndIf
	GUICtrlSetData($idCancelButton, $aLanguage[12])
	While True
		Switch GUIGetMsg()
			Case $idCancelButton, $GUI_EVENT_CLOSE
				_WinAPI_DestroyIcon($hAttentionIcon)
				_WinAPI_DestroyIcon($hOkIcon)
				_WinAPI_DestroyIcon($hInfoIcon)
				HttpSetUserAgent($sPrevUserAgent)
				If $hParent Then GUISetState(@SW_ENABLE, $hParent)
				Opt('GUIOnEventMode', $iOldEventMode)
				GUIDelete($hGui)
				_GDIPlus_Shutdown()
				Return SetError($iError, 0, 0)
		EndSwitch
	WEnd
EndFunc   ;==>_DownloadWithProgress

Func _DWP_GetLanguage($iLanguage)
	Local $aLanguage[13]
	Switch $iLanguage
		Case 1031 ; deutsch
			$aLanguage[0] = 'Dateiname:'
			$aLanguage[1] = 'Dateigröße:'
			$aLanguage[2] = 'Geschwindigkeit:'
			$aLanguage[3] = 'Downloadzeit:'
			$aLanguage[4] = 'Restzeit (geschätzt):'
			$aLanguage[5] = 'Download abbrechen'
			$aLanguage[6] = 'Dateigröße wird ermittelt! Bitte warten...'
			$aLanguage[7] = 'Datei wird heruntergeladen...'
			$aLanguage[8] = 'Download abgebrochen!'
			$aLanguage[9] = 'Download abgeschlossen!'
			$aLanguage[10] = 'Fehler! Nicht genug Platz auf dem Datenträger!'
			$aLanguage[11] = 'Fehler! Dateigröße konnte nicht ermittelt werden!'
			$aLanguage[12] = 'Fenster schließen'
		Case Else ; english
			$aLanguage[0] = 'Filename:'
			$aLanguage[1] = 'Filesize:'
			$aLanguage[2] = 'Downloadrate:'
			$aLanguage[3] = 'Downloadtime:'
			$aLanguage[4] = 'Remaining time (estimated):'
			$aLanguage[5] = 'Cancel Download'
			$aLanguage[6] = 'Calculate Filesize! Please wait...'
			$aLanguage[7] = 'Download File...'
			$aLanguage[8] = 'Download canceled!'
			$aLanguage[9] = 'Download completed!'
			$aLanguage[10] = 'Error! Not enough free space on disk!'
			$aLanguage[11] = 'Error! Cannot calculate filesize!'
			$aLanguage[12] = 'Close Window'
	EndSwitch
	Return $aLanguage
EndFunc   ;==>_DWP_GetLanguage

Func _GDIPlus_StripProgressbar($fPerc, $iW, $iH, $iBgColorGui = 0xFFF0F0F0, $iFgColor = 0xFFEE5F5B, $iBGColor = 0xFFF07673, $sText = 'Loading...', $iTextColor = 0x000000, $iDir = -1, $iSpeed = 1, $sFont = 'Arial', $bFlip = False, $bHBitmap = True)
	$fPerc = $fPerc < 0 ? 0 : $fPerc
	$fPerc = $fPerc > 100 ? 100 : $fPerc
	Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH)
	Local Const $hCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap)
	_GDIPlus_GraphicsSetPixelOffsetMode($hCtxt, $GDIP_PIXELOFFSETMODE_HIGHQUALITY)
	_GDIPlus_GraphicsClear($hCtxt, $iBgColorGui)

	Local $iWidth = $iH * 2, $iLen = $iWidth / 2, $iY
	Local $hBmp = _GDIPlus_BitmapCreateFromScan0($iWidth, $iH)
	Local Const $hCtxt_Bmp = _GDIPlus_ImageGetGraphicsContext($hBmp)
	_GDIPlus_GraphicsSetPixelOffsetMode($hCtxt_Bmp, $GDIP_PIXELOFFSETMODE_HIGHQUALITY)
	Local $hPen = _GDIPlus_PenCreate($iFgColor), $iPenSize = Int($iH / 12)
	_GDIPlus_GraphicsClear($hCtxt_Bmp, $iBGColor)
	Local Static $iX = 0
	For $iY = 0 To $iH - 1
		Switch $iDir
			Case 1
				_GDIPlus_GraphicsDrawLine($hCtxt_Bmp, $iX + $iY, $iY, $iX + $iY + $iLen, $iY, $hPen)
				_GDIPlus_GraphicsDrawLine($hCtxt_Bmp, $iX + $iY - 2 * $iLen, $iY, $iX + $iY - 1 * $iLen, $iY, $hPen)
			Case Else
				_GDIPlus_GraphicsDrawLine($hCtxt_Bmp, -$iX + $iY, $iY, -$iX + $iY + $iLen, $iY, $hPen)
				_GDIPlus_GraphicsDrawLine($hCtxt_Bmp, -$iX + $iY + 2 * $iLen, $iY, -$iX + $iY + 3 * $iLen, $iY, $hPen)
		EndSwitch
	Next
	Local $hLineBrush
	If $bFlip Then
		$hLineBrush = _GDIPlus_LineBrushCreate($iW / 2, $iH / 3, $iW / 2, $iH * 2 / 3, 0xB0FFFFFF, 0x00FFFFFF)
		_GDIPlus_GraphicsFillRect($hCtxt_Bmp, 0, $iH * 2 / 3 + 0, $iW, $iH / 3, $hLineBrush)
	Else
		$hLineBrush = _GDIPlus_LineBrushCreate($iW / 2, 0, $iW / 2, $iH / 3, 0xB0FFFFFF, 0x00FFFFFF)
		_GDIPlus_GraphicsFillRect($hCtxt_Bmp, 0, 0, $iW, $iH / 3, $hLineBrush)
	EndIf
	$iX = Mod($iX + $iSpeed, $iWidth)
	Local $hTextureBrush = _GDIPlus_TextureCreate($hBmp)
	_GDIPlus_GraphicsFillRect($hCtxt, 0, 0, $fPerc / 100 * $iW, $iH, $hTextureBrush)
	If $bFlip Then _GDIPlus_ImageRotateFlip($hBitmap, 6)
	_GDIPlus_GraphicsSetTextRenderingHint($hCtxt, 4)
	Local $hBrush = _GDIPlus_BrushCreateSolid(0xE0000000 + $iTextColor)
	Local $hFormat = _GDIPlus_StringFormatCreate()
	Local $hFamily = _GDIPlus_FontFamilyCreate($sFont)
	Local $hFont = _GDIPlus_FontCreate($hFamily, $iH * 3 / 6)
	Local $tLayout = _GDIPlus_RectFCreate(0, 4, $iW, $iH - 4)
	_GDIPlus_StringFormatSetAlign($hFormat, 1)
	_GDIPlus_StringFormatSetLineAlign($hFormat, 1)
	_GDIPlus_GraphicsDrawStringEx($hCtxt, $sText, $hFont, $tLayout, $hFormat, $hBrush)
	_GDIPlus_FontDispose($hFont)
	_GDIPlus_FontFamilyDispose($hFamily)
	_GDIPlus_StringFormatDispose($hFormat)
	_GDIPlus_BrushDispose($hBrush)
	_GDIPlus_PenDispose($hPen)
	_GDIPlus_GraphicsDispose($hCtxt)
	_GDIPlus_GraphicsDispose($hCtxt_Bmp)
	_GDIPlus_BitmapDispose($hBmp)
	_GDIPlus_BrushDispose($hTextureBrush)
	_GDIPlus_BrushDispose($hLineBrush)
	If $bHBitmap Then
		Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
		_GDIPlus_BitmapDispose($hBitmap)
		Return $hHBITMAP
	EndIf
	Return $hBitmap
EndFunc   ;==>_GDIPlus_StripProgressbar
