/*  This file is part of the QbtGStreamer project, a Qt GStreamer Wrapper
    Copyright (C) 2006 Tim Beaulen <tbscope@gmail.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#ifndef QBTGSTREAMERELEMENT
#define QBTGSTREAMERELEMENT

#include "qbtgstreamerobject.h"
#include "qbtgstreamerpad.h"
#include "qbtgstreamerdatapointer.h"
#include "qbtgstreamerbus.h"
#include "qbtgstreamerclock.h"
#include "qbtgstreamer_export.h" 
#include <QEvent>
#include <QTimerEvent>
#include <QList>

#include <gst/gst.h>

enum QbtGStreamerElementFlags
{
  QbtGStreamerElementLockedState = (QbtGStreamerObjectFlagLast << 0),
  QbtGStreamerElementIsSink = (QbtGStreamerObjectFlagLast << 1),
  QbtGStreamerElementUnparenting = (QbtGStreamerObjectFlagLast << 2),
  /* padding */
  QbtGStreamerElementFlagLast = (QbtGStreamerObjectFlagLast << 16)
};

enum QbtGStreamerState
{
  QbtGStreamerStateVoidPending = 0,
  QbtGStreamerStateNull = 1,
  QbtGStreamerStateReady = 2,
  QbtGStreamerStatePaused = 3,
  QbtGStreamerStatePlaying = 4
};

enum QbtGStreamerStateChangeReturn
{
  QbtGStreamerStateChangeFailure = 0,
  QbtGStreamerStateChangeSuccess = 1,
  QbtGStreamerStateChangeAsync = 2,
  QbtGStreamerStateChangeNoPreroll = 3
};

class QbtGStreamerElementPrivate
{
public:
    QbtGStreamerElementPrivate()
        : element(0)
    {
    }

    GstElement *element;

    // Callbacks
    static void new_pad(GstElement *element, GstPad *pad, gpointer data);
    static void remove_pad(GstElement *element, GstPad *pad, gpointer data);
    static void no_pads(GstElement *element, gpointer data);
};

class QBTGSTREAMER_EXPORT QbtGStreamerElement : public QbtGStreamerObject
{
Q_OBJECT

    friend class QbtGStreamerElementPrivate;
    friend class QbtGStreamerElementFactory;

public:
    QbtGStreamerElement();
    QbtGStreamerElement(const QbtGStreamerElement&);
    QbtGStreamerElement& operator= (const QbtGStreamerElement&);
    ~QbtGStreamerElement();

    /** Links this element to the destination
     */
    bool link(QbtGStreamerElement *destination);
    /** Unlinks this element from the destination
     */
    void unlink(QbtGStreamerElement *destination);

    /** Get the GstElement
        QbtGSteamerElement is a wrapper for GstElement.
      */
    GstElement *gstElement();
    /** Sets this GstElement
     */
    void setGstElement(GstElement *element);

    QbtGStreamerStateChangeReturn setState(QbtGStreamerState state);
    QbtGStreamerStateChangeReturn state(QbtGStreamerState &state, QbtGStreamerState &pending); //TODO: add timeout!

    void setProperty(const QString& property, const QString& value);

    bool addPad(QbtGStreamerPad *pad);

    QbtGStreamerPad *pad(const QString& name);

    void createAllPads();

    QbtGStreamerPad *compatiblePad(QbtGStreamerPad *pad, QbtGStreamerCapabilities *caps);
    QbtGStreamerPad *requestPad(const QString &name);
    QbtGStreamerPad *staticPad(const QString &name);

    void releaseRequestPad(QbtGStreamerPad *pad);

    bool removePad(QbtGStreamerPad *pad);

    QList<QbtGStreamerPad *> pads();
    QList<QbtGStreamerPad *> sinkPads();
    QList<QbtGStreamerPad *> sourcePads();

    bool linkPads(const QString &sourcePadName, QbtGStreamerElement *destination, const QString &destinationPadName);
    void unlinkPads(const QString &sourcePadName, QbtGStreamerElement *destination, const QString &destinationPadName);

    bool linkPadsFiltered(const QString &sourcePadName, QbtGStreamerElement *destination, const QString &destinationPadName, QbtGStreamerCapabilities *filter);

    bool linkFiltered(QbtGStreamerElement *destination, QbtGStreamerCapabilities *filter);

    QbtGStreamerClockTime baseTime();
    void setBaseTime(QbtGStreamerClockTime time);

    QbtGStreamerBus *bus();
    void setBus(QbtGStreamerBus *bus);

    //QbtGStreamerElementFactory *factory();

    bool indexable();

    /*gboolean    gst_element_query_duration      (GstElement *element,
                                             GstFormat *format,
                                             gint64 *duration);*/
    qint64 duration();

    //qint64 position();

    bool seekSimple(qint64 position);


signals:
    void padAdded(QbtGStreamerElement* element, QbtGStreamerPad* pad, QbtGStreamerDataPointer* data);
    void padRemoved(QbtGStreamerElement* element, QbtGStreamerPad* pad, QbtGStreamerDataPointer* data);
    void noMorePads(QbtGStreamerElement* element, QbtGStreamerDataPointer* data);

private:
    static QbtGStreamerElement* s_instance;
    static QbtGStreamerElement* instance() { return s_instance; }

    QbtGStreamerElementPrivate *d;
};

#endif
