#include "NetDriveMgr.h"
#include <QFile>
#include "GlobalDefine.h"
#include <QDate>
#include <ZTLog.h>
#include <EngLog.h>



/// sudo mount -t cifs -o domain=TID,user=JF,password=signal77240,vers=2.1 //192.168.50.110/TestZT /home/zonetest/ZT/NetDrive
/// /proc/self/mountinfo
/// /proc/self/mounts
/// /sys/class/net/eth0
///




CNetDriveMgr::CNetDriveMgr(QObject *parent) :
    QObject(parent)
{
    mNetDriveSMState = NET_DRIVE_MOUNTING_STATE;
    mProcessTimer = new QTimer();
    mProcessTimer->setSingleShot(true);
    connect(mProcessTimer,SIGNAL(timeout()),this,SLOT(ProcessExecTimerExpired()));

    mNASMountPath = NAS_MOUNT_POINT;
    mNASMountPath.append("/");

    mTransferProcess = new QProcess(this);
    connect(mTransferProcess,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(ProcessFinished(int,QProcess::ExitStatus)));

    mIsNetDriveEnabled = false;
}

CNetDriveMgr::~CNetDriveMgr()
{
    UnMountNetworkDrive();
    delete mProcessTimer;
    delete mTransferProcess;
}

bool CNetDriveMgr::IsNetworkDriveAvailable()
{
    bool ret = false;
    QFile *SysFile = new QFile("/sys/class/net/eth0/carrier");
    if(SysFile)
    {
        SysFile->open(QIODevice::ReadOnly | QIODevice::Text | QIODevice::Unbuffered);
        QString FileData = QString(SysFile->readAll());
        SysFile->close();

        if(FileData.isEmpty() == false)
        {
            if(FileData.left(1) == "1")
            {
                ret = true;
            }
            else if(FileData.left(1) == "0")
            {
                ret = false;
            }
            else
            {
                ret = false;
                qDebug("CNetDriveMgr: Valeur inatendue dans/sys/class/net/eth0/carrier");
            }
        }
    }
    delete SysFile;
    return ret;
}

bool CNetDriveMgr::IsNetworkDriveMounted()
{
    bool ret = false;
    QFile *MountInfo = new QFile("/proc/self/mounts");
    if(MountInfo)
    {
        MountInfo->open(QIODevice::ReadOnly | QIODevice::Text | QIODevice::Unbuffered);
        QString FileData = QString(MountInfo->readAll());
        MountInfo->close();

        if(FileData.contains(NAS_MOUNT_POINT) == true)
        {
            ret = true;
        }
    }
    delete MountInfo;
    return ret;

}

int CNetDriveMgr::CopyFileToNetworkDrive(QString FilePath)
{
    if(mIsNetDriveEnabled == false)
        return RET_ERROR;

    return RET_OK;
}

int CNetDriveMgr::TransferTrainLogToNetDrive(QString NewLogFileName, bool Detection)
{
    if(mIsNetDriveEnabled == false)
        return RET_ERROR;

    if(mNetDriveSMState != NET_DRIVE_STANDBY_STATE)
    {
        return RET_ERROR;
    }

    QString DestFilePath = NewLogFileName;
    if(Detection == true)
    {
       DestFilePath.prepend(mFilesPrefix + "-D-"); //Flag indiquant que ce passage contient des détections (D)
    }
    else
    {
        DestFilePath.prepend(mFilesPrefix + "-N-"); //Flag inidiquant un passage normal (sans détection) (N)
    }


    DestFilePath.prepend(mNASMountPath);
    QString OriginFilePath = NewLogFileName;
    OriginFilePath.prepend("./Trains/");

    QString Cmd = QString ("cp -f %1 %2").arg(OriginFilePath).arg(DestFilePath);


    mTransferProcess->start(Cmd);
    mProcessTimer->start(PROCESS_TIMEOUT);  //Allow some time to copy the file
    mNetDriveSMState = NET_DRIVE_TRANSFERRING_TRAIN_LOG_STATE;


    return RET_OK;
}

int CNetDriveMgr::TransferZTLogToNetDrive()
{
    if(mIsNetDriveEnabled == false)
        return RET_ERROR;


    QString DestFileDate = QDate::currentDate().toString("yyyyMMdd");
    QString DestFilePath = QString("%1%2%3_LogZT.txt").arg(mNASMountPath).arg(mFilesPrefix).arg(DestFileDate);
    QString OriginFilePath = QString("./LOG/LogZT.txt");

    QString Cmd = QString ("cp -f %1 %2").arg(OriginFilePath).arg(DestFilePath);


    mTransferProcess->start(Cmd);
    mProcessTimer->start(PROCESS_TIMEOUT);  //Allow some time to copy the file
    mNetDriveSMState = NET_DRIVE_TRANSFERRING_ZT_LOG_STATE;
    return RET_OK;
}

