#include <mbgl/geometry/anchor.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/test/util.hpp>
#include <mbgl/text/quads.hpp>
#include <mbgl/text/shaping.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>

using namespace mbgl;
using namespace mbgl::style;

TEST(getIconQuads, normal) {
    SymbolLayoutProperties layout;
    Anchor anchor(2.0, 3.0, 0.0, 0.5f, 0);
    SpriteAtlasElement image = {
        Rect<uint16_t>( 0, 0, 15, 11 ),
        std::shared_ptr<const SpriteImage>(),
        1.0f
    };
    PositionedIcon shapedIcon(image, -5.0, 6.0, -7.0, 8.0);
    GeometryCoordinates line;
    Shaping shapedText;

    SymbolQuads quads =
        getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

    ASSERT_EQ(quads.size(), 1u);
    ASSERT_EQ(quads[0].anchorPoint.x, 2);
    ASSERT_EQ(quads[0].anchorPoint.y, 3);
    ASSERT_EQ(quads[0].tl.x, -8);
    ASSERT_EQ(quads[0].tl.y, -6);
    ASSERT_EQ(quads[0].tr.x, 7);
    ASSERT_EQ(quads[0].tr.y, -6);
    ASSERT_EQ(quads[0].bl.x, -8);
    ASSERT_EQ(quads[0].bl.y, 5);
    ASSERT_EQ(quads[0].br.x, 7);
    ASSERT_EQ(quads[0].br.y, 5);
    ASSERT_EQ(quads[0].anchorAngle, 0.0f);
    ASSERT_EQ(quads[0].glyphAngle, 0.0f);
    ASSERT_EQ(quads[0].minScale, 0.5f);
}

