/*
 * QrfeProtocollHandlerBase.cpp
 *
 *  Created on: 15.01.2009
 *      Author: stefan.detter
 */

#include "QrfeReaderInterface.h"

#include <QrfeSleeper>
#include <QCoreApplication>

#include <QrfeProtocolHandler>


uint  QrfeReaderInterface::_traceLevel = 6;
ulong QrfeReaderInterface::_heartBeatMultiplier = 4;


QrfeReaderInterface::QrfeReaderInterface(QrfeProtocolHandler* ph, QObject* parent)
	: QObject(parent)
	, QrfeTraceModule("QrfeReaderInterface", _traceLevel)
	, m_ph(ph)
{
	// initialize the variables
	m_currentState = QrfeGlobal::STATE_OFFLINE;
	m_currentAction = QrfeGlobal::ACTION_IDLE;

	m_readerID 					= "Unknown";
	m_serialNumber				= "00-00-00-00";
	m_serialNumberExact 		= 0;
	m_readerType 				= QrfeGlobal::TYPE_UNKOWN;
	m_readerTypeExact 			= 0x00;
	m_readerTypeExactString		= "00-00-00-00";
	m_readerModule 				= QrfeGlobal::VERSION_RFE_PUR_RM1;
	m_tagType					= QrfeGlobal::TAG_UNKWON;

	m_hardwareRevision 			= 0x00;
	m_hardwareRevisionString	= "v0.00";
	m_softwareRevision			= 0x00;
	m_softwareRevisionString	= "v0.00";
	m_bootloaderRevision		= 0x00;
	m_bootloaderRevisionString 	= "v0.00";
	m_currentSystem				= QrfeGlobal::FIRMWARE;
	m_currentSystemString		= "Unknown";

	m_heartBeatDuplex			= false;
	m_heartBeatInterval 		= 0;
	m_heartBeatHappened 		= false;

	m_antennaCount				= 0;
	m_gpioValues 				= 0;
	m_statusRegister			= 0;

	m_heartBeatControl 			= new QTimer(this);
	m_heartBeatControl->setSingleShot(true);
	m_heartBeatHappened 		= false;

	m_deviceInit = false;
	m_deviceRemovalDetected = false;

	QObject::connect(m_heartBeatControl, SIGNAL(timeout()), this, SLOT(heartBeatTimeOut()));
	QObject::connect(m_ph, SIGNAL(deviceClosed()), this, SLOT(deviceWasRemoved()));
	QObject::connect(this, SIGNAL(resetHeartBeat()), m_heartBeatControl, SLOT(start()), Qt::QueuedConnection);

	m_ph->setParent(this);
}

QrfeReaderInterface::~QrfeReaderInterface ( )
{
	m_heartBeatControl->stop();
	delete m_heartBeatControl;
	delete m_ph;
}


QrfeTagManipulatorInterface* QrfeReaderInterface::getTagManipulator()
{
	return 0;
}

QString QrfeReaderInterface::name() const
{
	if(!m_readerName.isEmpty())
	{
		if(!m_readerLocation.isEmpty())
			return m_readerName + " @ " + m_readerLocation;
		else
			return m_readerName;
	}
	else
		return m_readerID;
}

QString QrfeReaderInterface::readerId() const
{
	return m_readerID;
}


QString QrfeReaderInterface::serialNumber() const
{
	return m_serialNumber;
}

ulong QrfeReaderInterface::serialNumberExact() const
{
	return m_serialNumberExact;
}


QrfeGlobal::ReaderType QrfeReaderInterface::readerType() const
{
	return m_readerType;
}

ulong QrfeReaderInterface::readerTypeExact() const
{
	return m_readerTypeExact;
}

QString QrfeReaderInterface::readerTypeExactString() const
{
	return m_readerTypeExactString;
}


QrfeGlobal::ReaderModule QrfeReaderInterface::readerModule() const
{
	return m_readerModule;
}

QString QrfeReaderInterface::readerModuleString() const
{
	return QrfeGlobal::readerModuleToString(m_readerModule);
}


QrfeGlobal::TagType QrfeReaderInterface::tagType() const
{
	return m_tagType;
}

QString QrfeReaderInterface::tagTypeString() const
{
	return QrfeGlobal::tagTypeToString(m_tagType);
}


ulong QrfeReaderInterface::hardwareRevision() const
{
	return m_hardwareRevision;
}

QString QrfeReaderInterface::hardwareRevisionString() const
{
	return m_hardwareRevisionString;
}


ulong QrfeReaderInterface::softwareRevision() const
{
	return m_softwareRevision;
}

QString	QrfeReaderInterface::softwareRevisionString() const
{
	return m_softwareRevisionString;
}


ulong QrfeReaderInterface::bootloaderRevision() const
{
	return m_bootloaderRevision;
}

QString	QrfeReaderInterface::bootloaderRevisionString() const
{
	return m_bootloaderRevisionString;
}


QString QrfeReaderInterface::buildDate() const
{
	return m_buildDate;
}

QString QrfeReaderInterface::buildTime() const
{
	return m_buildTime;
}

QString QrfeReaderInterface::buildRevision() const
{
	return m_buildRevision;
}


QrfeGlobal::ReaderSystem QrfeReaderInterface::currentSystem() const
{
	return m_currentSystem;
}

QString	QrfeReaderInterface::currentSystemString() const
{
	return m_currentSystemString;
}


QrfeGlobal::HandlerState QrfeReaderInterface::currentState() const
{
	return m_currentState;
}

QString QrfeReaderInterface::currentStateString() const
{
	return QrfeGlobal::stateToString(m_currentState);
}


