/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

#![allow(unsafe_code)]

use std::borrow::Cow;
use std::fmt;
use std::iter::FusedIterator;

use base::id::{BrowsingContextId, PipelineId};
use fonts_traits::ByteIndex;
use layout_api::wrapper_traits::{
    LayoutDataTrait, LayoutNode, PseudoElementChain, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
use layout_api::{
    GenericLayoutData, HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType,
    SVGElementData, StyleData, TrustedNodeAddress,
};
use net_traits::image_cache::Image;
use pixels::ImageMetadata;
use range::Range;
use selectors::Element as _;
use servo_arc::Arc;
use servo_url::ServoUrl;
use style;
use style::dom::{NodeInfo, TElement, TNode, TShadowRoot};
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;

use super::{
    ServoLayoutDocument, ServoLayoutElement, ServoShadowRoot, ServoThreadSafeLayoutElement,
};
use crate::dom::bindings::inheritance::NodeTypeId;
use crate::dom::bindings::root::LayoutDom;
use crate::dom::element::{Element, LayoutElementHelpers};
use crate::dom::node::{LayoutNodeHelpers, Node, NodeFlags, NodeTypeIdWrapper};

/// A wrapper around a `LayoutDom<Node>` which provides a safe interface that
/// can be used during layout. This implements the `LayoutNode` trait as well as
/// several style and selectors traits for use during layout. This version
/// should only be used on a single thread. If you need to use nodes across
/// threads use ServoThreadSafeLayoutNode.
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
pub struct ServoLayoutNode<'dom> {
    /// The wrapped private DOM node.
    pub(super) node: LayoutDom<'dom, Node>,
}

/// Those are supposed to be sound, but they aren't because the entire system
/// between script and layout so far has been designed to work around their
/// absence. Switching the entire thing to the inert crate infra will help.
///
/// FIXME(mrobinson): These are required because Layout 2020 sends non-threadsafe
/// nodes to different threads. This should be adressed in a comprehensive way.
unsafe impl Send for ServoLayoutNode<'_> {}
unsafe impl Sync for ServoLayoutNode<'_> {}

impl fmt::Debug for ServoLayoutNode<'_> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(el) = self.as_element() {
            el.fmt(f)
        } else if self.is_text_node() {
            write!(f, "<text node> ({:#x})", self.opaque().0)
        } else {
            write!(f, "<non-text node> ({:#x})", self.opaque().0)
        }
    }
}

impl<'dom> ServoLayoutNode<'dom> {
    pub(super) fn from_layout_js(n: LayoutDom<'dom, Node>) -> Self {
        ServoLayoutNode { node: n }
    }

    /// Create a new [`ServoLayoutNode`] for this given [`TrustedNodeAddress`].
    ///
    /// # Safety
    ///
    /// The address pointed to by `address` should point to a valid node in memory.
    pub unsafe fn new(address: &TrustedNodeAddress) -> Self {
        let node = unsafe { LayoutDom::from_trusted_node_address(*address) };
        ServoLayoutNode::from_layout_js(node)
    }

    pub(super) fn script_type_id(&self) -> NodeTypeId {
        self.node.type_id_for_layout()
    }

    /// Returns the interior of this node as a `LayoutDom`.
    pub(crate) fn get_jsmanaged(self) -> LayoutDom<'dom, Node> {
        self.node
    }

    pub(crate) fn assigned_slot(self) -> Option<ServoLayoutElement<'dom>> {
        self.node
            .assigned_slot_for_layout()
            .as_ref()
            .map(LayoutDom::upcast)
            .map(ServoLayoutElement::from_layout_js)
    }
}

impl style::dom::NodeInfo for ServoLayoutNode<'_> {
    fn is_element(&self) -> bool {
        self.node.is_element_for_layout()
    }

    fn is_text_node(&self) -> bool {
        self.node.is_text_node_for_layout()
    }
}

impl<'dom> style::dom::TNode for ServoLayoutNode<'dom> {
    type ConcreteDocument = ServoLayoutDocument<'dom>;
    type ConcreteElement = ServoLayoutElement<'dom>;
    type ConcreteShadowRoot = ServoShadowRoot<'dom>;

    fn parent_node(&self) -> Option<Self> {
        self.node.parent_node_ref().map(Self::from_layout_js)
    }

    fn first_child(&self) -> Option<Self> {
        self.node.first_child_ref().map(Self::from_layout_js)
    }

