#!/usr/bin/env python
# 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/.

"""
This scripts sets up a virtualenv and installs TPS into it.
It's probably best to specify a path NOT inside the repo, otherwise
all the virtualenv files will show up in e.g. hg status.
"""

from __future__ import absolute_import, print_function

import optparse
import os
import shutil
import subprocess
import sys
import urllib2
import zipfile


here = os.path.dirname(os.path.abspath(__file__))
usage_message = """
***********************************************************************

To run TPS, activate the virtualenv using:
    source {TARGET}/{BIN_NAME}

To change your TPS config, please edit the file:
    {TARGET}/config.json

To execute tps use:
    runtps --binary=/path/to/firefox

See runtps --help for all options

***********************************************************************
"""

# Link to the folder, which contains the zip archives of virtualenv
URL_VIRTUALENV = 'https://codeload.github.com/pypa/virtualenv/zip/'
VERSION_VIRTUALENV = '15.0.0'


if sys.platform == 'win32':
    bin_name = os.path.join('Scripts', 'activate.bat')
    activate_env = os.path.join('Scripts', 'activate_this.py')
    python_env = os.path.join('Scripts', 'python.exe')
else:
    bin_name = os.path.join('bin', 'activate')
    activate_env = os.path.join('bin', 'activate_this.py')
    python_env = os.path.join('bin', 'python')


def download(url, target):
    """Downloads the specified url to the given target."""
    response = urllib2.urlopen(url)
    with open(target, 'wb') as f:
        f.write(response.read())

    return target


def setup_virtualenv(target, python_bin=None):
    script_path = os.path.join(here, 'virtualenv-%s' % VERSION_VIRTUALENV,
                               'virtualenv.py')

    print('Downloading virtualenv {}'.format(VERSION_VIRTUALENV))
    zip_path = download(URL_VIRTUALENV + VERSION_VIRTUALENV,
                        os.path.join(here, 'virtualenv.zip'))

    try:
        with zipfile.ZipFile(zip_path, 'r') as f:
            f.extractall(here)

        print('Creating new virtual environment')
        cmd_args = [sys.executable, script_path, target]

        if python_bin:
            cmd_args.extend(['-p', python_bin])

        subprocess.check_call(cmd_args)
    finally:
        try:
            os.remove(zip_path)
        except OSError:
            pass

        shutil.rmtree(os.path.dirname(script_path), ignore_errors=True)


def update_configfile(source, target, replacements):
    lines = []

    with open(source) as config:
        for line in config:
            for source_string, target_string in replacements.iteritems():
                if target_string:
                    line = line.replace(source_string, target_string)
            lines.append(line)

    with open(target, 'w') as config:
        for line in lines:
            config.write(line)


def main():
    parser = optparse.OptionParser('Usage: %prog [options] path_to_venv')
    parser.add_option('--keep-config',
                      dest='keep_config',
                      action='store_true',
                      help='Keep the existing config file.')
    parser.add_option('--password',
                      type='string',
                      dest='password',
                      metavar='FX_ACCOUNT_PASSWORD',
                      default=None,
                      help='The Firefox Account password.')
    parser.add_option('-p', '--python',
                      type='string',
                      dest='python',
                      metavar='PYTHON_BIN',
                      default=None,
                      help='The Python interpreter to use.')
    parser.add_option('--sync-passphrase',
                      type='string',
                      dest='sync_passphrase',
                      metavar='SYNC_ACCOUNT_PASSPHRASE',
                      default=None,
                      help='The old Firefox Sync account passphrase.')
    parser.add_option('--sync-password',
                      type='string',
                      dest='sync_password',
                      metavar='SYNC_ACCOUNT_PASSWORD',
                      default=None,
                      help='The old Firefox Sync account password.')
    parser.add_option('--sync-username',
                      type='string',
                      dest='sync_username',
                      metavar='SYNC_ACCOUNT_USERNAME',
                      default=None,
                      help='The old Firefox Sync account username.')
    parser.add_option('--username',
                      type='string',
                      dest='username',
                      metavar='FX_ACCOUNT_USERNAME',
                      default=None,
                      help='The Firefox Account username.')

    (options, args) = parser.parse_args(args=None, values=None)

    if len(args) != 1:
        parser.error('Path to the environment has to be specified')
    target = args[0]
    assert(target)

    setup_virtualenv(target, python_bin=options.python)

    # Activate tps environment
    tps_env = os.path.join(target, activate_env)
    exec(open(tps_env).read(), dict(__file__=tps_env))

    # Install TPS in environment
    subprocess.check_call([os.path.join(target, python_env),
                           os.path.join(here, 'setup.py'), 'install'])

    # Get the path to tests and extensions directory by checking check where
    # the tests and extensions directories are located
    sync_dir = os.path.abspath(os.path.join(here, '..', '..', 'services',
                                            'sync'))
    if os.path.exists(sync_dir):
        testdir = os.path.join(sync_dir, 'tests', 'tps')
        extdir = os.path.join(sync_dir, 'tps', 'extensions')
    else:
        testdir = os.path.join(here, 'tests')
        extdir = os.path.join(here, 'extensions')

    if not options.keep_config:
        update_configfile(os.path.join(here, 'config', 'config.json.in'),
                          os.path.join(target, 'config.json'),
                          replacements={
                          '__TESTDIR__': testdir.replace('\\', '/'),
                          '__EXTENSIONDIR__': extdir.replace('\\', '/'),
                          '__FX_ACCOUNT_USERNAME__': options.username,
                          '__FX_ACCOUNT_PASSWORD__': options.password,
                          '__SYNC_ACCOUNT_USERNAME__': options.sync_username,
                          '__SYNC_ACCOUNT_PASSWORD__': options.sync_password,
                          '__SYNC_ACCOUNT_PASSPHRASE__': options.sync_passphrase})

        if not (options.username and options.password):
            print('\nFirefox Account credentials not specified.')
        if not (options.sync_username and options.sync_password and options.passphrase):
            print('\nFirefox Sync account credentials not specified.')

    # Print the user instructions
    print(usage_message.format(TARGET=target,
                               BIN_NAME=bin_name))


if __name__ == "__main__":
    main()
