# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

"""Utility functions for Talos"""
import os
import platform
import re
import string
import time
import urllib.parse
from sys import stdout

try:
    from mozlog import get_proxy_logger

    LOG = get_proxy_logger()
except ModuleNotFoundError:
    LOG = stdout

# directory of this file for use with interpolatePath()
here = os.path.dirname(os.path.realpath(__file__))


class Timer(object):
    def __init__(self):
        self._start_time = 0
        self.start()

    def start(self):
        self._start_time = time.time()

    def elapsed(self):
        seconds = time.time() - self._start_time
        return time.strftime("%H:%M:%S", time.gmtime(seconds))


class TalosError(Exception):
    "Errors found while running the talos harness."


class TalosRegression(Exception):
    """When a regression is detected at runtime, report it properly
    Currently this is a simple definition so we can detect the class type
    """


class TalosCrash(Exception):
    """Exception type where we want to report a crash and stay
    compatible with tbpl while allowing us to continue on.

    https://bugzilla.mozilla.org/show_bug.cgi?id=829734
    """


def interpolate(template, **kwargs):
    """
    Use string.Template to substitute variables in a string.

    The placeholder ${talos} is always defined and will be replaced by the
    folder containing this file (global variable 'here').

    You can add placeholders using kwargs.
    """
    kwargs.setdefault("talos", here)
    return string.Template(template).safe_substitute(**kwargs)


def findall(string, token):
    """find all occurences in a string"""
    return [m.start() for m in re.finditer(re.escape(token), string)]


def tokenize(string, start, end):
    """
    tokenize a string by start + end tokens,
    returns parts and position of last token
    """
    assert end not in start, "End token '%s' is contained in start token '%s'" % (
        end,
        start,
    )
    assert start not in end, "Start token '%s' is contained in end token '%s'" % (
        start,
        end,
    )
    _start = findall(string, start)
    _end = findall(string, end)
    if not _start and not _end:
        return [], -1
    assert len(_start), "Could not find start token: '%s'" % start
    assert len(_end), "Could not find end token: '%s'" % end
    assert len(_start) == len(
        _end
    ), "Unmatched number of tokens found: '%s' (%d) vs '%s' (%d)" % (
        start,
        len(_start),
        end,
        len(_end),
    )
    for i in range(len(_start)):
        assert _end[i] > _start[i], "End token '%s' occurs before start token '%s'" % (
            end,
            start,
        )
    parts = []
    for i in range(len(_start)):
        parts.append(string[_start[i] + len(start) : _end[i]])
    return parts, _end[-1]


def urlsplit(url, default_scheme="file"):
    """front-end to urlparse.urlsplit"""

    if "://" not in url:
        url = "%s://%s" % (default_scheme, url)

    if url.startswith("file://"):
        # file:// URLs do not play nice with windows
        # https://bugzilla.mozilla.org/show_bug.cgi?id=793875
        return ["file", "", url[len("file://") :], "", ""]

    # split the URL and return a list
    return [i for i in urllib.parse.urlsplit(url)]


def parse_pref(value):
    """parse a preference value from a string"""
    from mozprofile.prefs import Preferences

    return Preferences.cast(value)


def GenerateBrowserCommandLine(
    browser_path, extra_args, profile_dir, url, profiling_info=None
):
    # TODO: allow for spaces in file names on Windows
    command_args = [browser_path.strip()]

    if platform.system() == "Darwin":
        command_args.extend(["-foreground"])

    if isinstance(extra_args, list):
        command_args.extend(extra_args)

    elif extra_args.strip():
        command_args.extend([extra_args])

    command_args.extend(["-profile", profile_dir])

    if profiling_info:
        # pageloader tests use a tpmanifest browser pref instead of passing in a manifest url
        # profiling info is handled differently for pageloader vs non-pageloader (startup) tests
        # for pageloader the profiling info was mirrored already in an env var; so here just
        # need to setup profiling info for startup / non-pageloader tests
        if url is not None:
            # for non-pageloader/non-manifest tests the profiling info is added to the test url
            if url.find("?") != -1:
                url += "&" + urllib.parse.urlencode(profiling_info)
            else:
                url += "?" + urllib.parse.urlencode(profiling_info)
            command_args.extend(url.split(" "))

    # if there's a url i.e. startup test / non-manifest test, add it to the cmd line args
    if url is not None:
        command_args.extend(url.split(" "))

    return command_args


def run_in_debug_mode(browser_config):
    if (
        browser_config.get("debug")
        or browser_config.get("debugger")
        or browser_config.get("debugg_args")
    ):
        return True
    return False
