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

#include <QObject>
#include <QStringList>
#include <QScopedPointer>

#include "types.h"
#include "connmanobject.h"

class Service;
class ConfigurableObject : public QObject
{
    Q_OBJECT
public:
    explicit ConfigurableObject(ConnManObject *parent);

    virtual void apply();
    virtual void loadFromConfigData(const QString &data);

protected:
    void setServiceProperty(const QString &property, const QVariant &data);
    Service *m_service;

};

class IPV4DataPrivate;
class IPV4Data : public ConfigurableObject
{
    Q_OBJECT
    Q_PROPERTY(QString Method READ method WRITE setMethod NOTIFY methodChanged)
    Q_PROPERTY(QString Address READ address WRITE setAddress NOTIFY addressChanged)
    Q_PROPERTY(QString Netmask READ netmask WRITE setNetmask NOTIFY netmaskChanged)
    Q_PROPERTY(QString Gateway READ gateway WRITE setGateway NOTIFY gatewayChanged)
public:
    explicit IPV4Data(ConnManObject *parent);
    ~IPV4Data();

    QString method() const;
    void setMethod(const QString &method);

    QString address() const;
    void setAddress(const QString &address);

    QString netmask() const;
    void setNetmask(const QString &netmask);

    QString gateway() const;
    void setGateway(const QString &gateway);

Q_SIGNALS:
    void methodChanged();
    void addressChanged();
    void netmaskChanged();
    void gatewayChanged();

private:
    Q_DISABLE_COPY(IPV4Data)
    Q_DECLARE_PRIVATE(IPV4Data)
    QScopedPointer<IPV4DataPrivate> d_ptr;

};

class IPV6DataPrivate;
class IPV6Data : public ConfigurableObject
{
    Q_OBJECT
    Q_PROPERTY(QString Method READ method WRITE setMethod NOTIFY methodChanged)
    Q_PROPERTY(QString Address READ address WRITE setAddress NOTIFY addressChanged)
    Q_PROPERTY(QString PrefixLength READ prefixLength WRITE setPrefixLength NOTIFY prefixChanged)
    Q_PROPERTY(QString Gateway READ gateway WRITE setGateway NOTIFY gatewayChanged)
    Q_PROPERTY(QString Privacy READ privacy WRITE setPrivacy NOTIFY privacyChanged)
public:
    explicit IPV6Data(ConnManObject *parent);
    ~IPV6Data();

    QString method() const;
    void setMethod(const QString &method);

    QString address() const;
    void setAddress(const QString &address);

    QString prefixLength() const;
    void setPrefixLength(const QString &prefixLength);

    QString gateway() const;
    void setGateway(const QString &gateway);

    QString privacy() const;
    void setPrivacy(const QString &privacy);

Q_SIGNALS:
    void methodChanged();
    void addressChanged();
    void prefixChanged();
    void gatewayChanged();
    void privacyChanged();

private:
    Q_DISABLE_COPY(IPV6Data)
    Q_DECLARE_PRIVATE(IPV6Data)
    QScopedPointer<IPV6DataPrivate> d_ptr;

};

class ProxyDataPrivate;
class ProxyData : public ConfigurableObject
{
    Q_OBJECT
    Q_PROPERTY(QString Method READ method WRITE setMethod NOTIFY methodChanged)
    Q_PROPERTY(QString URL READ url WRITE setUrl NOTIFY urlChanged)
    Q_PROPERTY(QStringList Servers READ servers WRITE setServers NOTIFY serversChanged)
    Q_PROPERTY(QStringList Excludes READ excludes WRITE setExcludes NOTIFY excludesChanged)
public:
    explicit ProxyData(ConnManObject *parent);
    ~ProxyData();

    QString method() const;
    void setMethod(const QString &method);

    QString url() const;
    void setUrl(const QString &url);

    QStringList servers() const;
    void setServers(const QStringList &servers);

    QStringList excludes() const;
    void setExcludes(const QStringList &excludes);

Q_SIGNALS:
    void methodChanged();
    void urlChanged();
    void serversChanged();
    void excludesChanged();

private:
    Q_DISABLE_COPY(ProxyData)
    Q_DECLARE_PRIVATE(ProxyData)
    QScopedPointer<ProxyDataPrivate> d_ptr;

};

class EthernetDataPrivate;
class EthernetData : public ConfigurableObject
{
    Q_OBJECT
    Q_PROPERTY(QString Method READ method WRITE setMethod NOTIFY methodChanged)
    Q_PROPERTY(QString Interface READ interface WRITE setInterface NOTIFY interfaceChanged)
    Q_PROPERTY(QString Address READ address WRITE setAddress NOTIFY addressChanged)
    Q_PROPERTY(quint16 MTU READ mtu WRITE setMtu NOTIFY mtuChanged)
    Q_PROPERTY(quint16 Speed READ speed WRITE setSpeed NOTIFY speedChanged)
    Q_PROPERTY(QString Duplex READ duplex WRITE setDuplex NOTIFY duplexChanged)
public:
    EthernetData(ConnManObject *parent);
    ~EthernetData();

