/*
 * Copyright (C) 2008 Instituto Nokia de Tecnologia. All rights reserved.
 *
 * This file is part of QEdje.
 *
 * QEdje is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QEdje is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with QEdje.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __QEDJE_REALPART_H__
#define __QEDJE_REALPART_H__

#include "qzion.h"
#include "qedjeimage.h"

class QEdje;
class QRunningProgram;
class QEdjePart;
class QEdjePartDescription;
class QEdjeCalcParams;

/*!
  \class QEdjeRealPart
  \brief Control the runtime state of a QEdjePart.

  QEdjeRealPart instances hold and control the behaviour of the Edje parts
  statically described by QEdjePart objects.

  Each QEdjeRealPart is associated to one, and only one, QEdjePart.

  \todo Attributes: 'EvasList extraobjects', 'clicked button', 'gradient_id', \
'still_in'
  \todo Runtime change of swallowed object parameters (size, etc).
  \todo Drag.
  \todo Text struct data
  \todo eventsTo
 */

class QEdjeRealPart
{
public:
    struct {
        QEdjePartDescription *description;
        QEdjeRealPart *rel1ToX;
        QEdjeRealPart *rel1ToY;
        QEdjeRealPart *rel2ToX;
        QEdjeRealPart *rel2ToY;
    } param1, param2, custom;

    struct {
        QSize min;
        QSize max;
    } swallowParams;

    QEdjeRealPart(QEdje *edje, QEdjePart *part);
    virtual ~QEdjeRealPart();

    void setInitialState(const QString &name, double value);
    void setFinalState(const QString &name, double value);
    void unsetFinalState();

    QPoint pos();
    void setPos(const QPoint pos);

    QEdje *edje();
    QEdjePart *part();

    void setClipTo(QEdjeRealPart *clipTo);

    QRunningProgram *runningProgram();
    void setRunningProgram(QRunningProgram *rp);
    void setDescriptionPos(const double value);

    QEdjePartDescription *findDescription(QString &name, double value);

    virtual QSize size() const = 0;
    virtual void setSize(const QSize &size) = 0;

    virtual QColor color() const = 0;
    virtual void setColor(const QColor &color) = 0;

    virtual QZionObject *object() = 0;

    void swallow(QZionObject *objSwallow);
    QZionObject *unswallow(const bool recalc = true);
    QZionObject *embeddedObject();

    QSize fixedMinSize() const { return swallowParams.min; }
    QSize fixedMaxSize() const { return swallowParams.max; }
    void setFixedMinSize(const QSize &size) { swallowParams.min = size; }
    void setFixedMaxSize(const QSize &size) { swallowParams.max = size; }

protected:
    QEdje *_edje;
    QEdjePart *_part;
    QEdjeRealPart *_confineTo;
    QRunningProgram *_runningProgram;

    double _descriptionPos;
    QEdjePartDescription *_chosenDescription;

private:
    int calculated;
    int calculating;
    /* Accepted values: FLAG_NONE, FLAG_X, FLAG_Y, FLAG_XY */

    void recalculate(int flags);
    void recalculateRelativeTo(int flags);

    void recalculateSingle(QEdjePartDescription *desc,
                           QEdjePartDescription *chosen_desc,
                           QEdjeRealPart *rel1_to_x,
                           QEdjeRealPart *rel1_to_y,
                           QEdjeRealPart *rel2_to_x,
                           QEdjeRealPart *rel2_to_y,
                           QEdjeRealPart *confine_to,
                           QEdjeCalcParams *params,
                           int flags);

    void recalculateSingleGeometry(QEdjePartDescription *desc,
                                   QEdjeRealPart *rel1_to_x,
                                   QEdjeRealPart *rel1_to_y,
                                   QEdjeRealPart *rel2_to_x,
                                   QEdjeRealPart *rel2_to_y,
                                   QEdjeCalcParams *params,
                                   int flags);

    void recalculateSingleColors(QEdjePartDescription *desc,
                                 QEdjeCalcParams *params);

    void recalculateSingleMinMax(QEdjePartDescription *desc,
                                 QEdjeCalcParams *params);

    void recalculateSingleMinMaxApply(QEdjePartDescription *desc,
                                      QEdjeCalcParams *params, int flags);

