# Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import os
import subprocess


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument(
        '-x',
        '--xml_file',
        help='A Fast DDS XML configuration file',
        required=False
    )
    parser.add_argument(
        '-t',
        '--test_duration',
        help='The duration of test iteration [s]',
        required=False,
        default='1'
    )
    parser.add_argument(
        '-r',
        '--recoveries_file',
        help='A CSV file with maxima sleep time between bursts [ms]',
        required=False,
        default=None
    )
    parser.add_argument(
        '-f',
        '--demands_file',
        help='Filename of the demands configuration file',
        required=False,
        default=None
    )
    parser.add_argument(
        '-s',
        '--security',
        action='store_true',
        help='Enables security (Defaults: disable)',
        required=False
    )
    parser.add_argument(
        '-i',
        '--interprocess',
        action='store_true',
        help='Publisher and subscribers in separate processes. Defaults:False',
        required=False
    )
    parser.add_argument(
        '-d',
        '--data_sharing',
        choices=['on', 'off'],
        help='Explicitly enable/disable data sharing. (Defaults: Fast DDS default settings)',
        required=False
    )
    parser.add_argument(
        '-l',
        '--data_loans',
        action='store_true',
        help='Enable the use of the loan sample API (Defaults: disable)',
        required=False
    )
    parser.add_argument(
        '-R',
        '--reliability',
        action='store_true',
        help='Run with RELIABLE reliability (Defaults: disable)',
        required=False
    )
    parser.add_argument(
        '--shared_memory',
        choices=['on', 'off'],
        help='Explicitly enable/disable shared memory transport. (Defaults: Fast DDS default settings)',
        required=False
        )

    # Parse arguments
    args = parser.parse_args()
    xml_file = args.xml_file
    security = args.security
    interprocess = args.interprocess
    recoveries_file = args.recoveries_file

    if security and not interprocess:
        print('Intra-process delivery NOT supported with security')
        exit(1)  # Exit with error

    # Check that test_duration is positive
    if str.isdigit(args.test_duration) and int(args.test_duration) > 0:
        test_duration = str(args.test_duration)
    else:
        print(
            '"test_duration" must be a positive integer, NOT {}'.format(
                args.test_duration
            )
        )
        exit(1)  # Exit with error

    # XML options
    filename_options = 'default'
    xml_options = []
    if xml_file:
        if not os.path.isfile(xml_file):
            print('XML file "{}" is NOT a file'.format(xml_file))
            exit(1)  # Exit with error
        else:
            xml_options = ['--xml', xml_file]
            # Get reliability from XML
            filename_options = xml_file.split('/')[-1].split('\\')[-1]
            filename_options = filename_options.split('.')[-2].split('_')[1:]
            filename_options = '_'.join(filename_options)

    # Data sharing and loans options
    # modify output file names
    if args.data_sharing and 'on' == args.data_sharing and args.data_loans:
        filename_options += '_data_loans_and_sharing'
    elif args.data_sharing and 'on' == args.data_sharing:
        filename_options += '_data_sharing'
    elif args.data_loans:
        filename_options += '_data_loans'

    # Demands files options
    demands_options = []
    if args.demands_file:
        if not os.path.isfile(args.demands_file):
            print('Demands file "{}" is NOT a file'.format(args.demands_file))
            exit(1)  # Exit with error
        else:
            demands_options = [
                '--file',
                args.demands_file,
            ]

    # add flags to the command line
    data_options = []

    if args.data_sharing:
        if 'on' == args.data_sharing:
            data_options += ['--data_sharing=on']
        else:
            data_options += ['--data_sharing=off']

    if args.data_loans:
        data_options += ['--data_loans']

    reliability_options = []
    if args.reliability:
        reliability_options = ['--reliability=reliable']
    else:
        reliability_options = ['--reliability=besteffort']

    if args.shared_memory:
        if 'on' == args.shared_memory:
            data_options += ['--shared_memory=on']
        else:
            data_options += ['--shared_memory=off']

    # Recoveries files options
    recoveries_options = []
    if args.recoveries_file:
        if not os.path.isfile(args.recoveries_file):
            print(
                'Recoveries file "{}" is NOT a file'.format(
                    args.recoveries_file
                )
            )
            exit(1)  # Exit with error
        else:
            recoveries_options = [
                '--recoveries_file',
                args.recoveries_file,
            ]

    # Environment variables
    executable = os.environ.get('THROUGHPUT_TEST_BIN')
    certs_path = os.environ.get('CERTS_PATH')

    # Check that executable exists
    if executable:
        if not os.path.isfile(executable):
            print('THROUGHPUT_TEST_BIN does NOT specify a file')
            exit(1)  # Exit with error
    else:
        print('THROUGHPUT_TEST_BIN is NOT set')
        exit(1)  # Exit with error

    # Security
    security_options = []
    if security is True:
        if certs_path:
            if os.path.isdir(certs_path):
                security_options = ['--security=true', '--certs=' + certs_path]
            else:
                print('CERTS_PATH does NOT specify a directory')
                exit(1)  # Exit with error
        else:
            print('Cannot find CERTS_PATH environment variable')
            exit(1)  # Exit with error

    # Domain must be under 100 to prevent windows multicast issues
    domain = str(os.getpid() % 100)
    domain_options = ['--domain', domain]

    if interprocess is True:
        # Base of test command for publisher agent
        pub_command = [
            executable,
            'publisher',
            '--time',
            test_duration,
            '--export_csv',
        ]
        # Base of test command for subscriber agent
        sub_command = [
            executable,
            'subscriber',
        ]

        # Manage security
        if security is True:
            pub_command.append(
                './measurements_interprocess_{}_security.csv'.format(
                    filename_options
                )
            )
            pub_command += security_options
            sub_command += security_options
        else:
            pub_command.append(
                './measurements_interprocess_{}.csv'.format(
                    filename_options
                )
            )

        pub_command += demands_options
        pub_command += recoveries_options
        pub_command += domain_options
        pub_command += xml_options
        pub_command += data_options
        pub_command += reliability_options

        sub_command += domain_options
        sub_command += xml_options
        sub_command += data_options
        sub_command += reliability_options

        print('Publisher command: {}'.format(
            ' '.join(element for element in pub_command)),
            flush=True
        )
        print('Subscriber command: {}'.format(
            ' '.join(element for element in sub_command)),
            flush=True
        )

        # Spawn processes
        publisher = subprocess.Popen(pub_command)
        subscriber = subprocess.Popen(sub_command)
        # Wait until finish
        subscriber.communicate()
        publisher.communicate()

        if subscriber.returncode != 0:
            exit(subscriber.returncode)
        elif publisher.returncode != 0:
            exit(publisher.returncode)
    else:
        # Base of test command to execute
        command = [
            executable,
            'both',
            '--time',
            test_duration,
            '--export_csv',
        ]

        # Manage security
        if security is True:
            command.append(
                './measurements_intraprocess_{}_security.csv'.format(
                    filename_options,
                )
            )
            command += security_options
        else:
            command.append(
                './measurements_intraprocess_{}.csv'.format(
                    filename_options,
                )
            )

        command += demands_options
        command += recoveries_options
        command += domain_options
        command += xml_options
        command += data_options
        command += reliability_options

        print('Executable command: {}'.format(
            ' '.join(element for element in command)),
            flush=True
        )

        # Spawn process
        both = subprocess.Popen(command)
        # Wait until finish
        both.communicate()
        exit(both.returncode)
    exit(0)
