/* 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 http://mozilla.org/MPL/2.0/. */

//! A property declaration block.

#![deny(missing_docs)]

use context::QuirksMode;
use cssparser::{DeclarationListParser, parse_important, ParserInput};
use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
use error_reporting::{ParseErrorReporter, ContextualParseError};
use parser::{PARSING_MODE_DEFAULT, ParsingMode, ParserContext, log_css_error};
use properties::animated_properties::AnimationValue;
use selectors::parser::SelectorParseError;
use shared_lock::Locked;
use std::fmt;
use std::slice::Iter;
use style_traits::{ToCss, ParseError, StyleParseError};
use stylesheets::{CssRuleType, Origin, UrlExtraData};
use stylesheets::{MallocSizeOf, MallocSizeOfFn};
use super::*;
use values::computed::Context;
#[cfg(feature = "gecko")] use properties::animated_properties::AnimationValueMap;

/// The animation rules.
///
/// The first one is for Animation cascade level, and the second one is for
/// Transition cascade level.
pub struct AnimationRules<'a>(pub Option<&'a Arc<Locked<PropertyDeclarationBlock>>>,
                              pub Option<&'a Arc<Locked<PropertyDeclarationBlock>>>);

impl<'a> AnimationRules<'a> {
    /// Returns whether these animation rules represents an actual rule or not.
    pub fn is_empty(&self) -> bool {
        self.0.is_none() && self.1.is_none()
    }
}

/// A declaration [importance][importance].
///
/// [importance]: https://drafts.csswg.org/css-cascade/#importance
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Importance {
    /// Indicates a declaration without `!important`.
    Normal,

    /// Indicates a declaration with `!important`.
    Important,
}

impl MallocSizeOf for Importance {
    fn malloc_size_of_children(&self, _malloc_size_of: MallocSizeOfFn) -> usize {
        0
    }
}

impl Importance {
    /// Return whether this is an important declaration.
    pub fn important(self) -> bool {
        match self {
            Importance::Normal => false,
            Importance::Important => true,
        }
    }
}

/// Overridden declarations are skipped.
#[derive(Clone)]
pub struct PropertyDeclarationBlock {
    /// The group of declarations, along with their importance.
    ///
    /// Only deduplicated declarations appear here.
    declarations: Vec<(PropertyDeclaration, Importance)>,

    /// The number of entries in `self.declaration` with `Importance::Important`
    important_count: usize,

    longhands: LonghandIdSet,
}

impl MallocSizeOf for PropertyDeclarationBlock {
    fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn) -> usize {
        self.declarations.malloc_size_of_children(malloc_size_of)
    }
}

/// Iterator for PropertyDeclaration to be generated from PropertyDeclarationBlock.
#[derive(Clone)]
pub struct PropertyDeclarationIterator<'a> {
    iter: Iter<'a, (PropertyDeclaration, Importance)>,
}

impl<'a> Iterator for PropertyDeclarationIterator<'a> {
    type Item = &'a PropertyDeclaration;
    #[inline]
    fn next(&mut self) -> Option<&'a PropertyDeclaration> {
        // we use this function because a closure won't be `Clone`
        fn get_declaration(dec: &(PropertyDeclaration, Importance))
            -> &PropertyDeclaration {
            &dec.0
        }
        self.iter.next().map(get_declaration as fn(_) -> _)
    }
}

/// Iterator for AnimationValue to be generated from PropertyDeclarationBlock.
pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> {
    iter: Iter<'a, (PropertyDeclaration, Importance)>,
    context: &'cx mut Context<'cx_a>,
    default_values: &'a Arc<ComputedValues>,
}

impl<'a, 'cx, 'cx_a:'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
    fn new(declarations: &'a PropertyDeclarationBlock,
           context: &'cx mut Context<'cx_a>,
           default_values: &'a Arc<ComputedValues>) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
        AnimationValueIterator {
            iter: declarations.declarations().iter(),
            context: context,
            default_values: default_values,
        }
    }
}

