import json
import logging
from typing import Optional, List

from report.command import AlignCommand, BoldCommand, FontCommand, RepeatCommand, NewLineCommand

from ._Report import Report
from ._Part import Part
from ._JsonReport import JsonReport

logger = logging.getLogger("PosActions")


class ReportParser(object):
    def parse(self, report):
        # type: (str) -> Optional[Report]

        try:
            report_dict = json.loads(report, "utf-8")
        except Exception as _:
            logger.exception("Error parsing report JSON data: {}".format(report))
            return None

        if "key" not in report_dict or report_dict["key"] != Report.key:
            logger.error("Error getting report key")
            return None

        if "parts" not in report_dict or not isinstance(report_dict["parts"], list):
            logger.error("Error getting report parts")
            return None

        parts = []
        for part_dict in report_dict["parts"]:
            text = part_dict["text"]
            commands_json = []
            if "commands" in part_dict:
                commands_json = part_dict["commands"]
                if commands_json is None:
                    commands_json = []

            part_commands = self._get_commands(commands_json)
            parts.append(Part(text, part_commands))

        return JsonReport(parts, report_dict["width"])

    @staticmethod
    def _get_commands(
            commands_json   # type: str
    ):
        # type: (...) -> List

        part_commands = []
        for command in commands_json:
            command_type = command["type"]
            if command_type == "align":
                part_commands.append(AlignCommand(AlignCommand.Alignment(command["alignment"])))
                continue

            if command_type == "bold":
                part_commands.append(BoldCommand(command["activate"]))
                continue

            if command_type == "font":
                part_commands.append(FontCommand(command["font"]))
                continue

            if command_type == "repeat":
                part_commands.append(RepeatCommand(command["count"], command["text"]))
                continue

            if command_type == "newLine":
                part_commands.append(NewLineCommand())

        return part_commands
