# SPDX-License-Identifier: Apache-2.0
#
# Copyright (C) 2015, ARM Limited and contributors.
#
# 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 os

SCRIPT_NAME = 'remote_script.sh'

class TargetScript(object):
    """
    This class provides utility to create and run a script
    directly on a devlib target.

    The execute() method is made to look like Devlib's, so a Target instance can
    be swapped with an instance of this TargetScript class, and the commands
    will be accumulated for later use instead of being executed straight away.

    :param env: Reference TestEnv instance. Will be used for some commands
        that must really be executed instead of accumulated.
    :type env: TestEnv

    :param script_name: Name of the script that will be pushed on the target,
        defaults to "remote_script.sh"
    :type script_name: str
    """

    _target_attrs = ['screen_resolution', 'android_id', 'abi', 'os_version', 'model']

    def __init__(self, env, script_name=SCRIPT_NAME):
        self._env = env
        self._target = env.target
        self._script_name = script_name
        self.commands = []
        
    # This is made to look like the devlib Target execute()
    def execute(self, cmd):
        """
        Accumulate command for later execution.

        :param cmd: Command that would be run on the target
        :type cmd: str
        """
        self.append(cmd)

    def append(self, cmd):
        """
        Append a command to the script.

        :param cmd: Command string to append
        :type cmd: str
        """
        self.commands.append(cmd)

    # Some commands may require some info about the real target.
    # For instance, System.{h,v}swipe needs to get the value of
    # screen_resolution to generate a swipe command at a given
    # screen coordinate percentage.
    # Thus, if such a property is called on this object,
    # it will be fetched from the 'real' target object.
    def __getattr__(self, name):
        if name in self._target_attrs:
            return getattr(self._target, name)

        return getattr(super, name)
            
    def push(self):
        """
        Push a script to the target

        The script is created and stored on the host,
        and is then sent to the target.

        :param path: Path where the script will be locally created
        :type path: str
        :param actions: List of actions(commands) to run
        :type actions: list(str)
        """

        actions = ['set -e'] + self.commands + ['set +e']
        actions = ['#!{} sh'.format(self._target.busybox)] + actions
        actions = str.join('\n', actions)

        self._remote_path = self._target.path.join(self._target.executables_directory,
                                                   self._script_name)
        self._local_path = os.path.join(self._env.res_dir, self._script_name)

        # Create script locally
        with open(self._local_path, 'w') as script:
            script.write(actions)

        # Push it on target
        self._target.push(self._local_path, self._remote_path)
        self._target.execute('chmod +x {}'.format(self._remote_path))

    def run(self):
        """
        Run the previously pushed script
        """

        if self._target.file_exists(self._remote_path):
            self._target.execute(self._remote_path)
        else:
            raise IOError('Remote script was not found on target device')