#include "CRfePurFrequencySweepMeasurement.h"

#include <QDir>
#include <QStandardItemModel>
#include <QMessageBox>

#include <QrfeQwt>
#include <QrfeGuiLibGlobal>
#include <QrfeResourceGlobal>


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

#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_picker.h>
#include <qwt_picker.h>
#include <qwt_picker_machine.h>
#include <qwt_legend.h>

#include <reader/QrfeRfePurReader>
#include <as399x/AS399X_Defines.h>

#define CACHE_HEADER		QString("ReaderSettings - CRfePurFrequencySweepMeasurement - ")


CRfePurFrequencySweepMeasurement::CRfePurFrequencySweepMeasurement(QTextEdit* infoEdit, QWidget* parent)
    : ReaderTabWidget(tr("Frequency Sweep Measurement"), parent)
    , m_reader(0)
{
	ui.setupUi(this);
	setInfoEdit(infoEdit);

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

	connect(ui.freqSweepComboBox, 			SIGNAL(currentIndexChanged(int)), 
			this, 							  SLOT(sweepMethodChanged()));
	connect(ui.freqSweepStartSpinBox, 		SIGNAL(valueChanged(double)),
			this, 							  SLOT(sweepMeasurementValuesChanged()));
	connect(ui.freqSweepStopSpinBox, 		SIGNAL(valueChanged(double)),
			this, 							  SLOT(sweepMeasurementValuesChanged()));
	connect(ui.freqSweepStepSpinBox, 		SIGNAL(valueChanged(double)),
			this, 							  SLOT(sweepMeasurementValuesChanged()));

	connect(ui.attenuationSlider, 			SIGNAL(valueChanged(int)),
			this, 							  SLOT(setAttenuationLabel(int)));
	connect(ui.maxHoldCheckBox, 			SIGNAL(toggled(bool)),
			this, 							  SLOT(showMaxHold(bool)));
	connect(ui.loopBox,			 			SIGNAL(toggled(bool)),
			this, 							  SLOT(showLoopUsed(bool)));

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

	m_freqSweepPlot = new QwtPlot(this);
	ui.freqSweepPlotLayout->addWidget(m_freqSweepPlot);

	QPen pen;

	pen = QPen(Qt::red);
	pen.setWidthF(2);
	m_freqSweepdBmCurve = new QwtPlotCurve("RSSI Value (dBm)");
	m_freqSweepdBmCurve->attach(m_freqSweepPlot);
	m_freqSweepdBmCurve->setPen(pen);

	pen = QPen(Qt::darkCyan);
	pen.setWidthF(1.8);
	m_freqSweepdBmMaxCurve = new QwtPlotCurve("Max RSSI Value (dBm)");
	m_freqSweepdBmMaxCurve->attach(m_freqSweepPlot);
	m_freqSweepdBmMaxCurve->setPen(pen);

	pen = QPen(Qt::darkBlue);
	pen.setStyle(Qt::DashDotLine);
	pen.setWidthF(1.2);
	m_freqSweepRawICurve = new QwtPlotCurve("Channel I RSSI Level (dBm)");
	m_freqSweepRawICurve->attach(m_freqSweepPlot);
	m_freqSweepRawICurve->setPen(pen);

	pen = QPen(Qt::darkRed);
	pen.setStyle(Qt::DashLine);
	pen.setWidthF(1);
	m_freqSweepRawQCurve = new QwtPlotCurve("Channel Q RSSI Level (dBm)");
	m_freqSweepRawQCurve->attach(m_freqSweepPlot);
	m_freqSweepRawQCurve->setPen(pen);

    m_picker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft, QwtPlotPicker::CrossRubberBand, QwtPicker::ActiveOnly, m_freqSweepPlot->canvas());
    m_picker->setStateMachine(new QwtPickerDragPointMachine());
    m_picker->setRubberBandPen(QColor(Qt::darkGreen));
    m_picker->setRubberBand(QwtPicker::CrossRubberBand);
    m_picker->setTrackerPen(QColor(Qt::black));

	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(this), QwtPlot::BottomLegend);

	m_measurementActive = false;
	m_continueMeasurement = true;

	m_reader 	= 0;

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

CRfePurFrequencySweepMeasurement::~CRfePurFrequencySweepMeasurement()
{

}