int CNetDriveMgr::NetworkDriveStateMachine(int Event)
{
    switch(mNetDriveSMState)
    {
        case NET_DRIVE_STANDBY_STATE:
        {
            break;
        }
        case NET_DRIVE_TRANSFERRING_TRAIN_LOG_STATE:
        {
            switch(Event)
            {
                case NET_DRIVE_SM_PROCESS_TIMER_EXPIRED_EVENT:
                {
                    //The network drive is stale or disconnected
                    mTransferProcess->kill();
                    mNetDriveSMState = NET_DRIVE_STANDBY_STATE;
                    qDebug("Failed to transfer train log file to NAS");
                    break;
                }
                case NET_DRIVE_SM_PROCESS_FINISHED_EVENT:
                {
                    mProcessTimer->stop();
                    TransferZTLogToNetDrive();
                    mNetDriveSMState = NET_DRIVE_TRANSFERRING_ZT_LOG_STATE;
                    qDebug("NAS transfer result: %s @ %s",qPrintable(mTransferProcess->readAllStandardOutput()),qPrintable(mTransferProcess->readAllStandardError()));
                    break;
                }
            }

            break;
        }
        case NET_DRIVE_TRANSFERRING_ZT_LOG_STATE:
        {
            switch(Event)
            {
                case NET_DRIVE_SM_PROCESS_TIMER_EXPIRED_EVENT:
                {
                    //The network drive is stale or disconnected
                    mTransferProcess->kill();
                    mNetDriveSMState = NET_DRIVE_STANDBY_STATE;
                    qDebug("Failed to transfer ZT log file to NAS");
                    break;
                }
                case NET_DRIVE_SM_PROCESS_FINISHED_EVENT:
                {
                    mNetDriveSMState = NET_DRIVE_STANDBY_STATE;
                    qDebug("NAS transfer result: %s @ %s",qPrintable(mTransferProcess->readAllStandardOutput()),qPrintable(mTransferProcess->readAllStandardError()));
                    mProcessTimer->stop();
                    break;
                }
            }
            break;
        }
        case NET_DRIVE_TRASFERRING_MISC_FILE_STATE:
        {
            switch(Event)
            {
                case NET_DRIVE_SM_PROCESS_TIMER_EXPIRED_EVENT:
                {
                    break;
                }
                case NET_DRIVE_SM_PROCESS_FINISHED_EVENT:
                {
                    break;
                }
            }
            break;
        }
        case NET_DRIVE_MOUNTING_STATE:
        {
            switch(Event)
            {
                case NET_DRIVE_SM_PROCESS_TIMER_EXPIRED_EVENT:
                {
                    qDebug("Failed to mount network drive within allowed period.  Will retry later %s @ %s",qPrintable(mTransferProcess->readAllStandardOutput()),qPrintable(mTransferProcess->readAllStandardError()));
                    CEngLog::instance()->AddLogString(QString("Failed to mount network drive within allowed period.  Will retry later %1 @ %2").arg(QString(mTransferProcess->readAllStandardOutput()).arg(QString(qPrintable(mTransferProcess->readAllStandardError())))));

                    QString stdout = QString(mTransferProcess->readAllStandardOutput());
                    QString stderr = QString(mTransferProcess->readAllStandardError());

                    mTransferProcess->kill();
                    mNetDriveSMState = NET_DRIVE_RETRY_MOUNTING_STATE;

                    MountNetworkDrive();

                    break;
                }
                case NET_DRIVE_SM_PROCESS_FINISHED_EVENT:
                {
                    //QString StdOut = mTransferProcess->readAllStandardOutput();
                    //CEngLog::instance()->AddLogString(StdOut);
                  //  qDebug("%s",qPrintable(StdOut));
                    mProcessTimer->stop();

                    if(IsNetworkDriveMounted())
                    {
                        CZTLog::instance()->AddLogString("Répertoire réseau monté avec succès");
//                        qDebug("Drive mounted successfuly");
                        mNetDriveSMState = NET_DRIVE_STANDBY_STATE;
                    }
                    else
                    {
                        QString Line = QString("Echec de la commande mount : %1 - %2").arg(QString(mTransferProcess->readAllStandardOutput())).arg(QString(mTransferProcess->readAllStandardError()));
                        CEngLog::instance()->AddLogString(Line,1);
 //                       qDebug("Mount command failed: %s @ %s",qPrintable(mTransferProcess->readAllStandardOutput()),qPrintable(mTransferProcess->readAllStandardError()));


                        mNetDriveSMState = NET_DRIVE_RETRY_MOUNTING_STATE;
                        mProcessTimer->start(MOUNT_TIMEOUT);
                    }


                    break;
                }
            }
            break;
        }
        case NET_DRIVE_RETRY_MOUNTING_STATE:
        {
            switch(Event)
            {
                case NET_DRIVE_SM_PROCESS_TIMER_EXPIRED_EVENT:
                {
                    CEngLog::instance()->AddLogString("Tentative de remonter le drive réseau");
 //                   qDebug("Retrying to mount net drive");
                    MountNetworkDrive();
                    break;
                }
                case NET_DRIVE_SM_PROCESS_FINISHED_EVENT:
                {
                    //Should not come here...
                    break;
                }
            }
            break;
        }
    }

    return RET_OK;
}



