#pragma once

#include "MarkdownElement.h"

#include <vector>
#include <memory>

class MarkdownTextSpan : public MarkdownInlineElement
{
public:
    virtual ~MarkdownTextSpan() = default;

    Type getType() const override;
};


class MarkdownLink : public MarkdownInlineElement
{
public:
    MarkdownLink(const std::string& target);

    virtual ~MarkdownLink() = default;

    const std::string& getTarget() const;

    Type getType() const override;

    void setTarget(const std::string& target)
    {
        mTarget = target;
    }
private:
    std::string mTarget;
};

class MarkdownElementWithChildren : public MarkdownElement
{
public:
    void addChild(std::unique_ptr<MarkdownInlineElement> child);

    std::size_t getNumChildren() const;

    MarkdownInlineElement* getChild(std::size_t idx) const;

    MarkdownInlineElement* getLastChild() const;

    std::vector<MarkdownLink*> getAllLinks() const;

private:
    std::vector<std::unique_ptr<MarkdownInlineElement> > mChildren;
};

class MarkdownParagraph : public MarkdownElementWithChildren
{
public:
    virtual ~MarkdownParagraph() = default;

    Type getType() const override;

    void doFieldSubstitution(Type elementType, const std::string& searchPhrase, const std::string& replacementPhrase) override
    {
        for(auto& child : mChildren)
        {
            child->doFieldSubstitution(elementType, searchPhrase, replacementPhrase);
        }
    }
private:
    std::vector<std::unique_ptr<MarkdownInlineElement> > mChildren;
};

class MarkdownBulletItem : public MarkdownElementWithChildren
{
public:
    virtual ~MarkdownBulletItem() = default;

    Type getType() const override;
};

class MarkdownBulletList : public MarkdownElement
{
public:
    virtual ~MarkdownBulletList() = default;

    Type getType() const override;

    void addChild(std::unique_ptr<MarkdownBulletItem> child);

    std::size_t getNumChildren() const;

    MarkdownBulletItem* getChild(std::size_t idx) const;

private:
    std::vector<std::unique_ptr<MarkdownBulletItem> > mChildren;
};

class MarkdownHeading : public MarkdownElement
{
public:
    MarkdownHeading(unsigned level);

    virtual ~MarkdownHeading() = default;

    Type getType() const override;

    unsigned getLevel() const;

private:
    unsigned mLevel{1};
};

class MarkdownInlineQuote : public MarkdownInlineElement
{
public:

    virtual ~MarkdownInlineQuote() = default;

    Type getType() const override;
};

class MarkdownCustomInline : public MarkdownInlineElement
{
public:
    MarkdownCustomInline(const std::string& delimiter);
    virtual ~MarkdownCustomInline() = default;

    Type getType() const override;
private:
    std::string mDelimiter;
};

class MarkdownImage : public MarkdownInlineElement
{
public:
    MarkdownImage(const std::string& source, const std::string& alt);

    virtual ~MarkdownImage() = default;

    Type getType() const override;

    const std::string& getSource() const;

    const std::string& getAlt() const;

private:
    std::string mSource;
    std::string mAlt;
};

class MarkdownMultilineQuote : public MarkdownMultilineElement
{
public:
    MarkdownMultilineQuote(const std::string& tag);

    virtual ~MarkdownMultilineQuote() = default;

    Type getType() const override;
private:
    std::string mTag;
};

class MarkdownCustomMultiLine : public MarkdownMultilineElement
{
public:
    MarkdownCustomMultiLine(const std::string& tag, const std::string& delimiter);

    virtual ~MarkdownCustomMultiLine() = default;

    Type getType() const override;
private:
    std::string mTag;
    std::string mDelimiter;
};
