/*******************************************************************************
*                                                                              *
* Société de Transports de Montréal.                                    	   *
* 2012 - 2013                                                                        *
*                                                                              *
* Projet Zones Tests                                                           *
*                                                                              *
*                                                                              *
*                                                                              *
*******************************************************************************/
/*
	Description:
	Cette classe est responsable de la sauvegarde et de l'ouverture des fichiers
	log de passage des trains.
	
*/

/* ************************************************************************** */
/* Revision:
### YYYMMDD JFM
	Verision d'origine.
	
### YYYYMMDD Description du besoin ou du bug
	Description du changement.
 */

/* ************************************************************************** */

#include "TrainLogFileMgr.h"
#include <QFile>
#include <QTextStream>
#include "LogMgr.h"

CTrainLogFileMgr CTrainLogFileMgr::mSingleton;

CTrainLogFileMgr::CTrainLogFileMgr()
{
}

//unsigned int CTrainLogFileMgr::SaveTrainLog(QString LogFilePathName, CZT1Log *ZT1Log, QList<CZTDetectionData *> *ZT1DetectionsLog,QString StationName)
unsigned int CTrainLogFileMgr::SaveTrainLog(QString LogFilePathName, CZT1Log *ZT1Log, QVector<CZTDetectionData *> *ZT1DetectionsLog,QString StationName)
{
	QFile* BinaryLogFile = new QFile(LogFilePathName);
	if(BinaryLogFile)
	{
		if(BinaryLogFile->open(QIODevice::WriteOnly | QIODevice::Unbuffered) == false)
        {
            qDebug("Could not create log file : %s",LogFilePathName.toLatin1().data());
			delete BinaryLogFile;
            return RET_ERROR;
        }


	}
	else
		return RET_ERROR;

	QDataStream * OutputStream = new QDataStream(BinaryLogFile);
    OutputStream->setVersion(QDataStream::Qt_4_8);

	quint32 MagicNbr = 0xDEADBEEF;

	quint32 NbLogEntry = 0,NbDetections = 0;
    quint32 LogType = ZT1_LOG_TYPE;
	NbLogEntry = ZT1Log->mZT1LogData.size();
    NbDetections = ZT1DetectionsLog->size();
	quint32 TrainType = 0;
	quint32 NbElements = 0;
	quint64 ThreadDataStartTime = 0, ThreadDataEndTime = 0;
	qreal MeanSpeed = 0;
	QDateTime DateTime;


	//Compute some stats
	int SpeedSampleCount = 0;
	bool TrainTypeFound = false;
	unsigned int NbBogie = 0;
	bool ThreadStartTimeFound = false, ThreadEndTimeFound = false;

	for(unsigned int i = 0; i < NbLogEntry; i++)
	{
		if(ZT1Log->mZT1LogData.at(i)->mZT1ThreadData != 0)
		{
			//get the train type
			if(!TrainTypeFound)
			{
				if(ZT1Log->mZT1LogData.at(i)->mZT1ThreadData->mTrainType != TRAIN_TYPE_UNKNOWN)
				{
					TrainType = ZT1Log->mZT1LogData.at(i)->mZT1ThreadData->mTrainType;
					TrainTypeFound = true;
				}
			}

			//Get the rank count for the train
			if(ZT1Log->mZT1LogData.at(i)->mZT1ThreadData->mRank > NbBogie)
				NbBogie = ZT1Log->mZT1LogData.at(i)->mZT1ThreadData->mBogie;

			//Find the time limits
			if(ThreadStartTimeFound == false)
			{
				ThreadStartTimeFound = true;
				ThreadDataStartTime = ZT1Log->mZT1LogData.at(i)->mTimestamp;
			}

			//Compute the mean speed
			if(ZT1Log->mZT1LogData.at(i)->mZT1ThreadData->mTrainSpeed != 0)
			{
				MeanSpeed += ZT1Log->mZT1LogData.at(i)->mZT1ThreadData->mTrainSpeed;
				SpeedSampleCount++;
			}
		}
		else
		{
			//Find the time limits
			if(ThreadStartTimeFound == true && ThreadEndTimeFound == false)
			{
				ThreadEndTimeFound = true;
				ThreadDataEndTime = ZT1Log->mZT1LogData.at(i-1)->mTimestamp;
			}
		}
	}
	MeanSpeed /= SpeedSampleCount;
	NbElements = NbBogie/6;

	DateTime = ZT1Log->mZT1LogData.first()->mDateTime;



    *OutputStream << MagicNbr << LogType << NbLogEntry << NbDetections;
	*OutputStream << StationName;

	*OutputStream << ZT1Log->mZT1Flags;

	*OutputStream << TrainType << NbElements << ThreadDataStartTime << ThreadDataEndTime << MeanSpeed << DateTime;


	//write detections
	for(unsigned int i =0; i < NbDetections; i++)
	{
		*OutputStream << *ZT1DetectionsLog->at(i);
	}

    //write train passage log
    for(unsigned int i = 0; i < NbLogEntry; i++)
    {
		*OutputStream << *ZT1Log->mZT1LogData.at(i);
    }

#ifdef USE_ANALOG_ACQUISITION
	//write analog data if present.
	if(ZT1Log->mZT1Flags.mAnalogTracePresent == 1)
	{
		for(unsigned int i = 0; i < NbLogEntry; i++)
		{
			*OutputStream << ZT1Log->mZT1LogData.at(i)->mAnalogData;
		}
	}
#endif


    BinaryLogFile->close();
	delete BinaryLogFile;
	delete OutputStream;


	return RET_OK;

}

