/*
 * Copyright (C) 2002  KylinSoft 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include "systemdbusregister.h"
#include <polkitqt1-authority.h>
#include <QDBusConnection>
#include <QDBusError>
#include <QDBusMessage>
#include <QDebug>
#include <QThread>

using namespace PolkitQt1;

SystemDbusRegister::SystemDbusRegister()
{

}

//excute dd command
void SystemDbusRegister::MakeStart(QString sourcePath,QString targetPath){
    //root authorization
    sourceFile = sourcePath;
    Authority::Result result;
    SystemBusNameSubject subject(message().service());
    result = Authority::instance()->checkAuthorizationSync("com.kylinusbcreator.systemdbus.authoritycheck",
             subject , Authority::AllowUserInteraction);
    if (result == Authority::Yes){
        //TODO: send authorization failed dbus message
        emit authorityStatus("success");
    }else{
        //there's two cases NO and Challenge
        emit authorityStatus("failed");
        return ;
    }
    uDiskPath = targetPath;
QFileInfo info(sourcePath);
sourceFileSize = info.size()/1000000;
command_dd = new QProcess();
//指定输出语言
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("LANGUAGE","en_US:en");
command_dd->setProcessEnvironment(env);
//command_dd->setProcessChannelMode(QProcess::MergedChannels);
connect(command_dd,&QProcess::readyReadStandardOutput,this,&SystemDbusRegister::readBashStandardErrorInfo);
connect(command_dd,&QProcess::readyReadStandardError,this,&SystemDbusRegister::readBashStandardErrorInfo);
connect(command_dd,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(dd_finished(int,QProcess::ExitStatus)));
QTimer::singleShot(1*1000, this, &SystemDbusRegister::handletimeout);
  //  QThread::create([=](){
        qDebug("输出线程");
        if(!unmountDevice(targetPath)){
     //       TODO:Deal sbus message unmount_error
            QProcess *format=new QProcess;
//           format->start("bash");
            QStringList args512;
            args512<<"if=/dev/zero"<<"of="+targetPath.toLocal8Bit()<<"bs=512"<<"count=1";
            format->start("dd", args512);
            connect(format,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(clear_finished(int,QProcess::ExitStatus)));
            format->waitForStarted();
            if(format->waitForStarted()){
                qDebug()<<"58ag0"<<format->arguments();
            }

           // format->waitForFinished();
            emit makeFinish("unmount_error");
        }

        if(!unmountDevice(targetPath + "1")){
//      //      TODO:Deal sbus message unmount_error
            QProcess *format=new QProcess;
           QStringList args512;
            args512<<"if=/dev/zero"<<"of="+targetPath.toLocal8Bit()<<"bs=512"<<"count=1";
            format->start("dd", args512);
            connect(format,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(clear_finished(int,QProcess::ExitStatus)));
            format->waitForStarted();
            if(format->waitForStarted()){
                qDebug()<<"70ag0"<<format->arguments();
            }
            //format->waitForFinished();
            emit makeFinish("unmount_error");
        }
//        uDiskPath = targetPath;
//    QFileInfo info(sourcePath);
//    sourceFileSize = info.size()/1000000;
//    this->command_dd = new QProcess();
//    //指定输出语言
//    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
//    env.insert("LANGUAGE","en_US:en");
//    this->command_dd->setProcessEnvironment(env);
//    //command_dd->setProcessChannelMode(QProcess::MergedChannels);
//    connect(this->command_dd,&QProcess::readyReadStandardOutput,this,&SystemDbusRegister::readBashStandardErrorInfo);
//    connect(this->command_dd,&QProcess::readyReadStandardError,this,&SystemDbusRegister::readBashStandardErrorInfo);
//    connect(this->command_dd,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(dd_finished(int,QProcess::ExitStatus)));
//    QTimer::singleShot(1*1000, this, &SystemDbusRegister::handletimeout);
    //command_dd->start("bash");
  //  command_dd->start("bash");
//    QStringList args;
//    args<<"if="+sourcePath.toLocal8Bit()<<"of="+targetPath.toLocal8Bit()<<"status=progress"<<"bs=32M";
//    command_dd->start("dd", args);
//    command_dd->waitForStarted();
//    if(command_dd->waitForStarted()){
//        qDebug()<<"97command_dd->arguments()"<<this->command_dd->arguments();
//    }
//  //  QString ddshell = "dd if='"+sourcePath.toLocal8Bit()+"' of="+targetPath.toLocal8Bit()+" status=progress"+" bs=32M";
// //   command_dd->write(ddshell.toLocal8Bit() + '\n');
//    qDebug()<<"shuchu91"<<this->command_dd->arguments();
    //return ;
 //   })->start();
//    QStringList args;
//    args<<"if="+sourcePath.toLocal8Bit()<<"of="+targetPath.toLocal8Bit()<<"status=progress"<<"bs=32M";
//    command_dd->start("dd", args);
//    command_dd->waitForStarted();
//    if(command_dd->waitForStarted()){
//        qDebug()<<"97command_dd->arguments()"<<command_dd->arguments();
//    }
//  //  QString ddshell = "dd if='"+sourcePath.toLocal8Bit()+"' of="+targetPath.toLocal8Bit()+" status=progress"+" bs=32M";
// //   command_dd->write(ddshell.toLocal8Bit() + '\n');
//    qDebug()<<"shuchu91"<<command_dd->arguments();
//        if(!unmountDevice(targetPath)){
//     //       TODO:Deal sbus message unmount_error
//            QProcess *format=new QProcess;
//            format->start("bash");
//            QString fileformat="mkfs -t ext4 "+targetPath;
//            format->write(fileformat.toLocal8Bit()+'\n');
//            format->waitForFinished();
//            emit makeFinish("unmount_error");
//        }

//        if(!unmountDevice(targetPath + "1")){
//      //      TODO:Deal sbus message unmount_error
//            QProcess *format=new QProcess;
//            format->start("bash");
//            QString fileformat="mkfs -t ext4 "+targetPath+"1";
//            format->write(fileformat.toLocal8Bit()+'\n');
//            format->waitForFinished();
//            emit makeFinish("unmount_error");
//        }
//        uDiskPath = targetPath;

//   // udiskmountpoint();
////    QProcess *format=new QProcess;
////    format->start("bash");
////    QString fileformat="mkfs -t ext4 "+targetPath;
////    format->write(fileformat.toLocal8Bit()+'\n');
////    format->waitForFinished();
////    QProcess *clearor=new QProcess;
////    connect(clearor,SIGNAL(finished(int)),this,SLOT(clear_finished(int)));
////    QStringList args512;
//  //  args512<<"if=/dev/zero"<<"of="+targetPath.toLocal8Bit()<<"status=progress"<<"bs=512"<<"count=1";
//  //  clearor->start("dd", args512);
////    clearor->start("bash");
////    clearor->start("bash");
////    clearor->waitForStarted();
////    QString source="/dev/zero";
////    QString ddshell1 ="dd if='"+source.toLocal8Bit()+"' of="+targetPath.toLocal8Bit()+" status=progress"+" bs=512"+" count=1";
////    clearor->write(ddshell1.toLocal8Bit() + '\n');
//  //  connect(clearor,&QProcess::finished,this,&SystemDbusRegister::clear_finished);
//   // clearor->waitForFinished();
//    QFileInfo info(sourcePath);
//    sourceFileSize = info.size()/1000000;
//    command_dd = new QProcess();
//    //指定输出语言
//    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
//    env.insert("LANGUAGE","en_US:en");
//    command_dd->setProcessEnvironment(env);
//    connect(command_dd,&QProcess::readyReadStandardError,this,&SystemDbusRegister::readBashStandardErrorInfo);
//    connect(command_dd,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(dd_finished(int,QProcess::ExitStatus)));
//    QTimer::singleShot(1*1000, this, &SystemDbusRegister::handletimeout);
//    command_dd->start("bash");
//    command_dd->start("bash");
//    command_dd->waitForStarted();
//    QString ddshell = "dd if='"+sourcePath.toLocal8Bit()+"' of="+targetPath.toLocal8Bit()+" status=progress"+" bs=32M";
//    command_dd->write(ddshell.toLocal8Bit() + '\n');
//    qDebug()<<"shuchu91"<<command_dd->arguments();
  //  return ;
}
void SystemDbusRegister::clear_finished(int exitCode,QProcess::ExitStatus exitStatus){
    qDebug()<<"85exitCode"<<exitCode;
    qDebug("清空输出");
    if(exitStatus==QProcess::NormalExit){
    QStringList args;
    args<<"if="+sourceFile.toLocal8Bit()<<"of="+uDiskPath.toLocal8Bit()<<"status=progress"<<"bs=32M";
    command_dd->start("dd", args);
    command_dd->waitForStarted();
    if(command_dd->waitForStarted()){
        qDebug()<<"97command_dd->arguments()"<<command_dd->arguments();
    }
  //  QString ddshell = "dd if='"+sourcePath.toLocal8Bit()+"' of="+targetPath.toLocal8Bit()+" status=progress"+" bs=32M";
 //   command_dd->write(ddshell.toLocal8Bit() + '\n');
    qDebug()<<"shuchu91"<<command_dd->arguments();
    }
//    command_dd->start("bash");
//    command_dd->start("bash");
//    command_dd->waitForStarted();
//    QString ddshell = "dd if='"+sourceFile.toLocal8Bit()+"' of="+uDiskPath.toLocal8Bit()+" status=progress"+" bs=32M";
//    command_dd->write(ddshell.toLocal8Bit() + '\n');
}
void SystemDbusRegister::dd_finished(int exitCode, QProcess::ExitStatus exitStatus){
    if(exitStatus!=QProcess::NormalExit){
        qDebug("make_error");
        emit makeFinish("make_error");
    }
}
void SystemDbusRegister::handletimeout(){
    QFile file(sourceFile);
    if (file.exists()) {
        QTimer::singleShot(1*1000, this, &SystemDbusRegister::handletimeout);
    } else {
        command_dd->kill();
    }
}
//bool SystemDbusRegister::mountDevice(QString target){
//    QProcess mount;
//    qInfo()<<"start mounting disk:"<<target+"1";
//    mount.start("udisksctl",QStringList{"mount","-b",target+"1"});
//    if(!mount.waitForStarted()){
//        qWarning()<<"count process start failed";
//        return false;
//    }
//    if(!mount.waitForFinished()){
//        qWarning()<<"装载失败";
//        return false;
//    }
//    if(QProcess::NormalExit == mount.exitCode()){
//        qInfo()<<"Mount success!";
//        return true;
//    }
//    qWarning()<<"An unknown error occurred! Mount process exit code:"<<mount.exitCode();
//    return false;
//}

bool SystemDbusRegister::unmountDevice(QString target)
{
    QProcess unmount;
    unmount.start("udisksctl",QStringList{"unmount","-b",target});
    qDebug()<<"Start unmount disk:"<<target;
    if(!unmount.waitForStarted()){
        qWarning()<<"unmount process start failed.device path:"<<target;
        return false;
    }
    if(!unmount.waitForFinished()){
        qWarning()<<"unmount process finish failed,device path:"<<target;
        return false;
    }
    if(QProcess::NormalExit == unmount.exitCode()){
        qDebug()<<"unmount device success.device path:"<<target;
        return true;
    }else{
        QString output = unmount.readAll();
        qDebug()<<__func__<<__LINE__<<output;

    }
    qWarning()<<"An unknown error occurred! unmount process exit code:"<<unmount.exitCode();
    return false;
}
void SystemDbusRegister::udiskmountpoint(){
        QProcess lsblk;
        lsblk.start("lsblk -J");
        lsblk.waitForFinished();

        QProcess lsblk2;
        lsblk2.start("lsblk -JS");
        lsblk2.waitForFinished();
        QJsonArray arr1 = QStringToJsonArray(QString::fromLocal8Bit(lsblk.readAllStandardOutput()));  //获取json类型的shell执行结果
        QJsonArray arr2 = QStringToJsonArray(QString::fromLocal8Bit(lsblk2.readAllStandardOutput()));
        foreach (const QJsonValue& value, arr1) {
            QJsonObject jsonObj1 = value.toObject();
            foreach (const QJsonValue& value, arr2) {
                QJsonObject jsonObj2 = value.toObject();
                if(jsonObj1["name"] == jsonObj2["name"] && jsonObj2["tran"] == "usb" && jsonObj2["type"] == "disk"){
                    QString usbmountpoint=jsonObj1["mountpoint"].toString();
                    qDebug()<<"usbmountpoint"<<usbmountpoint;
                    if(!usbmountpoint.isEmpty()){
                        unmountDevice(uDiskPath);
                        unmountDevice(uDiskPath+"1");
                    }/*else{
                        QJsonArray arr3 = QStringToJsonArray(QString::fromLocal8Bit(lsblk.readAllStandardOutput()));  //获取json类型的shell执行结果
                        foreach (const QJsonValue& value, arr3) {
                            QJsonObject jsonObj3 = value.toObject();
                             QString name=jsonObj3["name"].toString();
                            {
                                foreach (const QJsonValue& value, arr2){
                                    QJsonObject jsonObj2 = value.toObject();
                                    QString name1=jsonObj2["name"].toString()+"1";
                                    if(name==name1){
                                        QString usbmountpoint1=jsonObj3["mountpoint"].toString();
                                        qDebug()<<"usbmountpoint"<<usbmountpoint1;
                                        if(!usbmountpoint1.isEmpty()){
                                            QString udiskpath1=uDiskPath+"1";
                                            unmountDevice(udiskpath1);
                                    }
                                }
                            }
                        }
                    }
                }*/
            }
        }
        }
}
//kill task process
void SystemDbusRegister::MakeExit(){
    qDebug()<<"exit dd process";
    if(!command_dd) return ;
    if(command_dd->Running){
        command_dd->kill();
    }
    return ;
}
void SystemDbusRegister::readBashStandardErrorInfo()
{
    qDebug()<<__func__<<__LINE__;
    QByteArray cmdout = command_dd->readAllStandardError();
    cmdout.trimmed();
    if(!cmdout.isEmpty() && cmdout != "\r" && cmdout != "\n"){
        QString str = cmdout;
        qDebug()<<str;
        str = str.replace(" ","");
//        if(str =="" || str.contains("[sudo]")) {return;}
        str = str.replace("\r","");
        QStringList bytes2 = str.split("bytes");
         QString size_progress = bytes2.first();
         bool ok = false;
         qulonglong progress_num = size_progress.toDouble(&ok)/1048576;
         int mission_percent = progress_num*100/sourceFileSize;
         //emit workingProgress(mission_percent);
         qDebug()<<"mission_percent"<<mission_percent;
         if(bytes2.count() == 1 || !ok){       
              finishEvent();
         }
        if(!mission_percent){
            return ;
        }
        QString ii=QString::number(mission_percent);
        if(ii.isEmpty()){
            return;
        }
         //send mission percent debus message every output
        qDebug()<<__func__<<__LINE__<<mission_percent;
         emit workingProgress(mission_percent);
       // emit errorstr(str);
    }else{
        return;
    }
}

