File Viewer

Download
from ..constants import ASSETS_PATH
from ..utils import download_image

from .node import Node
from .vector_elements import Line, Rectangle, UnknownElement
from .custom_elements import Button, Text, Image, TextEntry, ButtonHover

from jinja2 import Template
from pathlib import Path


class Frame(Node):
    def __init__(self, node, figma_file, output_path, frameCount=0):
        super().__init__(node)

        self.width, self.height = self.size()
        self.bg_color = self.color()

        self.counter = {}

        self.figma_file = figma_file

        self.output_path: Path = output_path
        self.assets_path: Path = output_path / ASSETS_PATH / f"frame{frameCount}"

        self.output_path.mkdir(parents=True, exist_ok=True)
        self.assets_path.mkdir(parents=True, exist_ok=True)

        self.elements = [
            self.create_element(child)
            for child in self.children
            if Node(child).visible
        ]

    def create_element(self, element):
        element_name = element["name"].strip().lower()
        element_type = element["type"].strip().lower()

        print(
            "Creating Element "
            f"{{ name: {element_name}, type: {element_type} }}"
        )

        if element_name == "button":
            self.counter[Button] = self.counter.get(Button, 0) + 1

            item_id = element["id"]
            image_url = self.figma_file.get_image(item_id)
            image_path = (
                self.assets_path / f"button_{self.counter[Button]}.png")
            download_image(image_url, image_path)

            image_path = image_path.relative_to(self.assets_path)

            return Button(
                element, self, image_path, id_=f"{self.counter[Button]}")

        #EXPERIMENTAL FEATURE 
        elif element_name == "buttonhover":
            self.counter[ButtonHover] = self.counter.get(ButtonHover, 0) + 1

            item_id = element["id"]
            image_url = self.figma_file.get_image(item_id)
            image_path = (
                self.assets_path / f"button_hover_{self.counter[ButtonHover]}.png")
            download_image(image_url, image_path)

            image_path = image_path.relative_to(self.assets_path)

            return ButtonHover(
                element, self, image_path)

        elif element_name in ("textbox", "textarea"):
            self.counter[TextEntry] = self.counter.get(TextEntry, 0) + 1

            item_id = element["id"]
            image_url = self.figma_file.get_image(item_id)
            image_path = (
                self.assets_path / f"entry_{self.counter[TextEntry]}.png")
            download_image(image_url, image_path)

            image_path = image_path.relative_to(self.assets_path)

            return TextEntry(
                element, self, image_path, id_=f"{self.counter[TextEntry]}")

        elif element_name == "image":
            self.counter[Image] = self.counter.get(Image, 0) + 1

            item_id = element["id"]
            image_url = self.figma_file.get_image(item_id)
            image_path = self.assets_path / f"image_{self.counter[Image]}.png"
            download_image(image_url, image_path)

            image_path = image_path.relative_to(self.assets_path)

            return Image(
                element, self, image_path, id_=f"{self.counter[Image]}")

        if element_name == "rectangle" or element_type == "rectangle":
            return Rectangle(element, self)

        if element_name == "line" or element_type == "line":
            return Line(element, self)

        elif element_type == "text":
            return Text(element, self)

        else:
            print(
                f"Element with the name: `{element_name}` cannot be parsed. "
                "Would be displayed as Black Rectangle")
            return UnknownElement(element, self)

    @property
    def children(self):
        # TODO: Convert nodes to Node objects before returning a list of them.
        return self.node.get("children")

    def color(self) -> str:
        """Returns HEX form of element RGB color (str)
        """
        try:
            color = self.node["fills"][0]["color"]
            r, g, b, *_ = [int(color.get(i, 0) * 255) for i in "rgba"]
            return f"#{r:02X}{g:02X}{b:02X}"
        except Exception:
            return "#FFFFFF"

    def size(self) -> tuple:
        """Returns element dimensions as width (int) and height (int)
        """
        bbox = self.node["absoluteBoundingBox"]
        width = bbox["width"]
        height = bbox["height"]
        return int(width), int(height)

    def to_code(self, template):
        t = Template(template)
        return t.render(
            window=self, elements=self.elements, assets_path=self.assets_path)


# Frame Subclasses


class Group(Frame):
    def __init__(self, node):
        super().__init__(node)


class Component(Frame):
    def __init__(self, node):
        super().__init__(node)


class ComponentSet(Frame):
    def __init__(self, node):
        super().__init__(node)


class Instance(Frame):
    def __init__(self, node):
        super().__init__(node)

    @property
    def component_id(self) -> str:
        self.node.get("componentId")