unsigned int CTrainLogFileMgr::SaveTrainLog(QString LogFilePathName, QVector<CZT2LogData *> *ZT2Log, QVector<CZTDetectionData *> *ZT2DetectionsLog, QString StationName)
{
    QFile* BinaryLogFile = new QFile(LogFilePathName);
    if(BinaryLogFile)
    {
        if(BinaryLogFile->open(QIODevice::WriteOnly | QIODevice::Unbuffered) == false)
        {
            qDebug("Could not create log file : %s",LogFilePathName.toLatin1().data());
			delete BinaryLogFile;
            return RET_ERROR;
        }


    }
    else
        return RET_ERROR;

    QDataStream * OutputStream = new QDataStream(BinaryLogFile);
    OutputStream->setVersion(QDataStream::Qt_4_8);

    quint32 MagicNbr = 0xDEADBEEF;

    quint32 NbLogEntry,NbDetections;
    quint32 LogType = ZT2_LOG_TYPE;
    NbLogEntry = ZT2Log->size();
    NbDetections = ZT2DetectionsLog->size();
	quint32 NbElements = 0;
	QDateTime DateTime = ZT2Log->at(0)->mDateTime;


	//Get some stats
	for(int j = 0; j < ZT2Log->size(); j++)
	{
		if(ZT2Log->at(j)->mZT2ThreadData != 0)
		{
			//Get the rank count for the train
			if(ZT2Log->at(j)->mZT2ThreadData->mRank > NbElements)
				NbElements = ZT2Log->at(j)->mZT2ThreadData->mBogie;
		}
	}

	NbElements /= 6;	//6 bogies per element



    *OutputStream << MagicNbr << LogType << NbLogEntry << NbDetections;
	*OutputStream << StationName;

	*OutputStream << NbElements << DateTime;

	//write detections
	for(unsigned int i =0; i < NbDetections; i++)
	{
		*OutputStream << *ZT2DetectionsLog->at(i);
	}


	//write train passage log
    for(unsigned int i = 0; i < NbLogEntry; i++)
    {
        *OutputStream << *ZT2Log->at(i);
    }

    BinaryLogFile->close();
    delete BinaryLogFile;
    delete OutputStream;

    return RET_OK;
}