    QString method() const;
    void setMethod(const QString &method);

    QString interface() const;
    void setInterface(const QString &interface);

    QString address() const;
    void setAddress(const QString &address);

    quint16 mtu() const;
    void setMtu(quint16 mtu);

    quint16 speed() const;
    void setSpeed(quint16 speed);

    QString duplex() const;
    void setDuplex(const QString &duplex);

Q_SIGNALS:
    void methodChanged();
    void interfaceChanged();
    void addressChanged();
    void mtuChanged();
    void speedChanged();
    void duplexChanged();

private:
    Q_DISABLE_COPY(EthernetData)
    Q_DECLARE_PRIVATE(EthernetData)
    QScopedPointer<EthernetDataPrivate> d_ptr;

};

class ProviderDataPrivate;
class ProviderData : public ConfigurableObject
{
    Q_OBJECT
    Q_PROPERTY(QString Host READ host WRITE setHost NOTIFY hostChanged)
    Q_PROPERTY(QString Domain READ domain WRITE setDomain NOTIFY domainChanged)
    Q_PROPERTY(QString Name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString Type READ type WRITE setType NOTIFY typeChanged)
public:
    explicit ProviderData(ConnManObject *parent);
    ~ProviderData();

    QString host() const;
    void setHost(const QString &host);

    QString domain() const;
    void setDomain(const QString &domain);

    QString name() const;
    void setName(const QString &name);

    QString type() const;
    void setType(const QString &type);

Q_SIGNALS:
    void hostChanged();
    void domainChanged();
    void nameChanged();
    void typeChanged();

private:
    Q_DISABLE_COPY(ProviderData)
    Q_DECLARE_PRIVATE(ProviderData)
    QScopedPointer<ProviderDataPrivate> d_ptr;

};

class QDBusObjectPath;
class ServiceConfiguration;
class ServicePrivate;
class Service : public ConnManObject
{
    Q_OBJECT
    Q_ENUMS(ServiceState)
    Q_PROPERTY(QString State READ stateInternal WRITE setStateInternal NOTIFY stateChanged)
    Q_PROPERTY(QString Error READ error WRITE setErrorInternal NOTIFY errorChanged)
    Q_PROPERTY(QString Name READ name WRITE setNameInternal NOTIFY nameChanged)
    Q_PROPERTY(QString Type READ type WRITE setTypeInternal NOTIFY typeChanged)
    Q_PROPERTY(QStringList Security READ security WRITE setSecurityInternal NOTIFY securityChanged)
    Q_PROPERTY(quint8 Strength READ strength WRITE setStrengthInternal NOTIFY strengthChanged)
    Q_PROPERTY(bool Favorite READ isFavorite WRITE setFavoriteInternal NOTIFY isFavoriteChanged)
    Q_PROPERTY(bool Immutable READ isImmutable WRITE setImmutableInternal NOTIFY isImmutableChanged)
    Q_PROPERTY(bool AutoConnect READ isAutoConnect WRITE setAutoConnectInternal NOTIFY isAutoConnectChanged)
    Q_PROPERTY(bool Roaming READ isRoaming WRITE setRoamingInternal NOTIFY isRoamingChanged)
    Q_PROPERTY(QStringList Nameservers READ nameservers WRITE setNameserversInternal NOTIFY nameserversChanged)
    Q_PROPERTY(QStringList NameserversConfiguration READ nameserversConfiguration WRITE setNameserversConfigurationInternal NOTIFY nameserversConfigurationChanged)
    Q_PROPERTY(QStringList Timeservers READ timeservers WRITE setTimeserversInternal NOTIFY timeserversChanged)
    Q_PROPERTY(QStringList TimeserversConfiguration READ timeserversConfiguration WRITE setTimeserversConfigurationInternal NOTIFY timeserversConfigurationChanged)
    Q_PROPERTY(QStringList Domains READ domains WRITE setDomainsInternal NOTIFY domainsChanged)
    Q_PROPERTY(QStringList DomainsConfiguration READ domainsConfiguration WRITE setDomainsConfigurationInternal NOTIFY domainsConfigurationChanged)

