/*
 * 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_H__
#define __QEDJE_H__

#include <QtCore>
#include <QtGui>

#include <qzion.h>

#include "qedjeimage.h"

#define EDJE_FILE_VERSION 2

#define FLAG_NONE 0
#define FLAG_X    0x01
#define FLAG_Y    0x02
#define FLAG_XY   (FLAG_X | FLAG_Y)


class QEdjeRealPart;
class QRunningProgram;
class QEdjeFile;

struct QEdjeProgram;
struct QEdjeColorClass;

/*!
  \class QEdje
  \brief Handler of parts described by and edje group.

  Handle swallows, signals, programs and parts of an edje group. It's a
  representation of an edje group and responsible about emitting signals, calling
  callbacks, moving/showing/hiding parts on the canvas and make everything respect
  the relatives positions.
 */
class QEdje : public QZionGroup
{
    Q_OBJECT

public:
    QEdje(QZionAbstractCanvas *canvas, const QString &filename,
          const QString &group);
    ~QEdje();

    virtual void canvasResizeEvent(QResizeEvent *event);

    void emitEdjeSignal(const QString &emission, const QString &source);
    bool connectEdjeSignal(const QString &emission, const QString &source,
                           QObject *receiver, const char *method);
    bool disconnectEdjeSignal(const QString &emission, const QString &source,
                              QObject *receiver = 0, const char *method = 0);
    bool disconnectEdjeSignal(QObject *receiver, const char *method = 0);

    void partSwallow(const QString &part, QZionObject *obj_swallow);
    QZionObject* partUnswallow(const QString &part);
    QZionObject* part(const QString &part);

    const QString& path() const { return _path; }
    const QString& group() const { return _group; }

    virtual void setSize(const QSize &size);
    inline QSize propMin() const;
    inline QSize propMax() const;

    void setFixedPartMinSize(const QString &part, QSize &size);
    void setFixedPartMaxSize(const QString &part, QSize &size);

    bool setFile(const QString &filename);

protected:
    virtual void mouseObjectEnterEvent(QZionObject *src, QMouseEvent *e);
    virtual void mouseObjectExitEvent(QZionObject *src, QMouseEvent *e);
    virtual void mouseObjectMoveEvent(QZionObject *src, QMouseEvent *e);
    virtual void mouseObjectPressEvent(QZionObject *src, QMouseEvent *e);
    virtual void mouseObjectReleaseEvent(QZionObject *src, QMouseEvent *e);
    virtual void wheelObjectEvent(QZionObject *src, QWheelEvent *e);

private:
    friend class QEdjeRealPart;
    friend class QRunningProgram;

    QEdjeRealPart* realPart(const QString &part);
    QEdjeRealPart* getRealPartRecursive(const QString &part);
    QEdjeRealPart* getRealPartRecursiveHelper(QStringList path, int index);

    QEdjeColorClass *colorClass(const QString &name) const;

    inline QEdjeRealPart *findPart(const int id);
    inline QEdjeProgram *findProgram(const int id);

    void recalculate();

    int freeze();
    int thaw();

    bool populate();
    void programStateSet(QEdjeProgram *program);
    void programStop(QEdjeProgram *program);
    void launchProgram(QEdjeProgram *program);
    void launchAfterPrograms(QEdjeProgram *program);
    void launchPrograms(const QString &signal, const QString &part);
    void notifyCallbacks(const QString &signal, const QString &part);
    void unrefRunningProgram(QRunningProgram *runningProgram);

    const QEdjeFile *edjeFile;
    QString _path;
    QString _group;

    QList <QEdjeRealPart *> tableParts;
    QList <QEdjeProgram *> tablePrograms;
    QList <QRunningProgram *> _runningPrograms;

    bool dirty;
    int frozen;
    bool recalc;
    bool calculateOnly;
    QZionObject *lastObjectPressed;

    QSize _propMin;
    QSize _propMax;

    // TODO: general missing fields

    enum AfterExecution { doExecuteAfter, doNotExecuteAfter };

    void iterateState(qreal value, QList<QEdjeRealPart*> &targets);
    void runLastIteration(QList<QEdjeRealPart *> &targets,
                          QEdjeProgram *program, AfterExecution after);

    struct Connection;
    QList<Connection *> _connections;
    void notifyConnections(const QString &emission, const QString &source);
    int _notifyingConnections;
    bool _connectionsToDelete;

    bool isReceiver(QObject *) const;

private Q_SLOTS:
    void clearConnections(QObject *obj);
};


/*!
  Returns a QEdjeRealPart searching by id.
*/
inline QEdjeRealPart *QEdje::findPart(const int id)
{
    if (id < 0 || id >= tableParts.size())
        return NULL;

    return tableParts[id];
}

/*!
  Returns a QEdjeProgram searching by id.
*/
inline QEdjeProgram *QEdje::findProgram(const int id)
{
    if (id < 0 || id >= tablePrograms.size())
        return NULL;

    return tablePrograms[id];
}

/*!
  Returns the minimum size specified by the group.
*/
inline QSize QEdje::propMin() const
{
    return _propMin;
}

/*!
  Returns the maximum size specified by the group.
*/
inline QSize QEdje::propMax() const
{
    return _propMax;
}


QStringList groupNamesFromFile(const QString &filename);

#endif