//It is the responsibility of the caller to make shure TargetElement is empty
CLogElement* CTrainLogFileMgr::OpenTrainLog(QString LogFilePathName,unsigned int &Retvalue,CLogElement* TargetElement,bool LoadData)
{
//	if(!ZT1Log->isEmpty() || !ZT1DetectionsLog->isEmpty())
//		return RET_ERROR;

    int LogFileVersion;
    bool FileProtected = false;

    if(QFileInfo(LogFilePathName).suffix() != "bin")
    {
        Retvalue = RET_ERROR;
        return 0;
    }

	QFile* BinaryLogFile = new QFile(LogFilePathName);
	if(BinaryLogFile)
	{
		if(BinaryLogFile->open(QIODevice::ReadOnly | QIODevice::Unbuffered) == false)
        {
            Retvalue = RET_ERROR;
			delete BinaryLogFile;
            return 0;
        }

	}
	else
    {
        Retvalue = RET_ERROR;
        return 0;
    }

	QDataStream * InputStream = new QDataStream(BinaryLogFile);
    InputStream->setVersion(QDataStream::Qt_4_8);

    quint32 MagicNbr,NbLogEntry,NbDetections,LogType;

	*InputStream >> MagicNbr;
    if(MagicNbr == 0xDEADBEEF)
    {
        LogFileVersion = 1;
        FileProtected = false;
    }
    else if(MagicNbr == 0xDEADBEEF+1)
    {
        LogFileVersion = 2;
        FileProtected = false;
    }
    else if(MagicNbr == 0xDEADBEEF+2)
    {
        LogFileVersion = 1;
        FileProtected = true;
    }
    else if(MagicNbr == 0xDEADBEEF+3)
    {
        LogFileVersion = 2;
        FileProtected = true;
    }
    else if(MagicNbr == 0xDEADBEEF+15 || MagicNbr == 0xDEADBEEF+16 )
    {
        LogFileVersion = 3;

        qint32 OutilZTFlags[10];
        for(int i = 0; i < 10; i++)
        {
            *InputStream >> OutilZTFlags[i];
        }

        if(OutilZTFlags[OUTILZT_FILE_PROTECTED_FLAG] == 1)
        {
            FileProtected = true;
        }
        else
        {
            FileProtected = false;
        }
    }
    else
	{
        qDebug(qPrintable(QString().sprintf("Fichier de passage invalide (Magic number) %s",qPrintable(LogFilePathName))));
		BinaryLogFile->close();
		delete BinaryLogFile;
		delete InputStream;

        Retvalue = RET_ERROR;
        return 0;
	}

    *InputStream >> LogType;

    if(LogType == ZT1_LOG_TYPE)
    {
		CZT1LogElement *PassageLog;
		if(TargetElement == 0)
		{
			PassageLog = new CZT1LogElement();
		}
		else
		{
			PassageLog = (CZT1LogElement*)TargetElement; //It is the responsibility of the caller to make shure TargetElement is empty
		}

		PassageLog->mLogFileName = LogFilePathName;
        PassageLog->mFileProtected = FileProtected;

        *InputStream >> NbLogEntry;
        *InputStream >> NbDetections;
		*InputStream >> PassageLog->mStationName;
        if(LogFileVersion == 1)
        {
           *InputStream >> PassageLog->mFlags.mExtPGOffset
                        >> PassageLog->mFlags.mIntPGOffset
                        >> PassageLog->mFlags.mPGCalibrationON
                        >> PassageLog->mFlags.mPGTresholdValue
                        >> PassageLog->mFlags.mAnalogTracePresent;

            PassageLog->mFlags.mTrainCompo1 = 0;
            PassageLog->mFlags.mTrainCompo2 = 0;
            PassageLog->mFlags.mTrainCompo3 = 0;
            PassageLog->mFlags.mModbusTrainType = MODBUS_CC_TRAIN_TYPE_INVALID_NOT_UPDATED;
            PassageLog->mFlags.mZT1ITI = ZT_PRIMARY_ITI;
        }
        else if(LogFileVersion == 2)
        {
            *InputStream >> PassageLog->mFlags.mExtPGOffset
                         >> PassageLog->mFlags.mIntPGOffset
                         >> PassageLog->mFlags.mPGCalibrationON
                         >> PassageLog->mFlags.mPGTresholdValue
                         >> PassageLog->mFlags.mAnalogTracePresent
                         >> PassageLog->mFlags.mIsProblematicPassage;

            PassageLog->mFlags.mTrainCompo1 = 0;
            PassageLog->mFlags.mTrainCompo2 = 0;
            PassageLog->mFlags.mTrainCompo3 = 0;
            PassageLog->mFlags.mModbusTrainType = MODBUS_CC_TRAIN_TYPE_INVALID_NOT_UPDATED;
            PassageLog->mFlags.mZT1ITI = ZT_PRIMARY_ITI;
        }
        else if(LogFileVersion == 3)
        {
            *InputStream >> PassageLog->mFlags;
        }

		*InputStream >> PassageLog->mTrainType;
		*InputStream >> PassageLog->mNbElements;
		*InputStream >> PassageLog->mThreadDataStartTime;
		*InputStream >> PassageLog->mThreadDataEndTime;
		*InputStream >> PassageLog->mMeanSpeed;
		*InputStream >> PassageLog->mPassageDateTime;

		for(unsigned int i = 0; i < NbDetections; i++)
		{
			CZTDetectionData *NewDetection = new CZTDetectionData();
			*InputStream >> *NewDetection;
			PassageLog->mZTDetections.append(NewDetection);
		}

		if(LoadData == true)
		{
			for(unsigned int i = 0; i < NbLogEntry; i++)
			{
				CZT1LogData *NewLogChunk = new CZT1LogData();
				*InputStream >> *NewLogChunk;
				PassageLog->mZTLogData.append(NewLogChunk);
			}

#ifdef USE_ANALOG_ACQUISITION
			if(PassageLog->mFlags.mAnalogTracePresent == 1)
			{
				for(int i = 0; i < PassageLog->mZTLogData.size(); i++)
				{
					*InputStream >> PassageLog->mZTLogData.at(i)->mAnalogData;
				}
			}
#endif
		}

        BinaryLogFile->close();
        delete BinaryLogFile;
        delete InputStream;

        Retvalue = RET_OK;
        return (CZT1LogElement*) PassageLog;
    }
    else if(LogType == ZT2_LOG_TYPE)
    {
		quint32 NbElements;
		QDateTime DateTime;

		CZT2LogElement *PassageLog;
		if(TargetElement == 0)
		{
			PassageLog = new CZT2LogElement();
		}
		else
		{
			PassageLog = (CZT2LogElement*) TargetElement;	//It is the responsibility of the caller to make shure TargetElement is empty
		}

        *InputStream >> NbLogEntry;
        *InputStream >> NbDetections;
		*InputStream >> PassageLog->mStationName;
        if(LogFileVersion == 2)
        {
            *InputStream >> PassageLog->mFlags.mIsProblematicPassage;
            PassageLog->mFlags.mModbusTrainType = MODBUS_CC_TRAIN_TYPE_INVALID_NOT_UPDATED;
            PassageLog->mFlags.mTrainCompo1 = 0;
            PassageLog->mFlags.mTrainCompo2 = 0;
            PassageLog->mFlags.mTrainCompo3 = 0;
        }
        else if(LogFileVersion == 3)
        {
            *InputStream >> PassageLog->mFlags;
        }
        else
        {
            PassageLog->mFlags.mIsProblematicPassage = 2;
            PassageLog->mFlags.mModbusTrainType = MODBUS_CC_TRAIN_TYPE_INVALID_NOT_UPDATED;
            PassageLog->mFlags.mTrainCompo1 = 0;
            PassageLog->mFlags.mTrainCompo2 = 0;
            PassageLog->mFlags.mTrainCompo3 = 0;
        }
		*InputStream >> NbElements;
		*InputStream >> DateTime;

		PassageLog->mNbElements = NbElements;
		PassageLog->mLogFileName = LogFilePathName;
		PassageLog->mPassageDateTime = DateTime;
        PassageLog->mFileProtected = FileProtected;

		for(unsigned int i = 0; i < NbDetections; i++)
		{
			CZTDetectionData *NewDetection = new CZTDetectionData();
			*InputStream >> *NewDetection;
			PassageLog->mZTDetections.append(NewDetection);
		}

		if(LoadData == true)
		{
			for(unsigned int i = 0; i < NbLogEntry; i++)
			{
				CZT2LogData *NewLogChunk = new CZT2LogData();
				*InputStream >> *NewLogChunk;
				PassageLog->mZTLogData.append(NewLogChunk);
			}
		}




        BinaryLogFile->close();
        delete BinaryLogFile;
        delete InputStream;

        Retvalue = RET_OK;
        return PassageLog;
    }
    else
    {
        qDebug("Invalid log type in file %s",LogFilePathName.toLatin1().data());
        Retvalue = RET_ERROR;
        return 0;


    }
}