    Q_PROPERTY(IPV4Data *IPv4 READ ipv4 NOTIFY ipv4Changed)
    Q_PROPERTY(IPV4Data *IPv4Configuration READ ipv4Configuration NOTIFY ipv4ConfigurationChanged)
    Q_PROPERTY(IPV6Data *IPv6 READ ipv6 NOTIFY ipv6Changed)
    Q_PROPERTY(IPV6Data *IPv6Configuration READ ipv6Configuration NOTIFY ipv6ConfigurationChanged)
    Q_PROPERTY(ProxyData *Proxy READ proxy NOTIFY proxyChanged)
    Q_PROPERTY(ProxyData *ProxyConfiguration READ proxyConfiguration NOTIFY proxyConfigurationChanged)

    Q_PROPERTY(EthernetData *Ethernet READ ethernet NOTIFY ethernetChanged)
    Q_PROPERTY(ProviderData *Provider READ provider NOTIFY providerChanged)

public:
    Service(const ObjectPropertyData &info, QObject *parent = 0);
    ~Service();

    enum ServiceState {
        UndefinedState,
        IdleState,
        FailureState,
        AssociationState,
        ConfigurationState,
        ReadyState,
        DisconnectState,
        OnlineState
    };
    ServiceState state() const;

    QDBusObjectPath objectPath() const;
    QString error() const;
    QString name() const;
    QString type() const;
    QStringList security() const;
    quint8 strength() const;
    bool isFavorite() const;
    bool isImmutable() const;
    bool isRoaming() const;

    bool isAutoConnect() const;
    void setAutoConnect(bool autoConnect);

    QStringList nameservers() const;
    QStringList nameserversConfiguration() const;
    void setNameserversConfiguration(const QStringList &nameServers);

    QStringList timeservers() const;
    QStringList timeserversConfiguration() const;
    void setTimeserversConfiguration(const QStringList &timeServers);

    QStringList domains() const;
    QStringList domainsConfiguration() const;
    void setDomainsConfiguration(const QStringList &domains);

    IPV4Data *ipv4() const;
    IPV4Data *ipv4Configuration() const;

    IPV6Data *ipv6() const;
    IPV6Data *ipv6Configuration() const;

    ProxyData *proxy() const;
    ProxyData *proxyConfiguration() const;

    EthernetData *ethernet() const;
    ProviderData *provider() const;

Q_SIGNALS:
    void stateChanged();
    void errorChanged();
    void nameChanged();
    void typeChanged();
    void securityChanged();
    void strengthChanged();
    void isFavoriteChanged();
    void isImmutableChanged();
    void isRoamingChanged();
    void isAutoConnectChanged();
    void nameserversChanged();
    void nameserversConfigurationChanged();
    void timeserversChanged();
    void timeserversConfigurationChanged();
    void domainsChanged();
    void domainsConfigurationChanged();

    void ipv4Changed();
    void ipv4ConfigurationChanged();
    void ipv6Changed();
    void ipv6ConfigurationChanged();
    void proxyChanged();
    void proxyConfigurationChanged();
    void ethernetChanged();
    void providerChanged();

    void connected();

public Q_SLOTS:
    void connect();
    void disconnect();
    void remove();
    void moveBefore(Service *service);
    void moveAfter(Service *service);
    void resetCounters();

protected:
    Service(ServicePrivate *dd, QObject *parent = 0);
    Q_DECLARE_PRIVATE(Service)
    QScopedPointer<ServicePrivate> d_ptr;

private:
    QString stateInternal() const;
    void setStateInternal(const QString &state);
    void setAutoConnectInternal(bool autoConnect);
    void setDomainsInternal(const QStringList &domains);
    void setTimeserversInternal(const QStringList &servers);
    void setNameserversInternal(const QStringList &servers);
    void setNameserversConfigurationInternal(const QStringList &nameServers);
    void setTimeserversConfigurationInternal(const QStringList &timeServers);
    void setDomainsConfigurationInternal(const QStringList &domains);
    void setErrorInternal(const QString &error);
    void setNameInternal(const QString &name);
    void setTypeInternal(const QString &type);
    void setSecurityInternal(const QStringList &security);
    void setStrengthInternal(quint8 strength);
    void setFavoriteInternal(bool favorite);
    void setImmutableInternal(bool immutable);
    void setRoamingInternal(bool roaming);

    Q_DISABLE_COPY(Service)
    friend class ConfigurableObject;

};
Q_DECLARE_METATYPE(Service*)