void SystemDbusRegister::finishEvent(){
    QTimer *diskRefreshDelay = new QTimer;
    connect(diskRefreshDelay,&QTimer::timeout,[=]{
        diskRefreshDelay->stop();
        if(isMakingSucess()){
            //send production success dbus message
            qInfo()<<"make success";
            QProcess sync;
            sync.start("sync");
            sync.waitForStarted();
            sync.waitForFinished();
            emit makeFinish("success");
            //mountDevice(uDiskPath);
        //    mountDevice(uDiskPath+"1");
            qDebug()<<"uDiskPath"<<uDiskPath;
        }else{
            //send production failure dbus message
            qDebug()<<"make failed";
            emit makeFinish("fail");
        }
    });
    diskRefreshDelay->start(2000);
}

bool SystemDbusRegister::mountDevice(QString target){

//    QProcess sync;
//    sync.start("sync");
//    sync.waitForStarted();
//    sync.waitForFinished();

    QProcess mount;
    qInfo()<<"start mounting disk:"<<target;
    mount.start("udisksctl",QStringList{"mount","-b",target});
    if(!mount.waitForStarted()){
        qWarning()<<"count process start failed";
        return false;
    }
    if(!mount.waitForFinished()){
        qWarning()<<"装载失败";
        return false;
    }
    if(QProcess::NormalExit == mount.exitCode()){
        qInfo()<<"Mount success!";
        return true;
    }
    qWarning()<<"An unknown error occurred! Mount process exit code:"<<mount.exitCode();
    return false;
}
bool SystemDbusRegister::isMakingSucess()
{
    QProcess lsblk;
    lsblk.start("lsblk -JS");
//    lsblk.waitForStarted();
    lsblk.waitForFinished();
//    qDebug()<<"lsblk output"<<lsblk.readAllStandardError();
    QJsonArray output = QStringToJsonArray(QString::fromLocal8Bit(lsblk.readAllStandardOutput()));
    foreach (const QJsonValue& value, output) {
        QString diskpath = value.toObject()["name"].toString();
        if("/dev/"+diskpath == uDiskPath) return true;
    }
//    for(QStorageInfo& disk : diskList)
//    {
//        QString diskPath = disk.device();
//        diskPath = diskPath.mid(0,8);
//        if(uDiskPath == diskPath)
//        {
//            return true;
//        }
//    }
    return false;
}
QJsonArray SystemDbusRegister::QStringToJsonArray(const QString jsonString){
    QJsonParseError err;
    QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonString.toLocal8Bit().data(),&err);
    if(jsonDocument.isNull())
    {
        qDebug()<< "JsonDocument is NULL.Origin data is:"<< jsonString.toLocal8Bit().data();
    }
    if(err.error != QJsonParseError::NoError){
        qDebug()<<"Parase json"<<jsonString<<" error:"<<err.error;
        //TODO：这里的错误处理后期还可以优化,目前处理错误了就会调用exit()退出程序
//        exit(-1);
    }
    QJsonObject obj = jsonDocument.object();
    return obj["blockdevices"].toArray();
}
QJsonArray SystemDbusRegister::QStringToJsonArray1(const QString jsonString){
    QJsonParseError err;
    QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonString.toLocal8Bit().data(),&err);
    if(jsonDocument.isNull())
    {
        qDebug()<< "JsonDocument is NULL.Origin data is:"<< jsonString.toLocal8Bit().data();
    }
    if(err.error != QJsonParseError::NoError){
        qDebug()<<"Parase json"<<jsonString<<" error:"<<err.error;
        //TODO：这里的错误处理后期还可以优化,目前处理错误了就会调用exit()退出程序
//        exit(-1);
    }
    QJsonObject obj = jsonDocument.object();
    return obj["children"].toArray();
}