unsigned int CTrainLogFileMgr::SetTrainLogProtected(bool IsProtected, QString LogFilePathName)
{
    QFile* BinaryLogFile = new QFile(LogFilePathName);
    if(BinaryLogFile)
    {
        if(BinaryLogFile->open(QIODevice::ReadWrite | QIODevice::Unbuffered) == false)
        {
            qDebug("Could not Open log file to set protection : %s",LogFilePathName.toLatin1().data());
            delete BinaryLogFile;
            return RET_ERROR;
        }


    }
    else
        return RET_ERROR;

    QDataStream * Stream = new QDataStream(BinaryLogFile);
    Stream->setVersion(QDataStream::Qt_4_8);

    quint32 MagicNbr;

    *Stream >> MagicNbr;



    if(IsProtected == true)
    {
        if(MagicNbr == 0xDEADBEEF + 2 || MagicNbr == 0xDEADBEEF + 3)
        {
            //file is already protected

        }
        else if(MagicNbr == 0xDEADBEEF || MagicNbr == 0xDEADBEEF + 1)
        {
            MagicNbr += 2;
            BinaryLogFile->seek(0);
            *Stream << MagicNbr;
        }
        else if(MagicNbr == 0xDEADBEEF + 15)
        {
            //Use the reserved registers inside the file...
            qint32 Flags[10];
            for(int i = 0; i < 10; i++)
            {
                *Stream >> Flags[i];
            }

            Flags[OUTILZT_FILE_PROTECTED_FLAG] = 1;
            BinaryLogFile->seek(0);
            *Stream >> MagicNbr;    //Dummy read;

            for(int i = 0; i < 10; i++)
            {
                *Stream << Flags[i];
            }
        }
        else
        {
            //Log File Error
            BinaryLogFile->close();
            qDebug("Invalid log file magic number to set protection : %s",LogFilePathName.toLatin1().data());
            delete BinaryLogFile;
        }

    }
    else
    {
        if(MagicNbr == 0xDEADBEEF + 2 || MagicNbr == 0xDEADBEEF + 3)
        {
            //file is already protected
            MagicNbr -= 2;
            BinaryLogFile->seek(0);
            *Stream << MagicNbr;

        }
        else if(MagicNbr == 0xDEADBEEF || MagicNbr == 0xDEADBEEF + 1)
        {
            //file is already unprotected
        }
        else if(MagicNbr == 0xDEADBEEF + 15)
        {
            //Use the reserved registers inside the file...
            qint32 Flags[10];
            for(int i = 0; i < 10; i++)
            {
                *Stream >> Flags[i];
            }

            Flags[OUTILZT_FILE_PROTECTED_FLAG] = 0;
            BinaryLogFile->seek(0);
            *Stream >> MagicNbr;    //Dummy read;

            for(int i = 0; i < 10; i++)
            {
                *Stream << Flags[i];
            }
        }
        else
        {
            //Log File Error
            BinaryLogFile->close();
            qDebug("Invalid log file magic number to set protection : %s",LogFilePathName.toLatin1().data());
            delete BinaryLogFile;
        }
    }

    BinaryLogFile->close();
    qDebug("Invalid log file magic number to set protection : %s",LogFilePathName.toLatin1().data());
    delete BinaryLogFile;

    return RET_OK;
}