    fn last_child(&self) -> Option<Self> {
        self.node.last_child_ref().map(Self::from_layout_js)
    }

    fn prev_sibling(&self) -> Option<Self> {
        self.node.prev_sibling_ref().map(Self::from_layout_js)
    }

    fn next_sibling(&self) -> Option<Self> {
        self.node.next_sibling_ref().map(Self::from_layout_js)
    }

    fn owner_doc(&self) -> Self::ConcreteDocument {
        ServoLayoutDocument::from_layout_js(self.node.owner_doc_for_layout())
    }

    fn traversal_parent(&self) -> Option<ServoLayoutElement<'dom>> {
        if let Some(assigned_slot) = self.assigned_slot() {
            return Some(assigned_slot);
        }
        let parent = self.parent_node()?;
        if let Some(shadow) = parent.as_shadow_root() {
            return Some(shadow.host());
        };
        parent.as_element()
    }

    fn opaque(&self) -> style::dom::OpaqueNode {
        self.get_jsmanaged().opaque()
    }

    fn debug_id(self) -> usize {
        self.opaque().0
    }

    fn as_element(&self) -> Option<ServoLayoutElement<'dom>> {
        self.node.downcast().map(ServoLayoutElement::from_layout_js)
    }

    fn as_document(&self) -> Option<ServoLayoutDocument<'dom>> {
        self.node
            .downcast()
            .map(ServoLayoutDocument::from_layout_js)
    }

    fn as_shadow_root(&self) -> Option<ServoShadowRoot<'dom>> {
        self.node.downcast().map(ServoShadowRoot::from_layout_js)
    }

    fn is_in_document(&self) -> bool {
        unsafe { self.node.get_flag(NodeFlags::IS_IN_A_DOCUMENT_TREE) }
    }
}

impl<'dom> LayoutNode<'dom> for ServoLayoutNode<'dom> {
    type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'dom>;

    fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode {
        ServoThreadSafeLayoutNode::new(*self)
    }

    fn type_id(&self) -> LayoutNodeType {
        NodeTypeIdWrapper(self.script_type_id()).into()
    }

    unsafe fn initialize_style_and_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self) {
        let inner = self.get_jsmanaged();
        if inner.style_data().is_none() {
            unsafe { inner.initialize_style_data() };
        }
        if inner.layout_data().is_none() {
            unsafe { inner.initialize_layout_data(Box::<RequestedLayoutDataType>::default()) };
        }
    }

    fn is_connected(&self) -> bool {
        unsafe { self.node.get_flag(NodeFlags::IS_CONNECTED) }
    }

    fn style_data(&self) -> Option<&'dom StyleData> {
        self.get_jsmanaged().style_data()
    }

    fn layout_data(&self) -> Option<&'dom GenericLayoutData> {
        self.get_jsmanaged().layout_data()
    }
}

/// A wrapper around a `ServoLayoutNode` that can be used safely on different threads.
/// It's very important that this never mutate anything except this wrapped node and
/// never access any other node apart from its parent.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ServoThreadSafeLayoutNode<'dom> {
    /// The wrapped [`ServoLayoutNode`].
    pub(super) node: ServoLayoutNode<'dom>,

    /// The possibly nested [`PseudoElementChain`] for this node.
    pub(super) pseudo_element_chain: PseudoElementChain,
}

impl<'dom> ServoThreadSafeLayoutNode<'dom> {
    /// Creates a new `ServoThreadSafeLayoutNode` from the given `ServoLayoutNode`.
    pub fn new(node: ServoLayoutNode<'dom>) -> Self {
        ServoThreadSafeLayoutNode {
            node,
            pseudo_element_chain: Default::default(),
        }
    }

