/* 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::Debug;

use atomic_refcell::AtomicRef;
use base::id::{BrowsingContextId, PipelineId};
use fonts_traits::ByteIndex;
use html5ever::{LocalName, Namespace};
use malloc_size_of_derive::MallocSizeOf;
use net_traits::image_cache::Image;
use pixels::ImageMetadata;
use range::Range;
use servo_arc::Arc;
use servo_url::ServoUrl;
use style::attr::AttrValue;
use style::context::SharedStyleContext;
use style::data::ElementData;
use style::dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TNode};
use style::properties::ComputedValues;
use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl};
use style::stylist::RuleInclusion;

use crate::{
    GenericLayoutData, GenericLayoutDataTrait, HTMLCanvasData, HTMLMediaData, LayoutNodeType,
    SVGElementData, StyleData,
};

pub trait LayoutDataTrait: GenericLayoutDataTrait + Default + Send + Sync + 'static {}

/// A wrapper so that layout can access only the methods that it should have access to. Layout must
/// only ever see these and must never see instances of `LayoutDom`.
/// FIXME(mrobinson): `Send + Sync` is required here for Layout 2020, but eventually it
/// should stop sending LayoutNodes to other threads and rely on ThreadSafeLayoutNode
/// or some other mechanism to ensure thread safety.
pub trait LayoutNode<'dom>: Copy + Debug + TNode + Send + Sync {
    type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'dom>;
    fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode;

    /// Returns the type ID of this node.
    fn type_id(&self) -> LayoutNodeType;

    /// Initialize this node with empty style and opaque layout data.
    ///
    /// # Safety
    ///
    /// This method is unsafe because it modifies the given node during
    /// layout. Callers should ensure that no other layout thread is
    /// attempting to read or modify the opaque layout data of this node.
    unsafe fn initialize_style_and_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self);

    /// Get the [`StyleData`] for this node. Returns None if the node is unstyled.
    fn style_data(&self) -> Option<&'dom StyleData>;

    /// Get the layout data of this node, attempting to downcast it to the desired type.
    /// Returns None if there is no layout data or it isn't of the desired type.
    fn layout_data(&self) -> Option<&'dom GenericLayoutData>;

    fn rev_children(self) -> LayoutIterator<ReverseChildrenIterator<Self>> {
        LayoutIterator(ReverseChildrenIterator {
            current: self.last_child(),
        })
    }

    fn traverse_preorder(self) -> TreeIterator<Self> {
        TreeIterator::new(self)
    }

    /// Returns whether the node is connected.
    fn is_connected(&self) -> bool;
}

pub struct ReverseChildrenIterator<ConcreteNode> {
    current: Option<ConcreteNode>,
}

impl<'dom, ConcreteNode> Iterator for ReverseChildrenIterator<ConcreteNode>
where
    ConcreteNode: LayoutNode<'dom>,
{
    type Item = ConcreteNode;
    fn next(&mut self) -> Option<ConcreteNode> {
        let node = self.current;
        self.current = node.and_then(|node| node.prev_sibling());
        node
    }
}

pub struct TreeIterator<ConcreteNode> {
    stack: Vec<ConcreteNode>,
}

impl<'dom, ConcreteNode> TreeIterator<ConcreteNode>
where
    ConcreteNode: LayoutNode<'dom>,
{
    fn new(root: ConcreteNode) -> TreeIterator<ConcreteNode> {
        let stack = vec![root];
        TreeIterator { stack }
    }

    pub fn next_skipping_children(&mut self) -> Option<ConcreteNode> {
        self.stack.pop()
    }
}

impl<'dom, ConcreteNode> Iterator for TreeIterator<ConcreteNode>
where
    ConcreteNode: LayoutNode<'dom>,
{
    type Item = ConcreteNode;
    fn next(&mut self) -> Option<ConcreteNode> {
        let ret = self.stack.pop();
        if let Some(node) = ret {
            self.stack.extend(node.rev_children())
        }
        ret
    }
}

/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout
/// node does not allow any parents or siblings of nodes to be accessed, to avoid races.
pub trait ThreadSafeLayoutNode<'dom>: Clone + Copy + Debug + NodeInfo + PartialEq + Sized {
    type ConcreteNode: LayoutNode<'dom, ConcreteThreadSafeLayoutNode = Self>;
    type ConcreteElement: TElement;

    type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<'dom, ConcreteThreadSafeLayoutNode = Self>
        + ::selectors::Element<Impl = SelectorImpl>;
    type ChildrenIterator: Iterator<Item = Self> + Sized;

    /// Converts self into an `OpaqueNode`.
    fn opaque(&self) -> OpaqueNode;

    /// Returns the type ID of this node.
    /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
    fn type_id(&self) -> Option<LayoutNodeType>;

    /// Returns the style for a text node. This is computed on the fly from the
    /// parent style to avoid traversing text nodes in the style system.
    ///
    /// Note that this does require accessing the parent, which this interface
    /// technically forbids. But accessing the parent is only unsafe insofar as
    /// it can be used to reach siblings and cousins. A simple immutable borrow
    /// of the parent data is fine, since the bottom-up traversal will not process
    /// the parent until all the children have been processed.
    fn parent_style(&self) -> Arc<ComputedValues>;

    /// Initialize this node with empty opaque layout data.
    ///
    /// # Safety
    ///
    /// This method is unsafe because it modifies the given node during
    /// layout. Callers should ensure that no other layout thread is
    /// attempting to read or modify the opaque layout data of this node.
    fn initialize_layout_data<RequestedLayoutDataType: LayoutDataTrait>(&self);

    fn debug_id(self) -> usize;

    /// Returns an iterator over this node's children.
    fn children(&self) -> LayoutIterator<Self::ChildrenIterator>;

    /// Returns a ThreadSafeLayoutElement if this is an element, None otherwise.
    fn as_element(&self) -> Option<Self::ConcreteThreadSafeLayoutElement>;

    /// Returns a ThreadSafeLayoutElement if this is an element in an HTML namespace, None otherwise.
    fn as_html_element(&self) -> Option<Self::ConcreteThreadSafeLayoutElement>;

    /// Get the [`StyleData`] for this node. Returns None if the node is unstyled.
    fn style_data(&self) -> Option<&'dom StyleData>;

    /// Get the layout data of this node, attempting to downcast it to the desired type.
    /// Returns None if there is no layout data or it isn't of the desired type.
    fn layout_data(&self) -> Option<&'dom GenericLayoutData>;

    fn style(&self, context: &SharedStyleContext) -> Arc<ComputedValues> {
        if let Some(el) = self.as_element() {
            el.style(context)
        } else {
            // Text nodes are not styled during traversal,instead we simply
            // return parent style here and do cascading during layout.
            debug_assert!(self.is_text_node());
            self.parent_style()
        }
    }

    /// Returns true if this node contributes content. This is used in the implementation of
    /// `empty_cells` per CSS 2.1 § 17.6.1.1.
    fn is_content(&self) -> bool {
        self.type_id().is_some()
    }

    /// Returns access to the underlying LayoutNode. This is breaks the abstraction
    /// barrier of ThreadSafeLayout wrapper layer, and can lead to races if not used
    /// carefully.
    ///
    /// We need this because the implementation of some methods need to access the layout
    /// data flags, and we have this annoying trait separation between script and layout :-(
    fn unsafe_get(self) -> Self::ConcreteNode;

    fn node_text_content(self) -> Cow<'dom, str>;

    /// If selection intersects this node, return it. Otherwise, returns `None`.
    fn selection(&self) -> Option<Range<ByteIndex>>;

    /// If this is an image element, returns its URL. If this is not an image element, fails.
    fn image_url(&self) -> Option<ServoUrl>;

    /// If this is an image element, returns its current-pixel-density. If this is not an image element, fails.
    fn image_density(&self) -> Option<f64>;

    /// If this is an image element, returns its image data. Otherwise, returns `None`.
    fn image_data(&self) -> Option<(Option<Image>, Option<ImageMetadata>)>;

    fn canvas_data(&self) -> Option<HTMLCanvasData>;

    fn svg_data(&self) -> Option<SVGElementData>;

    fn media_data(&self) -> Option<HTMLMediaData>;

    /// If this node is an iframe element, returns its browsing context ID. If this node is
    /// not an iframe element, fails. Returns None if there is no nested browsing context.
    fn iframe_browsing_context_id(&self) -> Option<BrowsingContextId>;

    /// If this node is an iframe element, returns its pipeline ID. If this node is
    /// not an iframe element, fails. Returns None if there is no nested browsing context.
    fn iframe_pipeline_id(&self) -> Option<PipelineId>;

    fn get_span(&self) -> Option<u32>;
    fn get_colspan(&self) -> Option<u32>;
    fn get_rowspan(&self) -> Option<u32>;

    fn pseudo_element_chain(&self) -> PseudoElementChain;

    fn with_pseudo(&self, pseudo_element_type: PseudoElement) -> Option<Self> {
        self.as_element()
            .and_then(|element| element.with_pseudo(pseudo_element_type))
            .as_ref()
            .map(ThreadSafeLayoutElement::as_node)
    }

    fn with_pseudo_element_chain(&self, pseudo_element_chain: PseudoElementChain) -> Self;
}

pub trait ThreadSafeLayoutElement<'dom>:
    Clone + Copy + Sized + Debug + ::selectors::Element<Impl = SelectorImpl>
{
    type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'dom, ConcreteThreadSafeLayoutElement = Self>;

    /// This type alias is just a work-around to avoid writing
    ///
    ///   <Self::ConcreteThreadSafeLayoutNode as ThreadSafeLayoutNode>::ConcreteElement
    ///
    type ConcreteElement: TElement;

    fn as_node(&self) -> Self::ConcreteThreadSafeLayoutNode;

    /// Creates a new `ThreadSafeLayoutElement` for the same `LayoutElement`
    /// with a different pseudo-element type.
    ///
    /// Returns `None` if this pseudo doesn't apply to the given element for one of
    /// the following reasons:
    ///
    ///  1. `pseudo` is eager and is not defined in the stylesheet. In this case, there
    ///     is not reason to process the pseudo element at all.
    ///  2. `pseudo` is for `::servo-details-summary` or `::servo-details-content` and
    ///     it doesn't apply to this element, either because it isn't a details or is
    ///     in the wrong state.
    fn with_pseudo(&self, pseudo: PseudoElement) -> Option<Self>;

    /// Returns the type ID of this node.
    /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
    fn type_id(&self) -> Option<LayoutNodeType>;

    /// Returns access to the underlying TElement. This is breaks the abstraction
    /// barrier of ThreadSafeLayout wrapper layer, and can lead to races if not used
    /// carefully.
    ///
    /// We need this so that the functions defined on this trait can call
    /// lazily_compute_pseudo_element_style, which operates on TElement.
    fn unsafe_get(self) -> Self::ConcreteElement;

    /// Get the local name of this element. See
    /// <https://dom.spec.whatwg.org/#concept-element-local-name>.
    fn get_local_name(&self) -> &LocalName;

    fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&str>;

    fn get_attr_enum(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue>;

    fn style_data(&self) -> AtomicRef<'_, ElementData>;

    fn pseudo_element_chain(&self) -> PseudoElementChain;

    /// Returns the style results for the given node. If CSS selector matching
    /// has not yet been performed, fails.
    ///
    /// Unlike the version on TNode, this handles pseudo-elements.
    #[inline]
    fn style(&self, context: &SharedStyleContext) -> Arc<ComputedValues> {
        let get_style_for_pseudo_element =
            |base_style: &Arc<ComputedValues>, pseudo_element: PseudoElement| {
                // Precompute non-eagerly-cascaded pseudo-element styles if not
                // cached before.
                match pseudo_element.cascade_type() {
                    // Already computed during the cascade.
                    PseudoElementCascadeType::Eager => self
                        .style_data()
                        .styles
                        .pseudos
                        .get(&pseudo_element)
                        .unwrap()
                        .clone(),
                    PseudoElementCascadeType::Precomputed => context
                        .stylist
                        .precomputed_values_for_pseudo::<Self::ConcreteElement>(
                            &context.guards,
                            &pseudo_element,
                            Some(base_style),
                        ),
                    PseudoElementCascadeType::Lazy => {
                        context
                            .stylist
                            .lazily_compute_pseudo_element_style(
                                &context.guards,
                                self.unsafe_get(),
                                &pseudo_element,
                                RuleInclusion::All,
                                base_style,
                                /* is_probe = */ false,
                                /* matching_func = */ None,
                            )
                            .unwrap()
                    },
                }
            };

        let data = self.style_data();
        let element_style = data.styles.primary();
        let pseudo_element_chain = self.pseudo_element_chain();

        let primary_pseudo_style = match pseudo_element_chain.primary {
            Some(pseudo_element) => get_style_for_pseudo_element(element_style, pseudo_element),
            None => return element_style.clone(),
        };
        match pseudo_element_chain.secondary {
            Some(pseudo_element) => {
                get_style_for_pseudo_element(&primary_pseudo_style, pseudo_element)
            },
            None => primary_pseudo_style,
        }
    }

    fn is_shadow_host(&self) -> bool;

    /// Returns whether this node is a body element of an html element root
    /// in an HTML element document.
    ///
    /// Note that this does require accessing the parent, which this interface
    /// technically forbids. But accessing the parent is only unsafe insofar as
    /// it can be used to reach siblings and cousins. A simple immutable borrow
    /// of the parent data is fine, since the bottom-up traversal will not process
    /// the parent until all the children have been processed.
    fn is_body_element_of_html_element_root(&self) -> bool;

    /// Returns whether this node is the root element in an HTML document element.
    ///
    /// Note that, like `Self::is_body_element_of_html_element_root`, this accesses the parent.
    /// As in that case, since this is an immutable borrow, we do not violate thread safety.
    fn is_root(&self) -> bool;
}

