# 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 for Web features such as WebViewWidget implementations"""

from .doc_page import DocPage
from typing import List
import json
import omni.kit.widget.webview as webview
import omni.ui as ui

_BASE_STYLE = {
    "WebViewWidget": {"border_width": 0.5, "margin": 5.0, "padding": 5.0, "border_color": 0xFFFD761D},
    "Label": {"color": 0xFF000000, "margin": 5.0},
    "CheckBox": {"margin": 5.0},
}


class WebViewWidgetDoc(DocPage):
    """ Document for WebViewWidget"""

    def __init__(self):
        self._sections = [
            ("Displaying an url", self.create_displaying_an_url),
            ("Styling", self.create_styling),
            ("Content loading", self.create_content_loading),
            ("Non-opaque contents", self.create_non_opaque_contents),
            ("Communication", self.create_js_host_communication),
            ("Web page debugging", self.create_web_page_debugging),
        ]

    def get_sections(self) -> List[str]:
        return [t for (t, _) in self._sections]

    def create_doc(self, navigate_to=None):
        self._section_title("WebViewWidget")
        for (title, create_func) in self._sections:
            self._caption(title, navigate_to)
            create_func()

    def create_displaying_an_url(self):
        self._text(
            """The WebViewWidget type displays web pages.

The url can be loaded with 'load_url()'.

The load progress can be observed with 'loading_changed_fn' and 'progress_changed_fn' as well as the WebViewWidget properties 'loading' and 'progress'.
"""
        )

        with ui.VStack(style=_BASE_STYLE):
            loading_label = ui.Label("Load label")

            def update_progress(progress: float):
                loading_label.text = f"Loading {(progress * 100.0):.0f}% ..."

            def update_loading(loading: bool):
                if not loading:
                    loading_label.text = "Loading done."

            web_view = webview.WebViewWidget(
                width=ui.Percent(100),
                height=ui.Pixel(500),
                loading_changed_fn=update_loading,
                progress_changed_fn=update_progress,
            )
            urls = ["https://www.nvidia.com", "https://news.ycombinator.com", "http://google.com"]
            web_view.load_url(urls[0])

            def change_url(model, _item):
                url = urls[model.get_item_value_model().as_int]
                web_view.load_url(url)

            url_selector = ui.ComboBox(0, *urls)
            url_selector.model.add_item_changed_fn(change_url)

    def create_styling(self):
        self._text(
            """The WebViewWidget can be styled normally.

Here we create a web view with rounded corners and wider borders.

In this example, we also use 'url' constructor property to start the load."""
        )
        style = {
            "WebViewWidget": {
                "border_width": 3,
                "border_radius": 7,
                "margin": 5.0,
                "padding": 5.0,
                "border_color": 0xFFFD761D,
            }
        }

        with ui.VStack(style=_BASE_STYLE):
            webview.WebViewWidget(width=ui.Percent(100), height=ui.Pixel(500), url="https://www.google.com")

    def create_content_loading(self):
        self._text(
            """The WebViewWidget can be populated with static html with the 'html' constructor property.

In this case, the 'url' property describes the base url of the document."""
        )
        style = {"WebViewWidget": {"border_width": 0.5, "margin": 5.0, "padding": 5.0, "border_color": 0xFFFD761D}}
        with ui.VStack(style=style):
            webview.WebViewWidget(
                width=ui.Percent(100),
                height=ui.Pixel(500),
                html='<body><h1>Hello from web page</h1><p>This is web content. Here\'s a link <a href="http://wwf.org">into the wild.</a></p></body>',
                url="http://example.com/content_loading",
            )

    def create_non_opaque_contents(self):
        self._text(
            """The WebViewWidget can be marked non-opaque so transparent or translucent contents work.

The magenta circles are omni.ui widgets and can be seen beneath and on top of the WebViewWidget.

The web page is marked as transparent with 'contents_is_opaque=False' and then with HTML body css property 'background: transparent'.
"""
        )

        html = """<body style="background: transparent">
  <h3 style="background: rgba(255, 0, 0, 0.4)">Web page input</h3>
  <input type="text" value="..text 1.." /> <br/>
  <input type="text" value="..text 2.." style="background: rgba(255,255,255,0.5)"/> <br/>
  <input type="text" value="..text 3.." /> <br/>
  <input type="text" value="..text 4.." style="background: rgba(255,255,255,0.5)"/> <br/>
  <input type="text" value="..text last.." /> <br/>
</body>
"""

        with ui.VStack(style=_BASE_STYLE):
            ui.Circle(
                radius=100,
                size_policy=ui.CircleSizePolicy.FIXED,
                alignment=ui.Alignment.LEFT_BOTTOM,
                style={"background_color": 0xDDFF00AA},
            )
            webview.WebViewWidget(
                width=ui.Percent(100),
                height=ui.Pixel(200),
                contents_is_opaque=False,
                html=html,
                url="http://example.com/non_opaque_contents",
                style={"background_color": 0},
            )
            ui.Circle(
                radius=100,
                size_policy=ui.CircleSizePolicy.FIXED,
                alignment=ui.Alignment.LEFT_TOP,
                style={"background_color": 0xDDFFAAAA},
            )

    def create_js_host_communication(self):
        self._text(
            """The WebViewWidget can control the JavaScript application by using WebViewWidget.evaluate_javascript.

The JavaScript application can send data to the host application by using window.nvwebview.messageHandlers.<name>.postMessage("msg").

"""
        )
        html = """<body>
  <script>
  function sendToHost() {
    var v = document.getElementById("toHost");
    window.nvwebview.messageHandlers.hostApp.postMessage(v.value);
  }
  function receiveFromHost(data)
  {
    document.getElementById('fromHost').value = data;
  }
  </script>
  <h3>From JS application to host application</h3>
  Text to send: <input id="toHost" type="text" value="Hello from &quot;JS&quot; application" size="75" /> <br/>
  <input type="button" value="Send message to host application" onclick="javascript: sendToHost();" /> <br/>
  <h3>From host application to JS application</h3>
  <input id="fromHost" type="text" value="Message from host application comes here" readonly size="75"/> <br/>
</body>
"""
        message_to_send = 'Hello from "host" application \U0001f600.'
        webview_widget = None
        message_from_js_label = None
        send_to_js_button = None
        with ui.VStack(style=_BASE_STYLE):
            send_to_js_button = ui.Button("Send hello to JS application", width=0)
            message_from_js_label = ui.Label("Message from JS application comes here")
            webview_widget = webview.WebViewWidget(width=ui.Percent(100), height=ui.Pixel(300))

        def send_to_js():
            webview_widget.evaluate_javascript(f"receiveFromHost({json.dumps(message_to_send)})")

        send_to_js_button.set_clicked_fn(send_to_js)

        def update_message_from_js_label(msg: str):
            message_from_js_label.text = msg

        webview_widget.set_user_script_message_handler_fn("hostApp", update_message_from_js_label)
        webview_widget.load_html_from_url(html, "https://example.com/js_host_communication")

    def create_web_page_debugging(self):
        self._text(
            """The WebViewWidget.set_remote_web_page_debugging_enabled(true) can be used to enable Chrome Web Inspector debugging for all the WebViewWidget instances.

Enable the web page debugging below. Using the desktop Chrome browser, navigate to chrome://inspect to see list of WebViewWidget instances in the process.
"""
        )
        webview.WebViewWidget.set_remote_web_page_debugging_enabled(False)
        checkbox = None

        def update_remote_debugging(value_model):
            webview.WebViewWidget.set_remote_web_page_debugging_enabled(value_model.get_value_as_bool())

        with ui.HStack(style=_BASE_STYLE):
            ui.Label("Remote web page debugging enabled", width=0, style={"color": 0xFF000000})
            checkbox = ui.CheckBox()
            checkbox.model.add_value_changed_fn(update_remote_debugging)
        with ui.VStack():
            ui.Spacer()
            ui.Spacer()
