# Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.  Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#
"""The documentation of the omni.ui aka UI Framework"""
from .abstract_model_doc import AbstractModelDoc
from .attribute_editor_demo import AttributeEditorWindow
from .canvas_frame_doc import CanvasFrameDoc
from .checkbox_doc import CheckBoxDoc
from .colorwidget_doc import ColorWidgetDoc
from .combobox_doc import ComboBoxDoc
from .custom_window_example import BrickSunStudyWindow
from .dnd_doc import DNDDoc
from .doc_page import DocPage
from .field_doc import FieldDoc
from .image_doc import ImageDoc
from .layout_doc import LayoutDoc
from .length_doc import LengthDoc
from .md_doc import MdDoc
from .menu_bar_doc import MenuBarDoc
from .menu_doc import MenuDoc
from .multifield_doc import MultiFieldDoc
from .plot_doc import PlotDoc
from .progressbar_doc import ProgressBarDoc
from .scrolling_frame_doc import ScrollingFrameDoc
from .shape_doc import ShapeDoc
from .slider_doc import SliderDoc
from .styling_doc import StylingDoc
from .treeview_doc import TreeViewDoc
from .widget_doc import WidgetDoc
from .window_doc import WindowDoc
from .workspace_doc import WorkspaceDoc
from omni.kit.documentation.builder import DocumentationBuilderWindow
from omni.kit.documentation.builder import DocumentationBuilderMd
from omni.ui import color as cl
from omni.ui import constant as fl
from pathlib import Path
import omni.kit.app as app
import omni.ui as ui

EXTENSION_NAME = "OMNI.UI Demo"
SPACING = 5
CURRENT_PATH = Path(__file__).parent
DOCS_PATH = CURRENT_PATH.parent.parent.parent.parent.joinpath("docs")
MVD_PAGES = ["overview.md", "model.md", "delegate.md"]