void CNetDriveMgr::ProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
    Q_UNUSED(exitCode)
    Q_UNUSED(exitStatus)

    CEngLog::instance()->AddLogString(QString("Process finished %1 - %2").arg(exitCode).arg(exitStatus));
  //  qDebug("Process finished %d - %d",exitCode,exitStatus);
    NetworkDriveStateMachine(NET_DRIVE_SM_PROCESS_FINISHED_EVENT);

}

void CNetDriveMgr::ProcessExecTimerExpired()
{
    NetworkDriveStateMachine(NET_DRIVE_SM_PROCESS_TIMER_EXPIRED_EVENT);
}

int CNetDriveMgr::InitNetDriveMgr(bool Enabled, QString RemoteAccessPath, QString RemoteLogin, QString RemotePwd, QString RemoteDomain, QString FilenamePrefix)
{
    if(Enabled == false)
    {
        mIsNetDriveEnabled = false;
        return RET_OK;
    }
    mIsNetDriveEnabled = true;

    mRemoteDriveAccessPath = RemoteAccessPath;
    mRemoteDriveLogin = RemoteLogin;
    mRemoteDrivePassword = RemotePwd;
    mRemoteDriveDomain = RemoteDomain;
    mFilesPrefix = FilenamePrefix;

    MountNetworkDrive();

}

int CNetDriveMgr::MountNetworkDrive()
{
    if(mIsNetDriveEnabled == false)
        return RET_ERROR;

    if(IsNetworkDriveMounted())
    {
        CZTLog::instance()->AddLogString("Répertoire réseau déjà monté");
        qDebug("Network drive already mounted, aborting mount operation");
        mNetDriveSMState = NET_DRIVE_STANDBY_STATE;
        return RET_ERROR;   //drive already mounted.
    }

    if(IsNetworkDriveAvailable() == false)  //Network is disconnected... retry later.
    {
        CEngLog::instance()->AddLogString("Interface réseau ETH0 déconnectée.  Impossible de monter le NAS");
        qDebug("Network interface not connected.  Cannot mount network drive.  Will retry later");
        mNetDriveSMState = NET_DRIVE_RETRY_MOUNTING_STATE;
        mProcessTimer->start(MOUNT_TIMEOUT);
        return RET_ERROR;
    }
    //sudo mount -t cifs -o domain=TID,user=JF,password=signal77240,vers=2.1 //192.168.50.110/TestZT /home/zonetest/ZT/NetDrive

    CEngLog::instance()->AddLogString("Montage du drive réseau");
    qDebug("Trying to mount network drive");
    QString Cmd;
    if(mRemoteDriveDomain.isEmpty())
        Cmd = QString("mount -t cifs -o user=%1,password=%2,vers=2.1 %3 %4").arg(mRemoteDriveLogin).arg(mRemoteDrivePassword).arg(mRemoteDriveAccessPath).arg(NAS_MOUNT_POINT);
    else
        Cmd = QString("mount -t cifs -o domain=%1,user=%2,password=%3,vers=2.1 %4 %5").arg(mRemoteDriveDomain).arg(mRemoteDriveLogin).arg(mRemoteDrivePassword).arg(mRemoteDriveAccessPath).arg(NAS_MOUNT_POINT);

    CEngLog::instance()->AddLogString(Cmd);
    qDebug("%s",qPrintable(Cmd));
    mTransferProcess->start(Cmd);
    mNetDriveSMState = NET_DRIVE_MOUNTING_STATE;
    mProcessTimer->start(MOUNT_TIMEOUT);

    return RET_OK;
}

int CNetDriveMgr::UnMountNetworkDrive()
{
    if(mIsNetDriveEnabled == false)
        return RET_ERROR;

    if(IsNetworkDriveMounted() == false)
    {
        qDebug("Network drive not mounted, aborting unmount operation");
        mNetDriveSMState = NET_DRIVE_MOUNTING_STATE;
        return RET_ERROR;   //drive already mounted.
    }

    QString Cmd = QString("umount %1").arg(NAS_MOUNT_POINT);
    QProcess::startDetached(Cmd);
    mNetDriveSMState = NET_DRIVE_MOUNTING_STATE;

    return RET_OK;

}

void CNetDriveMgr::NewTrainFileSaved(QString filename, bool Detection)
{
    TransferTrainLogToNetDrive(filename,Detection);
}
