#!/usr/bin/env python3
import sys
import random
import time
from os import path, remove

import pycurl


# Download size in MB, can be power of 8
dlSize = 256

# URI
baseURI = 'https://speedtest-01.speedtest.unitymedia.de'
baseURIipv6 = 'https://speedtest-01v6.speedtest.unitymedia.de'
baseDownload = '/data.zero.bin.' + str(dlSize) + 'M'

# ------------------------------------------------------------------------
random.seed(time.time())
randomComponent = random.random()

# ------------------------------------------------------------------------
def downloadSpeedTest():
    global dlSize, blockSize
    speedCollection = [0]
    downloadURL = baseURI + baseDownload + '?' + str(randomComponent)
    downloadData = []
    downloadSize = dlSize * (1024 * 1024)
    blockSize = 0
    blockStepSize = downloadSize / 100

    def writeLoop(data):
        global blockSize
        blockSize += len(data)
        if blockSize >= blockStepSize:
            print('.', end='', flush=True)
            blockSize -= blockStepSize

        downloadData.append(data)

    def writeProgress(dlTotal, dlNow, ulTotal, ulNow):
        if speedCollection[len(speedCollection) - 1] != dlNow:
            speedCollection.append(dlNow)

    print('Starting download of URI: \'%s\'\n' % downloadURL)
    c = pycurl.Curl()
    c.setopt(c.URL, downloadURL)
    c.setopt(c.USERAGENT, 'curl')
    c.setopt(c.VERBOSE, False)
    c.setopt(c.USE_SSL, True)
    c.setopt(c.ENCODING, 'utf-8')
    c.setopt(c.WRITEFUNCTION, writeLoop)
    c.setopt(c.PROGRESSFUNCTION, writeProgress)
    c.setopt(c.NOPROGRESS, False)
    c.perform()

    dlName = path.basename(baseDownload)
    dlSpeed = c.getinfo(c.SPEED_DOWNLOAD) / 1000.0 / 1000.0
    dlSize = c.getinfo(c.SIZE_DOWNLOAD)
    dlTime = c.getinfo(c.TOTAL_TIME)

    speedCollection = speedCollection[1:]
    speedCollection.reverse()
    speedCollection = speedCollection[1:]

    speedMin = speedCollection[0]
    speedMax = speedCollection[0]
    speedTotal = 0

    for index, item in enumerate(speedCollection):
        try:
            speed = item - speedCollection[index + 1]
        except:
            break

        if speed < speedMin:
            speedMin = speed
        if speed > speedMax:
            speedMax = speed
        speedTotal += speed

    speedMin = speedMin / 1024.0
    speedMax = speedMax / 1024.0
    speedAverage = speedTotal / len(speedCollection)

    print('\n\nFinished downloading \'%s\', %d bytes ( %.3f MB)\n\nAverage speed of %.3f MiB\n[MIN: %.3f KB ::: MAX: %.3f Kb ::: AVG: %.3f KB]\n\nMeasured in %d minutes and %d seconds (%.3f seconds total)\n\n' % (
        dlName, dlSize, dlSize / 1024.0 / 1024.0, dlSpeed, speedMin, speedMax * 2.0, speedAverage, dlTime / 60, dlTime % 60.0, dlTime))

    c.close()

# ------------------------------------------------------------------------

def uploadSpeedtest():
    speedCollection = [0]
    ulName = 'empty.txt'
    uploadURI = baseURI + '/empty.txt'
    uploadData = "0" * (10000000 * 2)

    with open(ulName, 'w') as uploadFile:
        uploadFile.write(uploadData)

    ulSize = len(uploadData)

    def readProgress(dlTotal, dlNow, ulTotal, ulNow):
        if speedCollection[len(speedCollection) - 1] != ulNow:
            speedCollection.append(ulNow)

    print('Starting upload of URI: \'%s\'\n' % uploadURI)

    c = pycurl.Curl()
    c.setopt(c.URL, uploadURI)
    c.setopt(c.USERAGENT, 'curl')
    c.setopt(c.VERBOSE, False)
    c.setopt(c.HTTPHEADER, ['Content-Type: application/octet-stream'])
    c.setopt(c.UPLOAD, True)
    c.setopt(c.USE_SSL, True)
    c.setopt(c.READFUNCTION, open('empty.txt', 'rb').read)
    c.setopt(c.PROGRESSFUNCTION, readProgress)
    c.setopt(c.NOPROGRESS, False)
    c.perform()

    remove(ulName)

    speedCollection = speedCollection[1:]
    speedCollection.reverse()
    speedCollection = speedCollection[1:]

    speedMin = speedCollection[0]
    speedMax = speedCollection[0]
    speedTotal = 0

    ulSpeed = c.getinfo(c.SPEED_UPLOAD) / 1000.0 / 1000.0
    ulSize = c.getinfo(c.SIZE_UPLOAD)
    ulTime = c.getinfo(c.TOTAL_TIME)

    for index, item in enumerate(speedCollection):
        try:
            speed = item - speedCollection[index + 1]
        except:
            break

    if speed < speedMin:
        speedMin = speed
    if speed > speedMax:
        speedMax = speed

    speedTotal += speed

    speedMin = speedMin / 1024.0
    speedMax = speedMax / 1024.0
    speedAverage = speedTotal / len(speedCollection)

    print('\n\nFinished uploading \'%s\', %d bytes ( %.3f MB)\n\nAverage speed of %.3f MiB\n[MIN: %.3f KB ::: MAX: %.3f Kb ::: AVG: %.3f KB]\n\nMeasured in %d minutes and %d seconds (%.3f seconds total)\n\n' % (
    ulName, ulSize, ulSize / 1024.0 / 1024.0, ulSpeed, speedMin, speedMax * 2.0, speedAverage, ulTime / 60, ulTime % 60.0, ulTime))

    c.close()

# ------------------------------------------------------------------------

if __name__ == "__main__":
    if len(sys.argv) == 1:
        downloadSpeedTest()
        uploadSpeedtest()
    else:
        for option in sys.argv:
            if option == '-d':
                downloadSpeedTest()
            elif option == '-u':
                uploadSpeedtest()
