#!/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_legacy 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))