bool CRfePurFrequencySweepMeasurement::init(QrfeReaderInterface* reader)
{
	m_reader = qobject_cast<QrfeRfePurReader*>(reader);
	if( m_reader == 0 )
		return 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);
	}

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

	clearInfo();
	sweepMethodChanged();
	sweepMeasurementValuesChanged();

	ui.antennaGroupBox->setEnabled(true);
	ui.antennaComboBox->clear();
	for(int i = 0; i < m_reader->antennaCount(); i++)
	{
		ui.antennaComboBox->addItem("Antenna #" + QString::number(i+1));
	}
	ui.antennaComboBox->setCurrentIndex(0);

	m_measurementActive = false;

	reloadLicenseData();
    loadValuesFromCache();

	return true;
}

void CRfePurFrequencySweepMeasurement::deinit()
{
	m_reader 	= 0;
}

void CRfePurFrequencySweepMeasurement::activated()
{
	if(m_reader == 0)
		return;

	ushort currentAtt;
	if(m_reader->getCurrentAttenuation(currentAtt) == QrfeGlobal::RES_OK)
	{
		ui.attenuationSlider->setValue(currentAtt);
		setAttenuationLabel(currentAtt);
		infoSet("-- The current Attenuation is " + ui.attenuationLabel->text() + " --");
	}
	else
	{
		infoSet("-- Could not read current attenuation --");
		showNOK();
		return;
	}

	showOK();
}

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


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

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

	m_measurementActive = true;

	clearInfo();

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

	ulong startFreq = ui.freqSweepStartSpinBox->value() * 1000;
	ulong stopFreq = ui.freqSweepStopSpinBox->value() * 1000;
	ulong stepsFreq = ui.freqSweepStepSpinBox->value() * 1000;
	ushort timeout = ui.timeoutBox->value();

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

	if(m_reader->setWorkingAntenna(ui.antennaComboBox->currentIndex() + 1) != QrfeGlobal::RES_OK)
	{
		infoSetError("-- Could not select " + ui.antennaComboBox->currentText() + " --");
		return;
	}
	else
		infoAppend("-- Selected " + ui.antennaComboBox->currentText() + " --");


	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() + " --");
		}
		else
		{
			infoAppend("-- Could not get Attenuation --");
			return;
		}
	}

	if(m_reader->getCurrentSensitivity(m_sensitivity) != QrfeGlobal::RES_OK)
	{
		infoSetError("-- Could not get Sensitivity --");
		return;
	}

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

	sweepMethodChanged();
	sweepMeasurementValuesChanged();

	ui.exportSweepButton->setEnabled(false);
	ui.measureTypeBox->setEnabled(false);
	ui.frequencyBox->setEnabled(false);
	ui.attenuationBox->setEnabled(false);
	ui.timeoutGroupBox->setEnabled(false);
	ui.antennaGroupBox->setEnabled(false);
	ui.loopBox->setEnabled(false);
	ui.maxHoldBox->setEnabled(false);

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

	int steps = (stopFreq - startFreq) / stepsFreq;
	steps++;
	ui.progressBar->setEnabled(true);
	ui.progressBar->setValue(0);
	ui.progressBar->setMaximum(steps);

	//-------------------------------------------------------------------------------------------
	// Measurement
	m_maxHoldVals.clear();
	m_maxHoldFreqs.clear();

	do
	{
		clearDynamicSweepValues();

		QVector<double> freqs;
		QVector<double> ivals;
		QVector<double> qvals;
		QVector<double> svals;

		int i = 0;

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

			double dBm, ival, qval;

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

			if(ui.freqSweepComboBox->currentIndex() == 0)
				measureRssiSweep(freq, timeout, dBm, ival, qval);
			else
				measureRfpSweep(freq, timeout, dBm, ival, qval);

			items << new QStandardItem(QString("%1").arg((int)dBm));
			items << new QStandardItem(QString("%1").arg((int)ival));
			items << new QStandardItem(QString("%1").arg((int)qval));

			m_freqSweepValueModel->appendRow(items);

			freqs.append(((double)freq) / 1000.0);
			qvals.append(qval);
			ivals.append(ival);
			svals.append(dBm);

			if(svals.size() > m_maxHoldVals.size())
				m_maxHoldVals.append(dBm);
			else if(dBm > m_maxHoldVals.at(i))
				m_maxHoldVals[i] = dBm;

			if(freqs.size() > m_maxHoldFreqs.size())
				m_maxHoldFreqs.append(((double)freq) / 1000.0);

			i++;

			m_freqSweepdBmMaxCurve->setSamples(m_maxHoldFreqs.data(), m_maxHoldVals.data(), m_maxHoldFreqs.size());
			m_freqSweepdBmCurve->setSamples(freqs.data(), svals.data(), freqs.size());
			m_freqSweepRawQCurve->setSamples(freqs.data(), qvals.data(), freqs.size());
			m_freqSweepRawICurve->setSamples(freqs.data(), ivals.data(), freqs.size());
			m_freqSweepPlot->replot();

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

	} while(ui.loopBox->isChecked() && m_continueMeasurement);

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

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

	ui.measureTypeBox->setEnabled(true);
	ui.frequencyBox->setEnabled(true);
	ui.attenuationBox->setEnabled(true);
	ui.exportSweepButton->setEnabled(true);
	ui.timeoutGroupBox->setEnabled(true);
	ui.antennaGroupBox->setEnabled(true);
	ui.loopBox->setEnabled(true);
	ui.maxHoldBox->setEnabled(ui.loopBox->isChecked());


	m_measurementActive = false;

	setIdle();
	reloadLicenseData();
}

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

	QString prefix;
	if(ui.freqSweepComboBox->currentIndex() == 0)
		prefix = "RSSI_";
	else
		prefix = "RFP_";
	QString fileName = path + "/" + prefix + "Results_" + QDateTime::currentDateTime().toString("yyyy_MM_dd-hh_mm");
	QString outputFileName;

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

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


