# 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/.

from __future__ import absolute_import, unicode_literals

import mozpack.path as mozpath

from mozbuild.base import (
    MachCommandBase,
)

from mach.decorators import (
    CommandArgument,
    CommandProvider,
    Command,
)

from mach.registrar import (
    Registrar
)

from shutil import rmtree
from subprocess import Popen
from sys import argv
from sys import exit
from tempfile import mkdtemp



DEFAULT_PORT = 8080
DEFAULT_HOSTNAME = 'localhost'

SRCDIR = mozpath.abspath(mozpath.dirname(__file__))

STORAGE_SERVER_SCRIPT = mozpath.join(SRCDIR, 'run_storage_server.js')

def SyncStorageCommand(func):
    """Decorator that adds shared command arguments to services commands."""

    port = CommandArgument('--port', metavar='PORT', type=int,
                           default=DEFAULT_PORT, help='Port to run server on.')
    func = port(func)

    address = CommandArgument('--address', metavar='ADDRESS',
                              default=DEFAULT_HOSTNAME,
                              help='Hostname to bind server to.')
    func = address(func)

    return func

Registrar.register_category(name='services',
                            title='Services utilities',
                            description='Commands for services development.')

@CommandProvider
class SyncTestCommands(MachCommandBase):
    def __init__(self, context):
        MachCommandBase.__init__(self, context)

    def run_server(self, js_file, hostname, port):
        topsrcdir = self.topsrcdir
        topobjdir = self.topobjdir

        unit_test_dir = mozpath.join(SRCDIR, 'unit')

        head_paths = [
            'head_global.js',
            'head_helpers.js',
            'head_http.js',
            ]

        head_paths = ['"%s"' % mozpath.join(unit_test_dir, path) for path in head_paths]

        args = [
            '%s/run-mozilla.sh' % self.bindir,
            '%s/xpcshell' % self.bindir,
            '-g', self.bindir,
            '-a', self.bindir,
            '-r', '%s/components/httpd.manifest' % self.bindir,
            '-m',
            '-s',
            '-e', 'const _TESTING_MODULES_DIR = "%s/_tests/modules";' % topobjdir,
            '-f', '%s/testing/xpcshell/head.js' % topsrcdir,
            '-e', 'const _SERVER_ADDR = "%s";' % hostname,
            '-e', 'const SERVER_PORT = "%s";' % port,
            '-e', 'const INCLUDE_FILES = [%s];' % ', '.join(head_paths),
            '-e', '_register_protocol_handlers();',
            '-e', 'for (let name of INCLUDE_FILES) load(name);',
            '-e', '_fakeIdleService.activate();',
            '-f', js_file
            ]

        profile_dir = mkdtemp()
        print 'Created profile directory: %s' % profile_dir

        try:
            env = {'XPCSHELL_TEST_PROFILE_DIR': profile_dir}
            proc = Popen(args, env=env)

            return proc.wait()

        finally:
            print 'Removing profile directory %s' % profile_dir
            rmtree(profile_dir)

    @Command('storage-server', category='services',
             description='Run a storage server.')
    @SyncStorageCommand
    def run_storage_server(self, port=DEFAULT_PORT, address=DEFAULT_HOSTNAME):
        exit(self.run_server(STORAGE_SERVER_SCRIPT, address, port))
