import re

from hypertube.utils.exception.HypertubeException import HypertubeException
from hypertube.utils.Command import Command
from hypertube.utils.ExceptionType import ExceptionType


class ExceptionThrower:

    @staticmethod
    def throw_exception(command_exception: Command):
        try:
            stack_classes, stack_methods, stack_lines, stack_files = "", "", "", ""
            exception_message = "Python Exception with empty message"
            exception_name = "Python exception"
            stack_command = ""
            traceback_str = ""
            original_exception = ""

            exception_payload_len = len(command_exception.payload)
            if exception_payload_len >=8:
                stack_classes, stack_methods, stack_lines, stack_files = ExceptionThrower.get_local_stack_trace(
                    command_exception.get_payload()[4],
                    command_exception.get_payload()[5],
                    command_exception.get_payload()[6],
                    command_exception.get_payload()[7])

            if exception_payload_len >= 4:
                exception_message = command_exception.get_payload()[3]

            if exception_payload_len >= 3:
                exception_name = command_exception.get_payload()[2]

            if exception_payload_len >= 2:
                stack_command = command_exception.get_payload()[1]

            if exception_payload_len >= 1:
                original_exception = ExceptionType.to_exception(command_exception.get_payload()[0])


            for i in range(len(stack_classes)):
                if i < len(stack_files) and stack_files[i]:
                    traceback_str += "File \"{}\"".format(stack_files[i])
                if i < len(stack_lines) and stack_lines[i]:
                    traceback_str += ", line {}".format(stack_lines[i])
                if i < len(stack_methods) and stack_methods[i]:
                    traceback_str += ", in {}".format(stack_methods[i])
                traceback_str += "\n"
                if i < len(stack_classes) and stack_classes[i]:
                    traceback_str += "    {}\n".format(stack_classes[i])

            return ExceptionThrower.raise_exception(original_exception, exception_message, traceback_str)
        except Exception as e:
            return HypertubeException(str(e), "Error while processing exception: " + str(command_exception), "")

    @staticmethod
    def raise_exception(original_exception, exception_message, traceback_str):
        return HypertubeException(str(original_exception), exception_message, traceback_str)

    @staticmethod
    def get_local_stack_trace(stack_trace_classes, stack_trace_methods, stack_trace_lines, stack_trace_files):
        try:
            stack_classes = re.split("\\|", stack_trace_classes)
        except Exception:
            stack_classes = ""

        try:
            stack_methods = re.split("\\|", stack_trace_methods)
        except Exception:
            stack_methods = ""

        try:
            stack_lines = re.split("\\|", stack_trace_lines)
        except Exception:
            stack_lines = ""

        try:
            stack_files = re.split("\\|", stack_trace_files)
        except Exception:
            stack_files = ""
        return [stack_classes, stack_methods, stack_lines, stack_files]
