/*
 * Kylin-video
 *
 * Copyright (C) 2021, 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 of the License, 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 <https://www.gnu.org/licenses/>.
 *
 * Authors: Liu Cong <liucong1@kylinos.cn>
 *
 */

#ifndef MPVCORE_H
#define MPVCORE_H

#include <QObject>
#include <mpv/client.h>
#include <mpv/opengl_cb.h>
#include "qthelper.hpp"
#include <core/mpvtypes.h>
#include <mutex>
#include <libffmpegthumbnailer/videothumbnailer.h>

using namespace ffmpegthumbnailer;

#define MPV_REPLY_COMMAND 1
#define MPV_REPLY_PROPERTY 2
#define OMX_DEC_MAX_WIDTH 4096
#define OMX_DEC_MAX_HEIGHT 4096

class PlayGLWidget;
class PlayList;
class QTimer;

class MpvCore : public QObject
{
    Q_OBJECT
public:
    explicit MpvCore(PlayGLWidget *pw, QObject *parent = nullptr);
    void setProperty(const QString& name, const QVariant& value);
    QVariant getProperty(const QString& name) const;

    const Mpv::FileInfo &getFileInfo()      { return fileInfo; }
    Mpv::PlayState getPlayState()           { return playState; }
    QString getFile()                       { return file; }
    QString getPath()                       { return path; }
    QString getScreenshotFormat()           { return screenshotFormat; }
    QString getScreenshotTemplate()         { return screenshotTemplate; }
    QString getScreenshotDir()              { return screenshotDir; }
    QString getVo()                         { return vo; }
    QString getMsgLevel()                   { return msgLevel; }
    double getSpeed()                       { return speed; }
    int getVolume()                         { return volume; }
    int getVid()                            { return vid; }
    int getAid()                            { return aid; }
    int getSid()                            { return sid; }
    bool getSubtitleVisibility()            { return subtitleVisibility; }
    bool getMute()                          { return mute; }

    int getOsdWidth()                       { return osdWidth; }
    int getOsdHeight()                      { return osdHeight; }

    int getRotate()                         { return rotate; }

    QString getMediaInfo();

public slots:
    void LoadTracks();
    void LoadChapters();
    void LoadVideoParams();
    void LoadAudioParams();
    void LoadMetadata();
    void LoadOsdSize();

    void Open(QString file, int start = 0);
    void Play();
    void Pause();
    void Stop();
    void Restart();
    void Volume(int/*, bool osd = false*/);
    void Channel(Mpv::Channel c);
    void Speed(double);
    void SpeedUp();
    void SpeedDown();
    void Mute(bool);
    void Seek(int pos, bool relative = false, bool osd = false);
    void BrightnessUp();
    void BrightnessDown();
    void SubId(int id);
    void AudioId(int id);
    void AudioNext();
    void NextFrame();
    void PrevFrame();
    void Aspect(Mpv::VideoAspect);
    void SetAspect(QString scale);
    void RestoreFrame();
    void ClockwiseRotate();
    void CounterClockwiseRotate();
    void FlipHorizontally();
    void FlipVertically();
    void AddSub(QString file);
    void AddSubs(QStringList files);
    void SubMoveUp();
    void SubMoveDown();
    void SubNext();
    void SubForward();
    void SubBackward();
    void SubFontSize(int size);
    void SubFontFamily(QString family);
    void AddBookMark(QString desc);
    void ScreenShot(bool with_sub);
    void ScreenshotFormat(QString s);
    void ScreenshotDirectory(QString d);
    void ShowInfo(bool is_show);
    void ShowText(QString text, int duration = 3000);
    void VideoDecoder(QString _decoder);
    void VideoOutput(QString output);
    void DecodeThreads(int threads);

private slots:
    void LoadFileInfo();
    void SetProperties();

    void setPlaylist(const QStringList& l)  { emit playlistChanged(l); }
    void setFileInfo()                      { emit fileInfoChanged(fileInfo);}
    void setFile(QString s)                 { emit fileChanged(file = s); }
    void setPath(QString s)                 { emit pathChanged(path = s); }
    void setScreenshotTemplate(QString s)   { emit screenshotTemplateChanged(screenshotTemplate = s); }
    void setVo(QString s)                   { emit voChanged(vo = s); }
    void setMsgLevel(QString s)             { emit msgLevelChanged(msgLevel = s); }
    void setVid(int i)                      { emit vidChanged(vid = i); }
    void setAid(int i)                      { emit aidChanged(aid = i); currentAid = aid;}
    void setSid(int i)                      { emit sidChanged(sid = i); }
    void setSubtitleVisibility(bool b)      { emit subtitleVisibilityChanged(subtitleVisibility = b); }


signals:
    void durationChanged(int);
    void positionChanged(int);
    void playlistChanged(const QStringList&);
    void fileInfoChanged(const Mpv::FileInfo&);
    void trackListChanged(const QList<Mpv::Track>&);
    void chaptersChanged(const QList<Mpv::Chapter>&);
    void videoParamsChanged(const Mpv::VideoParams&);
    void audioParamsChanged(const Mpv::AudioParams&);
    void fileChanging(int, int);
    void fileChanged(QString);
    void pathChanged(QString);
    void screenshotTemplateChanged(QString);
    void voChanged(QString);
    void msgLevelChanged(QString);
    void vidChanged(int);
    void aidChanged(int);
    void sidChanged(int);
    void debugChanged(bool);
    void subtitleVisibilityChanged(bool);
    void sigShowText(QString);

private:
    std::mutex              m_mtxFileInfo,
                            m_mtxTracks;
    mpv::qt::Handle         mpv_h;
    PlayGLWidget            *m_playWidget;
    mpv_opengl_cb_context   *mpv_gl;
    QTimer                  *showInfoTimer;

    VideoThumbnailer *m_videoTbr;
    QString         m_playingFile;
    Mpv::PlayState  playState = Mpv::Idle;
    Mpv::FileInfo   fileInfo;
    QString     file,
                path,
                screenshotFormat,
                screenshotTemplate,
                screenshotDir,
                suffix,
                vo,
                msgLevel,
                mediaInfo;
    double      subDelay = 0,
                lastTime = 0,
                duration = -1,
                speed = 1,
                avsync = 0,
                fps = 0;
    int         brightness = 0,
                seekTime = 0,
                volume = 100,
                index = 0,
                vid = -1,
                aid = -1,
                sid = -1,
                currentAid = -1,
                currentSid = -1,
                subCount,
                subPos,
                rotate = 0,
                videoBitrate = 0,
                audioBitrate = 0,
                vtracks = 0,
                atracks = 0,
                stracks = 0,
                lastStopTime = 0;
    bool        isVideo = false,
                needSeek = false,
                init = false,
                playlistVisible = false,
                subtitleVisibility = true,
                mute = false,
                showProfile = false,
                isLoaded = false,
                isHFlip = false,            // 是否水平翻转
                isVFlip = false,            // 是否竖直翻转
                isManualStop = false,       // 是否手动停止，如果是的话不要播放下一个
                canSaveScreenShot = true;   // 截图路径是否有权限保存截图
    int         osdWidth,
                osdHeight;

    int m_current_time;
    QVector<QString> m_subs;

    QVariant Command(const QVariant& params);
    void LoadOptions();
    void SetOption(QString key, QString val);
    int AsyncCommand(const char *args[]);
    void initMpvHandle();
    void initGlobalSig();

private slots:

protected:
    bool event(QEvent *event);
};

#endif // MPVCORE_H
