#include "CGen2TagReadPerformanceTest.h"

#include <ui_CGen2TagEngineeringDialog.h>
#include <QrfeReaderInterfaceGlobal>
#include <QrfeReaderInterface>
#include <reader/QrfeRfePurReader>
#include <tag/QrfeGen2Tag>
#include <epc/EPC_Defines>

#include <QrfeResourceGlobal>

#include <Cache.h>
#include <def.h>

#include <QMessageBox>
#include <QStandardItemModel>
#include <QFileDialog>
#include <QDir>
#include <QFileInfo>

#include <QrfeSleeper>
#include <QrfeQwt>
#include <QrfeGuiLibGlobal>


CGen2TagReadPerformanceTest::CGen2TagReadPerformanceTest(QTextEdit* infoEdit, QWidget* parent)
	: TagTabWidget(tr("Tag Read Performance Test"), parent)
	, m_parent(parent)
{
	ui.setupUi(this);
	setInfoEdit(infoEdit);

	connect(ui.startFreqSweepButton,	SIGNAL(clicked()),
			this, 						  SLOT(startButtonClicked()));
	connect(ui.exportSweepButton, 		SIGNAL(clicked()),
			this, 						  SLOT(exportResults()));

	connect(ui.attenuationSlider, 			SIGNAL(valueChanged(int)),
			this, 							  SLOT(setAttenuationLabel(int)));

	m_readTestValueModel = new QStandardItemModel(this);
	m_readTestValueModel->setColumnCount(3);
	ui.readTestTableView->setModel(m_readTestValueModel);


	m_measurementActive = false;
	m_continueMeasurement = true;

	m_reader 	= 0;
	m_tag 		= 0;
}


CGen2TagReadPerformanceTest::~CGen2TagReadPerformanceTest()
{

}

bool CGen2TagReadPerformanceTest::init(QrfeReaderInterface* reader, QrfeTagInterface* tag)
{
	if(qobject_cast<QrfeRfePurReader*>(reader) == 0)
		return false;
	else
		m_reader = qobject_cast<QrfeRfePurReader*>(reader);

	if(qobject_cast<QrfeGen2Tag*>(tag) == 0)
		return false;
	else
		m_tag = qobject_cast<QrfeGen2Tag*>(tag);

	ui.progressBar->setValue(0);
	ui.progressBar->setEnabled(false);

	ushort maxAtt = 0, currentAtt = 0;
	if(m_reader->getMaxAttenuation(maxAtt) == QrfeGlobal::RES_OK)
		ui.attenuationSlider->setMaximum(maxAtt);

	if(m_reader->getCurrentAttenuation(currentAtt) == QrfeGlobal::RES_OK){
		ui.attenuationSlider->setValue(currentAtt);
		setAttenuationLabel(currentAtt);
	}

	clearValues();

	ui.exportSweepButton->setEnabled(false);

	m_measurementActive = false;

	return true;
}

void CGen2TagReadPerformanceTest::deinit()
{
	m_reader 	= 0;
	m_tag 		= 0;
}

bool CGen2TagReadPerformanceTest::hasExecutionCount()
{
	return false;
}


void CGen2TagReadPerformanceTest::startButtonClicked()
{
	if(m_measurementActive)
		m_continueMeasurement = false;
	else{
		m_continueMeasurement = true;
		QTimer::singleShot(0, this, SLOT(runPerformanceTest()));
	}
}

