#!/usr/bin/env python

# Copyright (C) 2017 Apple Incorporated. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above
#    copyright notice, this list of conditions and the following
#    disclaimer.
# 2. Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following
#    disclaimer in the documentation and/or other materials
#    provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

import argparse
import subprocess
import sys

from webkitpy.common.host import Host
from webkitpy.layout_tests.controllers.layout_test_finder import LayoutTestFinder
from webkitpy.layout_tests.servers.run_webkit_httpd import run_server as run_webkit_httpd
from webkitpy.layout_tests.servers.run_webkit_httpd import parse_args as parse_httpd_args

def parse_args(args):
    description = """Open a layout test using the default browser. Script will make sure to start a server if test needs it."""
    parser = argparse.ArgumentParser(prog='open-layout-test', description=description, formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('test_name', nargs=1, help='test to open')

    options, args = parser.parse_known_args(args)
    return options, args


def main(argv, stdout, stderr):
    options, args  = parse_args(argv)
    test_name = options.test_name[0]

    host = Host()
    port = host.port_factory.get(None, {})
    driver = port.create_driver(0)
    finder = LayoutTestFinder(port, {})

    paths, tests = finder.find_tests(None, [test_name])
    test_files = [test.test_path for test in tests]
    test_name = paths[0]

    needs_server = False
    if driver.is_http_test(test_name) and not port.is_http_server_running():
        needs_server = not port.is_http_server_running()
    elif driver.is_web_platform_test(test_name) or driver.is_webkit_specific_web_platform_test(test_name):
        needs_server = not port.is_wpt_server_running()

    test_url = driver.test_to_uri(test_name)
    if not needs_server:
        print("Opening %s" % test_url)
        subprocess.Popen(['open', test_url])
        return

    httpd_options, httpd_args = parse_httpd_args(['-u', test_url])
    run_webkit_httpd(httpd_options, httpd_args, stdout, stderr)


if __name__ == '__main__':
    sys.exit(main(sys.argv[1:], sys.stdout, sys.stderr))