impl<'a, 'cx, 'cx_a:'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
    type Item = (TransitionProperty, AnimationValue);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        use properties::Importance;

        loop {
            let next = self.iter.next();
            match next {
                Some(&(ref decl, importance)) => {
                    if importance == Importance::Normal {
                        let property = TransitionProperty::from_declaration(decl);
                        let animation = AnimationValue::from_declaration(decl, &mut self.context,
                                                                         self.default_values);
                        debug_assert!(property.is_none() == animation.is_none(),
                                      "The failure condition of TransitionProperty::from_declaration \
                                       and AnimationValue::from_declaration should be the same");
                        // Skip the property if either ::from_declaration fails.
                        match (property, animation) {
                            (Some(p), Some(a)) => return Some((p, a)),
                            (_, _) => {},
                        }
                    }
                },
                None => return None,
            }
        }
    }
}

impl fmt::Debug for PropertyDeclarationBlock {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.declarations.fmt(f)
    }
}

impl PropertyDeclarationBlock {
    /// Returns the number of declarations in the block.
    pub fn len(&self) -> usize {
        self.declarations.len()
    }

    /// Create an empty block
    pub fn new() -> Self {
        PropertyDeclarationBlock {
            declarations: Vec::new(),
            important_count: 0,
            longhands: LonghandIdSet::new(),
        }
    }

    /// Create a block with a single declaration
    pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self {
        let mut longhands = LonghandIdSet::new();
        if let PropertyDeclarationId::Longhand(id) = declaration.id() {
            longhands.insert(id);
        }
        PropertyDeclarationBlock {
            declarations: vec![(declaration, importance)],
            important_count: if importance.important() { 1 } else { 0 },
            longhands: longhands,
        }
    }

    /// The declarations in this block
    pub fn declarations(&self) -> &[(PropertyDeclaration, Importance)] {
        &self.declarations
    }

    /// Iterate over only PropertyDeclaration.
    pub fn declarations_iter(&self) -> PropertyDeclarationIterator {
        PropertyDeclarationIterator {
            iter: self.declarations.iter(),
        }
    }

    /// Return an iterator of (TransitionProperty, AnimationValue).
    pub fn to_animation_value_iter<'a, 'cx, 'cx_a:'cx>(&'a self,
                                                       context: &'cx mut Context<'cx_a>,
                                                       default_values: &'a Arc<ComputedValues>)
                                                       -> AnimationValueIterator<'a, 'cx, 'cx_a> {
        AnimationValueIterator::new(self, context, default_values)
    }

    /// Returns whether this block contains any declaration with `!important`.
    ///
    /// This is based on the `important_count` counter,
    /// which should be maintained whenever `declarations` is changed.
    // FIXME: make fields private and maintain it here in methods?
    pub fn any_important(&self) -> bool {
        self.important_count > 0
    }

    /// Returns whether this block contains any declaration without `!important`.
    ///
    /// This is based on the `important_count` counter,
    /// which should be maintained whenever `declarations` is changed.
    // FIXME: make fields private and maintain it here in methods?
    pub fn any_normal(&self) -> bool {
        self.declarations.len() > self.important_count
    }

    /// Get a declaration for a given property.
    ///
    /// NOTE: This is linear time.
    pub fn get(&self, property: PropertyDeclarationId) -> Option< &(PropertyDeclaration, Importance)> {
        self.declarations.iter().find(|&&(ref decl, _)| decl.id() == property)
    }

    /// Find the value of the given property in this block and serialize it
    ///
    /// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
    pub fn property_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        // Step 1.1: done when parsing a string to PropertyId