void CGen2TagReadPerformanceTest::runPerformanceTest()
{
	if(m_reader == 0 || m_tag == 0 || m_measurementActive)
		return;

	m_measurementActive = true;

	if(m_reader->setAttenuation(ui.attenuationSlider->value()) != QrfeGlobal::RES_OK)
	{
		infoSetError("-- Could not set Attenuation to " + ui.attenuationLabel->text() + " --");

		ushort current;
		if(m_reader->getCurrentAttenuation(current) == QrfeGlobal::RES_OK)
		{
			ui.attenuationSlider->setValue(current);
			infoAppend("-- The current Attenuation is " + ui.attenuationLabel->text() + " --");
			return;
		}
		else
		{
			infoAppend("-- Could not get Attenuation --");
			return;
		}
	}

	if(!ui.accessPasswordEdit->hasAcceptableInput())
	{
		QMessageBox::critical(this, "Error", "The password is not valid!");
		return;
	}

	bool ok = false;
	QByteArray passw = QrfeGlobal::stringToBytes(ui.accessPasswordEdit->text(), &ok);
	if(!ok)
	{
		QMessageBox::critical(this, "Error", "The password is not valid!");
		return;
	}

	uchar 	membank = ui.memBankBox->currentIndex();
	ushort 	address = ui.wordAddressBox->value();
	uchar 	count   = ui.wordCountBox->value() * 2;

	//-------------------------------------------------------------------------------------------
	// Prepare GUI / Disable all parts
	setWorking();
	clearValues();
	clearInfo();

	ui.startFreqSweepButton->setText("Stop");
	ui.startFreqSweepButton->setIcon(QIcon(QrfeGlobal::getButtonIconResourcePath("stop")));

	ui.progressBar->setEnabled(true);
	ui.progressBar->setValue(0);
	ui.progressBar->setMaximum(ui.readCountSpinBox->value());

	ui.exportSweepButton->setEnabled(false);
	ui.attenuationBox->setEnabled(false);
	ui.targetBox->setEnabled(false);
	ui.modeBox->setEnabled(false);

	//-------------------------------------------------------------------------------------------
	// Measurement
	bool result = true;
	QByteArray handle;
	QTime t;

	QTime  	completeTime;
	uint 	okCount = 0;
	uint 	errorCount = 0;

	uint   	timeSum = 0;

	int 	readCount = ui.readCountSpinBox->value();
	int 	readCounter = 0;

	infoAppend("-- Starting measurement  --");

	completeTime.start();

	if(ui.modeComboBox->currentIndex() > 0)
	{
		m_reader->setAntennaPower(true);

		if(ui.modeComboBox->currentIndex() == 2)
		{
			t.start();
			if(!searchForHandle(handle))
			{
				infoSetError("-- Could not get handle --");
				m_reader->setAntennaPower(false);
				m_continueMeasurement = false;
				result = false;
			}
			else
			{
				infoAppend("Got handle after " + QString::number(t.elapsed()) + " ms");
			}
		}
	}

	while(1)
	{
		if(!m_continueMeasurement)
			break;

		QList<QStandardItem*> items;
		items << new QStandardItem(QString("#%1").arg(readCounter+1));

		QByteArray data;

		t.start();
		bool res = false;

		if(ui.modeComboBox->currentIndex() == 0 || ui.modeComboBox->currentIndex() == 1)
		{
			res = readIdBased(membank, address, count, passw, data);
		}
		else if(ui.modeComboBox->currentIndex() == 2)
		{
			res = readHandleBased(handle, membank, address, count, passw, data);
		}
		int time = t.elapsed();
		timeSum += time;

		if(ui.modeComboBox->currentIndex() == 2 && !res)
		{
			searchForHandle(handle);
			infoAppend("Retrieved handle...");
		}

		if(res)
		{
			items << new QStandardItem("OK");
			items.last()->setBackground(Qt::green);
			okCount++;
		}
		else
		{
			items << new QStandardItem("ERROR");
			items.last()->setBackground(Qt::red);
			errorCount++;
		}

		items << new QStandardItem(QString("%1 ms").arg(time));

		items << new QStandardItem(QString::fromLatin1(data.toHex()));
		items.last()->setTextAlignment(Qt::AlignCenter);

		m_readTestValueModel->appendRow(items);

		ui.progressBar->setValue(ui.progressBar->value()+1);

		ui.completeTimeLineEdit->setText(QString("%1 ms").arg(completeTime.elapsed()));
		ui.okCountLineEdit->setText(QString("%1").arg(okCount));
		ui.errorCountLineEdit->setText(QString("%1").arg(errorCount));


		ui.timeSumLineEdit->setText(QString("%1 ms").arg((double)timeSum));
		ui.averageTimeLineEdit->setText(QString("%1 ms").arg((double)timeSum / (double)(readCounter+1)));
		ui.timePerWordLineEdit->setText(QString("%1 bit/s").arg((1000.0 / ((double)timeSum / (double)(readCounter+1))) * ((double)count * 8)));

		ui.readTestTableView->resizeColumnsToContents();
		qApp->processEvents();

		readCounter++;

		if(readCount != 0 && readCounter >= readCount)
			break;
	}

	if(result)
		infoSetOK("-- Measurement ended--");

	m_reader->setAntennaPower(false);

	//-------------------------------------------------------------------------------------------
	// Restore GUI
	ui.progressBar->setValue(0);
	ui.progressBar->setMaximum(1);
	ui.progressBar->setEnabled(false);

	ui.startFreqSweepButton->setText("Start");
	ui.startFreqSweepButton->setIcon(QIcon(QrfeGlobal::getButtonIconResourcePath("start")));

	ui.exportSweepButton->setEnabled(true);
	ui.attenuationBox->setEnabled(true);
	ui.targetBox->setEnabled(true);
	ui.modeBox->setEnabled(true);

	m_measurementActive = false;

	setIdle();
}

