/*
 * CGen2TagMinimumPowerMeasurement.cpp
 *
 *  Created on: 05.05.2011
 *      Author: stefan.detter
 */

#include "CGen2TagMinimumPowerMeasurement.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 <QPen>
#include <QMessageBox>
#include <QStandardItemModel>
#include <QFileDialog>
#include <QDir>
#include <QFileInfo>

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

#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_grid.h>
#include <qwt_legend.h>
#include <qwt_symbol.h>


CGen2TagMinimumPowerMeasurement::CGen2TagMinimumPowerMeasurement(QTextEdit* infoEdit, QWidget* parent)
	: TagTabWidget(tr("Minimum Power Measurement"), parent)
	, m_parent(parent)
{
	ui.setupUi(this);
	setInfoEdit(infoEdit);

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

	connect(ui.startFrequencyBox, 		SIGNAL(valueChanged(double)),
			this, 						  SLOT(sweepValuesChanged()));
	connect(ui.stopFrequencyBox,	 	SIGNAL(valueChanged(double)),
			this, 						  SLOT(sweepValuesChanged()));
	connect(ui.stepsFrequencyBox, 		SIGNAL(valueChanged(double)),
			this, 						  SLOT(sweepValuesChanged()));

	connect(ui.refelectedPowerBox,		SIGNAL(toggled(bool)),
			this, 						  SLOT(sweepValuesChanged()));


	m_freqSweepValueModel = new QStandardItemModel(this);
	m_freqSweepValueModel->setColumnCount(3);
	ui.freqSweepTableView->setModel(m_freqSweepValueModel);


	m_freqSweepPlot = new QwtPlot(m_parent);
	m_freqSweepPlot->setAxisTitle(QwtPlot::xBottom, "Frequency (MHz)");
	m_freqSweepPlot->setAxisTitle(QwtPlot::yLeft, "Attenuation (steps)");
	ui.freqSweepPlotLayout->addWidget(m_freqSweepPlot);

	QPen pen;

	pen = QPen(QPen(Qt::red));
	pen.setWidth(2);
	m_reflectedPowerCurve = new QwtPlotCurve("Reflected Power (dBm)");
	m_reflectedPowerCurve->attach(m_freqSweepPlot);
	m_reflectedPowerCurve->setPen(pen);

	pen = QPen(QPen(Qt::green));
	pen.setWidth(2);
	QwtSymbol* sym = new QwtSymbol();
    sym->setStyle(QwtSymbol::Ellipse);
    sym->setPen(QColor(Qt::blue));
    sym->setBrush(QColor(Qt::yellow));
    sym->setSize(10);
	m_minimumPowerCurve = new QwtPlotCurve("First Read @ Attenuation (steps)");
	m_minimumPowerCurve->attach(m_freqSweepPlot);
	m_minimumPowerCurve->setPen(pen);
	m_minimumPowerCurve->setStyle(QwtPlotCurve::Sticks);
	m_minimumPowerCurve->setSymbol(sym);

	QwtPlotGrid* grid = new QwtPlotGrid();
    grid->enableXMin(true);
    grid->enableYMin(true);
    grid->setMajorPen(QPen(Qt::black, 0, Qt::DotLine));
    grid->setMinorPen(QPen(Qt::gray, 0 , Qt::DotLine));
	grid->attach(m_freqSweepPlot);

	m_freqSweepPlot->insertLegend(new QwtLegend(m_parent), QwtPlot::BottomLegend);

	m_measurementActive = false;
	m_continueMeasurement = true;

	m_reader 	= 0;
	m_tag 		= 0;

	License::d->remainingExecutionCount(this, EXEC_COUNT_ENGINEERING_TAG_MINIMUM_POWER);
}

CGen2TagMinimumPowerMeasurement::~CGen2TagMinimumPowerMeasurement()
{
}


bool CGen2TagMinimumPowerMeasurement::init(QrfeReaderInterface* reader, QrfeTagInterface* tag)
{
	m_reader 	= reader;

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

	connect(m_reader, 		SIGNAL(exclusive_cyclicInventory(const QrfeGlobal::TagReadEvent& )),
			this, 			  SLOT(cyclicInventory(const QrfeGlobal::TagReadEvent& )), Qt::DirectConnection );

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

	ushort maxAtt;
	m_reader->getMaxAttenuation(maxAtt);
	ui.startAttenuationBox->setValue(maxAtt);
	ui.startAttenuationBox->setMaximum(maxAtt);
	ui.stopAttenuationBox->setMaximum(maxAtt);
	ui.stepsAttenuationBox->setMaximum(maxAtt);
	ui.rfpAttenuationBox->setMaximum(maxAtt);

	clearValues();
	sweepValuesChanged();

	ui.exportSweepButton->setEnabled(false);

	m_measurementActive = false;

	reloadLicenseData();

	return true;
}

void CGen2TagMinimumPowerMeasurement::deinit()
{
	disconnect(	m_reader, 		SIGNAL(exclusive_cyclicInventory(const QrfeGlobal::TagReadEvent& )),
				this, 			  SLOT(cyclicInventory(const QrfeGlobal::TagReadEvent& )) );

	m_reader 	= 0;
	m_tag 		= 0;
}

