#!/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, test_files = finder.find_tests(None, [test_name])
    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))
