from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

import urllib.parse
import xlsxwriter
import argparse
import shutil
import os
import os.path
import time
import subprocess
import urllib.parse
import pathlib
import pprint
import signal
import socket
import collections
import json
import requests
import threading
import statistics

def forceend(v):
    v = True

def throw_exp(signum, frame):
    raise Exception("timeout")

def convertBW(bw):
    if bw == "25mbit":
        return 25 * 1000 * 1000 * 0.9
    elif bw == "8mbit":
        return 8 * 1000 * 1000 * 0.9

def run_test(url, testcount):
    result = []
    resultdict = []
    for i in range(0, testcount):
        try:
            signal.signal(signal.SIGALRM, throw_exp)

            frontBW = convertBW(os.environ["FRONTRATE"])
            backBW = convertBW(os.environ["BACKRATE"])
            surl = urllib.parse.urlsplit(url)

            print(frontBW, backBW)
#            requests.post(surl.scheme + "://" + surl.netloc + "/set", data={"frontbw": str(frontBW), "backbw": str(backBW)})

            print("start:", i)
            desired = DesiredCapabilities.CHROME
            desired["goog:loggingPrefs"] = {"browser": "ALL"}
            options = webdriver.ChromeOptions()
            options.add_argument("--incognito")
            #    options.add_argument("--headless")
            options.add_argument("--disable-notifications")
            options.add_argument("--disable-dev-shm-usage")
            options.add_argument("--disable-popup-blocking")
            driver = webdriver.Chrome(options=options, desired_capabilities=desired)

            try:
                signal.alarm(60 * 20)

                driver.get(url)
                time.sleep(3)
                driver.get(url)

                event_lists = []
                finished = False

                while not finished:
                    for msg in driver.get_log("browser"):
                        logmsg = msg["message"].split(" ")[2].replace("\"", "")
                        event_lists.append(logmsg)

                        if "ALL_FINISHED" in msg["message"]:
                            finished = True
                            signal.alarm(0)
            except Exception as ee:
                print ("retry")
                raise Exception("timeout")

            page_init_time = init_time = first_buffer_loaded = first_playback_started = total_playback_time = video_duration = stall_rate = -1
            quality_changes = []
            throughtput_change = []

            for e in event_lists:
                print(e)
                if "NaN" in e:
                    continue

                if "PAGE_LOADED" in e and page_init_time == -1:
                    page_init_time = int(e.split("|")[1])
                if "QUALITY_LIST" in e:
                    quality_changes = [int(x) for x in e.split("|")[1].split(",")]
                    print("skip set quality change")
                    #pass
                if "STREAM_INITIALIZING" in e and init_time == -1:
                    init_time = int(e.split("|")[1])
                if "BUFFER_LOADED" in e and first_buffer_loaded == -1:
                    first_buffer_loaded = int(e.split("|")[1])
                if "PLAYBACK_STARTED" in e and first_playback_started == -1:
                    first_playback_started = int(e.split("|")[1])
                if "TOTAL_PLAYBACK_TIME" in e and total_playback_time == -1:
                    total_playback_time = int(e.split("|")[1])
                if "VIDEO_DURATION" in e and video_duration == -1:
                    video_duration = round(float(e.split("|")[1]))
                if "STALL_RATE" in e and stall_rate == -1:
                    stall_rate = float(e.split("|")[1])
                if "FRAGMENT_LOADING_COMPLETED" in e:
                    quality_changes.append({
                        "time": int(e.split("|")[1]),
                        "q": int(float(e.split("|")[2]))
                    })
                if "THROUGHTPUT" in e:
                    throughtput_change.append({
                        "time": int(e.split("|")[1]),
                        "tp": round(float(e.split("|")[2]))
                    })

            video_duration = 634567
            # sequence, total playback time, video duration, stall rate, startup delay, average quality
            print("before")
#            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, -1])
#            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, statistics.mean([x["q"] for x in quality_changes])])
            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, statistics.mean(quality_changes)])
            print("end")
            resultdict.append({
                "seq": i,
                "totaltime": total_playback_time,
                "playduration": video_duration,
                "quality": quality_changes,
                "throughtput": throughtput_change
            })

        except Exception as e:
            print(e)
            result.append("timeout")

        try:
            driver.close()
            driver.quit()
        except:
            pass

    return result, resultdict

