# Copyright (c) 2020 Synopsys.
#
# SPDX-License-Identifier: Apache-2.0

'''Runners for Synopsys Metaware Debugger(mdb).'''


import shutil
import time
import os
from os import path

from runners.core import ZephyrBinaryRunner, RunnerCaps

try:
    import psutil
    MISSING_REQUIREMENTS = False
except ImportError:
    MISSING_REQUIREMENTS = True

# normally we should create class with common functionality inherited from
# ZephyrBinaryRunner and inherit MdbNsimBinaryRunner and MdbHwBinaryRunner
# from it. However as we do lookup for runners with
# ZephyrBinaryRunner.__subclasses__() such sub-sub-classes won't be found.
# So, we move all common functionality to helper functions instead.
def simulation_run(mdb_runner):
    return mdb_runner.nsim_args != ''

def get_cld_pid(mdb_process):
    try:
        parent = psutil.Process(mdb_process.pid)
        children = parent.children(recursive=True)
        for process in children:
            if process.name().startswith("cld"):
                return (True, process.pid)
    except psutil.Error:
        pass

    return (False, -1)

# MDB creates child process (cld) which won't be terminated if we simply
# terminate parents process (mdb). 'record_cld_pid' is provided to record 'cld'
# process pid to file (mdb.pid) so this process can be terminated correctly by
# twister infrastructure
def record_cld_pid(mdb_runner, mdb_process):
    for _i in range(100):
        found, pid = get_cld_pid(mdb_process)
        if found:
            mdb_pid_file = path.join(mdb_runner.build_dir, 'mdb.pid')
            mdb_runner.logger.debug("MDB CLD pid: " + str(pid) + " " + mdb_pid_file)
            with open(mdb_pid_file, 'w') as f:
                f.write(str(pid))
            return
        time.sleep(0.05)

def mdb_do_run(mdb_runner, command):
    commander = "mdb"

    mdb_runner.require(commander)

    mdb_basic_options = ['-nooptions', '-nogoifmain',
                        '-toggle=include_local_symbols=1']

    # remove previous .sc.project folder which has temporary settings
    # for MDB. This is useful for troubleshooting situations with
    # unexpected behavior of the debugger
    mdb_cfg_dir = path.join(mdb_runner.build_dir, '.sc.project')
    if path.exists(mdb_cfg_dir):
        shutil.rmtree(mdb_cfg_dir)

    # nsim
    if simulation_run(mdb_runner):
        mdb_target = ['-nsim', '@' + mdb_runner.nsim_args]
    # hardware target
    else:
        if mdb_runner.jtag == 'digilent':
            mdb_target = ['-digilent', mdb_runner.dig_device]
        else:
            # \todo: add support of other debuggers
            mdb_target = ['']

    if command == 'flash':
        if simulation_run(mdb_runner):
            # for nsim , can't run and quit immediately
            mdb_run = ['-run', '-cl']
        else:
            mdb_run = ['-run', '-cmd=-nowaitq run', '-cmd=quit', '-cl']
    elif command == 'debug':
        # use mdb gui to debug
        mdb_run = ['-OKN']

    if mdb_runner.cores == 1:
        # single core's mdb command is different with multicores
        mdb_cmd = ([commander] + mdb_basic_options + mdb_target +
                   mdb_run + [mdb_runner.elf_name])
    elif 1 < mdb_runner.cores <= 4:
        mdb_multifiles = '-multifiles='
        for i in range(mdb_runner.cores):
            # note that: mdb requires -pset starting from 1, not 0 !!!
            mdb_sub_cmd = ([commander] +
                        ['-pset={}'.format(i + 1),
                         '-psetname=core{}'.format(i),
            # -prop=download=2 is used for SMP application debug, only the 1st
            # core will download the shared image.
                         ('-prop=download=2' if i > 0 else '')] +
                         mdb_basic_options + mdb_target + [mdb_runner.elf_name])
            mdb_runner.check_call(mdb_sub_cmd)
            mdb_multifiles += ('core{}'.format(mdb_runner.cores-1-i) if i == 0 else ',core{}'.format(mdb_runner.cores-1-i))

        # to enable multi-core aware mode for use with the MetaWare debugger,
        # need to set the NSIM_MULTICORE environment variable to a non-zero value
        if simulation_run(mdb_runner):
            os.environ["NSIM_MULTICORE"] = '1'

        mdb_cmd = ([commander] + [mdb_multifiles] + mdb_run)
    else:
        raise ValueError('unsupported cores {}'.format(mdb_runner.cores))

    process = mdb_runner.popen_ignore_int(mdb_cmd)
    record_cld_pid(mdb_runner, process)


class MdbNsimBinaryRunner(ZephyrBinaryRunner):
    '''Runner front-end for nSIM via mdb.'''

    def __init__(self, cfg, cores=1, nsim_args=''):
        super().__init__(cfg)
        self.jtag = ''
        self.cores = int(cores)
        if nsim_args != '':
            self.nsim_args = path.join(cfg.board_dir, 'support', nsim_args)
        else:
            self.nsim_args = ''
        self.elf_name = cfg.elf_file
        self.build_dir = cfg.build_dir
        self.dig_device = ''

    @classmethod
    def name(cls):
        return 'mdb-nsim'

    @classmethod
    def capabilities(cls):
        return RunnerCaps(commands={'flash', 'debug'})

    @classmethod
    def do_add_parser(cls, parser):
        parser.add_argument('--cores', default=1,
                            help='''choose the cores that target has, e.g.
                                    --cores=1''')
        parser.add_argument('--nsim_args', default='',
                            help='''if given, arguments for nsim simulator
                                 through mdb which should be in
                                 <board_dir>/support, e.g. --nsim-args=
                                 mdb_em.args''')

    @classmethod
    def do_create(cls, cfg, args):
        return MdbNsimBinaryRunner(
            cfg,
            cores=args.cores,
            nsim_args=args.nsim_args)

    def do_run(self, command, **kwargs):
        mdb_do_run(self, command)


class MdbHwBinaryRunner(ZephyrBinaryRunner):
    '''Runner front-end for mdb.'''

    def __init__(self, cfg, cores=1, jtag='digilent', dig_device=''):
        super().__init__(cfg)
        self.jtag = jtag
        self.cores = int(cores)
        self.nsim_args = ''
        self.elf_name = cfg.elf_file
        if dig_device != '':
            self.dig_device = '-prop=dig_device=' + dig_device
        else:
            self.dig_device = ''
        self.build_dir = cfg.build_dir

    @classmethod
    def name(cls):
        return 'mdb-hw'

    @classmethod
    def capabilities(cls):
        return RunnerCaps(commands={'flash', 'debug'})

    @classmethod
    def do_add_parser(cls, parser):
        parser.add_argument('--jtag', default='digilent',
                            help='''choose the jtag interface for hardware
                                    targets, e.g. --jtat=digilent for digilent
                                    jtag adapter''')
        parser.add_argument('--cores', default=1,
                            help='''choose the number of cores that target has,
                                    e.g. --cores=1''')
        parser.add_argument('--dig-device', default='',
                            help='''choose the the specific digilent device to
                             connect, this is useful when multiple
                             targets are connected''')

    @classmethod
    def do_create(cls, cfg, args):
        return MdbHwBinaryRunner(
            cfg,
            cores=args.cores,
            jtag=args.jtag,
            dig_device=args.dig_device)

    def do_run(self, command, **kwargs):
        if MISSING_REQUIREMENTS:
            raise RuntimeError('one or more Python dependencies were missing; '
                               "see the getting started guide for details on "
                               "how to fix")

        mdb_do_run(self, command)