        // Step 1.2
        match property.as_shorthand() {
            Ok(shorthand) => {
                // Step 1.2.1
                let mut list = Vec::new();
                let mut important_count = 0;

                // Step 1.2.2
                for &longhand in shorthand.longhands() {
                    // Step 1.2.2.1
                    let declaration = self.get(PropertyDeclarationId::Longhand(longhand));

                    // Step 1.2.2.2 & 1.2.2.3
                    match declaration {
                        Some(&(ref declaration, importance)) => {
                            list.push(declaration);
                            if importance.important() {
                                important_count += 1;
                            }
                        },
                        None => return Ok(()),
                    }
                }

                // If there is one or more longhand with important, and one or more
                // without important, we don't serialize it as a shorthand.
                if important_count > 0 && important_count != list.len() {
                    return Ok(());
                }

                // Step 1.2.3
                // We don't print !important when serializing individual properties,
                // so we treat this as a normal-importance property
                match shorthand.get_shorthand_appendable_value(list) {
                    Some(appendable_value) =>
                        append_declaration_value(dest, appendable_value),
                    None => return Ok(()),
                }
            }
            Err(longhand_or_custom) => {
                if let Some(&(ref value, _importance)) = self.get(longhand_or_custom) {
                    // Step 2
                    value.to_css(dest)
                } else {
                    // Step 3
                    Ok(())
                }
            }
        }
    }

    /// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
    pub fn property_priority(&self, property: &PropertyId) -> Importance {
        // Step 1: done when parsing a string to PropertyId

        // Step 2
        match property.as_shorthand() {
            Ok(shorthand) => {
                // Step 2.1 & 2.2 & 2.3
                if shorthand.longhands().iter().all(|&l| {
                    self.get(PropertyDeclarationId::Longhand(l))
                        .map_or(false, |&(_, importance)| importance.important())
                }) {
                    Importance::Important
                } else {
                    Importance::Normal
                }
            }
            Err(longhand_or_custom) => {
                // Step 3
                self.get(longhand_or_custom).map_or(Importance::Normal, |&(_, importance)| importance)
            }
        }
    }

    /// Adds or overrides the declaration for a given property in this block,
    /// **except** if an existing declaration for the same property is more
    /// important.
    ///
    /// Always ensures that the property declaration is at the end.
    pub fn extend(&mut self, drain: SourcePropertyDeclarationDrain, importance: Importance) {
        self.extend_common(drain, importance, false);
    }

    /// Adds or overrides the declaration for a given property in this block,
    /// **even** if an existing declaration for the same property is more
    /// important, and reuses the same position in the block.
    ///
    /// Returns whether anything changed.
    pub fn extend_reset(&mut self, drain: SourcePropertyDeclarationDrain,
                        importance: Importance) -> bool {
        self.extend_common(drain, importance, true)
    }

    fn extend_common(
        &mut self,
        mut drain: SourcePropertyDeclarationDrain,
        importance: Importance,
        overwrite_more_important_and_reuse_slot: bool,
    ) -> bool {
        let all_shorthand_len = match drain.all_shorthand {
            AllShorthand::NotSet => 0,
            AllShorthand::CSSWideKeyword(_) |
            AllShorthand::WithVariables(_) => ShorthandId::All.longhands().len()
        };
        let push_calls_count = drain.declarations.len() + all_shorthand_len;

        // With deduplication the actual length increase may be less than this.
        self.declarations.reserve(push_calls_count);

        let mut changed = false;
        for decl in &mut drain.declarations {
            changed |= self.push_common(
                decl,
                importance,
                overwrite_more_important_and_reuse_slot,
            );
        }
        match drain.all_shorthand {
            AllShorthand::NotSet => {}
            AllShorthand::CSSWideKeyword(keyword) => {
                for &id in ShorthandId::All.longhands() {
                    let decl = PropertyDeclaration::CSSWideKeyword(id, keyword);
                    changed |= self.push_common(
                        decl,
                        importance,
                        overwrite_more_important_and_reuse_slot,
                    );
                }
            }
            AllShorthand::WithVariables(unparsed) => {
                for &id in ShorthandId::All.longhands() {
                    let decl = PropertyDeclaration::WithVariables(id, unparsed.clone());
                    changed |= self.push_common(
                        decl,
                        importance,
                        overwrite_more_important_and_reuse_slot,
                    );
                }
            }
        }
        changed
    }

    /// Adds or overrides the declaration for a given property in this block,
    /// **except** if an existing declaration for the same property is more
    /// important.
    ///
    /// Ensures that, if inserted, it's inserted at the end of the declaration
    /// block.
    pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) {
        self.push_common(declaration, importance, false);
    }

    fn push_common(
        &mut self,
        declaration: PropertyDeclaration,
        importance: Importance,
        overwrite_more_important_and_reuse_slot: bool
    ) -> bool {
        let definitely_new = if let PropertyDeclarationId::Longhand(id) = declaration.id() {
            !self.longhands.contains(id)
        } else {
            false  // For custom properties, always scan
        };


        if !definitely_new {
            let mut index_to_remove = None;
            for (i, slot) in self.declarations.iter_mut().enumerate() {
                if slot.0.id() == declaration.id() {
                    match (slot.1, importance) {
                        (Importance::Normal, Importance::Important) => {
                            self.important_count += 1;
                        }
                        (Importance::Important, Importance::Normal) => {
                            if overwrite_more_important_and_reuse_slot {
                                self.important_count -= 1;
                            } else {
                                return false
                            }
                        }
                        _ => if slot.0 == declaration {
                            return false;
                        }
                    }

                    if overwrite_more_important_and_reuse_slot {
                        *slot = (declaration, importance);
                        return true;
                    }

                    // NOTE(emilio): We could avoid this and just override for
                    // properties not affected by logical props, but it's not
                    // clear it's worth it given the `definitely_new` check.
                    index_to_remove = Some(i);
                    break;
                }
            }

            if let Some(index) = index_to_remove {
                self.declarations.remove(index);
                self.declarations.push((declaration, importance));
                return true;
            }
        }

        if let PropertyDeclarationId::Longhand(id) = declaration.id() {
            self.longhands.insert(id);
        }
        self.declarations.push((declaration, importance));
        if importance.important() {
            self.important_count += 1;
        }
        true
    }

    /// Set the declaration importance for a given property, if found.
    ///
    /// Returns whether any declaration was updated.
    pub fn set_importance(&mut self, property: &PropertyId, new_importance: Importance) -> bool {
        let mut updated_at_least_one = false;
        for &mut (ref declaration, ref mut importance) in &mut self.declarations {
            if declaration.id().is_or_is_longhand_of(property) {
                match (*importance, new_importance) {
                    (Importance::Normal, Importance::Important) => {
                        self.important_count += 1;
                    }
                    (Importance::Important, Importance::Normal) => {
                        self.important_count -= 1;
                    }
                    _ => {
                        continue;
                    }
                }
                updated_at_least_one = true;
                *importance = new_importance;
            }
        }
        updated_at_least_one
    }

    /// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-removeproperty
    ///
    /// Returns whether any declaration was actually removed.
    pub fn remove_property(&mut self, property: &PropertyId) -> bool {
        if let PropertyId::Longhand(id) = *property {
            if !self.longhands.contains(id) {
                return false
            }
        }
        let important_count = &mut self.important_count;
        let mut removed_at_least_one = false;
        let longhands = &mut self.longhands;
        self.declarations.retain(|&(ref declaration, importance)| {
            let id = declaration.id();
            let remove = id.is_or_is_longhand_of(property);
            if remove {
                removed_at_least_one = true;
                if let PropertyDeclarationId::Longhand(id) = id {
                    longhands.remove(id)
                }
                if importance.important() {
                    *important_count -= 1
                }
            }
            !remove
        });

        if let PropertyId::Longhand(_) = *property {
            debug_assert!(removed_at_least_one);
        }
        removed_at_least_one
    }

    /// Take a declaration block known to contain a single property and serialize it.
    pub fn single_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        match property.as_shorthand() {
            Err(_longhand_or_custom) => {
                if self.declarations.len() == 1 {
                    self.declarations[0].0.to_css(dest)
                } else {
                    Err(fmt::Error)
                }
            }
            Ok(shorthand) => {
                if !self.declarations.iter().all(|decl| decl.0.shorthands().contains(&shorthand)) {
                    return Err(fmt::Error)
                }
                let iter = self.declarations_iter();
                match shorthand.get_shorthand_appendable_value(iter) {
                    Some(AppendableValue::Css { css, .. }) => {
                        dest.write_str(css)
                    },
                    Some(AppendableValue::DeclarationsForShorthand(_, decls)) => {
                        shorthand.longhands_to_css(decls, dest)
                    }
                    _ => Ok(())
                }
            }
        }
    }

    /// Convert AnimationValueMap to PropertyDeclarationBlock.
    #[cfg(feature = "gecko")]
    pub fn from_animation_value_map(animation_value_map: &AnimationValueMap) -> Self {
        let mut declarations = vec![];
        let mut longhands = LonghandIdSet::new();

        for (property, animation_value) in animation_value_map.iter() {
          longhands.set_transition_property_bit(property);
          declarations.push((animation_value.uncompute(), Importance::Normal));
        }

        PropertyDeclarationBlock {
            declarations: declarations,
            important_count: 0,
            longhands: longhands,
        }
    }

    /// Returns true if the declaration block has a CSSWideKeyword for the given
    /// property.
    #[cfg(feature = "gecko")]
    pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
        if let PropertyId::Longhand(id) = *property {
            if !self.longhands.contains(id) {
                return false
            }
        }
        self.declarations.iter().any(|&(ref decl, _)|
            decl.id().is_or_is_longhand_of(property) &&
            decl.get_css_wide_keyword().is_some()
        )
    }
}

