/*
 * 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>
 *
 */

#include "playlist.h"

#include <QDir>
#include <QDebug>
#include <QProcess>

#include "global/global.h"
#include "global/extensions.h"
#include "core/util.h"

using namespace Global;

PlayList::PlayList(QObject *parent) : QObject(parent)
{
    srand(time(0));
    initGlobalSig();
}

/** **********************************
 * 添加文件到播放列表
 * 说明：只有在打开新文件的时候会调用
 * @param: filePath 文件全路径
 * @param: fileName 文件名称
 * @param: duration 媒体时长
 *************************************/
void PlayList::addListFile(QString filePath, QString fileName, int duration)
{
    // 新文件更新 m_path_name_map
    QPair<QString, int> pairin(fileName, duration);
    m_path_name_map[filePath] = pairin;
    m_fileList.push_back(filePath);
    // 写入数据库
    kvsqlite->insertPlayList(filePath, fileName, duration);
    // 告诉界面添加一条
    g_user_signal->addListItem(filePath, duration);
}

/** **********************************
 * 设置播放列表
 * 说明：初始化的时候调用（数据库中读取）
 * @param: path_name_vec
 *         <绝对路径, <文件名, 文件时长>>
 *************************************/
void PlayList::setList(QVector<QPair<QString, QPair<QString, int> > > path_name_vec)
{
    qDebug() << path_name_vec.size();
    for(QPair<QString, QPair<QString, int> > p : path_name_vec)
    {
        m_path_name_map[p.first] = p.second;
        m_fileList.push_back(p.first);
        g_user_signal->addListItem(p.first, p.second.second);
    }
}

/** **********************************
 * 设置当前索引
 * 说明：初始化时设置
 * @param: index 当前索引
 *************************************/
void PlayList::setCurrentIndex(int index)
{
    m_PlayIndex = index;
    g_core_signal->setPlayIndex(index);
}

/** **********************************
 * 添加文件夹
 * @param: dir 文件夹名称
 *************************************/
void PlayList::addDirectory(QString dir)
{
    Extensions e;
    QRegExp rx_ext(e.multimedia().forRegExp());
    rx_ext.setCaseSensitivity(Qt::CaseInsensitive);

    QStringList dir_list = QDir(dir).entryList();

    QStringList args;
    QString filename;
    QStringList::Iterator it = dir_list.begin();
    QString first_add_file = "";
    while( it != dir_list.end() ) {
        args.clear();
        args << "--no-config"
             << "--no-quiet"
             << "--terminal"
             << "--frames=1"
             << "--vo=null"
             << "--ao=null"
             << "--term-playing-msg=INFO_LENGTH=${=duration:${=length}}";
        filename = dir;
        if (filename.right(1)!="/") filename += "/";
        filename += (*it);
        QFileInfo fi(filename);
        if (!fi.isDir()) {
            if (rx_ext.indexIn(fi.suffix()) > -1) {
                // 第一个添加进来的文件需要播放
                if(first_add_file == "")
                    first_add_file = filename;
                // 如果列表存在的话不重复添加
                if(m_path_name_map.find(filename) != m_path_name_map.end())
                {
                    ++it;
                    continue;
                }
                m_fileList.push_back(filename);
                // 添加文件后需要获取媒体时长
                QProcess *p = new QProcess;
                connect(p, &QProcess::readyReadStandardOutput, [&](){
                    while (true) {
                        QString line = p->readLine();
                        if(line.length() == 0)
                            break;
                        if(line.indexOf("INFO_LENGTH") != -1)
                        {
                            QString value = line.split("=").last();
                            int duration = (int)value.left(value.length()-2).toDouble();
                            QPair<QString, int> pin(p->arguments().last().split("/").last(), duration);
                            m_path_name_map[p->arguments().last()] = pin;
                            // 告诉别人添加新文件了（主要是通知列表界面）
                            g_user_signal->addListItem(p->arguments().last(), duration);
                            // 写到数据库
                            kvsqlite->insertPlayList(p->arguments().last(), p->arguments().last().split("/").last(), duration);
                        }
                    }
                });
                p->setProgram("/usr/bin/mpv");
                args << filename;
                p->setArguments(args);
                p->start();
                p->waitForFinished();
                delete p;
            }
        }
        ++it;
    }
    // 播放 first_add_file，另外需要更新当前索引
    g_user_signal->open(first_add_file);
    for(int i=0; i<m_fileList.size(); i++)
    {
        if(m_fileList.at(i) == first_add_file)
        {
            g_core_signal->setPlayIndex(i);
            m_PlayIndex = i;
            break;
        }
    }
}

/** **********************************
 * 播放下一个
 *************************************/
void PlayList::playNext()
{
    switch (m_play_order) {
    case ONE_LOOP:
        break;
    case SEQUENCE:
        // 顺序播放，只播放一遍
        if(m_PlayIndex == m_fileList.size()-1)
            // 停止播放
            return;
        m_PlayIndex += 1;
        break;
    case LIST_LOOP:
        m_PlayIndex = ++m_PlayIndex > m_fileList.size() ? 0 : m_PlayIndex;
    case RANDOM:
        m_PlayIndex = rand()%m_fileList.size();
    default:
        break;
    }
    g_core_signal->setPlayIndex(m_PlayIndex);
    g_user_signal->open(m_fileList.at(m_PlayIndex));
}

#include <syslog.h>
void PlayList::initGlobalSig()
{
    connect(g_user_signal, &GlobalUserSignal::sigPlayNext, this, &PlayList::playNext);
    connect(g_user_signal, &GlobalUserSignal::sigAddDir, this, &PlayList::addDirectory);
    connect(g_user_signal, &GlobalUserSignal::sigPlayOrder, [&](PLAYORDER order){
        m_play_order = order;
        settings->setValue("General/play_order", (int)order);
    });
    connect(g_core_signal, &GlobalCoreSignal::sigFileInfoChange, [&](Mpv::FileInfo fi){
        // 播放文件改变 如果有则切换到该行 如果没有则添加
        syslog(LOG_ERR, "====== %s\n", fi.file_path.toStdString().c_str());
        if(m_path_name_map.find(fi.file_path) == m_path_name_map.end())
            addListFile(fi.file_path, fi.file_path.split("/").last(), fi.length);
        for(int i=0; i<m_fileList.size(); i++)
            if(m_fileList.at(i) == fi.file_path)
                m_PlayIndex = i;
        g_core_signal->setPlayIndex(m_PlayIndex);
    });
}
