#ifndef QLTRSRVCONNECTION_H
#define QLTRSRVCONNECTION_H

#include <QObject>
#include <QThread>
#include <QHostAddress>
#include <QMutex>
#include <QMutexLocker>
#include <QSharedPointer>
#include <QDateTime>

#include "LtrCrateInfo.h"
#include "ltr/include/ltrlogapi.h"

#ifdef Q_OS_WIN
    #define QSTRING_FROM_CSTR(str) QString::fromLocal8Bit(str)
#else
    #define QSTRING_FROM_CSTR(str) QString(str)
#endif

typedef enum {
    LTR_CONEVENT_ADD,
    LTR_CONEVENT_DATA_CHANGED,
    LTR_CONEVENT_REMOVE
} LtrConEvent;

class LtrSrvLogRec {
public:
    LtrSrvLogRec(const TLTRLOG_MSG *msg);

    QString text() const {return m_text;}
    en_LTR_LogLevel level() const {return m_lvl;}
    int errCode() const {return m_err;}
    QDateTime time() const {return m_time;}
private:
    QString m_text;
    en_LTR_LogLevel m_lvl;
    QDateTime m_time;
    int m_err;
};


/** Класс для работы с подключением к демону ltrd
    В одтельном потоке класс устанавливает соединение, а затем производит
    периодический опрос демона на состав крейтов и записей IP-адресов и
    с помощью сигналов оповещает о изменении этих параметров.
    Так же имеются слоты для манипулирования адресами (должны вызываться через
    соединения с сигналами, чтобы сама обработка была в другом потоке) */
class LtrdConnection : public QObject {
    Q_OBJECT
public:
    /** Статус соединения с демоном*/
    typedef enum {
        STATUS_OFFLINE,
        STATUS_CONNECTING,
        STATUS_ONLINE,
        STATUS_ERROR
    } connStatus;


    explicit LtrdConnection(QHostAddress addr = QHostAddress(QHostAddress::LocalHost),
                               bool autocon = true, quint16 port = LTRD_PORT_DEFAULT, QObject *parent = 0);
    ~LtrdConnection();

    QHostAddress addr() const {return m_addr;}
    quint16 port() const {return hnd.sport;}
    connStatus status() const {return m_status;}


    int cratesCount(void);
    LtrCrateInfo* crateInfo(int i);
    /* получить список записей с IP-адресами крейтов */
    QList<TLTR_CRATE_IP_ENTRY> ipEntryList();
    /* строка с версией ltrd */
    QString versionString() const {return  m_vers ? QString::number((m_vers >> 24) & 0xFF) + "." +
                                        QString::number((m_vers >> 16) & 0xFF) + "." +
                                        QString::number((m_vers >> 8) & 0xFF) + "." +
                                        QString::number(m_vers & 0xFF) : QString();}
    quint32 version() const {return m_vers;}




    bool autoconnect() const {return m_autocon;}
    void setAutoconnect(bool autocon) {m_autocon = autocon;}
    bool statisticAviableForMid(WORD mid) const;

    bool supportLog() const                     {return m_vers >= 0x02010000;}
    bool supportModuleNames() const             {return m_vers >= 0x02010300;}
    bool supportReconnection() const            {return m_vers >= 0x02010500;}
    bool supportModuleBufCfg() const            {return m_vers >= 0x02010600;}
    bool supportTCPNoDelayCfg() const           {return m_vers >= 0x02010800;}
    bool supportIndentifyModuleStat() const     {return m_vers >= 0x02010807;}


    int getLogLevel(unsigned *lvl);
    int setLogLevel(unsigned lvl);
    int getUintParam(int param, unsigned *val);
    int setUintParam(int param, unsigned val);

    /* сброс модуля в указанном слоте указанного крейта */
    int moduleReset(LtrCrateInfo* info, int slot);


    QList<QSharedPointer<LtrSrvLogRec> > logRecords() const {return m_logrecs;}
    void logLock();
    void logUnlock();

    static QString getErrorString(INT err);
    QList<TLTR_CRATE_IP_ENTRY> ipList() const {return m_ipList;}

Q_SIGNALS:
    void statusChanged(LtrdConnection::connStatus stat);
    void crateChanged(LtrCrateInfo* crate, LtrConEvent event);
    void ipAddrStatusChanged(TLTR_CRATE_IP_ENTRY ip, LtrConEvent event, int pos);
    void aboutToClose();
    void aboutToStart();
    void newLogRecords(QList<QSharedPointer<LtrSrvLogRec> > recs);
    void oldLogRecordsRemove(QList<QSharedPointer<LtrSrvLogRec> > recs);
public Q_SLOTS:
    void start();
    void remove();
    void wait();

    int ipEntryAdd(qint32 addr, qint32 flags, bool perm);
    int ipEntryRem(qint32 addr, bool perm);
    int ipEntryFlagsChange(qint32 addr,  qint32 flags, bool perm);
    int ipConnect(qint32 addr);
    int ipDisconnect(qint32 addr);
    int ipConnectAuto(void);
    int ipDisconnectAll(void);
    void closeConnection(void);
    void clearLog(void);

private Q_SLOTS:
    void privCloseConnection();
    void privStartConnection(bool restart=false);
    void restartConnection();
    void scheduleRestart();
protected:
    void timerEvent(QTimerEvent *event);
private:
    static const int restart_tout_init = 500;
    static const int restart_tout_max = 5000;
    static const int log_shutdown_tout = 2000;
    static const int log_max_recs = 10000;

    void clearConnection(void);
    void stopOnError();
    void checkCrates(void);
    int readLog(void);
    int findCrate(QString serial, int intf = LTR_CRATE_IFACE_UNKNOWN);
    int processCrate(char* serial, int intf = LTR_CRATE_IFACE_UNKNOWN);


    TLTR hnd;
    TLTRLOG m_loghnd;
    connStatus m_status;
    INT err;
    QList<LtrCrateInfo*> m_crateList;
    QList<TLTR_CRATE_IP_ENTRY> m_ipList;
    QHostAddress m_addr, m_crateAddr, m_crateMask;
    QMutex m_mutex;
    QMutex m_logmutex;
    quint32 m_vers;
    int m_tmr_id;
    bool m_autocon;
    QList<QSharedPointer<LtrSrvLogRec> > m_logrecs;
    QThread m_thread;
    int m_cur_restart_tout;
    int m_restart_tmr_id;
};

//Q_DECLARE_METATYPE(LtrSrvConnection::connStatus);

#endif // QLTRSRVCONNECTION_H