impl ToCss for PropertyDeclarationBlock {
    // https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        let mut is_first_serialization = true; // trailing serializations should have a prepended space

        // Step 1 -> dest = result list

        // Step 2
        let mut already_serialized = Vec::new();

        // Step 3
        for &(ref declaration, importance) in &*self.declarations {
            // Step 3.1
            let property = declaration.id();

            // Step 3.2
            if already_serialized.contains(&property) {
                continue;
            }

            // Step 3.3
            let shorthands = declaration.shorthands();
            if !shorthands.is_empty() {
                // Step 3.3.1
                let mut longhands = self.declarations.iter()
                    .filter(|d| !already_serialized.contains(&d.0.id()))
                    .collect::<Vec<_>>();

                // Step 3.3.2
                for &shorthand in shorthands {
                    let properties = shorthand.longhands();

                    // Substep 2 & 3
                    let mut current_longhands = Vec::new();
                    let mut important_count = 0;
                    let mut found_system = None;

                    if shorthand == ShorthandId::Font && longhands.iter().any(|&&(ref l, _)| l.get_system().is_some()) {
                        for &&(ref longhand, longhand_importance) in longhands.iter() {
                            if longhand.get_system().is_some() || longhand.is_default_line_height() {
                                current_longhands.push(longhand);
                                if found_system.is_none() {
                                   found_system = longhand.get_system();
                                }
                                if longhand_importance.important() {
                                    important_count += 1;
                                }
                            }
                        }
                    } else {
                        for &&(ref longhand, longhand_importance) in longhands.iter() {
                            if longhand.id().is_longhand_of(shorthand) {
                                current_longhands.push(longhand);
                                if longhand_importance.important() {
                                    important_count += 1;
                                }
                            }
                        }
                        // Substep 1:
                        //
                         // Assuming that the PropertyDeclarationBlock contains no
                         // duplicate entries, if the current_longhands length is
                         // equal to the properties length, it means that the
                         // properties that map to shorthand are present in longhands
                        if current_longhands.len() != properties.len() {
                            continue;
                        }
                    }

                    // Substep 4
                    let is_important = important_count > 0;
                    if is_important && important_count != current_longhands.len() {
                        continue;
                    }
                    let importance = if is_important {
                        Importance::Important
                    } else {
                        Importance::Normal
                    };

                    // Substep 5 - Let value be the result of invoking serialize
                    // a CSS value of current longhands.
                    let appendable_value =
                        match shorthand.get_shorthand_appendable_value(current_longhands.iter().cloned()) {
                            None => continue,
                            Some(appendable_value) => appendable_value,
                        };

                    // We avoid re-serializing if we're already an
                    // AppendableValue::Css.
                    let mut v = String::new();
                    let value = match (appendable_value, found_system) {
                        (AppendableValue::Css { css, with_variables }, _) => {
                            debug_assert!(!css.is_empty());
                            AppendableValue::Css {
                                css: css,
                                with_variables: with_variables,
                            }
                        }
                        #[cfg(feature = "gecko")]
                        (_, Some(sys)) => {
                            sys.to_css(&mut v)?;
                            AppendableValue::Css {
                                css: &v,
                                with_variables: false,
                            }
                        }
                        (other, _) => {
                            append_declaration_value(&mut v, other)?;

                            // Substep 6
                            if v.is_empty() {
                                continue;
                            }

                            AppendableValue::Css {
                                css: &v,
                                with_variables: false,
                            }
                        }
                    };

                    // Substeps 7 and 8
                    // We need to check the shorthand whether it's an alias property or not.
                    // If it's an alias property, it should be serialized like its longhand.
                    if shorthand.flags().contains(SHORTHAND_ALIAS_PROPERTY) {
                        append_serialization::<_, Cloned<slice::Iter< _>>, _>(
                             dest,
                             &property,
                             value,
                             importance,
                             &mut is_first_serialization)?;
                    } else {
                        append_serialization::<_, Cloned<slice::Iter< _>>, _>(
                             dest,
                             &shorthand,
                             value,
                             importance,
                             &mut is_first_serialization)?;
                    }

                    for current_longhand in &current_longhands {
                        // Substep 9
                        already_serialized.push(current_longhand.id());
                        let index_to_remove = longhands.iter().position(|l| l.0 == **current_longhand);
                        if let Some(index) = index_to_remove {
                            // Substep 10
                            longhands.remove(index);
                        }
                    }
                }
            }

            // Step 3.3.4
            if already_serialized.contains(&property) {
                continue;
            }

            use std::iter::Cloned;
            use std::slice;

            // Steps 3.3.5, 3.3.6 & 3.3.7
            // Need to specify an iterator type here even though it’s unused to work around
            // "error: unable to infer enough type information about `_`;
            //  type annotations or generic parameter binding required [E0282]"
            // Use the same type as earlier call to reuse generated code.
            append_serialization::<_, Cloned<slice::Iter<_>>, _>(
                dest,
                &property,
                AppendableValue::Declaration(declaration),
                importance,
                &mut is_first_serialization)?;

            // Step 3.3.8
            already_serialized.push(property);
        }

