#pragma once

#include <TextField.h>
#include <UIMLView.h>

class LogicTree;

class RecipieIngredientElement : public Framework::UIMLElement
{
private:
    LogicTree* parse(Framework::XML::Element* zElement);

public:
    RecipieIngredientElement();
    //! prüft, ob dieses UIML Element für ein bestimmtes xml Element zuständig
    //! ist
    bool isApplicableFor(Framework::XML::Element& element) override;
    //! erstellt eine neue Drawable zu einem gegebenen xml Element
    Framework::Drawable* parseElement(Framework::XML::Element& element,
        Framework::UIMLContainer& generalFactory) override;
    bool updateElement(Framework::XML::Element& element,
        Framework::Drawable& z,
        Framework::UIMLContainer& generalFactory) override;
    //! wendet die layout parameter zu einer Drawable an
    void layout(Framework::XML::Element& element,
        Framework::Drawable& z,
        int pWidth,
        int pHeight,
        Framework::UIMLContainer& generalLayouter) override;
};

class RecipieIngredient : public Framework::DrawableBackground
{
private:
    Framework::RCArray<Framework::Image> icons;
    Framework::RCArray<Framework::Text> toolTips;
    Framework::Array<int> itemTypes;
    Framework::TextField* toolTip;
    int currentIconIndex;
    double timtUntilNextIcon;
    int amount;

public:
    RecipieIngredient(int amount);

    void addPossibleItem(
        Framework::Image* icon, Framework::Text* toolTip, int itemType);

    bool tick(double tickVal) override;
    void render(Framework::Image& rObj) override;
    void doMouseEvent(Framework::MouseEvent& me, bool userRet) override;
};

enum class AttributeOperator
{
    Equals,
    NotEquals,
    GreaterThan,
    GreaterThanOrEquals,
    LessThan,
    LessThanOrEquals
};

class Requirement : public Framework::ReferenceCounter
{
private:
    Framework::Text attribute;
    Framework::Text value;
    AttributeOperator op;

public:
    Requirement(
        Framework::Text attribute, Framework::Text value, AttributeOperator op);

    void negate();
    Requirement* clone();
    bool contradicts(Requirement* zOther);
    bool merge(Requirement* zOther);
    int getItemType();
    Framework::Text getDescription();
};

class RequirementSet : public Framework::ReferenceCounter
{
private:
    Framework::RCArray<Requirement> requirements;

public:
    RequirementSet();

    void addRequirement(Requirement* zReq);
    RequirementSet* clone();
    void addRequirements(RequirementSet* zOther);

    void negate(LogicTree* zNode);

    bool isNoneMatch() const;
    bool isAnyMatch() const;
    Framework::Text renderToTooltip() const;
    Framework::Image* getIcon() const;
    int getItemType() const;
};

enum class LogicalOperator
{
    AND,
    OR
};

class LogicTree : public Framework::ReferenceCounter
{
private:
    LogicalOperator op;
    RequirementSet* requirementSet;
    Framework::RCArray<LogicTree> children;

    Framework::RCArray<RequirementSet>* multiply(
        Framework::RCArray<RequirementSet>* a,
        Framework::RCArray<RequirementSet>* b);

public:
    LogicTree(LogicalOperator op, RequirementSet* set);
    ~LogicTree();

    void addChildren(LogicTree* tree);

    LogicTree* clone();
    void negate();
    Framework::RCArray<RequirementSet>* resolve();
};