QrfeGlobal::HandlerAction QrfeReaderInterface::currentAction() const
{
	return m_currentAction;
}

QString QrfeReaderInterface::currentActionString() const
{
	return QrfeGlobal::actionToString(m_currentAction);
}


qulonglong QrfeReaderInterface::statusRegister() const
{
	return m_statusRegister;
}

QStringList QrfeReaderInterface::statusRegisterBitDescriptions() const
{
	QStringList desc;
	for(uchar i = 0; i < (sizeof(m_statusRegister)*8); i++)
	{
		if( ( (m_statusRegister>>i) & 0x01) != 0)
		{
			QString text = "Bit #" + QString("%1").arg(i, 2, 10, QChar('0'));
			text += " = ";
			text += m_statusRegisterBitDescritption.value(i);
			desc << text;
		}
	}
	desc << statusStrings();
	return desc;
}


ulong QrfeReaderInterface::gpioValues() const
{
	return m_gpioValues;
}


uchar QrfeReaderInterface::antennaCount() const
{
	return m_antennaCount;
}




QString	QrfeReaderInterface::deviceName() const
{
	return m_ph->deviceName();
}

QrfeGlobal::DeviceType QrfeReaderInterface::deviceType() const
{
	return m_ph->deviceType();
}

ulong QrfeReaderInterface::readerCaps () const
{
	return QrfeGlobal::readerCaps(m_readerTypeExact, m_hardwareRevision, m_softwareRevision, m_currentSystem);
}

ulong QrfeReaderInterface::tagFunctionCaps () const
{
	return QrfeGlobal::tagFunctionCaps(m_readerTypeExact, m_hardwareRevision, m_softwareRevision, m_currentSystem);
}


QString QrfeReaderInterface::readerName() const
{
	return m_readerName;
}

QString QrfeReaderInterface::readerLocation() const
{
	return m_readerLocation;
}


QStringList QrfeReaderInterface::statusStrings() const
{
	return QStringList();
}

void QrfeReaderInterface::setState(QrfeGlobal::HandlerState state)
{
	// set state and emit it only if it is different to the state before
	if(m_currentState != state){
		m_currentState = state;

		emit changedState(m_currentState);

		if(m_currentState == QrfeGlobal::STATE_OFFLINE){
			setAction(QrfeGlobal::ACTION_OFFLINE);
			if(!m_ph->deviceRemoved())
				emit lostConnection();
		}
	}
}

void QrfeReaderInterface::setAction(QrfeGlobal::HandlerAction action)
{
	// set state and emit it only if it is different to the state before
	if(m_currentAction != action){
		if(m_currentAction == QrfeGlobal::ACTION_SCANNING && action == QrfeGlobal::ACTION_IDLE)
			emit inventoryStoped();
		else if(action == QrfeGlobal::ACTION_SCANNING && m_currentAction == QrfeGlobal::ACTION_IDLE)
			emit inventoryStarted();
		else if(action == QrfeGlobal::ACTION_OFFLINE)
			emit inventoryStoped();

		m_currentAction = action;
		emit changedAction(m_currentAction);

		// process events so everyone can get the signal
		//qApp->processEvents();
	}
}


void QrfeReaderInterface::destroy()
{
	m_ph->releaseDeviceImmediatly();
	setState(QrfeGlobal::STATE_OFFLINE);
	emit requestForDelete();
}

void QrfeReaderInterface::heartBeatTimeOut()
{
	if(m_deviceInit == false || m_ph->deviceRemoved())
		return;

	if(m_heartBeatHappened)
	{
		trc(4, "HeartBeat Check OK");
		m_heartBeatHappened = false;
		m_heartBeatControl->start();
		return;
	}

	warning("HeartBeat Check ERROR");
	warning(m_readerID + " - Did not receive heartbeat for " + QString::number(m_lastHeartBeat.elapsed()) + "ms -> going offline");

	deviceWasRemoved();
}


void QrfeReaderInterface::deviceWasRemoved()
{
	if(m_deviceRemovalDetected)
		return;
	m_deviceRemovalDetected = true;
	m_ph->deviceWasRemoved();
	m_ph->releaseDeviceImmediatly();
	setState(QrfeGlobal::STATE_OFFLINE);
	emit lostConnection();
}


void QrfeReaderInterface::handleProtocolHandlerError(const QrfeGlobal::Result res)
{
	switch(res) 
	{
	case QrfeGlobal::RES_OK:
	case QrfeGlobal::RES_NA:
		if(m_heartBeatControl->isActive())
			emit resetHeartBeat();
		setState(QrfeGlobal::STATE_ONLINE);
		break;
	case QrfeGlobal::RES_ERROR:
		setState(QrfeGlobal::STATE_ONLINE);
		break;
	case QrfeGlobal::RES_COMMERROR:
		setState(QrfeGlobal::STATE_OFFLINE);
		break;
	case QrfeGlobal::RES_NORESPONSE:
		setState(QrfeGlobal::STATE_NOTRESPONDING);
		break;
	}
}

void QrfeReaderInterface::handleProtocolHandlerState(int state)
{
	QrfeGlobal::ReaderState newState = (QrfeGlobal::ReaderState) state;
	switch(newState)
	{
	case QrfeGlobal::STATE_IDLE:
		setAction(QrfeGlobal::ACTION_IDLE);
		break;
	case QrfeGlobal::STATE_SCANNING:
		setAction(QrfeGlobal::ACTION_SCANNING);
		break;
	case QrfeGlobal::STATE_REBOOTING:
		setState(QrfeGlobal::STATE_OFFLINE);
		break;
	}
}