def run_test_dt(url, testcount):
    result = []
    resultdict = []
    for i in range(0, testcount):
        try:
            signal.signal(signal.SIGALRM, throw_exp)

            frontBW = convertBW(os.environ["FRONTRATE"])
            backBW = convertBW(os.environ["BACKRATE"])
            surl = urllib.parse.urlsplit(url)

            print(frontBW, backBW)
#            requests.post(surl.scheme + "://" + surl.netloc + "/set", data={"frontbw": str(frontBW), "backbw": str(backBW)})

            print("start:", i)
            desired = DesiredCapabilities.CHROME
            desired["goog:loggingPrefs"] = {"browser": "ALL"}
            options = webdriver.ChromeOptions()
            options.add_argument("--incognito")
            #    options.add_argument("--headless")
            options.add_argument("--disable-notifications")
            options.add_argument("--disable-dev-shm-usage")
            options.add_argument("--disable-popup-blocking")
            driver = webdriver.Chrome(options=options, desired_capabilities=desired)

            try:
                signal.alarm(30 * 600)

                driver.get(url)
                time.sleep(3)
                driver.get(url)

                event_lists = []
                finished = False

                while not finished:
                    for msg in driver.get_log("browser"):
                        logmsg = msg["message"].split(" ")[2].replace("\"", "")
                        event_lists.append(logmsg)

                        if "ALL_FINISHED" in msg["message"]:
                            finished = True
                            signal.alarm(0)
            except Exception as ee:
                print ("retry")
                raise Exception("timeout")

            page_init_time = init_time = first_buffer_loaded = first_playback_started = total_playback_time = video_duration = stall_rate = -1
            quality_changes = []
            throughtput_change = []

            for e in event_lists:
                print(e)
                if "NaN" in e:
                    continue

                if "PAGE_LOADED" in e and page_init_time == -1:
                    page_init_time = int(e.split("|")[1])
                if "QUALITY_LIST" in e:
                    quality_changes = [int(x) for x in e.split("|")[1].split(",")]
                    print("skip set quality change")
                    pass
                if "STREAM_INITIALIZING" in e and init_time == -1:
                    init_time = int(e.split("|")[1])
                if "BUFFER_LOADED" in e and first_buffer_loaded == -1:
                    first_buffer_loaded = int(e.split("|")[1])
                if "PLAYBACK_STARTED" in e and first_playback_started == -1:
                    first_playback_started = int(e.split("|")[1])
                if "TOTAL_PLAYBACK_TIME" in e and total_playback_time == -1:
                    total_playback_time = int(e.split("|")[1])
                if "VIDEO_DURATION" in e and video_duration == -1:
                    video_duration = round(float(e.split("|")[1]))
                if "STALL_RATE" in e and stall_rate == -1:
                    stall_rate = float(e.split("|")[1])
                if "FRAGMENT_LOADING_COMPLETED" in e:
                    quality_changes.append({
                        "time": int(e.split("|")[1]),
                        "q": int(float(e.split("|")[2]))
                    })
                if "THROUGHTPUT" in e:
                    throughtput_change.append({
                        "time": int(e.split("|")[1]),
                        "tp": round(float(e.split("|")[2]))
                    })

            video_duration = 634567
            # sequence, total playback time, video duration, stall rate, startup delay, average quality
            print("before")
#            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, -1])
#            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, statistics.mean([x["q"] for x in quality_changes])])
            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, 0])
            print("end")

        except Exception as e:
            print(e)
            result.append("timeout")

        try:
            driver.close()
            driver.quit()
        except:
            pass

    return result


def run_test_simple(url, testcount):
    result = []
    resultdict = []
    for i in range(0, testcount):
        try:
            signal.signal(signal.SIGALRM, throw_exp)

            frontBW = convertBW(os.environ["FRONTRATE"])
            backBW = convertBW(os.environ["BACKRATE"])
            surl = urllib.parse.urlsplit(url)

            print(frontBW, backBW)