void CRfePurFrequencySweepMeasurement::measureRssiSweep(ulong freq, ushort time, double &dBm, double &ival, double &qval)
{
	char rssi = 0;
	uchar rawQ = 0, rawI = 0;

	m_reader->measureRSSILevels(freq, time, rawQ, rawI, rssi);

	if(rssi == -128)
		rssi = m_sensitivity;

	dBm = (double) rssi;
	ival = (double) rawI;
	qval = (double) rawQ;
}

void CRfePurFrequencySweepMeasurement::measureRfpSweep(ulong freq, ushort time, double &dBm, double &ival, double &qval)
{
	dBm = ival = qval = 0.0;

	char chI, chQ;
	uchar G;
	QrfeGlobal::Result res = m_reader->measureReflectedPower(freq, time, chI, chQ, G);
	if(res == QrfeGlobal::RES_OK)
	{
		showOK();
		infoAppend("-- Measured for frequency " + QString::number(freq) + " the values " + QString::number(chI) + ", " + QString::number(chQ) + " with G=" + QString::number(G) + " --");

		if(G != 0)
		{
			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 CRfePurFrequencySweepMeasurement::setAttenuationLabel ( int value )
{
	ui.attenuationLabel->setText(QString::number(value) + " steps");
}

void CRfePurFrequencySweepMeasurement::showMaxHold ( bool /*on*/ )
{
	sweepMethodChanged();
}

void CRfePurFrequencySweepMeasurement::showLoopUsed ( bool /*on*/ )
{
	sweepMethodChanged();
}


void CRfePurFrequencySweepMeasurement::clearAllSweepValues ( )
{
	m_freqSweepdBmMaxCurve->setSamples(0, 0, 0);
	m_freqSweepdBmMaxCurve->show();

	clearDynamicSweepValues();
}

void CRfePurFrequencySweepMeasurement::clearDynamicSweepValues ( )
{
	m_freqSweepdBmCurve->setSamples(0, 0, 0);
	m_freqSweepdBmCurve->show();

	m_freqSweepRawICurve->setSamples(0, 0, 0);
	m_freqSweepRawICurve->show();

	m_freqSweepRawQCurve->setSamples(0, 0, 0);
	m_freqSweepRawQCurve->show();

	m_freqSweepPlot->replot();
}

void CRfePurFrequencySweepMeasurement::sweepMeasurementValuesChanged ( )
{
	m_freqSweepPlot->setAxisScale(2, 	ui.freqSweepStartSpinBox->value(),
										ui.freqSweepStopSpinBox->value());

	m_freqSweepPlot->setAxisAutoScale(0);

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

void CRfePurFrequencySweepMeasurement::sweepMethodChanged()
{
	clearAllSweepValues();

	ui.exportSweepButton->setEnabled(false);
	m_freqSweepValueModel->clear();
	m_freqSweepValueModel->setColumnCount(4);
	m_freqSweepPlot->setAxisTitle(QwtPlot::xBottom, "Frequency (MHz)");

	if(ui.freqSweepComboBox->currentIndex() == 0)
	{
		m_freqSweepValueModel->setHorizontalHeaderLabels(QStringList() << tr("Frequency (MHz)") << tr("RSSI Value\n(dBm)") << tr("Channel I RSSI\nLevel (dB)") << tr("Channel Q RSSI\nLevel (dB)"));

		if(ui.maxHoldCheckBox->isChecked() && ui.loopBox->isChecked())
		{
			m_freqSweepdBmMaxCurve->show();
			m_freqSweepdBmMaxCurve->attach(m_freqSweepPlot);
		}
		else
		{
			m_freqSweepdBmMaxCurve->detach();
			m_freqSweepdBmMaxCurve->hide();
		}

		m_freqSweepdBmCurve->setTitle(tr("RSSI Value (dBm)"));
		m_freqSweepRawICurve->setTitle(tr("Channel I RSSI Level (dB)"));
		m_freqSweepRawQCurve->setTitle(tr("Channel Q RSSI Level (dB)"));
		m_freqSweepPlot->setAxisTitle(QwtPlot::yLeft, "RSSI Value (dBm)");

		ui.attenuationBox->setVisible(false);
		ui.maxHoldBox->setVisible(true);

		ui.maxHoldBox->setEnabled(ui.loopBox->isChecked());
	}
	else
	{
		m_freqSweepValueModel->setHorizontalHeaderLabels(QStringList() << tr("Frequency (MHz)") << tr("Reflected Power\n(dBm)") << tr("Channel I rfp\nLevel (dB)") << tr("Channel Q rfp\nLevel (dB)"));

		m_freqSweepdBmMaxCurve->detach();

		m_freqSweepdBmCurve->setTitle(tr("Reflected Power (dBm)"));
		m_freqSweepRawICurve->setTitle(tr("Channel I rfp Level (dB)"));
		m_freqSweepRawQCurve->setTitle(tr("Channel Q rfp Level (dB)"));
		m_freqSweepPlot->setAxisTitle(QwtPlot::yLeft, "Reflected Power (dBm)");

		ui.attenuationBox->setVisible(true);
		ui.maxHoldBox->setVisible(false);
	}

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


void CRfePurFrequencySweepMeasurement::loadValuesFromCache()
{
    ui.freqSweepComboBox->setCurrentIndex( Cache::d.value(CACHE_HEADER + "MeasureType", 1).toUInt() );
    ui.freqSweepStartSpinBox->setValue( Cache::d.value(CACHE_HEADER + "StartFrequ", 850.0).toDouble() );
    ui.freqSweepStopSpinBox->setValue( Cache::d.value(CACHE_HEADER + "StopFrequ", 950.0).toDouble() );
    ui.freqSweepStepSpinBox->setValue( Cache::d.value(CACHE_HEADER + "StepFrequ", 1).toDouble() );
    ui.timeoutBox->setValue( Cache::d.value(CACHE_HEADER + "Timeout", 1).toUInt() );
    ui.attenuationSlider->setValue( Cache::d.value(CACHE_HEADER + "Attenuation", 19).toUInt() );
    ui.antennaComboBox->setCurrentIndex( Cache::d.value(CACHE_HEADER + "Antenna", 0).toUInt() );
}

void CRfePurFrequencySweepMeasurement::saveValuesToCache()
{
    Cache::d.setValue(CACHE_HEADER + "MeasureType", ui.freqSweepComboBox->currentIndex());
    Cache::d.setValue(CACHE_HEADER + "StartFrequ", ui.freqSweepStartSpinBox->value() );
    Cache::d.setValue(CACHE_HEADER + "StopFrequ", ui.freqSweepStopSpinBox->value() );
    Cache::d.setValue(CACHE_HEADER + "StepFrequ", ui.freqSweepStepSpinBox->value() );
    Cache::d.setValue(CACHE_HEADER + "Timeout", ui.timeoutBox->value() );
    Cache::d.setValue(CACHE_HEADER + "Attenuation", ui.attenuationSlider->value() );
    Cache::d.setValue(CACHE_HEADER + "Antenna", ui.antennaComboBox->currentIndex() );
}

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