/*
 * Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co., Ltd.
 *
 * Author:     ZhangYong <zhangyong@uniontech.com>
 *
 * Maintainer: ZhangYong <ZhangYong@uniontech.com>
 *
 * 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 of the License, or
 * 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/>.
 */
#ifndef DBMANAGER_H
#define DBMANAGER_H

// ImageTable
///////////////////////////////////////////////////////
//FilePath           | FileName | Dir        | Time | ChangeTime //
//TEXT primari key   | TEXT     | TEXT       | TEXT | TEXT //
///////////////////////////////////////////////////////

// AlbumTable
/////////////////////////////////////////////////////
//AP               | AlbumName         | FilePath  //
//TEXT primari key | TEXT              | TEXT      //
/////////////////////////////////////////////////////

#include <QObject>
#include <QDateTime>
#include <QMutex>
#include <QDebug>
#include <QSqlDatabase>
//#include "connectionpool.h"

const QString DATETIME_FORMAT_DATABASE = "yyyy.MM.dd hh:mm";

struct DBAlbumInfo {
    QString name;
//    int count;
    QDateTime beginTime;
    QDateTime endTime;
};

struct DBImgInfo {
    QString filePath;
    QString fileName;
    QString dirHash;
    QDateTime time;     // 图片创建时间
    QDateTime changeTime;   // 文件修改时间
    QDateTime importTime;   // 导入时间 Or 删除时间
    QString albumname;      // 图片所属相册名，以","分隔
    QString albumSize;      //原图片分辨率

    bool operator==(const DBImgInfo &other) const
    {
        return (filePath == other.filePath &&
                fileName == other.fileName &&
                dirHash == other.dirHash &&
                time == other.time &&
                changeTime == other.changeTime &&
                importTime == other.importTime &&
                albumname == other.albumname &&
                albumSize == other.albumSize);
    }

    friend QDebug operator<<(QDebug &dbg, const DBImgInfo &info)
    {
        dbg << "(DBImgInfo)["
            << "Path:" << info.filePath
            << "Name:" << info.fileName
            << "Dir:" << info.dirHash
            << "Time:" << info.time
            << "ChangeTime:" << info.changeTime
            << "ImportTime:" << info.importTime
            << "AlbumName:" << info.albumname
            << "AlbumSize:" << info.albumSize
            << "]";
        return dbg;
    }
};
typedef QList<DBImgInfo> DBImgInfoList;

enum AlbumDBType {
    Favourite,
    Custom
};

class QSqlDatabase;

class DBManager : public QObject
{
    Q_OBJECT
public:
    static DBManager  *instance();
    explicit DBManager(QObject *parent = nullptr);
    ~DBManager()
    {
//        ConnectionPool::release(); //释放数据库连接
    }

    // TableImage
    const QStringList       getAllPaths() const;
    const DBImgInfoList     getAllInfos(int loadCount = 0) const;
    const QStringList       getAllTimelines() const;
    const DBImgInfoList     getInfosByTimeline(const QString &timeline) const;
    const QStringList       getImportTimelines() const;
    const DBImgInfoList     getInfosByImportTimeline(const QString &timeline) const;
//    const DBImgInfo         getInfoByName(const QString &name) const;
    const DBImgInfo         getInfoByPath(const QString &path) const;
//    const DBImgInfo         getInfoByPathHash(const QString &pathHash) const;
    int                     getImgsCount() const;
//    bool                    isImgExist(const QString &path) const;
    void                    insertImgInfos(const DBImgInfoList &infos);
    void                    insertImgInfo(const DBImgInfo &info);
    void                    removeImgInfos(const QStringList &paths);
    void                    removeImgInfosNoSignal(const QStringList &paths);
    const DBImgInfoList     getInfosForKeyword(const QString &keywords) const;
    const DBImgInfoList     getTrashInfosForKeyword(const QString &keywords) const;
    const DBImgInfoList     getInfosForKeyword(const QString &album, const QString &keywords) const;

    // TableAlbum
    const QMultiMap<QString, QString> getAllPathAlbumNames() const;
    const QStringList       getAllAlbumNames(AlbumDBType atype = AlbumDBType::Custom) const;
    const QStringList       getPathsByAlbum(const QString &album, AlbumDBType atype = AlbumDBType::Custom) const;
    const DBImgInfoList     getInfosByAlbum(const QString &album, AlbumDBType atype = AlbumDBType::Custom) const;
    int                     getImgsCountByAlbum(const QString &album, AlbumDBType atype = AlbumDBType::Custom) const;
//    int                     getAlbumsCount() const;
    bool                    isAlbumExistInDB(const QString &album, AlbumDBType atype = AlbumDBType::Custom) const;
    bool                    isImgExistInAlbum(const QString &album, const QString &path, AlbumDBType atype = AlbumDBType::Custom) const;
    void                    insertIntoAlbum(const QString &album, const QStringList &paths, AlbumDBType atype = AlbumDBType::Custom);
    void                    removeAlbum(const QString &album, AlbumDBType atype = AlbumDBType::Custom);
    void                    removeFromAlbum(const QString &album, const QStringList &paths, AlbumDBType atype = AlbumDBType::Custom);
    void                    renameAlbum(const QString &oldAlbum, const QString &newAlbum, AlbumDBType atype = AlbumDBType::Custom);
//    void                    removeFromAlbumNoSignal(const QString &album, const QStringList &paths, AlbumDBType atype = AlbumDBType::Custom);
    void                    insertIntoAlbumNoSignal(const QString &album, const QStringList &paths, AlbumDBType atype = AlbumDBType::Custom);
    // TabelTrash
    const QStringList       getAllTrashPaths() const;
    const DBImgInfoList     getAllTrashInfos() const;
    void                    insertTrashImgInfos(const DBImgInfoList &infos);
    void                    removeTrashImgInfos(const QStringList &paths);
    void                    removeTrashImgInfosNoSignal(const QStringList &paths);
    const DBImgInfo         getTrashInfoByPath(const QString &path) const;
    const DBImgInfoList     getTrashImgInfos(const QString &key, const QString &value) const;
    int                     getTrashImgsCount() const;
    const QSqlDatabase      getDatabase() const;
private:
    const DBImgInfoList     getInfosByNameTimeline(const QString &value) const;
    const DBImgInfoList     getImgInfos(const QString &key, const QString &value, const bool &needlock = true) const;


    void                    checkDatabase();
    static DBManager       *m_dbManager;
private:
    //QString m_connectionName;
    mutable QMutex m_mutex;

//    mutable QMutex m_mutex1;
    mutable QSqlDatabase m_db;
};

#endif // DBMANAGER_H