//unsigned int CTrainLogFileMgr::SaveCSVFile(QString CSVFilePathName, CZT1Log *ZT1Log, QList<CZTDetectionData *> *ZT1DetectionsLog, QString StationName)
unsigned int CTrainLogFileMgr::SaveCSVFile(QString CSVFilePathName, CZT1Log *ZT1Log, QVector<CZTDetectionData *> *ZT1DetectionsLog, QString StationName)
{
	return SaveCSVFile(CSVFilePathName, &ZT1Log->mZT1LogData, &ZT1Log->mZT1Flags, ZT1DetectionsLog,StationName);
}

//unsigned int CTrainLogFileMgr::SaveCSVFile(QString CSVFilePathName, QList<CZT1LogData*> *ZT1Log, CZT1FlagsData *ZT1Flags, QList<CZTDetectionData *> *ZT1DetectionsLog, QString StationName)
unsigned int CTrainLogFileMgr::SaveCSVFile(QString CSVFilePathName, QVector<CZT1LogData*> *ZT1Log, CZT1FlagsData *ZT1Flags, QVector<CZTDetectionData *> *ZT1DetectionsLog, QString StationName)
{
	QFile CSVFile(CSVFilePathName);
	if(!CSVFile.open(QIODevice::QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate))
		return RET_ERROR;

	QTextStream CSVStream(&CSVFile);

	CSVStream << "Log de passage du train dans la ZT1\n";

	CSVStream << QString::fromUtf8("Station : ") << StationName << "\n";
	CSVStream << QString::fromUtf8("Valeur seuil Pneu de guidage : ") << ZT1Flags->mPGTresholdValue << "\n";
	CSVStream << QString::fromUtf8("Valeur zérotage PG Extérieur : ") << ZT1Flags->mExtPGOffset << "\n";
	CSVStream << QString::fromUtf8("Valeur zérotage PG Intérieur : ") << ZT1Flags->mIntPGOffset << "\n";
	if(ZT1Flags->mPGCalibrationON == 1)
	{
		CSVStream << "Calibration PG en cours lors du passage: OUI\n";
	}
	else
		CSVStream << "Calibration PG en cours lors du passage: NON\n";

	CSVStream << QString::fromUtf8("Nombre de déclenchements : ") << ZT1DetectionsLog->size() << "\n";



	if(ZT1DetectionsLog->size() > 0)
	{
		for(int i = 0; i < ZT1DetectionsLog->size(); i++)
		{
			CSVStream << QString::fromUtf8("Déclenchement ") << i+1 << ": " << ZT1DetectionsLog->at(i)->mTimeStamp << " - " << QString::fromUtf8(CZTData::GetErrorString(ZT1DetectionsLog->at(i)->mDetectionID)) << " au rang " << ZT1DetectionsLog->at(i)->mRank << "\n";
		}


	}
	CSVStream << "\n";

    CSVStream << "Date,Heure,Timestamp,CI,CDV Approche,CDV ZT1,S1,S2,FN,PPI,PPE,PG,Vitesse,Bogie,Rang,Laser Ext,Laser Int,Train";

    if(ZT1Flags->mAnalogTracePresent == 1)
    {
        CSVStream << ",4-20mA SDF";
    }

    CSVStream << "\n";

	for(int i = 0; i < ZT1Log->size(); i++)
	{
		CSVStream << ZT1Log->at(i)->mDateTime.toString("yyyy-MM-dd, hh:mm:ss:zzz") << ",";
		CSVStream << ZT1Log->at(i)->mTimestamp << ",";
		CSVStream << ZT1Log->at(i)->mCIZT1 << ",";
		CSVStream << ZT1Log->at(i)->mCDVApproach_ZT1 << ",";
		CSVStream << ZT1Log->at(i)->mCDVARM_ZT1 << ",";

        if(ZT1Log->at(i)->mZT1ThreadData != 0)
		{
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mS1 << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mS2 << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mFN << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mPInt << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mPExt << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mPG << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mTrainSpeed << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mBogie << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mRank << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mPGExtValue << ",";
			CSVStream << ZT1Log->at(i)->mZT1ThreadData->mPGIntValue << ",";
            CSVStream << CZTData::GetTrainTypeString(ZT1Log->at(i)->mZT1ThreadData->mTrainType);
		}
		else
		{
			CSVStream << "0,0,0,0,0,0,0,0,0,0,0,0";
            //CSVStream <<"\n";
		}

        if(ZT1Flags->mAnalogTracePresent == 1)
        {
            CSVStream << "," << ZT1Log->at(i)->mAnalogData ;
        }

        CSVStream << "\n";
	}

	CSVFile.flush();
	CSVFile.close();

	return RET_OK;
}



