/*******************************************************************************
*                                                                              *
* Société de Transports de Montréal.                                    	   *
* 2012 - 2013                                                                        *
*                                                                              *
* Projet Zones Tests                                                           *
*                                                                              *
*                                                                              *
*                                                                              *
*******************************************************************************/
/*
	Description:
	Description du fichier si nécessaire.
	
*/

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

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

#include "GlobalDefine.h"
#include "ZT2AnalysisThread.h"
#include "PCIIOMgr.h"
#include "AbstractLazerProbe.h"
#include <QElapsedTimer>
#include "ZTconfigmgr.h"

//const char * ErrorString[25] = {"Erreur de comptage S1-S2",
//									   "Déclenchement frotteur négatif",
//									   "Déclenchement pneu de guidage intérieur",
//									   "Déclenchement pneu de guidage extérieur",
//									   "Déclenchement pneu porteur intérieur",
//									   "Déclenchement pneu porteur extérieur",
//									   "Pré-détection frotteur négatif"};

CZT2AnalysisThread::CZT2AnalysisThread()
{
	mLastInputs = 0;
    mZT2TrainState = ZT2_PRE_DETECTION_STATE;

	mPCIInputsHandle = 0;
	mExitLoop = false;
    mZT2Analyzing = false;
}

unsigned int CZT2AnalysisThread::Init(CPCIIOMgr *PCIIOHandle,GenericInputMasks_t *InputMasks,QElapsedTimer *RefTimer)
{
	mPCIInputsHandle = PCIIOHandle;
	mInputMasksPtr = InputMasks;
	mReferenceTimer = RefTimer;

	return RET_OK;
}

void CZT2AnalysisThread::AnalyzeZT2Train()
{

    qDebug("ZT2 Thread started!");
	mExitLoop = false;
    mZT2Analyzing = true;


    mZT2TrainState = ZT2_PRE_DETECTION_STATE;
	unsigned int PCIInputs = 0;
	bool Run = true;

	//inputs
    unsigned int S1 = 0, Pint = 0, Pext = 0;

	//Train analysis variables
	unsigned int Bogie = 0;
	unsigned int Rank = 0;
	unsigned int CountS1 = 0;


	bool PPIDetected = false;
	bool PPEDetected = false;


	while(Run == true)
	{
		PCIInputs = mPCIInputsHandle->GetInputs();

        if(PCIInputs != mLastInputs)
		{
			//Extract useful flags

            S1 = ((PCIInputs & mInputMasksPtr->InputZT2S1Mask) != 0);
            Pint = ((PCIInputs & mInputMasksPtr->InputZT2PIMask) != 0);
            Pext = ((PCIInputs & mInputMasksPtr->InputZT2PEMask) != 0);

            if(mZT2TrainState == ZT2_PRE_DETECTION_STATE)
            {
                if(/*S1 != 0 || */Pint != 0 || Pext != 0)
                {
                    RegisterDetection(DETECTION_ZT1_FN_PRE_DETECTION,0,mReferenceTimer->nsecsElapsed());
                }
                mZT2TrainState = ZT2_WAIT_FOR_S1_STATE;
            }

            switch(mZT2TrainState)
            {
                case ZT2_PRE_DETECTION_STATE:
                {
                    qDebug("ZT2AnalysisThread::Logic error, in ZT2 Pre detection state and should not...");
                    mZT2TrainState = ZT2_WAIT_FOR_S1_STATE;
                    break;
                }
                case ZT2_WAIT_FOR_S1_STATE:
                {
                    if(Pint != 0)
                    {
                        if(PPIDetected == false)
                        {
                            PPIDetected = true;
                            RegisterDetection(DETECTION_ZT2_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
                        }
                    }
                    if(Pext != 0)
                    {
                        if(PPEDetected == false)
                        {
                            PPEDetected = true;
                            RegisterDetection(DETECTION_ZT2_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
                        }
                    }

                    if(S1 == 1)
                    {
                        Rank++;
                        CountS1++;
                        if(Rank %2 == 1)
                            Bogie++;

                        PPIDetected = false;
                        PPEDetected = false;

                        mZT2TrainState = ZT2_S1_ACTIVE_STATE;
                    }
                    break;
                }
                case ZT2_S1_ACTIVE_STATE:
                {
                    if(Pint != 0)
                    {
                        if(PPIDetected == false)
                        {
                            PPIDetected = true;
                            RegisterDetection(DETECTION_ZT2_PPI_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
                        }
                    }
                    if(Pext != 0)
                    {
                        if(PPEDetected == false)
                        {
                            PPEDetected = true;
                            RegisterDetection(DETECTION_ZT2_PPE_DETECTION,Rank,mReferenceTimer->nsecsElapsed());
                        }
                    }

                    if(S1 == 0)
                    {
                        mZT2TrainState = ZT2_WAIT_FOR_S1_STATE;
                    }
                    break;
                }
            }//switch(mZT2TrainState)

			mLastInputs = PCIInputs;

            CZT2ThreadData *Data = new CZT2ThreadData();
			Data->mTimeStamp = mReferenceTimer->nsecsElapsed();
//			Data->mDateTime = QDateTime::currentDateTime();
			Data->mS1 = S1;
            Data->mPPExt = Pext;
            Data->mPPInt = Pint;

			Data->mBogie = Bogie;
			Data->mRank = Rank;
			Data->mS1Count = CountS1;


            emit ZT2DataUpdate(Data);

		}//if(PCIInputs != mLastInputs)


		mMutex.lock();
		if(mExitLoop == true)
			Run = false;
		mMutex.unlock();

	}//while

    mZT2Analyzing = false;

}

void CZT2AnalysisThread::TerminateAnalysis()
{
	mMutex.lock();
	mExitLoop = true;
	mMutex.unlock();
}

bool CZT2AnalysisThread::UpdateDetectionConfig(CZTDetectionFunctionConfig *NewConfig)
{
    //do not update in the middle of a train analysis.
    bool Go;
    mMutex.lock();
    Go = mZT2Analyzing;
    mMutex.unlock();

    if(Go == true)
        return false;

    //No need for a Mutex here since the thread is
    //not analyzing.
    mDetectionConfig = *NewConfig;


    return true;
}

void CZT2AnalysisThread::RegisterDetection(unsigned int DetectionID, unsigned int Rank,qint64 TimeStamp)
{
    if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_ZT2].AnalysisActive == false)
        return;


    switch(DetectionID)
    {
        case DETECTION_ZT2_PRE_DETECTION:
        {
            break;
        }
        case DETECTION_ZT2_MAGNETIC_SENCOR_COUNT:
        {
            break;
        }
        case DETECTION_ZT2_PPI_DETECTION:
        {
            if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_PP2].AnalysisActive == false)
            {
                return;
            }
            break;
        }
        case DETECTION_ZT2_PPE_DETECTION:
        {
            if(mDetectionConfig.mZTDetectionConfig[DETECTION_FCT_PP2].AnalysisActive == false)
            {
                return;
            }
            break;
        }
    }


	CZTDetectionData *DetectData = new CZTDetectionData;
	DetectData->mTimeStap = TimeStamp;
	DetectData->mRank = Rank;
	DetectData->mDetectionID = DetectionID;

    emit DetectionTriggered(DetectData);


	qDebug("%s -> Rang %d",CZTData::GetErrorString(DetectionID),Rank);
}

