//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Model/Mask/MaskItems.h
//! @brief     Defines classes MaskItem, RectangleItem, ..., FullframeItem.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#ifndef BORNAGAIN_GUI_MODEL_MASK_MASKITEMS_H
#define BORNAGAIN_GUI_MODEL_MASK_MASKITEMS_H

#include "Base/Type/OwningVector.h"
#include "GUI/Model/Descriptor/DoubleProperty.h"
#include "GUI/Model/Mask/OverlayItem.h"

class IShape2D;
class PointItem;

//! Abstract base class for mask items that describe one specific shape.

class MaskItem : public OverlayItem {
public:
    ~MaskItem() override;

    virtual std::unique_ptr<IShape2D> createShape() const = 0;

    bool maskValue() const { return m_mask_value; }
    void setMaskValue(bool mask_value);

    bool isVisible() const { return m_is_visible; }
    void setIsVisible(bool visible);

    bool wasVisible() const { return m_was_visible; }
    void setWasVisible(bool v) { m_was_visible = v; }

    virtual void writeTo(QXmlStreamWriter* w) const;
    virtual void readFrom(QXmlStreamReader* r);

protected:
    MaskItem();
    bool m_mask_value = true;
    bool m_is_visible = true;
    bool m_was_visible = m_is_visible; // do not serialize
};

class RectangleItem : public MaskItem {
public:
    RectangleItem();
    std::unique_ptr<IShape2D> createShape() const override;

    DoubleProperty& xLow() { return m_x_low; }
    const DoubleProperty& xLow() const { return m_x_low; }
    void setXLow(double val);
    DoubleProperty& yLow() { return m_y_low; }
    const DoubleProperty& yLow() const { return m_y_low; }
    void setYLow(double val);
    DoubleProperty& xUp() { return m_x_up; }
    const DoubleProperty& xUp() const { return m_x_up; }
    void setXUp(double val);
    DoubleProperty& yUp() { return m_y_up; }
    const DoubleProperty& yUp() const { return m_y_up; }
    void setYUp(double val);

    void writeTo(QXmlStreamWriter* w) const override;
    void readFrom(QXmlStreamReader* r) override;

private:
    DoubleProperty m_x_low;
    DoubleProperty m_y_low;
    DoubleProperty m_x_up;
    DoubleProperty m_y_up;
};

class RegionOfInterestItem : public RectangleItem {
public:
    RegionOfInterestItem();
    std::unique_ptr<IShape2D> createShape() const override;
};

class PolygonItem : public MaskItem {
public:
    PolygonItem();
    std::unique_ptr<IShape2D> createShape() const override;

    bool isClosed() const { return m_is_closed; }
    void setIsClosed(bool closed);

    QVector<PointItem*> points() const;
    void addPoint(double x, double y);

    void writeTo(QXmlStreamWriter* w) const override;
    void readFrom(QXmlStreamReader* r) override;

private:
    bool m_is_closed = false;
    OwningVector<PointItem> m_points;
};

class LineItem : public MaskItem {
public:
    LineItem();
    DoubleProperty& pos() { return m_pos; }
    const DoubleProperty& pos() const { return m_pos; }
    void setPos(double val);

    void writeTo(QXmlStreamWriter* w) const override;
    void readFrom(QXmlStreamReader* r) override;

    virtual Qt::Orientation orientation() const = 0;

protected:
    DoubleProperty m_pos;
};

class VerticalLineItem : public LineItem {
public:
    VerticalLineItem();
    std::unique_ptr<IShape2D> createShape() const override;
    Qt::Orientation orientation() const override { return Qt::Vertical; }
};

class HorizontalLineItem : public LineItem {
public:
    HorizontalLineItem();
    std::unique_ptr<IShape2D> createShape() const override;
    Qt::Orientation orientation() const override { return Qt::Horizontal; }
};

class EllipseItem : public MaskItem {
public:
    EllipseItem();
    std::unique_ptr<IShape2D> createShape() const override;

    DoubleProperty& xCenter() { return m_x_center; }
    const DoubleProperty& xCenter() const { return m_x_center; }
    void setXCenter(double val);

    DoubleProperty& yCenter() { return m_y_center; }
    const DoubleProperty& yCenter() const { return m_y_center; }
    void setYCenter(double val);

    DoubleProperty& xRadius() { return m_x_radius; }
    const DoubleProperty& xRadius() const { return m_x_radius; }
    void setXRadius(double val);

    DoubleProperty& yRadius() { return m_y_radius; }
    const DoubleProperty& yRadius() const { return m_y_radius; }
    void setYRadius(double val);

    DoubleProperty& angle() { return m_angle; }
    const DoubleProperty& angle() const { return m_angle; }
    void setAngle(double val);

    void writeTo(QXmlStreamWriter* w) const override;
    void readFrom(QXmlStreamReader* r) override;

private:
    DoubleProperty m_x_center;
    DoubleProperty m_y_center;
    DoubleProperty m_x_radius;
    DoubleProperty m_y_radius;
    DoubleProperty m_angle;
};

class FullframeItem : public MaskItem {
public:
    FullframeItem();
    std::unique_ptr<IShape2D> createShape() const override;
};

#endif // BORNAGAIN_GUI_MODEL_MASK_MASKITEMS_H
