/*
 * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/&gt;.
 *
 */
#ifndef UKMEDIAVOLUMECONTROL_H
#define UKMEDIAVOLUMECONTROL_H

#include <pulse/ext-stream-restore.h>
#if HAVE_EXT_DEVICE_RESTORE_API
#  include <pulse/ext-device-restore.h>
#endif

#include <signal.h>
#include <string.h>
#include <glib.h>
#include <QObject>
#include <pulse/pulseaudio.h>
#include <pulse/glib-mainloop.h>
#include <pulse/ext-stream-restore.h>
#include <pulse/ext-device-restore.h>
#include <pulse/ext-device-manager.h>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusObjectPath>
#include <QDBusReply>
#include <QLabel>
#include <QTimer>
#include "config.h"
#include "ukmedia_custom_sound.h"
#include <QDialog>

#define PANGUW_SINK "alsa_output.platform-raoliang-sndcard.analog-stereo"


class PortInfo {
public:
      QByteArray name;
      QByteArray description;
      uint32_t priority;
      int available;
      int direction;
      int64_t latency_offset;
      std::vector<QByteArray> profiles;
};

class UkmediaVolumeControl : public QObject{
    Q_OBJECT
public:
    UkmediaVolumeControl();
    virtual ~UkmediaVolumeControl();

    int boolToInt(bool b);
    void updateCard(UkmediaVolumeControl *c,const pa_card_info &info);
    bool updateSink(UkmediaVolumeControl *c,const pa_sink_info &info);
    void updateSource(const pa_source_info &info);
    void updateSinkInput(const pa_sink_input_info &info);
    void updateSourceOutput(const pa_source_output_info &info);
    void updateClient(const pa_client_info &info);
    void updateServer(const pa_server_info &info);
    void updateRole(const pa_ext_stream_restore_info &info);

    void updateDeviceInfo(const pa_ext_device_restore_info &info) ;
    void setSinkMute(bool status); //设置输出设备静音状态
    void setSinkVolume(int index,int value); //设置输出设备音量值
    void setSourceMute(bool status); //设置输入设备静音状态
    void setSourceVolume(int index,int value); //设置输入设备音量值
    bool getSinkMute(); //获取输出设备静音状态
    int getSinkVolume(); //获取输出设备音量值
    bool getSourceMute(); //获取输入设备静音状态
    int getSourceVolume(); //获取输入设备音量值
    bool getSinkInputMuted(QString description);
    int getModuleIndexByName(QString name);

    int getDefaultSinkIndex();
    int getSinkInputVolume(const gchar *name); //根据name获取sink input的音量值
    void setSinkInputVolume(int index,int value,int channel); //设置sink input 音量值
    void setSinkInputMuted(int index,bool status); //设置sink input 静音状态
    void setSourceOutputVolume(int index, int value, int channel);
    void setSourceOutputMuted(int index, bool status);
    int getSourceOutputVolume(const gchar *name); //根据name获取source output的音量值
    bool setCardProfile(int index,const gchar *name); //设置声卡的配置文件
    bool setDefaultSink(const gchar *name); //设置默认的输出设备
    bool setDefaultSource(const gchar *name); //设置默认的输入设备
    bool setSinkPort(const gchar *sinkName,const gchar *name); //设置输出设备的端口
    QString stringRemoveUnrecignizedChar(QString str);//移除xml中不能识别的字符
    bool setSourcePort(const gchar *portName, const gchar *name); //设置输入设备的端口


    bool killSinkInput(int index); //kill 索引为index的sink input
//#if HAVE_EXT_DEVICE_RESTORE_API
////    void updateDeviceInfo(const pa_ext_device_restore_info &info);
//#endif

    void removeCard(uint32_t index);
    void removeSink(uint32_t index);
    void removeSource(uint32_t index);
    void removeSinkInput(uint32_t index);
    void removeSourceOutput(uint32_t index);
    void removeClient(uint32_t index);

    void setConnectingMessage(const char *string = NULL);

    void showError(const char *txt);
    static void decOutstanding(UkmediaVolumeControl *w);
    static void cardCb(pa_context *, const pa_card_info *i, int eol, void *userdata);
    static void sinkIndexCb(pa_context *c, const pa_sink_info *i, int eol, void *userdata);
    static void sourceIndexCb(pa_context *c, const pa_source_info *i, int eol, void *userdata);

    static void sinkCb(pa_context *c, const pa_sink_info *i, int eol, void *userdata);
    static void sourceCb(pa_context *, const pa_source_info *i, int eol, void *userdata);
    static void sinkInputCb(pa_context *, const pa_sink_input_info *i, int eol, void *userdata);
    static void sinkInputCallback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); //不更新sink input
    static void sourceOutputCb(pa_context *, const pa_source_output_info *i, int eol, void *userdata);
    static void clientCb(pa_context *, const pa_client_info *i, int eol, void *userdata);
    static void serverInfoCb(pa_context *, const pa_server_info *i, void *userdata);
    static void serverInfoIndexCb(pa_context *, const pa_server_info *i, void *userdata);
    static void extStreamRestoreReadCb(pa_context *,const pa_ext_stream_restore_info *i,int eol,void *userdata);
    static void extStreamRestoreSubscribeCb(pa_context *c, void *userdata);