void CGen2TagReadPerformanceTest::clearValues()
{
	if(m_reader == 0 || m_tag == 0)
		return;

	m_readTestValueModel->clear();
	m_readTestValueModel->setColumnCount(4);

	m_readTestValueModel->setHorizontalHeaderLabels(QStringList() << tr("Nr") << tr("Result") << tr("Time") << tr("Data"));

	ui.readTestTableView->verticalHeader()->setVisible(false);
	ui.readTestTableView->horizontalHeader()->setStretchLastSection(false);
	ui.readTestTableView->setColumnWidth(0, 50);
	ui.readTestTableView->setColumnWidth(1, 50);
	ui.readTestTableView->setColumnWidth(2, 50);
	ui.readTestTableView->setColumnWidth(3, 300);
}

void CGen2TagReadPerformanceTest::exportResults()
{
	if(m_reader == 0 || m_tag == 0)
		return;

	QString path = Cache::d.value(EXPORT_LAST_USED_FILEPATH, QDir::rootPath()).toString();

	QString prefix;
	prefix = "ReadTest_" + m_tag->tagId() + "_";
	QString fileName = path + "/" + prefix + "Results_" + QDateTime::currentDateTime().toString("yyyy_MM_dd-hh_mm");
	QString outputFileName;

	if(!QrfeGlobal::saveStandardModelToFile(m_readTestValueModel, m_parent, "Save Data to File", fileName, outputFileName))
		return;

	QFileInfo info(outputFileName);
    Cache::d.setValue(EXPORT_LAST_USED_FILEPATH, info.absolutePath());
}


void CGen2TagReadPerformanceTest::setAttenuationLabel ( int value )
{
	ui.attenuationLabel->setText(QString::number(value) + " steps");
}

bool CGen2TagReadPerformanceTest::readIdBased(uchar memBank, ushort wordAddress, uchar wordCount, const QByteArray& passwd, QByteArray& data)
{
	return (m_tag->readFromTag((QrfeGen2Tag::MEMORY_BANK)memBank, wordAddress, passwd, wordCount, data) == QrfeGlobal::TMI_OK);
}


bool CGen2TagReadPerformanceTest::searchForHandle(QByteArray& handle)
{
	if(m_reader->getTagHandle(m_tag->tagId(), handle) != QrfeGlobal::RES_OK)
	{
		infoSetError("-- Could not get Handle of tag --");
		return false;
	}

	return true;
}

bool CGen2TagReadPerformanceTest::readHandleBased(const QByteArray& handle, uchar memBank, ushort wordAddress, uchar wordCount, const QByteArray& passwd, QByteArray& data)
{
	return (m_reader->readFromHandle(handle, memBank, wordAddress, passwd, wordCount, data) == QrfeGlobal::TMI_OK);
}
