# Copyright (c) 2021 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from abc import abstractmethod

from .abstract_board import AbstractBoard
from ...resources.resource import AbstractResource

from typing import List, Optional
import os

import m5

class KernelDiskWorkload:
    """
    The purpose of this abstract class is to enable a full-system boot
    consisting of of a kernel which will then load a disk image.

    For this to function correctly, the KernelDiskWorkload class should be
    added as a superclass to a board and the abstract methods implemented.
    E.g.:

    ```
    class X86Board(AbstractBoard, KernelDiskWorkload):
        ...
        @overrides(KernelDiskWorkload)
        def get_default_kernel_args(self) -> List[str]:
            return [
                "earlyprintk=ttyS0",
                "console=ttyS0",
                "lpj=7999923",
                "root={root_value}",
            ]
        ...
    ```

    Notes
    -----

    * This assumes only one disk is set.
    * This assumes the Linux kernel is used.
    """

    @abstractmethod
    def get_default_kernel_args(self) -> List[str]:
        """
        Returns a default list of arguments for the workload kernel. We assume
        the following strings may be used as placeholders, to be replaced when
        `set_kernel_disk_workload` is executed:

        * `{root_value}` : set to `get_default_kernel_root_val()`.

        :returns: A default list of arguments for the workload kernel.
        """
        raise NotImplementedError

    @abstractmethod
    def get_disk_device(self) -> str:
        """
        Get the disk device, e.g., "/dev/sda", where the disk image is placed.

        :returns: The disk device.
        """
        raise NotImplementedError

    @abstractmethod
    def _add_disk_to_board(self, disk_image: AbstractResource) -> None:
        """
        Sets the configuration needed to add the disk image to the board.

        **Note:** This will be executed at the end of the
        `set_kernel_disk_workload` function.

        :param disk_image: The disk image to add to the system.
        """
        raise NotImplementedError

    def get_disk_root_partition(
        cls, disk_image: AbstractResource
    ) -> Optional[str]:
        """
        Obtains the root partition of a disk image by inspecting the resource's
        metadata.

        :returns: The disk image's root partition.
        """
        try:
            return disk_image.get_metadata()["additional_metadata"][
                "root_partition"
            ]
        except KeyError:
            return None

    def get_default_kernel_root_val(self, disk_image: AbstractResource) -> str:
        """
        Get the default kernel root value to be passed to the kernel. This is
        determined by the value implemented in the `get_disk_device()`
        function, and the disk image partition, obtained from
        `get_disk_root_partition()`


        :param disk_image: The disk image to be added to the system.
        :returns: The default value for the 'root' argument to be passed to the
        kernel.
        """
        return self.get_disk_device() + (
            self.get_disk_root_partition(disk_image) or ""
        )

    def set_kernel_disk_workload(
        self,
        kernel: AbstractResource,
        disk_image: AbstractResource,
        bootloader: Optional[AbstractResource] = None,
        readfile: Optional[str] = None,
        readfile_contents: Optional[str] = None,
        kernel_args: Optional[List[str]] = None,
        exit_on_work_items: bool = True,
    ) -> None:
        """
        This function allows the setting of a full-system run with a Kernel
        and a disk image.

        :param kernel: The kernel to boot.
        :param disk_image: The disk image to mount.
        :param bootloader: The current implementation of the ARM board requires
        three resources to operate -- kernel, disk image, and, a bootloader.
        :param readfile: An optional parameter stating the file to be read by
        by `m5 readfile`.
        :param readfile_contents: An optional parameter stating the contents of
        the readfile file. If set with `readfile`, the contents of `readfile`
        will be overwritten with `readfile_contents`, otherwise a new file will
        be created with the value of `readfile_contents`.
        :param kernel_args: An optional parameter for setting arguments to be
        passed to the kernel. By default set to `get_default_kernel_args()`.
        :param exit_on_work_items: Whether the simulation should exit on work
        items. True by default.
        """

        # We assume this this is in a multiple-inheritance setup with an
        # Abstract board. This function will not work otherwise.
        assert(isinstance(self,AbstractBoard))

        # If we are setting a workload of this type, we need to run as a
        # full-system simulation.
        self._set_fullsystem(True)

        # Set the kernel to use.
        self.workload.object_file = kernel.get_local_path()

        # Set the arguments to be passed to the kernel.
        self.workload.command_line = (
            " ".join(kernel_args or self.get_default_kernel_args())
        ).format(
            root_value=self.get_default_kernel_root_val(disk_image=disk_image)
        )

        # Setting the bootloader information for ARM board. The current
        # implementation of the ArmBoard class expects a boot loader file to be
        # provided along with the kernel and the disk image.

        if bootloader is not None:
            self._bootloader = [bootloader.get_local_path()]

        # Set the readfile.
        if readfile:
            self.readfile = readfile
        elif readfile_contents:
            self.readfile = os.path.join(m5.options.outdir, "readfile")

        # Add the contents to the readfile, if specified.
        if readfile_contents:
            file = open(self.readfile, "w+")
            file.write(readfile_contents)
            file.close()

        self._add_disk_to_board(disk_image=disk_image)

        # Set whether to exit on work items.
        self.exit_on_work_items = exit_on_work_items