class UIDoc(DocPage):
    """UI Doc Class"""

    def __init__(self, extension_path):
        super().__init__(extension_path)
        self.omniverse_version, _, _ = app.get_app_interface().get_build_version().partition("-")
        self.vertical_scrollbar_on = True

        self._extension_path = extension_path
        self._style_system = {
            "Button": {
                "background_color": 0xFFE1E1E1,
                "border_color": 0xFFADADAD,
                "border_width": 0.5,
                "border_radius": 0.0,
                "margin": 5.0,
                "padding": 5.0,
            },
            "Button.Label": {"color": 0xFF000000},
            "Button:hovered": {"background_color": 0xFFFBF1E5, "border_color": 0xFFD77800},
            "Button:pressed": {"background_color": 0xFFF7E4CC, "border_color": 0xFF995400, "border_width": 1.0},
        }

        self._example_windows = {}

        self._window_list = [["Attribute Editor", AttributeEditorWindow()], ["Custom Window", BrickSunStudyWindow()]]

        self._mvd_pages = [DocumentationBuilderMd(DOCS_PATH.joinpath(filename)) for filename in MVD_PAGES]
        self.index_list = [
            ["LAYOUT"],
            [
                "Arrangement of elements",
                LayoutDoc(extension_path),
                [
                    "HStack",
                    "VStack",
                    "ZStack",
                    "Spacing",
                    "Frame",
                    "VGrid",
                    "HGrid",
                    "CollapsableFrame",
                    "Placer",
                    "Visibility",
                    "Direction",
                ],
            ],
            ["Lengths", LengthDoc(extension_path), ["Pixel", "Percent", "Fraction"]],
            ["WIDGETS"],
            ["Styling", StylingDoc(extension_path), ["The Style Sheet Syntax", "Shades", "URL Shades", "Font Size"]],
            [
                "Base Widgets",
                WidgetDoc(extension_path),
                ["Button", "RadioButton", "Label", "Tooltip", "Debug Color", "Font"],
            ],
            ["Menu", MenuDoc(extension_path), []],
            ["ScrollingFrame", ScrollingFrameDoc(extension_path), []],
            ["CanvasFrame", CanvasFrameDoc(extension_path), []],
            ["Image", ImageDoc(extension_path), []],
            ["CheckBox", CheckBoxDoc(extension_path), []],
            ["AbstractValueModel", AbstractModelDoc(extension_path), []],
            ["ComboBox", ComboBoxDoc(extension_path), []],
            ["ColorWidget", ColorWidgetDoc(extension_path), []],
            ["MultiField", MultiFieldDoc(extension_path), []],
            ["TreeView", TreeViewDoc(extension_path), []],
            [
                "Shapes",
                ShapeDoc(extension_path),
                ["Rectangle", "Circle", "Triangle", "Line", "FreeRectangle", "FreeBezierCurve"],
            ],
            ["Fields", FieldDoc(extension_path), ["StringField"]],
            ["Sliders", SliderDoc(extension_path), ["FloatSlider", "IntSlider", "FloatDrag", "IntDrag"]],
            ["ProgressBar", ProgressBarDoc(extension_path), []],
            ["Plot", PlotDoc(extension_path), []],
            ["Drag and Drop", DNDDoc(extension_path), ["Minimal Example", "Styling and Tooltips"]],
        ]

        # Add .md files here
        self.index_list.append(["MODEL-DELEGATE-VIEW"])
        for page in self._mvd_pages:
            catalog = page.catalog
            topic = catalog[0]["name"]
            sub_topics = [c["name"] for c in catalog[0]["children"]]
            self.index_list.append([topic, MdDoc(extension_path, page), sub_topics])

        self.index_list += [
            ["WINDOWING SYSTEM"],
            [
                "Windows",
                WindowDoc(extension_path),
                ["Window", "ToolBar", "Multiple Modal Windows", "Overlay Other Windows", "Workspace", "Popup"],
            ],
            ["MenuBar", MenuBarDoc(extension_path), ["MenuBar"]],
            ["Workspace", WorkspaceDoc(extension_path), ["Controlling Windows", "Capture Layout"]],
        ]

        try:
            # TODO(vyudin): can we remove?
            import omni.kit.widget.webview

            webview_enabled = True
        except:
            webview_enabled = False

        if webview_enabled:
            from .web_doc import WebViewWidgetDoc

            web_view_widget_doc = WebViewWidgetDoc()
            self.index_list += [
                ["WEB WIDGETS"],
                ["WebViewWidget", web_view_widget_doc, web_view_widget_doc.get_sections()],
            ]

    def get_style(self):
        cl.ui_docs_nvidia = cl("#76b900")

        # Content
        cl.ui_docs_bg = cl.white
        cl.ui_docs_text = cl("#1a1a1a")
        cl.ui_docs_h1_bg = cl.black
        cl.ui_docs_code_bg = cl("#eeeeee")
        cl.ui_docs_code_line = cl("#bbbbbb")

        fl.ui_docs_code_radius = 2
        fl.ui_docs_text_size = 18

        # Catalog
        cl.ui_docs_catalog_bg = cl.black
        cl.ui_docs_catalog_hovered = cl("#1b1f20")

        style = DocumentationBuilderWindow.get_style()

        style.update({
            "Button::placed:hovered": {"background_color": 0xFF1111FF, "border_color": 0xFFFF0000, "border_width": 2},
            "CanvasFrame": {"background_color": 0xFFDDDDDD},
            "Circle::blue": {"background_color": 0xFFFF1111, "border_color": 0xFF0000CC, "border_width": 2},
            "Circle::default": {"background_color": 0xFF000000, "border_color": 0xFFFFFFFF, "border_width": 1},
            "Circle::placed:pressed": {"background_color": 0xFF1111FF, "border_color": 0xFFFF0000, "border_width": 2},
            "Circle::red": {"background_color": 0xFF1111FF, "border_color": 0xFFFF0000, "border_width": 2},
            "Image::index_h2": {"color": 0xFF484849, "image_url": f"{self._extension_path}/icons/plus.svg"},
            "Image::index_h2:selected": {"color": 0xFF5D5D5D, "image_url": f"{self._extension_path}/icons/minus.svg"},
            "Image::omniverse_image": {"image_url": "resources/icons/ov_logo_square.png", "margin": 5},
            "Label::caption": {"color": 0xFFFFFFFF, "font_size": 22.0, "margin_width": 10, "margin_height": 4},
            "Label::code": {"color": cl.ui_docs_text},
            "Label::index_h1": {
                "color": cl.ui_docs_nvidia,
                "font_size": 16.0,
                "margin_height": 5,
                "margin_width": 20,
            },
            "Label::index_h2": {"color": 0xFFD9D9D9, "font_size": 16.0, "margin_height": 5, "margin_width": 5},
            "Label::index_h2:selected": {"color": 0xFF404040},
            "Label::index_h3": {"color": 0xFF404040, "font_size": 16.0, "margin_height": 5, "margin_width": 30},
            "Label::omniverse_version": {"font_size": 16.0, "color": 0xFF4D4D4D, "margin": 10},
            "Label::section": {
                "color": cl.ui_docs_nvidia,
                "font_size": 22.0,
                "margin_width": 10,
                "margin_height": 4,
            },
            "Label::text": {"color": cl.ui_docs_text, "font_size": fl.ui_docs_text_size},
            "Line::default": {"color": 0xFF000000, "border_width": 1},
            "Line::demo": {"color": 0xFF555500, "border_width": 3},
            "Line::separator": {"color": 0xFF111111, "border_width": 2},
            "Line::underline": {"color": 0xFF444444, "border_width": 2},
            "Rectangle::caption": {"background_color": cl.ui_docs_nvidia},
            "Rectangle::code": {
                "background_color": cl.ui_docs_code_bg,
                "border_color": cl.ui_docs_code_line,
                "border_width": 1.0,
                "border_radius": fl.ui_docs_code_radius,
            },
            "Rectangle::placed:hovered": {
                "background_color": 0xFFFF6E00,
                "border_color": 0xFF111111,
                "border_width": 2,
            },
            "Rectangle::section": {"background_color": cl.ui_docs_h1_bg},
            "Rectangle::selection_h2": {"background_color": cl.ui_docs_catalog_bg},
            "Rectangle::selection_h2:hovered": {"background_color": 0xFF4A4A4E},
            "Rectangle::selection_h2:pressed": {"background_color": 0xFFB98029},
            "Rectangle::selection_h2:selected": {"background_color": 0xFFFCFCFC},
            "Rectangle::selection_h3": {"background_color": 0xFFE3E3E3},
            "Rectangle::selection_h3:hovered": {"background_color": 0xFFD6D6D6},
            "Rectangle::table": {"background_color": 0x0, "border_color": 0xFFCCCCCC, "border_width": 0.25},
            "ScrollingFrame::canvas": {"background_color": cl.ui_docs_bg},
            "Triangle::default": {"background_color": 0xFF00FF00, "border_color": 0xFFFFFFFF, "border_width": 1},
            "Triangle::orientation": {"background_color": 0xFF444444, "border_color": 0xFFFFFFFF, "border_width": 3},
            "VStack::layout": {"margin": 50},
            "VStack::layout_md": {"margin": 1},
        })

        return style

    def build_window(self, title):
        """Caled to load the extension"""
        self._window = ui.Window(title, width=1000, height=600, dockPreference=ui.DockPreference.LEFT_BOTTOM)
        # Populate UI once the window is visible
        self._window.frame.set_build_fn(self.build_window_content)

        # Dock it to the same space where Layers is docked
        if ui.Workspace.get_window("Content"):
            self._window.deferred_dock_in("Content")

    def rebuild(self):
        """Rebuild all the content"""
        self._window.frame.rebuild()

    def build_window_content(self):
        global_style = self.get_style()
        with ui.HStack():
            # Side panel with the table of contents
            with ui.ScrollingFrame(
                width=250,
                horizontal_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF,
                vertical_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF,
            ):
                with ui.ZStack(height=0):
                    ui.Rectangle(style={"background_color": 0xFF313134})
                    with ui.VStack(style=global_style, height=0):
                        # Omniverse logo and version
                        with ui.ZStack():
                            ui.Rectangle(style={"background_color": 0xFF000000})
                            with ui.VStack(style=global_style, height=0):
                                ui.Image(height=250, alignment=ui.Alignment.CENTER, name="omniverse_image")

                                # Cut the end of the version. It's enough to print:
                                # "Omniverse Version: 103.0+master..."
                                text = f"Omniverse Version: {self.omniverse_version}"
                                if len(text) > 32:
                                    text = text[:32] + "..."

                                ui.Label(
                                    text,
                                    alignment=ui.Alignment.CENTER,
                                    name="omniverse_version",
                                    tooltip=self.omniverse_version,
                                    # elided_text=True,
                                    content_clipping=True,
                                )

                        # The table of contents
                        with ui.VStack():
                            for entry in self.index_list:
                                if len(entry) == 1:
                                    # If entry has nothing, it's a h1 title
                                    ui.Label(entry[0], name="index_h1")
                                else:
                                    # Otherwise it's h2 title and it has h3 subtitles
                                    title = entry[0]
                                    sub_titles = entry[2]

                                    if len(entry) < 4:
                                        entry.append(None)
                                        entry.append(None)

                                    # Draw h2 title
                                    stack = ui.ZStack()
                                    entry[3] = stack

                                    with stack:
                                        ui.Rectangle(
                                            name="selection_h2",
                                            mouse_pressed_fn=lambda x, y, b, a, e=entry: self.show_a_doc(e),
                                        )
                                        with ui.HStack():
                                            ui.Spacer(width=10)
                                            with ui.VStack(width=0):
                                                ui.Spacer()
                                                ui.Image(name="index_h2", width=10, height=10)
                                                ui.Spacer()
                                            ui.Label(title, name="index_h2")

                                    # Draw h3 titles, they appear only if h2 is selected
                                    stack = ui.VStack(visible=False)
                                    entry[4] = stack
                                    with stack:
                                        for sub in sub_titles:
                                            with ui.ZStack():
                                                ui.Rectangle(
                                                    name="selection_h3",
                                                    mouse_pressed_fn=lambda x, y, b, a, e=entry, n=sub: self.show_a_doc(
                                                        e, n
                                                    ),
                                                )
                                                ui.Label(sub, name="index_h3")
                        ui.Label("WINDOW EXAMPLES", name="index_h1")

                        with ui.VStack():
                            for entry in self._window_list:
                                with ui.ZStack():
                                    ui.Rectangle(
                                        name="selection_h2",
                                        mouse_pressed_fn=lambda x, y, b, a, n=entry[0], w=entry[1]: self._show_a_window(
                                            n, w
                                        ),
                                    )
                                    with ui.HStack():
                                        ui.Spacer(width=20)
                                        ui.Label(entry[0], name="index_h2")

                        ui.Spacer(height=10)

            # The document
            if self.vertical_scrollbar_on:
                vertical_scrollbar_policy = ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_ON
            else:
                vertical_scrollbar_policy = ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF
            self._doc_scrolling_frame = ui.ScrollingFrame(
                style=global_style,
                name="canvas",
                horizontal_scrollbar_policy=ui.ScrollBarPolicy.SCROLLBAR_ALWAYS_OFF,
                vertical_scrollbar_policy=vertical_scrollbar_policy,
            )
            self._add_all_docs()

    def clean_entries(self):
        """Should be called when the extesion is reloaded to destroy the items, that can't be auto destroyed."""
        for entry in self.index_list:
            if len(entry) > 1 and entry[1]:
                entry[1].clean()

    def shutdown(self):
        """Should be called when the extesion us unloaded"""
        # Unfortunatley, the member variables are not destroyed when the extension is unloaded. We need to do it
        # automatically. Usually, it's OK because the Python garbage collector will eventually destroy everythigng. But
        # we need the images to be destroyed right now because Kit know nothing about Python garbage collector and it
        # will fire warning that texture is not destroyed.
        for page in self._mvd_pages:
            page.destroy()
        self._mvd_pages = []

        self.clean_entries()
        self._window = None

    def show_a_doc(self, entry, navigate_to=None):
        """ show a single doc """
        # Unselect/uncheck everything on the side panel
        for index_entry in self.index_list:
            if len(index_entry) == 5:
                _, _, _, item, sub_items = index_entry
                item.selected = False
                sub_items.visible = False

        self.clean_entries()

        # Select and show the given title
        _, doc, _, item, sub_items = entry
        item.selected = True
        sub_items.visible = True

        if isinstance(doc, MdDoc):
            style = "layout_md"
        else:
            style = "layout"

        with self._doc_scrolling_frame:  # The page itself
            with ui.VStack(height=0, spacing=20, name=style):
                doc.create_doc(navigate_to)

        if not navigate_to:
            # Scroll up if there is nothing to jump to because scrolling frame remembers the scrolling position of
            # the previous page
            self._doc_scrolling_frame.scroll_y = 0

    def _show_a_window(self, name, window_class):
        """ window an example window """
        if name not in self._example_windows:
            self._example_windows[name] = window_class.build_window()

        self._example_windows[name].visible = True

    def _add_all_docs(self):
        """The body of the document"""
        self.clean_entries()
        with self._doc_scrolling_frame:  # The page itself
            with ui.VStack(height=0, spacing=20, name="layout"):
                self._section_title("What is Omni::UI?")
                self._text(
                    "Omni::UI is Omniverse's UI toolkit for creating beautiful and flexible graphical user interfaces "
                    "in the Kit extensions. Omni::UI provides the basic types necessary to create rich extensions with "
                    "a fluid and dynamic user interface in Omniverse Kit. It gives a layout system and includes "
                    "widgets for creating visual components, receiving user input, and creating data models. It allows "
                    "user interface components to be built around their behavior and enables a declarative flavor of "
                    "describing the layout of the application. Omni::UI gives a very flexible styling system that "
                    "allows for deep customizing of the final look of the application."
                )

                for entry in self.index_list:
                    if len(entry) > 1 and entry[1] is not None:
                        entry[1].create_doc()