#            requests.post(surl.scheme + "://" + surl.netloc + "/set", data={"frontbw": str(frontBW), "backbw": str(backBW)})

            print("start:", i)
            desired = DesiredCapabilities.CHROME
            desired["goog:loggingPrefs"] = {"browser": "ALL"}
            options = webdriver.ChromeOptions()
            options.add_argument("--incognito")
            #    options.add_argument("--headless")
            options.add_argument("--disable-notifications")
            options.add_argument("--disable-dev-shm-usage")
            options.add_argument("--disable-popup-blocking")
            driver = webdriver.Chrome(options=options, desired_capabilities=desired)

            try:
                signal.alarm(30 * 600)

                driver.get(url)
                time.sleep(3)
                driver.get(url)

                event_lists = []
                finished = False

                while not finished:
                    for msg in driver.get_log("browser"):
                        logmsg = msg["message"].split(" ")[2].replace("\"", "")
                        event_lists.append(logmsg)

                        if "ALL_FINISHED" in msg["message"]:
                            finished = True
                            signal.alarm(0)
            except Exception as ee:
                print ("retry")
                raise Exception("timeout")

            page_init_time = init_time = first_buffer_loaded = first_playback_started = total_playback_time = video_duration = stall_rate = -1
            quality_changes = []
            throughtput_change = []

            for e in event_lists:
                print(e)
                if "NaN" in e:
                    continue

                if "PAGE_LOADED" in e and page_init_time == -1:
                    page_init_time = int(e.split("|")[1])
                if "QUALITY_LIST" in e:
                    quality_changes = [int(x) for x in e.split("|")[1].split(",")]
                    print("skip set quality change")
                    pass
                if "STREAM_INITIALIZING" in e and init_time == -1:
                    init_time = int(e.split("|")[1])
                if "BUFFER_LOADED" in e and first_buffer_loaded == -1:
                    first_buffer_loaded = int(e.split("|")[1])
                if "PLAYBACK_STARTED" in e and first_playback_started == -1:
                    first_playback_started = int(e.split("|")[1])
                if "TOTAL_PLAYBACK_TIME" in e and total_playback_time == -1:
                    total_playback_time = int(e.split("|")[1])
                if "VIDEO_DURATION" in e and video_duration == -1:
                    video_duration = round(float(e.split("|")[1]))
                if "STALL_RATE" in e and stall_rate == -1:
                    stall_rate = float(e.split("|")[1])
                if "FRAGMENT_LOADING_COMPLETED" in e:
                    quality_changes.append({
                        "time": int(e.split("|")[1]),
                        "q": int(float(e.split("|")[2]))
                    })
                if "THROUGHTPUT" in e:
                    throughtput_change.append({
                        "time": int(e.split("|")[1]),
                        "tp": round(float(e.split("|")[2]))
                    })

            video_duration = 634567
            # sequence, total playback time, video duration, stall rate, startup delay, average quality
            print("before")
#            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, -1])
            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, statistics.mean([x["q"] for x in quality_changes])])
#            result.append([i, total_playback_time, video_duration, (total_playback_time - video_duration)/video_duration, first_playback_started - init_time, init_time - page_init_time, statistics.mean(quality_changes)])
            print("end")

        except Exception as e:
            print(e)
            result.append("timeout")

        try:
            driver.close()
            driver.quit()
        except:
            pass

    return result

def main(args):
    url = args.url
    excel_name = args.name + "." + os.path.basename(url) + ".xlsx"

    if args.print_name_only:
        print(excel_name)
        return
    print("save as", excel_name)
    if args.skipexist and os.path.exists(excel_name):
        print ("file exist. skip")
        return

    workbook = xlsxwriter.Workbook(excel_name)
    worksheet = workbook.add_worksheet()

    print(url)
    if args.simple:
        v = run_test_simple(url, args.testcount)
    else:
        v = run_test_dt(url, args.testcount)

    name = ["sequence", "total playback time", "video duration", "stall rate", "startup delay", "page startup delay", "average quality"]
    v.insert(0, name)
    for i, line in enumerate(v):
        for col_num, data in enumerate(line):
            worksheet.write(i, col_num, data)

    workbook.close()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--url", type=str, required=True)
    parser.add_argument("--name", type=str, required=True)
    parser.add_argument("--testcount", type=int)
    parser.add_argument("--simple", type=str)
#    parser.add_argument("--timeout", type=int, required=True)
    parser.add_argument("--ratelist", type=str)
    parser.add_argument("--containername", type=str)
    parser.add_argument("--dockerrestart", type=str)
    parser.add_argument("--skipexist", type=str)
    parser.add_argument("--print_name_only", type=str)
    main(parser.parse_args())