    /// Returns the interior of this node as a `LayoutDom`. This is highly unsafe for layout to
    /// call and as such is marked `unsafe`.
    unsafe fn get_jsmanaged(&self) -> LayoutDom<'dom, Node> {
        self.node.get_jsmanaged()
    }

    /// Get the first child of this node. Important: this is not safe for
    /// layout to call, so it should *never* be made public.
    unsafe fn dangerous_first_child(&self) -> Option<Self> {
        let js_managed = unsafe { self.get_jsmanaged() };
        js_managed
            .first_child_ref()
            .map(ServoLayoutNode::from_layout_js)
            .map(Self::new)
    }

    /// Get the next sibling of this node. Important: this is not safe for
    /// layout to call, so it should *never* be made public.
    unsafe fn dangerous_next_sibling(&self) -> Option<Self> {
        let js_managed = unsafe { self.get_jsmanaged() };
        js_managed
            .next_sibling_ref()
            .map(ServoLayoutNode::from_layout_js)
            .map(Self::new)
    }

    /// Whether this is a container for the text within a single-line text input. This
    /// is used to solve the special case of line height for a text entry widget.
    /// <https://html.spec.whatwg.org/multipage/#the-input-element-as-a-text-entry-widget>
    // TODO(stevennovaryo): Remove the addition of HTMLInputElement here once all of the
    //                      input element is implemented with UA shadow DOM. This is temporary
    //                      workaround for past version of input element where we are
    //                      rendering it as a bare html element.
    pub fn is_single_line_text_input(&self) -> bool {
        self.type_id() == Some(LayoutNodeType::Element(LayoutElementType::HTMLInputElement)) ||
            (self.pseudo_element_chain.is_empty() &&
                self.node.node.is_text_container_of_single_line_input())
    }

    pub fn is_text_input(&self) -> bool {
        self.node.node.is_text_input()
    }

    pub fn selected_style(&self) -> Arc<ComputedValues> {
        let Some(element) = self.as_element() else {
            // TODO(stshine): What should the selected style be for text?
            debug_assert!(self.is_text_node());
            return self.parent_style();
        };

        let style_data = &element.style_data().styles;
        let get_selected_style = || {
            // This is a workaround for handling the `::selection` pseudos where it would not
            // propagate to the children and Shadow DOM elements. For this case, UA widget
            // inner elements should follow the originating element in terms of selection.
            if self.node.node.is_in_ua_widget() {
                return Some(element.containing_shadow_host()?.as_node().selected_style());
            }
            style_data.pseudos.get(&PseudoElement::Selection).cloned()
        };

        get_selected_style().unwrap_or_else(|| style_data.primary().clone())
    }
}

impl style::dom::NodeInfo for ServoThreadSafeLayoutNode<'_> {
    fn is_element(&self) -> bool {
        self.node.is_element()
    }

    fn is_text_node(&self) -> bool {
        self.node.is_text_node()
    }
}