bool CGen2TagMinimumPowerMeasurement::hasExecutionCount()
{
//	if(!License::d->hasLicense(QrfeLicense::ReaderSuite_EngineeringLicense))
//		return true;
	return false;
}


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

void CGen2TagMinimumPowerMeasurement::runFrequencySweep()
{
	if(m_reader == 0 || m_tag == 0 || m_measurementActive)
		return;

	m_measurementActive = true;

	//-------------------------------------------------------------------------------------------
	// Get and Check Input Values

	ulong startFreq = ui.startFrequencyBox->value() * 1000;
	ulong stopFreq = ui.stopFrequencyBox->value() * 1000;
	ulong stepsFreq = ui.stepsFrequencyBox->value() * 1000;

	ushort startAtt = ui.startAttenuationBox->value();
	ushort stopAtt = ui.stopAttenuationBox->value();
	ushort stepsAtt = ui.stepsAttenuationBox->value();
	int timeoutAtt = ui.timeoutAttenuationBox->value();

	ushort rfpAtt = ui.rfpAttenuationBox->value();
	ushort rfpTimeout = ui.rfpTimeoutBox->value();
	uint generalSteps = (stopFreq - startFreq) / stepsFreq;
	generalSteps++;

	if(stopFreq < startFreq)
	{
		QMessageBox::critical(m_parent, "Error", "The start frequency value for the sweep must be lower than the stop frequency value!");
		m_measurementActive = false;
		return;
	}

	if(startAtt < stopAtt)
	{
		QMessageBox::critical(m_parent, "Error", "The start attenuation value for the sweep must be higher than the stop attenuation value!");
		m_measurementActive = false;
		return;
	}

	//-------------------------------------------------------------------------------------------
	// Prepare GUI / Disable all parts
	License::d->decrementExecutionCount(this);
	setWorking();
	clearValues();
	clearInfo();

	ui.exportSweepButton->setEnabled(false);
	ui.frequencyBox->setEnabled(false);
	ui.minimumPowerBox->setEnabled(false);
	ui.refelectedPowerBox->setEnabled(false);

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

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

	//-------------------------------------------------------------------------------------------
	// Measurement

	QVector<double> attVals;
	QVector<double> rfpVals;
	QVector<double> freqs;

	infoAppend("-- Starting measurement  --");
	for(ulong freq = startFreq; freq <= stopFreq; freq += stepsFreq)
	{
		if(!m_continueMeasurement)
			break;

		QList<QStandardItem*> items;
		items << new QStandardItem(QString("%1").arg(((double)freq)/1000.0));

		freqs.append(((double)freq) / 1000.0);

		ushort maxAtt;
		measureMinimumPower(freq, startAtt, stopAtt, stepsAtt, timeoutAtt, maxAtt);
		if(maxAtt != 0xFFFF)
		{
			items << new QStandardItem(QString("%1").arg(maxAtt));
			attVals.append(maxAtt);
		}
		else
		{
			items << new QStandardItem(QString("--"));
			attVals.append(-1);
		}
		m_minimumPowerCurve->setSamples(freqs.data(), attVals.data(), freqs.size());


		if(ui.refelectedPowerBox->isChecked())
		{
			double dBm, ival, qval;
			measureReflectedPowerValue(freq, rfpTimeout, rfpAtt, dBm, ival, qval);
			rfpVals.append(dBm);
			m_reflectedPowerCurve->setSamples(freqs.data(), rfpVals.data(), freqs.size());
			items << new QStandardItem(QString("%1").arg((int)dBm));
		}
		else
		{
			items << new QStandardItem(QString("--"));
		}

		m_freqSweepValueModel->appendRow(items);
		m_freqSweepPlot->replot();

		ui.progressBar->setValue(ui.progressBar->value()+1);
		qApp->processEvents();
	}
	infoSetOK("-- Measurement ended--");

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

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

	ui.exportSweepButton->setEnabled(true);
	ui.frequencyBox->setEnabled(true);
	ui.minimumPowerBox->setEnabled(true);
	ui.refelectedPowerBox->setEnabled(true);

	m_measurementActive = false;

	setIdle();
	reloadLicenseData();
}

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

	m_reflectedPowerCurve->setSamples(0, 0, 0);
	m_reflectedPowerCurve->show();
	m_minimumPowerCurve->setSamples(0, 0, 0);
	m_minimumPowerCurve->show();
	m_freqSweepPlot->replot();

	m_freqSweepValueModel->clear();
	m_freqSweepValueModel->setColumnCount(3);

	m_freqSweepValueModel->setHorizontalHeaderLabels(QStringList() << tr("Frequency (MHz)") << tr("Max Attenuation\n(steps)") << tr("Reflected Power\n(dBm)"));

	ui.freqSweepTableView->verticalHeader()->setVisible(false);
	ui.freqSweepTableView->horizontalHeader()->setStretchLastSection(false);
	ui.freqSweepTableView->resizeColumnsToContents();
}