        // Step 4
        Ok(())
    }
}

/// A convenient enum to represent different kinds of stuff that can represent a
/// _value_ in the serialization of a property declaration.
pub enum AppendableValue<'a, I>
    where I: Iterator<Item=&'a PropertyDeclaration>,
{
    /// A given declaration, of which we'll serialize just the value.
    Declaration(&'a PropertyDeclaration),
    /// A set of declarations for a given shorthand.
    ///
    /// FIXME: This needs more docs, where are the shorthands expanded? We print
    /// the property name before-hand, don't we?
    DeclarationsForShorthand(ShorthandId, I),
    /// A raw CSS string, coming for example from a property with CSS variables,
    /// or when storing a serialized shorthand value before appending directly.
    Css {
        /// The raw CSS string.
        css: &'a str,
        /// Whether the original serialization contained variables or not.
        with_variables: bool,
    }
}

/// Potentially appends whitespace after the first (property: value;) pair.
fn handle_first_serialization<W>(dest: &mut W,
                                 is_first_serialization: &mut bool)
                                 -> fmt::Result
    where W: fmt::Write,
{
    if !*is_first_serialization {
        dest.write_str(" ")
    } else {
        *is_first_serialization = false;
        Ok(())
    }
}

/// Append a given kind of appendable value to a serialization.
pub fn append_declaration_value<'a, W, I>(dest: &mut W,
                                          appendable_value: AppendableValue<'a, I>)
                                          -> fmt::Result
    where W: fmt::Write,
          I: Iterator<Item=&'a PropertyDeclaration>,
{
    match appendable_value {
        AppendableValue::Css { css, .. } => {
            dest.write_str(css)
        },
        AppendableValue::Declaration(decl) => {
            decl.to_css(dest)
        },
        AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
            shorthand.longhands_to_css(decls, dest)
        }
    }
}

