/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 * Copyright (C) 2013 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "CSSPropertyNames.h"
#include "CSSValueKeywords.h"
#include "StyleProperties.h"
#include "WritingDirection.h"
#include <wtf/RefCounted.h>
#include <wtf/TriState.h>
#include <wtf/text/WTFString.h>

namespace WebCore {

class CSSStyleDeclaration;
class CSSComputedStyleDeclaration;
class CSSPrimitiveValue;
class CSSValue;
class ComputedStyleExtractor;
class Document;
class Element;
class HTMLElement;
class MutableStyleProperties;
class Node;
class Position;
class QualifiedName;
class RenderStyle;
class StyleProperties;
class StyledElement;
class VisibleSelection;

enum class TextDecorationChange { None, Add, Remove };

// FIXME: "Keep" should be "Resolve" instead and resolve all generic font family names.
enum class StandardFontFamilySerializationMode : uint8_t { Keep, Strip };

class EditingStyle : public RefCounted<EditingStyle> {
public:

    enum PropertiesToInclude { AllProperties, OnlyEditingInheritableProperties, EditingPropertiesInEffect };

    enum ShouldPreserveWritingDirection { PreserveWritingDirection, DoNotPreserveWritingDirection };
    enum ShouldExtractMatchingStyle { ExtractMatchingStyle, DoNotExtractMatchingStyle };
    static float NoFontDelta;

    static Ref<EditingStyle> create()
    {
        return adoptRef(*new EditingStyle);
    }

    static Ref<EditingStyle> create(Node* node, PropertiesToInclude propertiesToInclude = OnlyEditingInheritableProperties)
    {
        return adoptRef(*new EditingStyle(node, propertiesToInclude));
    }

    static Ref<EditingStyle> create(const Position& position, PropertiesToInclude propertiesToInclude = OnlyEditingInheritableProperties)
    {
        return adoptRef(*new EditingStyle(position, propertiesToInclude));
    }

    static Ref<EditingStyle> create(const StyleProperties* style)
    {
        return adoptRef(*new EditingStyle(style));
    }

    static Ref<EditingStyle> create(const CSSStyleDeclaration* style)
    {
        return adoptRef(*new EditingStyle(style));
    }

    static Ref<EditingStyle> create(CSSPropertyID propertyID, const String& value)
    {
        return adoptRef(*new EditingStyle(propertyID, value));
    }

    static Ref<EditingStyle> create(CSSPropertyID propertyID, CSSValueID value)
    {
        return adoptRef(*new EditingStyle(propertyID, value));
    }

    WEBCORE_EXPORT ~EditingStyle();

    MutableStyleProperties* style() { return m_mutableStyle.get(); }
    Ref<MutableStyleProperties> styleWithResolvedTextDecorations() const;
    Optional<WritingDirection> textDirection() const;
    bool isEmpty() const;
    void setStyle(RefPtr<MutableStyleProperties>&&);
    void overrideWithStyle(const StyleProperties&);
    void overrideTypingStyleAt(const EditingStyle&, const Position&);
    void clear();
    Ref<EditingStyle> copy() const;
    Ref<EditingStyle> extractAndRemoveBlockProperties();
    Ref<EditingStyle> extractAndRemoveTextDirection();
    void removeBlockProperties();
    void removeStyleAddedByNode(Node*);
    void removeStyleConflictingWithStyleOfNode(Node&);
    template<typename T> void removeEquivalentProperties(T&);
    void collapseTextDecorationProperties();
    enum ShouldIgnoreTextOnlyProperties { IgnoreTextOnlyProperties, DoNotIgnoreTextOnlyProperties };
    TriState triStateOfStyle(EditingStyle*) const;
    TriState triStateOfStyle(const VisibleSelection&) const;
    bool conflictsWithInlineStyleOfElement(StyledElement& element) const { return conflictsWithInlineStyleOfElement(element, nullptr, nullptr); }
    bool conflictsWithInlineStyleOfElement(StyledElement& element, RefPtr<MutableStyleProperties>& newInlineStyle, EditingStyle* extractedStyle) const
    {
        return conflictsWithInlineStyleOfElement(element, &newInlineStyle, extractedStyle);
    }
    bool conflictsWithImplicitStyleOfElement(HTMLElement&, EditingStyle* extractedStyle = nullptr, ShouldExtractMatchingStyle = DoNotExtractMatchingStyle) const;
    bool conflictsWithImplicitStyleOfAttributes(HTMLElement&) const;
    bool extractConflictingImplicitStyleOfAttributes(HTMLElement&, ShouldPreserveWritingDirection, EditingStyle* extractedStyle, Vector<QualifiedName>& conflictingAttributes, ShouldExtractMatchingStyle) const;
    bool styleIsPresentInComputedStyleOfNode(Node&) const;

    static bool elementIsStyledSpanOrHTMLEquivalent(const HTMLElement&);

