extends HTTPRequest

var kinds = {
	"topo": "http://imbrium.mit.edu/DATA/SLDEM2015/TILES/FLOAT_IMG/%s",
	"color": "https://nextcloud.alfi.li/nextcloud/index.php/s/dMELm8P8sPxbC5f/download?path=%2F&files=%s" 
}

var downloads = {}
var downloading = false

onready var UI = get_node("/root/Main/UI/Downloader")

signal file_downloaded
signal downloads_finished
signal stats_updated
signal downloads_started

export(bool)            var blind_mode : bool   = false

var _headers   : Array = []

var _last_method : int
var _ssl         : bool = false

var _file := File.new()

var _timer : float = 0.0

var currentDownload : Download
class Download:
	var _file_name : String
	var _file_size : float
	var _current_url       : String
	var _kind : String
	var _downloaded_percent : float = 0
	var _downloaded_size    : float = 0

func _init() -> void:
	set_process(false)
	connect("request_completed", self, "_on_request_completed")
	
func _ready():
	connect("stats_updated", Messenger, "_on_statusUpdate")

func get_stats() -> Download:
	return currentDownload
	
func _reset() -> void:
	currentDownload = Download.new()
	
func _downloads_done() -> void:
	set_process(false)
	_update_stats()
	_file.close()
	emit_signal("downloads_finished", currentDownload)
	_reset()
	downloading = false
	UI.hide()
	
func _update_stats() -> void:
	if blind_mode == false:
		_calculate_percentage()
		emit_signal("stats_updated",currentDownload)
	
func _process(delta):
	if not downloading:
		if len(downloads) == 0:
			set_process(false)
			return
		for kind in downloads:
			for file in downloads[kind]:
				var dl = downloads[kind][file]
				currentDownload = dl
				_download()
	_timer += delta
	if _timer > 1:
		_update_stats()
		_timer = 0.0
		
func _download():
	ensureFolder(currentDownload._kind)
	download_file = currentDownload._file_name
	_send_head_request()
	print("downloading %s" %currentDownload._current_url)
	downloading = true
	UI.show()

func ensureFolder(kind):
	var dir = Directory.new()
	dir.open("user://")
	if not dir.dir_exists(kind):
		dir.make_dir(kind)
	
	
func download(file, kind):
	set_process(true)
	if not kinds.has(kind):
		print("don't know kind %s"%kind)
		return
	if not downloads.has(kind):
		downloads[kind] = {}
	if downloads[kind].has(file):
		return
	var download = Download.new()
	download._file_name = "user://%s/%s"%[kind, file]
	download._current_url = make_filename(kind, file)
	download._kind = kind
	downloads[kind][download._file_name] = download
	
func make_filename(kind, file):
	return kinds[kind]%file
	
func _send_head_request() -> void:
	# The HEAD method only gets the head and not the body. Therefore, doesn't
	#   download the file.
	request(currentDownload._current_url, _headers, _ssl, HTTPClient.METHOD_HEAD)
	_last_method = HTTPClient.METHOD_HEAD
	
	
func _send_get_request() -> void:
	var error = request(currentDownload._current_url, _headers, _ssl, HTTPClient.METHOD_GET)
	if error == OK:
		emit_signal("downloads_started")
		_last_method = HTTPClient.METHOD_GET
		set_process(true)
	
	elif error == ERR_INVALID_PARAMETER:
		print("Given string isn't a valid url ")
	elif error == ERR_CANT_CONNECT:
		print("Can't connect to host")
	
func _on_request_completed(p_result,
						   _p_response_code,
						   p_headers,
						   _p_body) -> void:
	if p_result == RESULT_SUCCESS:
		if _p_response_code != 200:
			push_error("Download HTTP Error %s:%s" %[_p_response_code,_p_body])
			return
		if _last_method == HTTPClient.METHOD_HEAD and blind_mode == false:
			var regex = "(?i)content-length: [0-9]*"
			var size  = _extract_regex_from_header(regex, p_headers.join(' '))
			size = size.replace("Content-Length: ", "")
			currentDownload._file_size = size.to_float()
			_send_get_request()
			
		elif _last_method == HTTPClient.METHOD_HEAD and blind_mode == true:
			_send_get_request()
			
		elif _last_method == HTTPClient.METHOD_GET:
			print("file download complete %s"%currentDownload._current_url)
			_file.close()
			emit_signal("file_downloaded", currentDownload)
			Messenger._on_file_downloaded(currentDownload)
			downloading = false
			remove_download()
				
	elif p_result == RESULT_DOWNLOAD_FILE_CANT_OPEN:
		push_error("Download cannot open file %s" %currentDownload._file_name)
	else:
		print("HTTP Request error: ", p_result)

func remove_download():
	downloads[currentDownload._kind].erase(currentDownload._file_name)
	if len(downloads[currentDownload._kind]) == 0:
		downloads.erase(currentDownload._kind)
	if len(downloads) == 0:
		_downloads_done()

func _calculate_percentage() -> void:
	var error : int
	error = _file.open(download_file, File.READ)

	if error == OK and currentDownload._file_size > 0:
		currentDownload._downloaded_size    = _file.get_len()
		currentDownload._downloaded_percent = (currentDownload._downloaded_size / currentDownload._file_size) *100
		
func _extract_regex_from_header(p_regex  : String,
								p_header : String) -> String:
	var regex = RegEx.new()
	regex.compile(p_regex)
	
	var result = regex.search(p_header)
	return result.get_string()