/// Append a given property and value pair to a serialization.
pub fn append_serialization<'a, W, I, N>(dest: &mut W,
                                         property_name: &N,
                                         appendable_value: AppendableValue<'a, I>,
                                         importance: Importance,
                                         is_first_serialization: &mut bool)
                                         -> fmt::Result
    where W: fmt::Write,
          I: Iterator<Item=&'a PropertyDeclaration>,
          N: ToCss,
{
    try!(handle_first_serialization(dest, is_first_serialization));

    try!(property_name.to_css(dest));
    try!(dest.write_char(':'));

    // for normal parsed values, add a space between key: and value
    match appendable_value {
        AppendableValue::Declaration(decl) => {
            if !decl.value_is_unparsed() {
                // For normal parsed values, add a space between key: and value.
                dest.write_str(" ")?
            }
        },
        AppendableValue::Css { with_variables, .. } => {
            if !with_variables {
                dest.write_str(" ")?
            }
        }
        // Currently append_serialization is only called with a Css or
        // a Declaration AppendableValue.
        AppendableValue::DeclarationsForShorthand(..) => unreachable!(),
    }

    try!(append_declaration_value(dest, appendable_value));

    if importance.important() {
        try!(dest.write_str(" !important"));
    }

    dest.write_char(';')
}

