/*
 * Copyright (C) 2018 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:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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

#if ENABLE(LAYOUT_FORMATTING_CONTEXT)

#include "LayoutBox.h"
#include "LayoutInlineBox.h"
#include "LayoutLineBreakBox.h"

namespace WebCore {
namespace Layout {

class InlineItem {
public:
    InlineItem(const Box& layoutBox);

    enum class Type { Text, HardLineBreak, InlineBox, Float };
    Type type() const;
    const Box& layoutBox() const { return m_layoutBox; }
    const RenderStyle& style() const { return m_layoutBox.style(); }
    String textContent() const;
    // DetachingRule indicates whether the inline element needs to be wrapped in a dediceted run or break from previous/next runs.
    // <span>start</span><span style="position: relative;"> middle </span><span>end</span>
    // input to line breaking -> <start middle end>
    // output of line breaking (considering infinite constraint) -> <start middle end>
    // due to the in-flow positioning, the final runs are: <start>< middle ><end>
    // "start" -> n/a
    // " middle " -> BreakAtStart and BreakAtEnd
    // "end" -> n/a
    //
    // <span>parent </span><span style="padding: 10px;">start<span> middle </span>end</span><span> parent</span>
    // input to line breaking -> <parent start middle end parent>
    // output of line breaking (considering infinite constraint) -> <parent start middle end parent>
    // due to padding, final runs -> <parent><start middle end><parent>
    // "parent" -> n/a
    // "start" -> BreakAtStart
    // " middle " -> n/a
    // "end" -> BreakAtEnd
    // "parent" -> n/a
    enum class DetachingRule {
        BreakAtStart = 1 << 0,
        BreakAtEnd = 1 << 1
    };
    void addDetachingRule(OptionSet<DetachingRule> detachingRule) { m_detachingRules.add(detachingRule); }
    OptionSet<DetachingRule> detachingRules() const { return m_detachingRules; }

    // Non-breakable start/end marks margin/padding/border space (even when it does not directly come from the associated layout box)
    // <span style="padding: 5px"><span>nested content with padding parent</span</span>
    // <nested content with padding parent> inline run has 5px non-breakable start/end.
    LayoutUnit nonBreakableStart() const { return m_nonBreakableStart; }
    LayoutUnit nonBreakableEnd() const { return m_nonBreakableEnd; }
    void addNonBreakableStart(LayoutUnit value) { m_nonBreakableStart += value; }
    void addNonBreakableEnd(LayoutUnit value) { m_nonBreakableEnd += value; }

private:
    const Box& m_layoutBox;
    OptionSet<DetachingRule> m_detachingRules;
    LayoutUnit m_nonBreakableStart;
    LayoutUnit m_nonBreakableEnd;
};

using InlineContent = ListHashSet<std::unique_ptr<InlineItem>>;

inline InlineItem::InlineItem(const Box& layoutBox)
    : m_layoutBox(layoutBox)
{
}

inline InlineItem::Type InlineItem::type() const
{
    if (is<InlineBox>(m_layoutBox) && downcast<InlineBox>(m_layoutBox).hasTextContent())
        return Type::Text;

    if (is<LineBreakBox>(m_layoutBox))
        return Type::HardLineBreak;

    if (m_layoutBox.isFloatingPositioned())
        return Type::Float;

    ASSERT(m_layoutBox.isInlineLevelBox());
    return Type::InlineBox;
}

inline String InlineItem::textContent() const
{
    if (type() != Type::Text)
        return { };

    return downcast<InlineBox>(m_layoutBox).textContent();
}

}
}
#endif
