/*
 * Copyright (C) 2012 Matt Broadstone
 * Contact: http://bitbucket.org/devonit/qconnman
 *
 * This file is part of the QConnman Library.
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * 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
 * Lesser General Public License for more details.
 */

#ifndef MANAGER_H
#define MANAGER_H

#include <QAbstractItemModel>
#include <QStringList>
#include <QList>
#include <QPointer>
#include <QDBusVariant>
#include <QDBusArgument>
#include <QScopedPointer>

#include "agent.h"
#include "technology.h"
#include "service.h"

class QDBusServiceWatcher;
class QDBusPendingCallWatcher;
class ManagerPrivate;
class Manager : public QAbstractItemModel
{
    Q_OBJECT
    Q_ENUMS(State)
    Q_PROPERTY(bool OfflineMode READ offlineMode WRITE setOfflineModeInternal NOTIFY offlineModeChanged)
    Q_PROPERTY(bool SessionMode READ sessionMode WRITE setSessionModeInternal NOTIFY sessionModeChanged)
    Q_PROPERTY(Manager::State State READ state WRITE setStateInternal NOTIFY stateChanged)
    Q_PROPERTY(Service *connectedService READ connectedService NOTIFY connectedServiceChanged)
    Q_PROPERTY(bool ignoreHiddenNetworks READ ignoreHiddenNetworks WRITE setIgnoreHiddenNetworks NOTIFY ignoreHiddenNetworksChanged)

public:
    enum ManagerDataRoles {
        TechnologyRole = Qt::UserRole + 1,
        ServiceRole,
        IconRole
    };

    Manager(QObject *parent = 0);
    virtual ~Manager();

    enum State {
      Offline,
      Idle,
      Ready,
      Online
    };
    State state() const;
    void setState(State state) ;

    bool offlineMode() const;
    void setOfflineMode(bool offlineMode);

    bool sessionMode() const;
    void setSessionMode(bool sessionMode);

    QList<Agent*> agents() const;
    QList<Technology*> technologies() const;
    QList<Service*> services() const;

    bool hasService(const QString &name) const;
    bool hasService(const QDBusObjectPath &path) const;
    Service *service(const QString &name);
    Service *service(const QDBusObjectPath &path);
    Service *connectedService();

    static QStringList configuredServices(const QString &path = QString());

    // vpn support
    QDBusObjectPath connectProvider(const QVariant &provider);
    bool removeProvider(const QDBusObjectPath &path);
    bool removeProvider(const QString &provider);
    QString provider(const QDBusObjectPath &path) const;
    QDBusObjectPath provider(const QString &provider);
    QList<QString> providers() const;

    // Setting it to true the model will ignore any hidden wireless network
    virtual bool ignoreHiddenNetworks() const;
    void setIgnoreHiddenNetworks( bool hide );

    // QAbstractItemModel specific
    QHash<int, QByteArray> roleNames() const;
    QVariant data(const QModelIndex &index, int role) const;
    QModelIndex index(int row, int column,
                      const QModelIndex &parent = QModelIndex()) const;
    QModelIndex parent(const QModelIndex &index) const;
    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    int columnCount(const QModelIndex &parent = QModelIndex()) const;

Q_SIGNALS:
    void stateChanged();
    void offlineModeChanged();
    void sessionModeChanged();
    void servicesChanged();
    void connectedServiceChanged();
    void ignoreHiddenNetworksChanged();

public Q_SLOTS:
    void registerAgent(Agent *agent);
    void unregisterAgent(Agent *agent);
    void unregisterAgent(const QDBusObjectPath &path);
    void disconnectServices();

private Q_SLOTS:
    void connmanRegistered();
    void connmanUnregistered();

    void propertyChanged(const QString &name, const QDBusVariant &value);
    void servicesChanged(const QList<ObjectPropertyData> &changedServices,
                         const QList<QDBusObjectPath> &removedServices);

    void technologyAdded(const QDBusObjectPath &path, const QVariantMap &properties);
    void technologyRemoved(const QDBusObjectPath &path);

    void getTechnologiesResponse(QDBusPendingCallWatcher *call);
    void getServicesResponse(QDBusPendingCallWatcher *call);
    void getPropertiesResponse(QDBusPendingCallWatcher *call);

    void setObjectProperty(QObject *object, const QString &property, const QVariant &value);

protected:
    /* Constructs a model without calling the initialize method. The initialize method
       should be called manually by the user.
       Calling the initialize method from constructor of derived classes avoids a issue
       with virtual methods and Qt SLOTS. Because into a SLOT it is not possible to call
       a derived virtual method from the base class.

       NOTE: This constructor should be ONLY called from the constructor of derived classes.
     */
    Manager(bool initialize, QObject *parent = 0);
    void initialize();

    // Returns a list of ignored technologies that will be ignored by the model
    virtual QStringList ignoredTechnologies() const;

    // This function returns the technology name that the model will use to provide
    // the Qt::DisplayRole
    virtual QString technologyName(Technology *technology) const;
    virtual QIcon technologyIcon(Technology *technology) const;

    // This function returns the service name that the model will use to provide
    // the Qt::DisplayRole
    virtual QString serviceName(Service *service) const;
    virtual QIcon serviceIcon(Service *service) const;

    // This function returns the technology icon that the model will
    // use to provide the Qt::DecorationRole and Manager::IconRole
    virtual QString iconName(const QString &type) const;

private:
    void setStateInternal(const State state);
    void setOfflineModeInternal(bool offlineMode);
    void setSessionModeInternal(bool sessionMode);

    Q_DISABLE_COPY(Manager)
    Q_DECLARE_PRIVATE(Manager)
    QScopedPointer<ManagerPrivate> d_ptr;

};

#endif