/// A helper to parse the style attribute of an element, in order for this to be
/// shared between Servo and Gecko.
pub fn parse_style_attribute(input: &str,
                             url_data: &UrlExtraData,
                             error_reporter: &ParseErrorReporter,
                             quirks_mode: QuirksMode)
                             -> PropertyDeclarationBlock {
    let context = ParserContext::new(Origin::Author,
                                     url_data,
                                     error_reporter,
                                     Some(CssRuleType::Style),
                                     PARSING_MODE_DEFAULT,
                                     quirks_mode);
    let mut input = ParserInput::new(input);
    parse_property_declaration_list(&context, &mut Parser::new(&mut input))
}

/// Parse a given property declaration. Can result in multiple
/// `PropertyDeclaration`s when expanding a shorthand, for example.
///
/// This does not attempt to parse !important at all.
pub fn parse_one_declaration_into(declarations: &mut SourcePropertyDeclaration,
                                  id: PropertyId,
                                  input: &str,
                                  url_data: &UrlExtraData,
                                  error_reporter: &ParseErrorReporter,
                                  parsing_mode: ParsingMode,
                                  quirks_mode: QuirksMode)
                                  -> Result<(), ()> {
    let context = ParserContext::new(Origin::Author,
                                     url_data,
                                     error_reporter,
                                     Some(CssRuleType::Style),
                                     parsing_mode,
                                     quirks_mode);
    let mut input = ParserInput::new(input);
    Parser::new(&mut input).parse_entirely(|parser| {
        PropertyDeclaration::parse_into(declarations, id, &context, parser)
            .map_err(|e| e.into())
    }).map_err(|_| ())
}

/// A struct to parse property declarations.
struct PropertyDeclarationParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    declarations: &'a mut SourcePropertyDeclaration,
}


/// Default methods reject all at rules.
impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'b> {
    type Prelude = ();
    type AtRule = Importance;
    type Error = SelectorParseError<'i, StyleParseError<'i>>;
}

impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
    type Declaration = Importance;
    type Error = SelectorParseError<'i, StyleParseError<'i>>;

    fn parse_value<'t>(&mut self, name: Cow<'i, str>, input: &mut Parser<'i, 't>)
                       -> Result<Importance, ParseError<'i>> {
        let id = try!(PropertyId::parse(name));
        input.parse_until_before(Delimiter::Bang, |input| {
            PropertyDeclaration::parse_into(self.declarations, id, self.context, input)
                .map_err(|e| e.into())
        })?;
        let importance = match input.try(parse_important) {
            Ok(()) => Importance::Important,
            Err(_) => Importance::Normal,
        };
        // In case there is still unparsed text in the declaration, we should roll back.
        input.expect_exhausted()?;
        Ok(importance)
    }
}


/// Parse a list of property declarations and return a property declaration
/// block.
pub fn parse_property_declaration_list(context: &ParserContext,
                                       input: &mut Parser)
                                       -> PropertyDeclarationBlock {
    let mut declarations = SourcePropertyDeclaration::new();
    let mut block = PropertyDeclarationBlock::new();
    let parser = PropertyDeclarationParser {
        context: context,
        declarations: &mut declarations,
    };
    let mut iter = DeclarationListParser::new(input, parser);
    while let Some(declaration) = iter.next() {
        match declaration {
            Ok(importance) => {
                block.extend(iter.parser.declarations.drain(), importance);
            }
            Err(err) => {
                iter.parser.declarations.clear();
                let pos = err.span.start;
                let error = ContextualParseError::UnsupportedPropertyDeclaration(
                    iter.input.slice(err.span), err.error);
                log_css_error(iter.input, pos, error, &context);
            }
        }
    }
    block
}