void CGen2TagMinimumPowerMeasurement::sweepValuesChanged ( )
{
	if(m_reader == 0 || m_tag == 0)
		return;

	m_freqSweepPlot->setAxisScale(2, 	ui.startFrequencyBox->value(),
										ui.stopFrequencyBox->value());

	if(ui.refelectedPowerBox->isChecked())
		m_freqSweepPlot->setAxisAutoScale(0);
	else
		m_freqSweepPlot->setAxisScale(0, ui.stopAttenuationBox->value(), ui.startAttenuationBox->value());

	m_freqSweepPlot->updateAxes();
	m_freqSweepPlot->replot();

	m_freqSweepValueModel->clear();
	m_freqSweepValueModel->setColumnCount(3);

	m_freqSweepValueModel->setHorizontalHeaderLabels(QStringList() << tr("Frequency (MHz)") << tr("Max Attenuation\n(steps)") << tr("Reflected Power\n(dBm)"));

	ui.freqSweepTableView->verticalHeader()->setVisible(false);
	ui.freqSweepTableView->horizontalHeader()->setStretchLastSection(false);
	ui.freqSweepTableView->resizeColumnsToContents();

}


void CGen2TagMinimumPowerMeasurement::measureReflectedPowerValue(ulong freq, ushort time, ushort att, double &dBm, double &ival, double &qval)
{
	if(m_reader == 0 || m_tag == 0)
		return;

	dBm = ival = qval = 0.0;

	char chI, chQ;
	uchar G;

	infoSet("Measuring reflected power");

	if(m_reader->setAttenuation(att) != QrfeGlobal::RES_OK)
	{
		infoAppend("Could not set attenuation.");
		showNOK();
		return;
	}
	else
	{
		infoAppend("-- Attenuation set to " + QString::number(att) + "steps --");
		showOK();
	}

	QrfeRfePurReader* reader = qobject_cast<QrfeRfePurReader*>(m_reader);
	if( reader == 0 )
		return;

	QrfeGlobal::Result res = reader->measureReflectedPower(freq, time, chI, chQ, G);
	if(res == QrfeGlobal::RES_OK)	{
		double offset = 20*log10(0.5/G);
		if(offset < 0)
			offset *= -1;

		ival = chI;
		qval = chQ;
		dBm = sqrt( (ival*ival) + (qval*qval) );
		if (dBm == 0)
			dBm = 0.5;
		dBm = 20*log10(dBm/G);
	}
}

void CGen2TagMinimumPowerMeasurement::measureMinimumPower(ulong freq, ushort startAtt, ushort stopAtt, ushort stepsAtt, int timeout, ushort& maxAtt)
{
	if(m_reader == 0 || m_tag == 0)
		return;

	infoSet("Measuring minimum power");

	if(m_reader->setFrequency(0, QList<uint>() << freq) != QrfeGlobal::RES_OK)
	{
		infoAppend("Could not set frequency to " + QString::number(freq) + "kHz");
		showNOK();
		maxAtt = 0xFFFF;
		return;
	}
	else
	{
		infoAppend("-- Frequency set to " + QString::number(freq) + "kHz --");
		showOK();
	}

	for(maxAtt = startAtt; maxAtt >= stopAtt;  maxAtt -= stepsAtt)
	{
		if(maxAtt > startAtt)
			break;

		if(m_reader->setAttenuation(maxAtt) != QrfeGlobal::RES_OK)
		{
			infoAppend("Could not set attenuation to " + QString::number(maxAtt) + "steps --");
			showNOK();
			break;
		}
		else
		{
			infoAppend("-- Attenuation set to " + QString::number(maxAtt) + "steps --");
			showOK();
		}

		m_tagList.clear();

		m_reader->startCyclicInventory();

		QrfeSleeper::MSleepAlive(timeout);

		m_reader->stopCyclicInventory();

		if(m_tagList.contains(m_tag->tagId()) )
		{
			infoAppend("->  Tag detected");
			showOK();
			return;
		}

		qApp->processEvents();
	}

	maxAtt = 0xFFFF;
	return;
}

void CGen2TagMinimumPowerMeasurement::cyclicInventory(const QrfeGlobal::TagReadEvent& tag)
{
	if(m_reader == 0 || m_tag == 0)
		return;

	m_tagList << tag.tagId;
}


void CGen2TagMinimumPowerMeasurement::exportSweepResults()
{
	if(m_reader == 0 || m_tag == 0)
		return;

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

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

	if(ui.tabWidget->currentIndex() == 0)
	{
		if(!QrfeQwt::savePlotToFile(m_freqSweepPlot, m_parent, "Save Plot to File", fileName, outputFileName))
			return;
	}
	else
	{
		if(!QrfeGlobal::saveStandardModelToFile(m_freqSweepValueModel, m_parent, "Save Data to File", fileName, outputFileName))
			return;
	}

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


void CGen2TagMinimumPowerMeasurement::reloadLicenseData()
{
    ui.startFreqSweepButton->setEnabled(true);
    ui.exportSweepButton->setEnabled(true);
}