class WifiServiceConfiguration;
class WifiServicePrivate;
class WifiService : public Service
{
    Q_OBJECT
    Q_PROPERTY(QString EAP READ eap WRITE setEapInternal NOTIFY eapChanged)
    Q_PROPERTY(QString CACertFile READ caCertificateFile WRITE setCaCertificateFileInternal NOTIFY caCertificateFileChanged)
    Q_PROPERTY(QString ClientCertFile READ clientCertificateFile WRITE setClientCertificateFileInternal NOTIFY clientCertificateFileChanged)
    Q_PROPERTY(QString PrivateKeyFile READ privateKeyFile WRITE setPrivateKeyFileInternal NOTIFY privateKeyFileChanged)
    Q_PROPERTY(QString PrivateKeyPassphrase READ privateKeyPassphrase WRITE setPrivateKeyPassphraseInternal NOTIFY privateKeyPassphraseChanged)
    Q_PROPERTY(QString PrivateKeyPassphraseType READ privateKeyPassphraseType WRITE setPrivateKeyPassphraseTypeInternal NOTIFY privateKeyPassphraseTypeChanged)
    Q_PROPERTY(QString Identity READ identity WRITE setIdentityInternal NOTIFY identityChanged)
    Q_PROPERTY(QString Phase2 READ phase2 WRITE setPhase2Internal NOTIFY phase2Changed)
    Q_PROPERTY(QString Passphrase READ passphrase WRITE setPassphraseInternal NOTIFY passphraseChanged)
    Q_PROPERTY(bool Hidden READ isHidden WRITE setHiddenInternal NOTIFY isHiddenChanged)

public:
    WifiService(const ObjectPropertyData &info, QObject *parent = 0);
    ~WifiService();

    QString eap() const;
    void setEap(const QString &method);

    QString caCertificateFile() const;
    void setCaCertificateFile(const QString &path);

    QString clientCertificateFile() const;
    void setClientCertificateFile(const QString &path);

    QString privateKeyFile() const;
    void setPrivateKeyFile(const QString &path);

    QString privateKeyPassphrase() const;
    void setPrivateKeyPassphrase(const QString &passphrase);

    QString privateKeyPassphraseType() const;
    void setPrivateKeyPassphraseType(const QString &type);

    QString identity() const;
    void setIdentity(const QString &identity);

    QString phase2() const;
    void setPhase2(const QString &phase2);

    QString passphrase() const;
    void setPassphrase(const QString &passphrase);

    bool isHidden() const;

Q_SIGNALS:
    void eapChanged();
    void caCertificateFileChanged();
    void clientCertificateFileChanged();
    void privateKeyFileChanged();
    void privateKeyPassphraseChanged();
    void privateKeyPassphraseTypeChanged();
    void identityChanged();
    void phase2Changed();
    void passphraseChanged();
    void isHiddenChanged();

protected:
    WifiService(WifiServicePrivate *dd, QObject *parent = 0);
    Q_DISABLE_COPY(WifiService)
    Q_DECLARE_PRIVATE(WifiService)

private:
    void setEapInternal(const QString &method);
    void setCaCertificateFileInternal(const QString &path);
    void setClientCertificateFileInternal(const QString &path);
    void setPrivateKeyFileInternal(const QString &path);
    void setPrivateKeyPassphraseInternal(const QString &passphrase);
    void setPrivateKeyPassphraseTypeInternal(const QString &type);
    void setIdentityInternal(const QString &identity);
    void setPhase2Internal(const QString &phase2);
    void setPassphraseInternal(const QString &passphrase);
    void setHiddenInternal(bool hidden);

};
Q_DECLARE_METATYPE(WifiService*)

#if QT_VERSION <= 0x050000
Q_DECLARE_BUILTIN_METATYPE(ConfigurableObject*, QObjectStar)
Q_DECLARE_BUILTIN_METATYPE(IPV4Data*, QObjectStar)
Q_DECLARE_BUILTIN_METATYPE(IPV6Data*, QObjectStar)
Q_DECLARE_BUILTIN_METATYPE(ProxyData*, QObjectStar)
Q_DECLARE_BUILTIN_METATYPE(EthernetData*, QObjectStar)
Q_DECLARE_BUILTIN_METATYPE(ProviderData*, QObjectStar)
#else
Q_DECLARE_BUILTIN_METATYPE(ConfigurableObjectStar, QMetaType::QObjectStar, ConfigurableObject*)
Q_DECLARE_BUILTIN_METATYPE(IPV4DataStar, QMetaType::QObjectStar, IPV4Data*)
Q_DECLARE_BUILTIN_METATYPE(IPV6DataStar, QMetaType::QObjectStar, IPV6Data*)
Q_DECLARE_BUILTIN_METATYPE(ProxyDataStar, QMetaType::QObjectStar, ProxyData*)
Q_DECLARE_BUILTIN_METATYPE(EthernetDataStar, QMetaType::QObjectStar, EthernetData*)
Q_DECLARE_BUILTIN_METATYPE(ProviderDataStar, QMetaType::QObjectStar, ProviderData*)
#endif

QDebug operator<<(QDebug, const Service *);
QDebug operator<<(QDebug, const ConfigurableObject *);

#endif