    void recalculateSingleFill(QEdjePartDescription *desc,
                               QEdjeCalcParams *params,
                               int flags);

    void recalculateImageApply(QEdje *edje,
                               QEdjeRealPart *part,
                               QEdjeCalcParams *params,
                               QEdjePartDescription *desc,
                               double pos);

    void setSwallowParamsFromObject(QZionObject *obj);

    friend class QEdje;
};


#define QEDJE_REAL_PART_OVERLOAD_EVENTS(cls)         \
    virtual void mouseMoveEvent(QMouseEvent *) {}    \
    virtual void mousePressEvent(QMouseEvent *) {}   \
    virtual void mouseReleaseEvent(QMouseEvent *) {} \
    virtual void wheelEvent(QWheelEvent *) {}


#define QEDJE_REAL_PART_OVERLOAD_METHODS(cls)                           \
    virtual QZionObject *object() { return this; }                      \
    virtual QColor color() const { return cls::color(); }               \
    virtual void setColor(const QColor &color) { cls::setColor(color); } \
    virtual QSize size() const { return cls::size(); }                  \
    virtual void setSize(const QSize &size) { cls::setSize(size); }


/*!
  \class QEdjeRealPartRectangle
  \brief Represents a QEdjeRealPart specialization for a QZionRectangle.
*/
class QEdjeRealPartRectangle : public QZionRectangle, public QEdjeRealPart
{
    Q_OBJECT

public:
    QEdjeRealPartRectangle(QEdje *edje, QEdjePart *part);

    QEDJE_REAL_PART_OVERLOAD_EVENTS(QZionRectangle)
    QEDJE_REAL_PART_OVERLOAD_METHODS(QZionRectangle)
};


/*!
  \class QEdjeRealPartImage
  \brief Represents a QEdjeRealPart specialization for a QEdjeImage.
*/
class QEdjeRealPartImage : public QEdjeImage, public QEdjeRealPart
{
    Q_OBJECT

public:
    QEdjeRealPartImage(QEdje *edje, QEdjePart *part);

    QEDJE_REAL_PART_OVERLOAD_EVENTS(QEdjeImage)
    QEDJE_REAL_PART_OVERLOAD_METHODS(QEdjeImage)
};


/*!
  \class QEdjeRealPartText
  \brief Represents a QEdjeRealPart specialization for a QZionText.
*/
class QEdjeRealPartText : public QZionText, public QEdjeRealPart
{
    Q_OBJECT

public:
    QEdjeRealPartText(QEdje *edje, QEdjePart *part);

    QEDJE_REAL_PART_OVERLOAD_EVENTS(QZionText)
    QEDJE_REAL_PART_OVERLOAD_METHODS(QZionText)
};


/*!
  \class QEdjeRealPartTextBlock
  \brief Represents a QEdjeRealPart specialization for a QZionTextBlock.
*/
class QEdjeRealPartTextBlock : public QZionTextBlock, public QEdjeRealPart
{
    Q_OBJECT

public:
    QEdjeRealPartTextBlock(QEdje *edje, QEdjePart *part);

    QEDJE_REAL_PART_OVERLOAD_EVENTS(QZionTextBlock)
    QEDJE_REAL_PART_OVERLOAD_METHODS(QZionTextBlock)
};


/*!
  \class QEdjeRealPartGroup
  \brief Represents a QEdjeRealPart specialization for a QZionGroup.
*/
class QEdjeRealPartGroup : public QZionGroup, public QEdjeRealPart
{
    Q_OBJECT

public:
    QEdjeRealPartGroup(QEdje *edje, QEdjePart *part);

    QEDJE_REAL_PART_OVERLOAD_METHODS(QZionGroup)

public Q_SLOTS:
    void signalProxy(const QString &emission, const QString &source);
};


/*!
  \class QEdjeRealPartSwallow
  \brief Represents a QEdjeRealPart specialization for a QZionGroup.
*/
class QEdjeRealPartSwallow : public QZionGroup, public QEdjeRealPart
{
    Q_OBJECT

public:
    QEdjeRealPartSwallow(QEdje *edje, QEdjePart *part);

    QEDJE_REAL_PART_OVERLOAD_METHODS(QZionGroup)
};

#endif