    void prepareToApplyAt(const Position&, ShouldPreserveWritingDirection = DoNotPreserveWritingDirection);
    void mergeTypingStyle(Document&);
    enum CSSPropertyOverrideMode { OverrideValues, DoNotOverrideValues };
    void mergeInlineStyleOfElement(StyledElement&, CSSPropertyOverrideMode, PropertiesToInclude = AllProperties);
    static Ref<EditingStyle> wrappingStyleForSerialization(Node& context, bool shouldAnnotate, StandardFontFamilySerializationMode);
    void mergeStyleFromRules(StyledElement&);
    void mergeStyleFromRulesForSerialization(StyledElement&, StandardFontFamilySerializationMode);
    void removeStyleFromRulesAndContext(StyledElement&, Node* context);
    void removePropertiesInElementDefaultStyle(Element&);
    void forceInline();
    void addDisplayContents();
    bool convertPositionStyle();
    bool isFloating();
    int legacyFontSize(Document&) const;

    float fontSizeDelta() const { return m_fontSizeDelta; }
    bool hasFontSizeDelta() const { return m_fontSizeDelta != NoFontDelta; }
    bool shouldUseFixedDefaultFontSize() const { return m_shouldUseFixedDefaultFontSize; }
    
    void setUnderlineChange(TextDecorationChange change) { m_underlineChange = static_cast<unsigned>(change); }
    TextDecorationChange underlineChange() const { return static_cast<TextDecorationChange>(m_underlineChange); }
    void setStrikeThroughChange(TextDecorationChange change) { m_strikeThroughChange = static_cast<unsigned>(change); }
    TextDecorationChange strikeThroughChange() const { return static_cast<TextDecorationChange>(m_strikeThroughChange); }

    WEBCORE_EXPORT bool hasStyle(CSSPropertyID, const String& value);
    WEBCORE_EXPORT static RefPtr<EditingStyle> styleAtSelectionStart(const VisibleSelection&, bool shouldUseBackgroundColorInEffect = false);
    static WritingDirection textDirectionForSelection(const VisibleSelection&, EditingStyle* typingStyle, bool& hasNestedOrMultipleEmbeddings);

    Ref<EditingStyle> inverseTransformColorIfNeeded(Element&);

private:
    EditingStyle();
    EditingStyle(Node*, PropertiesToInclude);
    EditingStyle(const Position&, PropertiesToInclude);
    WEBCORE_EXPORT explicit EditingStyle(const CSSStyleDeclaration*);
    explicit EditingStyle(const StyleProperties*);
    EditingStyle(CSSPropertyID, const String& value);
    EditingStyle(CSSPropertyID, CSSValueID);
    void init(Node*, PropertiesToInclude);
    void removeTextFillAndStrokeColorsIfNeeded(const RenderStyle*);
    void setProperty(CSSPropertyID, const String& value, bool important = false);
    void extractFontSizeDelta();
    template<typename T> TriState triStateOfStyle(T& styleToCompare, ShouldIgnoreTextOnlyProperties) const;
    bool conflictsWithInlineStyleOfElement(StyledElement&, RefPtr<MutableStyleProperties>* newInlineStyle, EditingStyle* extractedStyle) const;
    void mergeInlineAndImplicitStyleOfElement(StyledElement&, CSSPropertyOverrideMode, PropertiesToInclude, StandardFontFamilySerializationMode);
    void mergeStyle(const StyleProperties*, CSSPropertyOverrideMode);

    RefPtr<MutableStyleProperties> m_mutableStyle;
    unsigned m_shouldUseFixedDefaultFontSize : 1;
    unsigned m_underlineChange : 2;
    unsigned m_strikeThroughChange : 2;
    float m_fontSizeDelta = NoFontDelta;

    friend class HTMLElementEquivalent;
    friend class HTMLAttributeEquivalent;
    friend class HTMLTextDecorationEquivalent;
};

class StyleChange {
public:
    StyleChange() { }
    StyleChange(EditingStyle*, const Position&);

    const StyleProperties* cssStyle() const { return m_cssStyle.get(); }
    bool applyBold() const { return m_applyBold; }
    bool applyItalic() const { return m_applyItalic; }
    bool applyUnderline() const { return m_applyUnderline; }
    bool applyLineThrough() const { return m_applyLineThrough; }
    bool applySubscript() const { return m_applySubscript; }
    bool applySuperscript() const { return m_applySuperscript; }
    bool applyFontColor() const { return m_applyFontColor.length() > 0; }
    bool applyFontFace() const { return m_applyFontFace.length() > 0; }
    bool applyFontSize() const { return m_applyFontSize.length() > 0; }

    String fontColor() { return m_applyFontColor; }
    String fontFace() { return m_applyFontFace; }
    String fontSize() { return m_applyFontSize; }

    bool operator==(const StyleChange&);
    bool operator!=(const StyleChange& other)
    {
        return !(*this == other);
    }
private:
    void extractTextStyles(Document&, MutableStyleProperties&, bool shouldUseFixedFontDefaultSize);

    RefPtr<MutableStyleProperties> m_cssStyle;
    bool m_applyBold = false;
    bool m_applyItalic = false;
    bool m_applyUnderline = false;
    bool m_applyLineThrough = false;
    bool m_applySubscript = false;
    bool m_applySuperscript = false;
    String m_applyFontColor;
    String m_applyFontFace;
    String m_applyFontSize;
};

} // namespace WebCore