/// A chain of pseudo-elements up to two levels deep. This is used to represent cases
/// where a pseudo-element has its own child pseudo element (for instance
/// `.div::after::marker`). If both [`Self::primary`] and [`Self::secondary`] are `None`,
/// then this chain represents the element itself. Not all combinations of pseudo-elements
/// are possible and we may not be able to calculate a style for all
/// [`PseudoElementChain`]s.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct PseudoElementChain {
    pub primary: Option<PseudoElement>,
    pub secondary: Option<PseudoElement>,
}

impl PseudoElementChain {
    pub fn unnested(pseudo_element: PseudoElement) -> Self {
        Self {
            primary: Some(pseudo_element),
            secondary: None,
        }
    }

    pub fn innermost(&self) -> Option<PseudoElement> {
        self.secondary.or(self.primary)
    }

    /// Return a possibly nested [`PseudoElementChain`]. Currently only `::before` and
    /// `::after` only support nesting. If the primary [`PseudoElement`] on the chain is
    /// not `::before` or `::after` a single element chain is returned for the given
    /// [`PseudoElement`].
    pub fn with_pseudo(&self, pseudo_element: PseudoElement) -> Self {
        match self.primary {
            Some(primary) if primary.is_before_or_after() => Self {
                primary: self.primary,
                secondary: Some(pseudo_element),
            },
            _ => {
                assert!(self.secondary.is_none());
                Self::unnested(pseudo_element)
            },
        }
    }

    pub fn is_empty(&self) -> bool {
        self.primary.is_none()
    }
}