TEST(getIconQuads, style) {
    Anchor anchor(0.0, 0.0, 0.0, 0.5f, 0);
    SpriteAtlasElement image = {
        Rect<uint16_t>( 0, 0, 20, 20 ),
        std::shared_ptr<const SpriteImage>(),
        1.0f
    };
    PositionedIcon shapedIcon(image, -10.0, 10.0, -10.0, 10.0);
    GeometryCoordinates line;
    Shaping shapedText;
    shapedText.top = -10.0f;
    shapedText.bottom = 30.0f;
    shapedText.left = -60.0f;
    shapedText.right = 20.0f;
    shapedText.positionedGlyphs.emplace_back(PositionedGlyph(32, 0.0f, 0.0f));

    // none
    {
        SymbolLayoutProperties layout;
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads.size(), 1u);
        ASSERT_EQ(quads[0].anchorPoint.x, 0);
        ASSERT_EQ(quads[0].anchorPoint.y, 0);
        ASSERT_EQ(quads[0].tl.x, -11);
        ASSERT_EQ(quads[0].tl.y, -11);
        ASSERT_EQ(quads[0].tr.x, 9);
        ASSERT_EQ(quads[0].tr.y, -11);
        ASSERT_EQ(quads[0].bl.x, -11);
        ASSERT_EQ(quads[0].bl.y, 9);
        ASSERT_EQ(quads[0].br.x, 9);
        ASSERT_EQ(quads[0].br.y, 9);
        ASSERT_EQ(quads[0].anchorAngle, 0.0f);
        ASSERT_EQ(quads[0].glyphAngle, 0.0f);
        ASSERT_EQ(quads[0].minScale, 0.5f);
    }

    // width
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(24.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Width);
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -60);
        ASSERT_EQ(quads[0].tl.y, 0);
        ASSERT_EQ(quads[0].tr.x, 20);
        ASSERT_EQ(quads[0].tr.y, 0);
        ASSERT_EQ(quads[0].bl.x, -60);
        ASSERT_EQ(quads[0].bl.y, 20);
        ASSERT_EQ(quads[0].br.x, 20);
        ASSERT_EQ(quads[0].br.y, 20);
    }

    // width x textSize
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(12.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Width);
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -30);
        ASSERT_EQ(quads[0].tl.y, -5);
        ASSERT_EQ(quads[0].tr.x, 10);
        ASSERT_EQ(quads[0].tr.y, -5);
        ASSERT_EQ(quads[0].bl.x, -30);
        ASSERT_EQ(quads[0].bl.y, 15);
        ASSERT_EQ(quads[0].br.x, 10);
        ASSERT_EQ(quads[0].br.y, 15);
    }

    // width x textSize + padding
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(12.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Width);
        layout.iconTextFitPadding.value[0] = 5.0f;
        layout.iconTextFitPadding.value[1] = 10.0f;
        layout.iconTextFitPadding.value[2] = 5.0f;
        layout.iconTextFitPadding.value[3] = 10.0f;
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -40);
        ASSERT_EQ(quads[0].tl.y, -10);
        ASSERT_EQ(quads[0].tr.x, 20);
        ASSERT_EQ(quads[0].tr.y, -10);
        ASSERT_EQ(quads[0].bl.x, -40);
        ASSERT_EQ(quads[0].bl.y, 20);
        ASSERT_EQ(quads[0].br.x, 20);
        ASSERT_EQ(quads[0].br.y, 20);
    }

    // height
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(24.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Height);
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -30);
        ASSERT_EQ(quads[0].tl.y, -10);
        ASSERT_EQ(quads[0].tr.x, -10);
        ASSERT_EQ(quads[0].tr.y, -10);
        ASSERT_EQ(quads[0].bl.x, -30);
        ASSERT_EQ(quads[0].bl.y, 30);
        ASSERT_EQ(quads[0].br.x, -10);
        ASSERT_EQ(quads[0].br.y, 30);
    }

    // height x textSize
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(12.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Height);
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -20);
        ASSERT_EQ(quads[0].tl.y, -5);
        ASSERT_EQ(quads[0].tr.x, 0);
        ASSERT_EQ(quads[0].tr.y, -5);
        ASSERT_EQ(quads[0].bl.x, -20);
        ASSERT_EQ(quads[0].bl.y, 15);
        ASSERT_EQ(quads[0].br.x, 0);
        ASSERT_EQ(quads[0].br.y, 15);
    }

    // height x textSize + padding
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(12.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Height);
        layout.iconTextFitPadding.value[0] = 5.0f;
        layout.iconTextFitPadding.value[1] = 10.0f;
        layout.iconTextFitPadding.value[2] = 5.0f;
        layout.iconTextFitPadding.value[3] = 10.0f;
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -30);
        ASSERT_EQ(quads[0].tl.y, -10);
        ASSERT_EQ(quads[0].tr.x, 10);
        ASSERT_EQ(quads[0].tr.y, -10);
        ASSERT_EQ(quads[0].bl.x, -30);
        ASSERT_EQ(quads[0].bl.y, 20);
        ASSERT_EQ(quads[0].br.x, 10);
        ASSERT_EQ(quads[0].br.y, 20);
    }

    // both
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(24.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Both);
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -60);
        ASSERT_EQ(quads[0].tl.y, -10);
        ASSERT_EQ(quads[0].tr.x, 20);
        ASSERT_EQ(quads[0].tr.y, -10);
        ASSERT_EQ(quads[0].bl.x, -60);
        ASSERT_EQ(quads[0].bl.y, 30);
        ASSERT_EQ(quads[0].br.x, 20);
        ASSERT_EQ(quads[0].br.y, 30);
    }

    // both x textSize
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(12.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Both);
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -30);
        ASSERT_EQ(quads[0].tl.y, -5);
        ASSERT_EQ(quads[0].tr.x, 10);
        ASSERT_EQ(quads[0].tr.y, -5);
        ASSERT_EQ(quads[0].bl.x, -30);
        ASSERT_EQ(quads[0].bl.y, 15);
        ASSERT_EQ(quads[0].br.x, 10);
        ASSERT_EQ(quads[0].br.y, 15);
    }

    // both x textSize + padding
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(12.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Both);
        layout.iconTextFitPadding.value[0] = 5.0f;
        layout.iconTextFitPadding.value[1] = 10.0f;
        layout.iconTextFitPadding.value[2] = 5.0f;
        layout.iconTextFitPadding.value[3] = 10.0f;
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -40);
        ASSERT_EQ(quads[0].tl.y, -10);
        ASSERT_EQ(quads[0].tr.x, 20);
        ASSERT_EQ(quads[0].tr.y, -10);
        ASSERT_EQ(quads[0].bl.x, -40);
        ASSERT_EQ(quads[0].bl.y, 20);
        ASSERT_EQ(quads[0].br.x, 20);
        ASSERT_EQ(quads[0].br.y, 20);
    }

    // both x textSize + padding t/r/b/l
    {
        SymbolLayoutProperties layout;
        layout.textSize = LayoutProperty<float>(12.0f);
        layout.iconTextFit = LayoutProperty<IconTextFitType>(IconTextFitType::Both);
        layout.iconTextFitPadding.value[0] = 0.0f;
        layout.iconTextFitPadding.value[1] = 5.0f;
        layout.iconTextFitPadding.value[2] = 10.0f;
        layout.iconTextFitPadding.value[3] = 15.0f;
        SymbolQuads quads =
            getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);

        ASSERT_EQ(quads[0].tl.x, -45);
        ASSERT_EQ(quads[0].tl.y, -5);
        ASSERT_EQ(quads[0].tr.x, 15);
        ASSERT_EQ(quads[0].tr.y, -5);
        ASSERT_EQ(quads[0].bl.x, -45);
        ASSERT_EQ(quads[0].bl.y, 25);
        ASSERT_EQ(quads[0].br.x, 15);
        ASSERT_EQ(quads[0].br.y, 25);
    }
}