//    void ext_device_restore_read_cb(pa_context *,const pa_ext_device_restore_info *i,int eol,void *userdata);
//    static void ext_device_restore_subscribe_cb(pa_context *c, pa_device_type_t type, uint32_t idx, void *userdata);
    static void extDeviceManagerReadCb(pa_context *,const pa_ext_device_manager_info *,int eol,void *userdata);
    static void extDeviceManagerSubscribeCb(pa_context *c, void *userdata);
    static void subscribeCb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata);
    static void contextStateCallback(pa_context *c, void *userdata);
    static void moduleInfoCb(pa_context *c, const pa_module_info *i, int eol, void *userdata);
    pa_context* getContext(void);
    gboolean connectToPulse(gpointer userdata);

    void removeOutputPortMap(int index); //移除指定索引的output port
    void removeInputPortMap(int index); //移除指定索引的input port
    void removeCardMap(int index); //移除指定索引的 card
    void removeCardProfileMap(int index); //移除声卡profile map
    void removeSinkPortMap(int index);
    void removeProfileMap(int index);
    void removeInputProfile(int index);
    bool isExitOutputPort(QString name);
    int findOutputPort(QString name);
    QString findSinkActivePortName(QString name);
    bool isExitInputPort(QString name);
    void sendPortChangedSignal();

    std::vector< std::pair<QByteArray,QByteArray> > profiles;
    std::map<QByteArray, PortInfo> ports;

    std::vector< std::pair<QByteArray,QByteArray> > dPorts;
    QByteArray activePort;

    QByteArray activeProfile;
    QByteArray noInOutProfile;
    QByteArray lastActiveProfile;
    bool hasSinks;
    bool hasSources;
    bool firstRun = true;
    pa_cvolume m_defaultSinkVolume;

    const pa_sink_info *m_pDefaultSink = nullptr;
    pa_context* m_pPaContext;
    std::map<uint32_t, char*> clientNames;
    SinkInputType showSinkInputType;
    SinkType showSinkType;
    SourceOutputType showSourceOutputType;
    SourceType showSourceType;
    int sinkVolume = 0; //输出音量
    int sourceVolume = 0; //输入音量
    bool sinkMuted; //输出静音状态
    bool sourceMuted; //输入静音状态
    int sinkInputVolume; //sink input 音量
    bool sinkInputMuted; //sink input 静音状态

    int signalCount = 0;   //为了防止多次发送信号的情况，当signalCount>=2时，置1
    bool updateSinkFirstEnterFlag = true;

    float balance; //平衡音量值
    int channel = 0; //通道数
    int inputChannel = 0;
    int sinkInputChannel = 0;
    int sourceOutputChannel = 0;
    QString sourcePortName = ""; //输入设备端口名
    QString sinkPortName = ""; //输出设备端口名
    const gchar *sinkPortLabel; //输出设备端口名

    int defaultOutputCard;
    int defaultInputCard;
    QString findModuleStr = ""; //需要查找的module name
    int findModuleIndex = -1; //查找到模块的index

    pa_channel_map channelMap;
    friend class UkmediaMainWidget;

    QMap<int, QString> sinkMap; //输出设备
    QMap<QString,QString> sinkActivePortMap; //输出设备活跃端口
    QMap<int, QString> sourceMap; //输入设备
    QMap<int,QMap<QString,QString>> outputPortMap; //输出端口
    QMap<int,QMap<QString,QString>> inputPortMap; //输入端口
    QMap<int,QMap<QString,QString>> profileNameMap; //声卡输出配置文件
    QMap<int, QMap<QString,QString>>inputPortProfileNameMap; //声卡输入配置文件
    QMap<int, QMap<QString,int>> cardProfilePriorityMap; //记录声卡优先级配置文件
    QMap<int, QList<QString>> cardProfileMap;
    QMap<int, QString> cardMap;
    QMap<int,QMap<QString,QString>> sinkPortMap;
    QMap<int,QMap<QString,QString>> sourcePortMap;
    QMap<int,QString> cardActiveProfileMap;

Q_SIGNALS:
    void paContextReady();
    void updateVolume(int value);
    void updateSourceVolume(int value);
    void updateMute(bool state);
    void updateSourceMute(bool state);
    void addSinkInputSignal(const gchar* name,const gchar *id,int index,int value,int channel); //添加应用信号
    void sinkInputVolumeChangedSignal(const gchar* name,const gchar *id,int value); //sink input音量改变信号
    void removeSinkInputSignal(const gchar* name);
    void addSourceOutputSignal(const gchar* name,const gchar *id,int index);
    void removeSourceOutputSignal(const gchar* name);
    void checkDeviceSelectionSianal(const pa_card_info *info);
    void updatePortSignal();
    void deviceChangedSignal();
    void removeSinkSignal();
    void device_changed_signal(QString str);

protected Q_SLOTS:
    void timeoutSlot();

public:
    void setConnectionState(gboolean connected);
    pa_stream* createMonitorStreamForSource(uint32_t source_idx, uint32_t stream_idx, bool suspend);

    void setIconFromProplist(QLabel *icon, pa_proplist *l, const char *name);

    pa_context *context;
    QByteArray defaultSinkName, defaultSourceName;
    int n_outstanding = 0;
    int reconnectTimeout = 0;
    bool canRenameDevices;
    int sinkIndex; //输出设备索引
    int sourceIndex; //输入设备索引
//    int sinkInputVolume;
    pa_mainloop_api* api;

    //针对一个应用产生多个sinkinput，indexMap记录应用产生sinkinput的每个index, valueMap刷新应用的最新音量
    QMap<int, QString> sinkInputIndexMap;
    QMap<QString, int> sinkInputValueMap;
    QMap<int, QString> sourceOutputIndexMap;
    QMap<QString, int> sourceOutputValueMap;
    QMap<QString, int> sinkInputMuteMap;
    QStringList sinkInputList;

private:

    CustomSound *customSoundFile;
    gboolean m_connected;
    gchar* m_config_filename;
    int firstgo = true;
    int firstGoWithNoSink = true;
};


#endif // UKMEDIAVOLUMECONTROL_H