unsigned int CTrainLogFileMgr::SaveCSVFile(QString CSVFilePathName, QVector<CZT2LogData *> *ZT2Log, QVector<CZTDetectionData *> *ZT2DetectionsLog, QString StationName)
//unsigned int CTrainLogFileMgr::SaveCSVFile(QString CSVFilePathName, QVector<CZT2LogData *> *ZT2Log, QVector<CZTDetectionData *> *ZT2DetectionsLog, QString StationName)
{
    QFile CSVFile(CSVFilePathName);
    if(!CSVFile.open(QIODevice::QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate))
        return RET_ERROR;

    QTextStream CSVStream(&CSVFile);

    CSVStream << "Log de passage du train dans la ZT2\n";
	CSVStream << QString::fromUtf8("Station : ") << StationName << "\n";

    CSVStream << QString::fromUtf8("Nombre de déclenchements : ") << ZT2DetectionsLog->size() << "\n";


    if(ZT2DetectionsLog->size() > 0)
    {
        for(int i = 0; i < ZT2DetectionsLog->size(); i++)
        {
            CSVStream << QString::fromUtf8("Déclenchement ") << i+1 << ": " << ZT2DetectionsLog->at(i)->mTimeStamp << " - " << QString::fromUtf8(CZTData::GetErrorString(ZT2DetectionsLog->at(i)->mDetectionID)) << " au rang " << ZT2DetectionsLog->at(i)->mRank << "\n";
        }

        CSVStream << "\n";
    }

    CSVStream << "Date,Heure,Timestamp,CI,CDV ZT2,S1,PPI,PPE,Bogie,Rang\n";

    for(int i = 0; i < ZT2Log->size(); i++)
    {
        CSVStream << ZT2Log->at(i)->mDateTime.toString("yyyy-MM-dd, hh:mm:ss:zzz") << ",";
        CSVStream << ZT2Log->at(i)->mTimestamp << ",";
        CSVStream << ZT2Log->at(i)->mCIZT2 << ",";
        CSVStream << ZT2Log->at(i)->mCDVARM_ZT2 << ",";
        if(ZT2Log->at(i)->mZT2ThreadData != 0)
        {
            CSVStream << ZT2Log->at(i)->mZT2ThreadData->mS1 << ",";
            CSVStream << ZT2Log->at(i)->mZT2ThreadData->mPPInt << ",";
            CSVStream << ZT2Log->at(i)->mZT2ThreadData->mPPExt << ",";
            CSVStream << ZT2Log->at(i)->mZT2ThreadData->mBogie << ",";
            CSVStream << ZT2Log->at(i)->mZT2ThreadData->mRank << ",";
        }
        else
		{
            CSVStream << "0,0,0,0,0";
			CSVStream <<"\n";
		}
    }

    CSVFile.flush();
    CSVFile.close();

    return RET_OK;
}