impl<'dom> ThreadSafeLayoutNode<'dom> for ServoThreadSafeLayoutNode<'dom> {
    type ConcreteNode = ServoLayoutNode<'dom>;
    type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'dom>;
    type ConcreteElement = ServoLayoutElement<'dom>;
    type ChildrenIterator = ServoThreadSafeLayoutNodeChildrenIterator<'dom>;

    fn opaque(&self) -> style::dom::OpaqueNode {
        unsafe { self.get_jsmanaged().opaque() }
    }

    fn pseudo_element_chain(&self) -> PseudoElementChain {
        self.pseudo_element_chain
    }

    fn type_id(&self) -> Option<LayoutNodeType> {
        if self.pseudo_element_chain.is_empty() {
            Some(self.node.type_id())
        } else {
            None
        }
    }

    fn parent_style(&self) -> Arc<ComputedValues> {
        let parent_element = self.node.traversal_parent().unwrap();
        let parent_data = parent_element.borrow_data().unwrap();
        parent_data.styles.primary().clone()
    }

    fn initialize_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self) {
        let inner = self.node.get_jsmanaged();
        if inner.layout_data().is_none() {
            unsafe {
                inner.initialize_layout_data(Box::<RequestedLayoutDataType>::default());
            }
        }
    }

    fn debug_id(self) -> usize {
        self.node.debug_id()
    }

    fn children(&self) -> style::dom::LayoutIterator<Self::ChildrenIterator> {
        style::dom::LayoutIterator(ServoThreadSafeLayoutNodeChildrenIterator::new(*self))
    }

    fn as_element(&self) -> Option<ServoThreadSafeLayoutElement<'dom>> {
        self.node
            .as_element()
            .map(|el| ServoThreadSafeLayoutElement {
                element: el,
                pseudo_element_chain: self.pseudo_element_chain,
            })
    }

    fn as_html_element(&self) -> Option<ServoThreadSafeLayoutElement<'dom>> {
        self.as_element()
            .filter(|element| element.element.is_html_element())
    }

    fn style_data(&self) -> Option<&'dom StyleData> {
        self.node.style_data()
    }

    fn layout_data(&self) -> Option<&'dom GenericLayoutData> {
        self.node.layout_data()
    }

    fn unsafe_get(self) -> Self::ConcreteNode {
        self.node
    }

    fn node_text_content(self) -> Cow<'dom, str> {
        unsafe { self.get_jsmanaged().text_content() }
    }

    fn selection(&self) -> Option<Range<ByteIndex>> {
        let this = unsafe { self.get_jsmanaged() };

        this.selection().map(|range| {
            Range::new(
                ByteIndex(range.start as isize),
                ByteIndex(range.len() as isize),
            )
        })
    }

    fn image_url(&self) -> Option<ServoUrl> {
        let this = unsafe { self.get_jsmanaged() };
        this.image_url()
    }

    fn image_density(&self) -> Option<f64> {
        let this = unsafe { self.get_jsmanaged() };
        this.image_density()
    }

    fn image_data(&self) -> Option<(Option<Image>, Option<ImageMetadata>)> {
        let this = unsafe { self.get_jsmanaged() };
        this.image_data()
    }

    fn canvas_data(&self) -> Option<HTMLCanvasData> {
        let this = unsafe { self.get_jsmanaged() };
        this.canvas_data()
    }

    fn media_data(&self) -> Option<HTMLMediaData> {
        let this = unsafe { self.get_jsmanaged() };
        this.media_data()
    }

    fn svg_data(&self) -> Option<SVGElementData> {
        let this = unsafe { self.get_jsmanaged() };
        this.svg_data()
    }

    // Can return None if the iframe has no nested browsing context
    fn iframe_browsing_context_id(&self) -> Option<BrowsingContextId> {
        let this = unsafe { self.get_jsmanaged() };
        this.iframe_browsing_context_id()
    }

    // Can return None if the iframe has no nested browsing context
    fn iframe_pipeline_id(&self) -> Option<PipelineId> {
        let this = unsafe { self.get_jsmanaged() };
        this.iframe_pipeline_id()
    }

    fn get_span(&self) -> Option<u32> {
        unsafe {
            self.get_jsmanaged()
                .downcast::<Element>()
                .unwrap()
                .get_span()
        }
    }

    fn get_colspan(&self) -> Option<u32> {
        unsafe {
            self.get_jsmanaged()
                .downcast::<Element>()
                .unwrap()
                .get_colspan()
        }
    }

    fn get_rowspan(&self) -> Option<u32> {
        unsafe {
            self.get_jsmanaged()
                .downcast::<Element>()
                .unwrap()
                .get_rowspan()
        }
    }

    fn with_pseudo_element_chain(&self, pseudo_element_chain: PseudoElementChain) -> Self {
        Self {
            node: self.node,
            pseudo_element_chain,
        }
    }
}

pub enum ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
    /// Iterating over the children of a node
    Node(Option<ServoThreadSafeLayoutNode<'dom>>),
    /// Iterating over the assigned nodes of a `HTMLSlotElement`
    Slottables(<Vec<ServoLayoutNode<'dom>> as IntoIterator>::IntoIter),
}

impl<'dom> ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
    #[allow(unsafe_code)]
    fn new(
        parent: ServoThreadSafeLayoutNode<'dom>,
    ) -> ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
        if let Some(element) = parent.as_element() {
            if let Some(shadow) = element.shadow_root() {
                return Self::new(shadow.as_node().to_threadsafe());
            };

            let slotted_nodes = element.slotted_nodes();
            if !slotted_nodes.is_empty() {
                #[allow(clippy::unnecessary_to_owned)] // Clippy is wrong.
                return Self::Slottables(slotted_nodes.to_owned().into_iter());
            }
        }

        Self::Node(unsafe { parent.dangerous_first_child() })
    }
}

impl<'dom> Iterator for ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
    type Item = ServoThreadSafeLayoutNode<'dom>;

    fn next(&mut self) -> Option<Self::Item> {
        match self {
            Self::Node(node) => {
                let next_sibling = unsafe { (*node)?.dangerous_next_sibling() };
                std::mem::replace(node, next_sibling)
            },
            Self::Slottables(slots) => slots.next().map(|node| node.to_threadsafe()),
        }
    }
}

impl FusedIterator for ServoThreadSafeLayoutNodeChildrenIterator<'_> {}
