# DExTer : Debugging Experience Tester
# ~~~~~~   ~         ~~         ~   ~~
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
from collections import OrderedDict
import os
from typing import List

from dex.dextIR.BuilderIR import BuilderIR
from dex.dextIR.DebuggerIR import DebuggerIR
from dex.dextIR.StepIR import StepIR, StepKind


def _step_kind_func(context, step):
    if (step.current_location.path is None or
        not os.path.exists(step.current_location.path)):
        return StepKind.FUNC_UNKNOWN

    if any(os.path.samefile(step.current_location.path, f)
           for f in context.options.source_files):
        return StepKind.FUNC

    return StepKind.FUNC_EXTERNAL


class DextIR:
    """A full Dexter test report.

    This is composed of all the other *IR classes. They are used together to
    record Dexter inputs and the resultant debugger steps, providing a single
    high level access container.

    The Heuristic class works with dexter commands and the generated DextIR to
    determine the debugging score for a given test.

    Args:
        commands: { name (str), commands (list[CommandIR])
    """

    def __init__(self,
                 dexter_version: str,
                 executable_path: str,
                 source_paths: List[str],
                 builder: BuilderIR = None,
                 debugger: DebuggerIR = None,
                 commands: OrderedDict = None):
        self.dexter_version = dexter_version
        self.executable_path = executable_path
        self.source_paths = source_paths
        self.builder = builder
        self.debugger = debugger
        self.commands = commands
        self.steps: List[StepIR] = []

    def __str__(self):
        colors = 'rgby'
        st = '## BEGIN ##\n'
        color_idx = 0
        for step in self.steps:
            if step.step_kind in (StepKind.FUNC, StepKind.FUNC_EXTERNAL,
                                  StepKind.FUNC_UNKNOWN):
                color_idx += 1

            color = colors[color_idx % len(colors)]
            st += '<{}>{}</>\n'.format(color, step)
        st += '## END ({} step{}) ##\n'.format(
            self.num_steps, '' if self.num_steps == 1 else 's')
        return st

    @property
    def num_steps(self):
        return len(self.steps)

    def _get_prev_step_in_this_frame(self, step):
        """Find the most recent step in the same frame as `step`.

        Returns:
            StepIR or None if there is no previous step in this frame.
        """
        return next((s for s in reversed(self.steps)
            if s.current_function == step.current_function
            and s.num_frames == step.num_frames), None)

    def _get_new_step_kind(self, context, step):
        if step.current_function is None:
            return StepKind.UNKNOWN

        if len(self.steps) == 0:
            return _step_kind_func(context, step)

        prev_step = self.steps[-1]

        if prev_step.current_function is None:
            return StepKind.UNKNOWN

        if prev_step.num_frames < step.num_frames:
            return _step_kind_func(context, step)

        if prev_step.num_frames > step.num_frames:
            frame_step = self._get_prev_step_in_this_frame(step)
            prev_step = frame_step if frame_step is not None else prev_step

        # If we're missing line numbers to compare then the step kind has to be UNKNOWN.
        if prev_step.current_location.lineno is None or step.current_location.lineno is None:
            return StepKind.UNKNOWN

        # We're in the same func as prev step, check lineo.
        if prev_step.current_location.lineno > step.current_location.lineno:
            return StepKind.VERTICAL_BACKWARD

        if prev_step.current_location.lineno < step.current_location.lineno:
            return StepKind.VERTICAL_FORWARD

        # We're on the same line as prev step, check column.
        if prev_step.current_location.column > step.current_location.column:
            return StepKind.HORIZONTAL_BACKWARD

        if prev_step.current_location.column < step.current_location.column:
            return StepKind.HORIZONTAL_FORWARD

        # This step is in exactly the same location as the prev step.
        return StepKind.SAME

    def new_step(self, context, step):
        assert isinstance(step, StepIR), type(step)
        step.step_kind = self._get_new_step_kind(context, step)
        self.steps.append(step)
        return step

    def clear_steps(self):
        self.steps.clear()