//Cette fonction a été écrite pour des fins de tests et n'est PAS du tout robuste.
//utiliser avec précaution.
unsigned int CTrainLogFileMgr::SaveBINFromCSV(QString CSVFilePathName)
{
	QFile CSVFile(CSVFilePathName);
	if(!CSVFile.open(QIODevice::ReadOnly|QIODevice::Text))
		return RET_ERROR;

	QTextStream CSVStream(&CSVFile);

	bool IsZT1 = true;
	QString Line;
	QStringList LineElements;
	QString StationName;
	Line.clear();
	LineElements.clear();

	Line = CSVStream.readLine();	//Log de passage du train dans la ZT1
	if(Line.contains("ZT1") == true)
	{
		IsZT1 = true;
	}
	else if(Line.contains("ZT2") == true)
	{
		IsZT1 = false;
	}
	else
	{
		//invalid file
		CSVFile.close();
		return RET_ERROR;
	}

	Line = CSVStream.readLine();	//Station : Snowdon
	LineElements = Line.split(":");
	if(LineElements.isEmpty())
	{
		CSVFile.close();
		return RET_ERROR;
	}
	StationName = LineElements.at(1);
	Line.clear();

	if(IsZT1 == true)
	{
		CZT1Log *ZT1LOG = new CZT1Log();

		Line = CSVStream.readLine();	//Valeur seuil Pneu de guidage : 15625
		LineElements = Line.split(":");
		if(LineElements.isEmpty())
		{
			CSVFile.close();
			return RET_ERROR;
		}
		ZT1LOG->mZT1Flags.mPGTresholdValue = LineElements.at(1).toInt();
		Line.clear();

		Line = CSVStream.readLine();	//Valeur zérotage PG Extérieur : 128457
		LineElements = Line.split(":");
		if(LineElements.isEmpty())
		{
			CSVFile.close();
			return RET_ERROR;
		}
		ZT1LOG->mZT1Flags.mExtPGOffset = LineElements.at(1).toInt();
		Line.clear();

		Line = CSVStream.readLine();	//Valeur zérotage PG Intérieur : 1300637
		LineElements = Line.split(":");
		if(LineElements.isEmpty())
		{
			CSVFile.close();
			return RET_ERROR;
		}
		ZT1LOG->mZT1Flags.mIntPGOffset = LineElements.at(1).toInt();
		Line.clear();

		Line = CSVStream.readLine();	//Calibration PG en cours lors du passage: NON
		if(Line.contains("OUI") == true)
		{
			ZT1LOG->mZT1Flags.mPGCalibrationON = true;
		}
		else if(Line.contains("NON") == true)
		{
			ZT1LOG->mZT1Flags.mPGCalibrationON = false;
		}
		else
		{
			CSVFile.close();
			return RET_ERROR;
		}
		Line.clear();

		int NbDetections;
		Line = CSVStream.readLine();	//Nombre de déclenchements : 12
		LineElements = Line.split(":");
		if(LineElements.isEmpty())
		{
			CSVFile.close();
			return RET_ERROR;
		}
		NbDetections = LineElements.at(1).toInt();
		Line.clear();

		//Ignore detections...
		for(int i = 0; i < NbDetections; i++)
		{
			Line = CSVStream.readLine();
			Line.clear();
		}

		//Skip the empty line after the detections.
		Line = CSVStream.readLine();
		Line.clear();

		//Skip the table header
		Line = CSVStream.readLine();
		Line.clear();

		quint32 LastS1 = 0, LastS2 = 0, LastFN = 0;
		quint32 S1Count = 0;
		quint32 S2Count = 0;
		quint32 FNCount = 0;
		while(CSVStream.atEnd() == false)
		{

			Line.clear();
			LineElements.clear();

			Line = CSVStream.readLine(); //Date	Heure Timestamp	CI CDV Approche	CDV ZT1	S1	S2	FN	PPI	PPE	PG	Vitesse	Bogie	Rang	Sonde Ext	 Sonde Int	Train
			LineElements = Line.split(",");
			if(LineElements.count() != 18)
			{
				CSVFile.close();
				return RET_ERROR;
			}

			QDate date = QDate::fromString(LineElements.at(0),"yyyy-MM-dd");
			if(date.isValid() == false)
			{
				CSVFile.close();
				return RET_ERROR;
			}

			QTime time = QTime::fromString(LineElements.at(1).trimmed(),"hh:mm:ss:zzz");
			if(time.isValid() == false)
			{
				CSVFile.close();
				return RET_ERROR;
			}

			qint64 timestamp = LineElements.at(2).toLongLong();

			quint32 CIZT1 = LineElements.at(3).toUInt();

			quint32 CDVApproach_ZT1 = LineElements.at(4).toUInt();

			quint32 CDVARM_ZT1 = LineElements.at(5).toUInt();

			CZT1LogData *LogData;
			CZT1ThreadData *ThreadData;
			if(LineElements.at(17) == "0")	//Check if ThreadData is valid
			{
				//Thread data not valid...
				LogData = new CZT1LogData();
			}
			else
			{
				ThreadData = new CZT1ThreadData();
				LogData = new CZT1LogData(ThreadData);


				quint32 S1 = LineElements.at(6).toUInt();
				quint32 S2 = LineElements.at(7).toUInt();
				quint32 FN = LineElements.at(8).toUInt();
				quint32 PInt = LineElements.at(9).toUInt();
				quint32 PExt = LineElements.at(10).toUInt();
				quint32 PG = LineElements.at(11).toUInt();
				qreal TrainSpeed = LineElements.at(12).toFloat();
				quint32 Bogie = LineElements.at(13).toUInt();
				quint32 Rank = LineElements.at(14).toUInt();
				qint32 PGIntValue = LineElements.at(15).toInt();
				qint32 PGExtValue = LineElements.at(16).toInt();

				quint32 TrainType;
				if(LineElements.at(17) == "Inconnu")
				{
					TrainType = TRAIN_TYPE_UNKNOWN;
				}
				else if(LineElements.at(17) == "MR63/73")
				{
					TrainType = TRAIN_TYPE_MR63_MR73;
				}
				else if(LineElements.at(17) == "MPM10")
				{
					TrainType = TRAIN_TYPE_MPM10;
				}
				else
				{
					CSVFile.close();
					return RET_ERROR;
				}

				if(S1 == 1 && LastS1 == 0)
					S1Count++;

				if(S2 == 1 && LastS2 == 0)
					S2Count++;

				if(FN == 1 && LastFN == 0)
					FNCount++;

				LastS1 = S1;
				LastS2 = S2;
				LastFN = FN;

				ThreadData->mTimeStamp = timestamp;	//nanosecs
				ThreadData->mDateTime.setDate(date);
				ThreadData->mDateTime.setTime(time);
				ThreadData->mS1 = S1;
				ThreadData->mS2 = S2;
				ThreadData->mFN = FN;
				ThreadData->mPInt = PInt;
				ThreadData->mPExt = PExt;
				ThreadData->mPG = PG;
				ThreadData->mTrainSpeed = TrainSpeed;
				ThreadData->mBogie = Bogie;
				ThreadData->mRank = Rank;
				ThreadData->mPGIntValue = PGIntValue;
				ThreadData->mPGExtValue = PGExtValue;
				ThreadData->mS1Count = S1Count;
				ThreadData->mS2Count = S2Count;
				ThreadData->mFNCount = FNCount;
				ThreadData->mTrainType = TrainType;
			}

			LogData->mTimestamp = timestamp;
			LogData->mCIZT1 = CIZT1;
			LogData->mCDVApproach_ZT1 = CDVApproach_ZT1;
			LogData->mCDVARM_ZT1 = CDVARM_ZT1;
			LogData->mDateTime.setDate(date);
			LogData->mDateTime.setTime(time);

			ZT1LOG->mZT1LogData.append(LogData);
		}

	//	QList<CZTDetectionData*> Dummy;	//JFM
		QVector<CZTDetectionData*> Dummy;
		Dummy.clear();

		SaveTrainLog(CSVFilePathName.replace("csv","bin"),ZT1LOG,&Dummy,StationName);

		for(int i = 0; i < ZT1LOG->mZT1LogData.size(); i++)
		{
			delete ZT1LOG->mZT1LogData.at(i);
		}
		ZT1LOG->mZT1LogData.clear();
		delete ZT1LOG;




	}
	else	//ZT1
	{
	}


	return RET_OK;
}
