#!/usr/bin/env python3

# This is copied to NICOS_TEST_ROOT/bin/nicos-simulate when the tests run.
# It is adapted from bin/nicos-simulate to run correctly in the test
# environment.

import os
import sys
from shutil import which

from nicos import config
from nicos.core.sessions.simulation import SimulationSession
from nicos.protocols.cache import cache_load

from test.utils import runtime_root, selfDestructAfter

try:
    import coverage
except ImportError:
    pass
else:
    # Note: This will only fire up coverage if the COVERAGE_PROCESS_START env
    # variable is set
    coverage.process_startup()


sync_cache_file = None


class TestSimulationSession(SimulationSession):
    """
    Special session for the dry run tests.

    In the test suite, simulation mode cannot synchronize initial values from
    the cache, since there is no running cache that has values from the actual
    hardware (such as units from a Tango server).  Therefore, necessary values
    are given by a file.

    We need to apply the values from this file in two places:

    * apply them to the device configuration (as if they were given in the
      setup file) for values that need to be correct at device initialization
    * apply them as if they came from the cache in a normal dry run for values
      that are volatile
    """

    def begin_setup(self):
        # do not set log handler to ERROR level like in parent class

        def apply_param(dev, param, value):
            # apply a device parameter in all setups that contain this device
            for info in self._setup_info.values():
                for setupdev in info['devices']:
                    if setupdev.lower() == dev:
                        info['devices'][setupdev][1][param] = value

        # this hasn't been done at this point yet
        self.readSetups()

        # read the sync cache file and apply the values to the device config
        self._db = {}
        if sync_cache_file is None:
            return
        with open(sync_cache_file, encoding='utf-8') as fp:
            for line in fp:
                if line.startswith('nicos/'):
                    line = line[6:]
                key, value = line.split('=', 1)
                self._db[key] = cache_load(value)
                dev, param = key.split('/', 1)
                apply_param(dev, param, cache_load(value))

    def simulationSync(self, db=None):
        self._simulationSync_applyValues(self._db)


args = sys.argv[1:]
if len(args) < 4:
    raise SystemExit('Usage: nicos-simulate sock uuid setups user '
                     '[setup_subdirs [sync_cache_file]]')
sock = args[0]
uuid = args[1]
setups = args[2].split(',')
user = args[3]

if len(args) > 4:
    setup_subdirs = args[4].split(',')
else:
    setup_subdirs = ['../test']

if len(args) > 5 and os.path.isfile(args[5]):
    sync_cache_file = args[5]

code = sys.stdin.read()

config.apply()
config.nicos_root = runtime_root
config.setup_subdirs = setup_subdirs

# enable this if the helper is installed
config.sandbox_simulation = bool(which('nicos-sandbox-helper'))

selfDestructAfter(30)
TestSimulationSession.run(sock, uuid, setups, user, code)
