#include "CRfePurNetworkAnalyzer.h"

#include <QStandardItemModel>
#include <QWizard>
#include <QWizardPage>
#include <QMessageBox>
#include <QDir>
#include <QFileInfo>
#include <QPainter>
#include <QFileDialog>

#include <QrfeMathGlobal.h>
#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 <qwt_painter.h>
#include <qwt_symbol.h>

#include <reader/QrfeRfePurReader>

#define MIN_Y_AMPL 		-20
#define MIN_AMPLITUDE	-50

#define CALIBRATION_MAGIC_NUMBER		0x45665312

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


class SmithBackgroundImage: public QwtPlotItem
{
	CRfePurNetworkAnalyzer* 	m_parent;
	QPixmap						m_pixmapOrigin;

	static QRect		_pixmapRect;
	static QPixmap*		_pixmap;
	static QRectF		_canvasRect;

public:
	SmithBackgroundImage(CRfePurNetworkAnalyzer* parent)
		: m_parent(parent)
	{
		setZ(0.0);
		m_pixmapOrigin = QPixmap(":/pictures/networkAnalyzer/smithChart");
		if(!_pixmap)
			_pixmap = new QPixmap();
	}
	
	virtual int rtti() const
	{
		return QwtPlotItem::Rtti_PlotUserItem + 1;
	}

	virtual void draw (QPainter *painter, const QwtScaleMap &/*xMap*/, const QwtScaleMap &/*yMap*/, const QRectF &canvasRect) const
	{
		if(_canvasRect != canvasRect)
		{
			_canvasRect = QRectF(canvasRect.topLeft(), canvasRect.size() );

			int min = qMin(canvasRect.width(), canvasRect.height());
			
			(*_pixmap) = m_pixmapOrigin.scaled(min, min, Qt::KeepAspectRatio, Qt::SmoothTransformation);

			QPoint center = canvasRect.center().toPoint();
			QPoint topLeft ( center.x() - (min/2), center.y() - (min/2) );

			_pixmapRect = QRect(topLeft, QSize(min, min) );
		}

		QwtPainter::drawPixmap(painter, _pixmapRect, *_pixmap);
	}
};

QRect		SmithBackgroundImage::_pixmapRect;
QPixmap*	SmithBackgroundImage::_pixmap = 0;
QRectF		SmithBackgroundImage::_canvasRect;


CRfePurNetworkAnalyzer::CRfePurNetworkAnalyzer(QTextEdit* infoEdit, QWidget* parent)
	: ReaderTabWidget(tr("Network Analyzer"), parent)
    , m_reader(0)
{
	ui.setupUi(this);
	setInfoEdit(infoEdit);

	connect(ui.runCalibrationButton,	SIGNAL(clicked()),
			this, 						  SLOT(calibrateButtonClicked()));
	connect(ui.loadCalibrationButton,	SIGNAL(clicked()),
			this, 						  SLOT(loadCalibration()));
	connect(ui.startButton,				SIGNAL(clicked()),
			this, 						  SLOT(startButtonClicked()));
	connect(ui.exportButton, 			SIGNAL(clicked()),
			this, 						  SLOT(exportButtonClicked()));

	connect(ui.freqSweepStartSpinBox, 	SIGNAL(valueChanged ( double )),
			this, 						  SLOT(inputParametersChanged()) );
	connect(ui.freqSweepStopSpinBox, 	SIGNAL(valueChanged ( double )),
			this, 						  SLOT(inputParametersChanged()) );
	connect(ui.freqSweepStepSpinBox, 	SIGNAL(valueChanged ( double )),
			this, 						  SLOT(inputParametersChanged()) );
	connect(ui.timeoutBox,			 	SIGNAL(valueChanged ( int )),
			this, 						  SLOT(inputParametersChanged()) );
	connect(ui.antennaComboBox,		 	SIGNAL(currentIndexChanged ( int )),
			this, 						  SLOT(inputParametersChanged()) );

	connect(ui.tabWidget, 				SIGNAL(currentChanged(int)),
			this, 						  SLOT(rescaleSmithPlot()));

	m_dataModel = new QStandardItemModel(this);
	m_dataModel->setColumnCount(4);
	ui.tableView->setModel(m_dataModel);

	m_measurementActive = false;
	m_continueMeasurement = true;

	m_reader 	= 0;

	createCalibrateWizard();
	createAmplitudePlot();
	createSmithPlot();

	m_dataModel = new QStandardItemModel(this);
	ui.tableView->setModel(m_dataModel);
	m_dataModel->setColumnCount(5);
	m_dataModel->setHorizontalHeaderLabels(QStringList() << tr("Frequency (MHz)") << tr("Reflected Power\n(dB)") << tr("Phase\n(Rad)") << tr("Reflection\nCoefficent") << tr("Impedance"));

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

CRfePurNetworkAnalyzer::~CRfePurNetworkAnalyzer()
{
}

bool CRfePurNetworkAnalyzer::init(QrfeReaderInterface* reader)
{
	m_reader = qobject_cast<QrfeRfePurReader*>(reader);
	if( m_reader == 0 )
		return false;

	m_maxAttenuation = 19;
	m_reader->getMaxAttenuation(m_maxAttenuation);

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

	clearInfo();

	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_calibrated = false;
	m_dataToExport = false;

	m_measurementActive = false;

	reloadLicenseData();
    loadValuesFromCache();

	return true;
}

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

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

	showOK();
}

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


void CRfePurNetworkAnalyzer::saveCalibration()
{
	if(!m_calibrated)
	{
		QMessageBox::critical(this, tr("Error"), tr("No Calibration can be saved."));
		return;
	}

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

	QString fileName = path + "/NetworkAnalyzer_Calibration_[" + QDateTime::currentDateTime().toString("yyyy_MM_dd-hh_mm") + "]_Reader_[" + m_reader->readerId() + "]";

	QString outputFileName = QFileDialog::getSaveFileName(this, tr("Save Calibration"), fileName, tr("Calibration-File (*.rfecal)"));

	if(outputFileName.isNull())
		return;

	QFile file(outputFileName);

	if(!file.open(QIODevice::WriteOnly))
	{
		QMessageBox::critical(this, tr("Error"), tr("Could not open file."));
		return;
	}

	QDataStream stream(&file);

	stream << (uint)CALIBRATION_MAGIC_NUMBER;
	stream << m_calibration.frequencyStart;
	stream << m_calibration.frequencyStop;
	stream << m_calibration.frequencyStep;
	stream << m_calibration.frequencies;
	stream << m_calibration.timeout;
	stream << m_calibration.antenna;
	stream << m_calibration.err1;
	stream << m_calibration.err2;
	stream << m_calibration.err3;

	file.close();

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

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

	QString outputFileName = QFileDialog::getOpenFileName(this, tr("Load Calibration"), path, tr("Calibration-File (*.rfecal)"));

	if(outputFileName.isNull())
		return;

	QFile file(outputFileName);

	if(!file.open(QIODevice::ReadOnly))
	{
		QMessageBox::critical(this, tr("Error"), tr("Could not open file."));
		return;
	}

	QDataStream stream(&file);

	uint magicNr;
	stream >> magicNr;
	if(magicNr != CALIBRATION_MAGIC_NUMBER)
	{
		QMessageBox::critical(this, tr("Error"), tr("File is not valid. ERR: Identifier"));
		return;
	}

	CALIBRATION calib;
	stream >> calib.frequencyStart;
	stream >> calib.frequencyStop;
	stream >> calib.frequencyStep;
	stream >> calib.frequencies;
	stream >> calib.timeout;
	stream >> calib.antenna;
	stream >> calib.err1;
	stream >> calib.err2;
	stream >> calib.err3;

	if(calib.frequencies.size() != calib.err1.size() || calib.frequencies.size() != calib.err2.size() || calib.frequencies.size() != calib.err3.size())
	{
		QMessageBox::critical(this, tr("Error"), tr("File is not valid. ERR: Vector"));
		return;
	}

	if(calib.antenna >= ui.antennaComboBox->count())
	{
		QMessageBox::critical(this, tr("Error"), tr("File is not valid. ERR: Antenna"));
		return;
	}

	m_calibration = calib;
	ui.freqSweepStartSpinBox->setValue(m_calibration.frequencyStart);
	ui.freqSweepStopSpinBox->setValue(m_calibration.frequencyStop);
	ui.freqSweepStepSpinBox->setValue(m_calibration.frequencyStep);
	ui.antennaComboBox->setCurrentIndex(m_calibration.antenna);
	ui.timeoutBox->setValue(m_calibration.timeout);
	m_calibrated = true;
	m_measurementActive = false;

	reloadMarkerList();

	QMessageBox::information(this, tr("Load"), tr("Calibration loaded successfully."));

	reloadLicenseData();
}

void CRfePurNetworkAnalyzer::calibrateButtonClicked()
{
	if(m_reader == 0 || m_measurementActive)
		return;

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

	double startFreq = ui.freqSweepStartSpinBox->value();
	double stopFreq = ui.freqSweepStopSpinBox->value();
	double stepsFreq = ui.freqSweepStepSpinBox->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(m_maxAttenuation) != QrfeGlobal::RES_OK)
	{
		infoSetError("-- Could not set Attenuation to " + QString::number(m_maxAttenuation) + " steps --");
		return;
	}

	m_calibration.frequencyStart = startFreq;
	m_calibration.frequencyStop = stopFreq;
	m_calibration.frequencyStep = stepsFreq;
	m_calibration.timeout = ui.timeoutBox->value();
	m_calibration.antenna = ui.antennaComboBox->currentIndex();
	m_calibration.frequencies.clear();
	for(double freq = startFreq; freq <= stopFreq; freq += stepsFreq)
		m_calibration.frequencies.append(freq);


	setWorking();

	m_calibrateWizard->restart();
	int res = m_calibrateWizard->exec();

	if(res == QDialog::Accepted)
	{
		ui.continousCheckBox->setEnabled(true);
		ui.startButton->setEnabled(true);
		ui.markerGroupBox->setEnabled(true);
		m_calibrated = true;
		m_measurementActive = false;

		reloadMarkerList();

		if(m_calibrateEndSave->isChecked())
			saveCalibration();
	}

	setIdle();
}

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

void CRfePurNetworkAnalyzer::exportButtonClicked()
{
	if(!m_dataToExport)
	{
		QMessageBox::critical(this, tr("Export"), tr("Nothing to export"));
		return;
	}
	QString path = Cache::d.value(EXPORT_LAST_USED_FILEPATH, QDir::rootPath()).toString();

	QString fileName = path + "/NetworkAnalyzer_" + QDateTime::currentDateTime().toString("yyyy_MM_dd-hh_mm");
	QString outputFileName;

	if(ui.tabWidget->currentIndex() == ui.tabWidget->indexOf(ui.plotTab))
	{
		if(!QrfeQwt::savePlotToFile(m_amplitudePlot, this, "Save Plot to File", fileName, outputFileName))
			return;
	}
	else if(ui.tabWidget->currentIndex() == ui.tabWidget->indexOf(ui.smithTab))
	{
		if(!QrfeQwt::savePlotToFile(m_smithPlot, this, "Save Plot to File", fileName, outputFileName))
			return;
	}
	else if(ui.tabWidget->currentIndex() == ui.tabWidget->indexOf(ui.tableTab))
	{
		if(!QrfeGlobal::saveStandardModelToFile(m_dataModel, this, "Save Data to File", fileName, outputFileName))
			return;
	}
	else
		return;

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



void CRfePurNetworkAnalyzer::inputParametersChanged()
{
	m_calibrated = false;
	ui.startButton->setEnabled(false);

	m_amplitudePlot->setAxisScale(2, 	ui.freqSweepStartSpinBox->value(),
										ui.freqSweepStopSpinBox->value());
	m_amplitudePlot->replot();
}

void CRfePurNetworkAnalyzer::wizardPageChanged ( int id )
{
    static QVector<QrfeComplexNumber > resultLoad;
    static QVector<QrfeComplexNumber > resultShort;
    static QVector<QrfeComplexNumber > resultOpen;


	switch((WIZZARD_PAGES)id)
	{
	case MEASURE_LOAD:
		m_calibrateWizard->setButtonLayout(QList<QWizard::WizardButton>() << QWizard::Stretch << QWizard::NextButton << QWizard::CancelButton);
		return;
	case WAIT_LOAD:
		m_calibrateWizard->setButtonLayout(QList<QWizard::WizardButton>());
		m_continueMeasurement = true;
		resultLoad.clear();
		if(!runCalibrationSweep(resultLoad, m_calibrateLoadProgress))
		{
			QMessageBox::critical(this, tr("Error"), tr("An error occured while calibrating. Please check your settings and restart the procedure."));
			m_calibrateWizard->reject();
			return;
		}
		m_calibrateWizard->next();
		return;
	case MEASURE_SHORT:
		m_calibrateWizard->setButtonLayout(QList<QWizard::WizardButton>() << QWizard::Stretch << QWizard::BackButton << QWizard::NextButton << QWizard::CancelButton);
		return;
	case WAIT_SHORT:
		m_calibrateWizard->setButtonLayout(QList<QWizard::WizardButton>());
		resultShort.clear();
		if(!runCalibrationSweep(resultShort, m_calibrateShortProgress))
		{
			QMessageBox::critical(this, tr("Error"), tr("An error occured while calibrating. Please check your settings and restart the procedure."));
			m_calibrateWizard->reject();
			return;
		}
		m_calibrateWizard->next();
		return;
	case MEASURE_OPEN:
		m_calibrateWizard->setButtonLayout(QList<QWizard::WizardButton>() << QWizard::Stretch << QWizard::BackButton << QWizard::NextButton << QWizard::CancelButton);
		return;
	case WAIT_OPEN:
		m_calibrateWizard->setButtonLayout(QList<QWizard::WizardButton>());
		resultOpen.clear();
		if(!runCalibrationSweep(resultOpen, m_calibrateOpenProgress))
		{
			QMessageBox::critical(this, tr("Error"), tr("An error occured while calibrating. Please check your settings and restart the procedure."));
			m_calibrateWizard->reject();
			return;
		}
		m_calibrateWizard->next();
		return;
	case END:
		m_calibrateWizard->setButtonLayout(QList<QWizard::WizardButton>() << QWizard::Stretch << QWizard::FinishButton);
		calibrate(resultLoad, resultShort, resultOpen, m_calibration.err1, m_calibration.err2, m_calibration.err3);
		return;
	}

}



bool CRfePurNetworkAnalyzer::runCalibrationSweep ( QVector<QrfeComplexNumber> &output, QProgressBar* progressBar )
{
	clearInfo();

	progressBar->setEnabled(true);
	progressBar->setValue(0);
	progressBar->setMaximum(m_calibration.frequencies.size());

	//-------------------------------------------------------------------------------------------
	// Measurement
	infoAppend("-- Starting measurement  --");
	for(int i = 0; i < m_calibration.frequencies.size(); i++)
	{
		if(!m_continueMeasurement)
			break;

		double freq = m_calibration.frequencies.at(i);

		char iVal, qVal;
		uchar G;
		QrfeGlobal::Result res = m_reader->measureReflectedPower(freq*1000, m_calibration.timeout, iVal, qVal, G);
		if(res == QrfeGlobal::RES_OK)
		{
			showOK();
			infoAppend("-- Measured for frequency " + QString::number(freq) + " the values " + QString::number(iVal) + ", " + QString::number(qVal) + " with G=" + QString::number(G) + " --");
		}
		else
			return false;

		output.append(QrfeComplexNumber(iVal, qVal));

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

	return true;
}

void CRfePurNetworkAnalyzer::runMeasurementSweep ( )
{
	if(m_reader == 0 || m_measurementActive == true)
		return;

	m_measurementActive = true;

	clearInfo();


	//-------------------------------------------------------------------------------------------
	// Prepare Reader
	if(m_reader->setWorkingAntenna(m_calibration.antenna + 1 ) != QrfeGlobal::RES_OK)
	{
		infoSetError("-- Could not select Antenna #" + QString::number(m_calibration.antenna) + " --");
		return;
	}
	else
		infoAppend("-- Selected Antenna #" + QString::number(m_calibration.antenna) + " --");


	if(m_reader->setAttenuation(m_maxAttenuation) != QrfeGlobal::RES_OK)
	{
		infoSetError("-- Could not set Attenuation to " + QString::number(m_maxAttenuation) + " steps --");
		return;
	}
	else
		infoAppend("-- Set Attenuation to " + QString::number(m_maxAttenuation) + " steps --");


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

	ui.frequencyBox->setEnabled(false);
	ui.timeoutGroupBox->setEnabled(false);
	ui.antennaGroupBox->setEnabled(false);
	ui.portExtensionSpinBox->setEnabled(false);
	ui.calibrationGroupBox->setEnabled(false);

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

	ui.progressBar->setEnabled(true);

	m_amplitudePlot->setAxisScale(2, 	ui.freqSweepStartSpinBox->value(),
										ui.freqSweepStopSpinBox->value());
	m_amplitudePlot->setAxisScale(0, 	MIN_Y_AMPL,	0);

	m_amplitudeCurveOld->setSamples(0, 0, 0);
	m_amplitudeCurveOld->hide();

	m_smithCurveOld->setSamples(0, 0, 0);
	m_smithCurveOld->hide();

	rescaleSmithPlot();

	double portExtension = ui.portExtensionSpinBox->value();

	License::d->decrementExecutionCount(this);
    saveValuesToCache();

	//-------------------------------------------------------------------------------------------
	// Measurement
	do
	{
		ui.progressBar->setValue(0);
		ui.progressBar->setMaximum(m_calibration.frequencies.size());

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

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

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

		m_dataModel->clear();
		m_dataModel->setHorizontalHeaderLabels(QStringList() << tr("Frequency (MHz)") << tr("Reflected Power\n(dB)") << tr("Phase\n(Rad)") << tr("Reflection\nCoefficent") << tr("Impedance"));

		ui.marker1AmplitudeLabel->clear();
		ui.marker1Reflection->clear();
		ui.marker1Impedance->clear();

		ui.marker2AmplitudeLabel->clear();
		ui.marker2Reflection->clear();
		ui.marker2Impedance->clear();

		ui.marker3AmplitudeLabel->clear();
		ui.marker3Reflection->clear();
		ui.marker3Impedance->clear();

		QVector<double> amplitudeFreqs;
		QVector<double> amplitudeVals;

		QVector<double> smithReal;
		QVector<double> smithImaginary;

		QVector<double> smithMarkerReal;
		QVector<double> smithMarkerImaginary;

		double minAmpl = MIN_Y_AMPL;

		infoAppend("-- Starting measurement  --");
		for(int i = 0; i < m_calibration.frequencies.size(); i++ )
		{
			if(!m_continueMeasurement)
				break;

			double freq = m_calibration.frequencies.at(i);

			char chI, chQ;
			uchar G;
			QrfeGlobal::Result res = m_reader->measureReflectedPower(freq*1000, m_calibration.timeout, 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) + " --");
			}

			QrfeComplexNumber M(chI, chQ);
			QrfeComplexNumber reflection, impedance;
			double amplitude;
			double phase;

			calculate(freq, portExtension, m_calibration.err1.at(i), m_calibration.err2.at(i), m_calibration.err3.at(i), M, reflection, impedance, amplitude, phase);

			QList<QStandardItem*> items;
			items << new QStandardItem(QString("%1").arg((double)freq));
			items << new QStandardItem(QString("%1").arg((double)amplitude));
			items << new QStandardItem(QString("%1").arg((double)phase));
			items << new QStandardItem(QString("%1").arg(reflection.toString(3)));
			items << new QStandardItem(QString("%1").arg(impedance.toString(3)));
			m_dataModel->appendRow(items);

			amplitudeFreqs 	<< freq;
			amplitudeVals 	<< amplitude;

			smithReal 		<< reflection.realPart();
			smithImaginary 	<< reflection.imaginaryPart();

			if(amplitude < minAmpl)
			{
				minAmpl = amplitude;
				m_amplitudePlot->setAxisScale(0, 	minAmpl, 	0);
			}

			m_amplitudeCurve->setSamples(amplitudeFreqs.data(), amplitudeVals.data(), amplitudeFreqs.size());
			m_amplitudePlot->replot();

			if(i == ui.marker1FrequencyComboBox->currentIndex())
			{
				smithMarkerReal			<< reflection.realPart();
				smithMarkerImaginary	<< reflection.imaginaryPart();
				ui.marker1AmplitudeLabel->setText(QString::number(amplitude) + " dB");
				ui.marker1Reflection->setText(reflection.toString(3));
				ui.marker1Impedance->setText(impedance.toString(3));
			}
			if(i == ui.marker2FrequencyComboBox->currentIndex())
			{
				smithMarkerReal			<< reflection.realPart();
				smithMarkerImaginary	<< reflection.imaginaryPart();
				ui.marker2AmplitudeLabel->setText(QString::number(amplitude) + " dB");
				ui.marker2Reflection->setText(reflection.toString(3));
				ui.marker2Impedance->setText(impedance.toString(3));
			}
			if(i == ui.marker3FrequencyComboBox->currentIndex())
			{
				smithMarkerReal			<< reflection.realPart();
				smithMarkerImaginary	<< reflection.imaginaryPart();
				ui.marker3AmplitudeLabel->setText(QString::number(amplitude) + " dB");
				ui.marker3Reflection->setText(reflection.toString(3));
				ui.marker3Impedance->setText(impedance.toString(3));
			}

			m_smithCurve->setSamples(smithReal.data(), smithImaginary.data(), smithReal.size());
			m_smithMarker->setSamples(smithMarkerReal.data(), smithMarkerImaginary.data(), smithMarkerReal.size());
			m_smithPlot->replot();

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

		if(ui.continousCheckBox->isChecked() && m_continueMeasurement)
		{
			m_amplitudeCurveOld->setSamples(amplitudeFreqs.data(), amplitudeVals.data(), amplitudeFreqs.size());
			m_amplitudeCurveOld->show();
			m_amplitudePlot->replot();

			m_smithCurveOld->setSamples(smithReal.data(), smithImaginary.data(), smithReal.size());
			m_smithCurveOld->show();
			m_smithPlot->replot();
		}

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

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

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

	ui.frequencyBox->setEnabled(true);
	ui.exportButton->setEnabled(true);
	ui.timeoutGroupBox->setEnabled(true);
	ui.antennaGroupBox->setEnabled(true);
	ui.portExtensionSpinBox->setEnabled(true);
	ui.calibrationGroupBox->setEnabled(true);

	m_dataToExport = true;
	m_measurementActive = false;

	setIdle();
	reloadLicenseData();
}



void CRfePurNetworkAnalyzer::createCalibrateWizard()
{
	QVBoxLayout* layout;
	QLabel* pic;

    m_calibrateLoad		= new QWizardPage();
    m_calibrateLoad->setTitle(tr("Calibrate"));
    m_calibrateLoad->setSubTitle(tr("Measure Load"));
    layout = new QVBoxLayout(m_calibrateLoad);
    layout->addWidget(new QLabel(tr("Measure the reflected power with a terminating resistor."), m_calibrateLoad));
    layout->addStretch();
    layout->addWidget(pic = new QLabel(m_calibrateLoad));
    layout->addStretch();
    m_calibrateLoad->setLayout(layout);
    pic->setPixmap(QPixmap(":/pictures/networkAnalyzer/load"));
    pic->setAlignment(Qt::AlignCenter);

    m_calibrateLoadWait		= new QWizardPage();
    m_calibrateLoadWait->setTitle(tr("Calibrate"));
    m_calibrateLoadWait->setSubTitle(tr("Measuring"));
    layout = new QVBoxLayout(m_calibrateLoadWait);
    layout->addStretch();
	layout->addWidget(new QLabel(tr("Measuring"), m_calibrateLoadWait));
    layout->addWidget(m_calibrateLoadProgress = new QProgressBar(m_calibrateLoadWait));
    layout->addStretch();
    m_calibrateLoadWait->setLayout(layout);
    m_calibrateLoadProgress->setValue(0);
    m_calibrateLoadProgress->setMinimum(0);
    m_calibrateLoadProgress->setMaximum(100);

    m_calibrateShort	= new QWizardPage();
    m_calibrateShort->setTitle(tr("Calibrate"));
    m_calibrateShort->setSubTitle(tr("Measure Short"));
    layout = new QVBoxLayout(m_calibrateShort);
    layout->addWidget(new QLabel(tr("Measure the reflected power with a short circuit."), m_calibrateShort));
    layout->addStretch();
    layout->addWidget(pic = new QLabel(m_calibrateShort));
    layout->addStretch();
    m_calibrateShort->setLayout(layout);
    pic->setPixmap(QPixmap(":/pictures/networkAnalyzer/short"));
    pic->setAlignment(Qt::AlignCenter);

    m_calibrateShortWait	= new QWizardPage();
    m_calibrateShortWait->setTitle(tr("Calibrate"));
    m_calibrateShortWait->setSubTitle(tr("Measuring"));
    layout = new QVBoxLayout(m_calibrateShortWait);
    layout->addStretch();
	layout->addWidget(new QLabel(tr("Measuring"), m_calibrateShortWait));
    layout->addWidget(m_calibrateShortProgress = new QProgressBar(m_calibrateShortWait));
    layout->addStretch();
    m_calibrateShortWait->setLayout(layout);
    m_calibrateShortProgress->setValue(0);
    m_calibrateShortProgress->setMinimum(0);
    m_calibrateShortProgress->setMaximum(100);

    m_calibrateOpen		= new QWizardPage();
    m_calibrateOpen->setTitle(tr("Calibrate"));
    m_calibrateOpen->setSubTitle(tr("Measure Open"));
    layout = new QVBoxLayout(m_calibrateOpen);
    layout->addWidget(new QLabel(tr("Measure the reflected power with nothing connected."), m_calibrateOpen));
    layout->addStretch();
    layout->addWidget(pic = new QLabel(m_calibrateOpen));
    layout->addStretch();
	m_calibrateOpen->setLayout(layout);
    pic->setPixmap(QPixmap(":/pictures/networkAnalyzer/open"));
    pic->setAlignment(Qt::AlignCenter);

    m_calibrateOpenWait		= new QWizardPage();
    m_calibrateOpenWait->setTitle(tr("Calibrate"));
    m_calibrateOpenWait->setSubTitle(tr("Measuring"));
    layout = new QVBoxLayout(m_calibrateOpenWait);
    layout->addStretch();
	layout->addWidget(new QLabel(tr("Measuring"), m_calibrateOpenWait));
    layout->addWidget(m_calibrateOpenProgress = new QProgressBar(m_calibrateOpenWait));
    layout->addStretch();
    m_calibrateOpenWait->setLayout(layout);
    m_calibrateOpenProgress->setValue(0);
    m_calibrateOpenProgress->setMinimum(0);
    m_calibrateOpenProgress->setMaximum(100);

    m_calibrateEnd		= new QWizardPage();
    m_calibrateEnd->setTitle(tr("Calibrate"));
    m_calibrateEnd->setSubTitle(tr("End"));
    layout = new QVBoxLayout(m_calibrateEnd);
    layout->addWidget(new QLabel(tr("The system is now calibrated and can be used for measuring the antenna."), m_calibrateEnd));
    layout->addStretch();
    layout->addWidget(m_calibrateEndSave = new QCheckBox("Save", m_calibrateEnd));
    layout->addStretch();
    m_calibrateEnd->setLayout(layout);
    m_calibrateEndSave->setChecked(true);

    m_calibrateWizard 	= new QWizard(this);
    m_calibrateWizard->setPage(MEASURE_LOAD, m_calibrateLoad);
    m_calibrateWizard->setPage(WAIT_LOAD, m_calibrateLoadWait);
    m_calibrateWizard->setPage(MEASURE_SHORT, m_calibrateShort);
    m_calibrateWizard->setPage(WAIT_SHORT, m_calibrateShortWait);
    m_calibrateWizard->setPage(MEASURE_OPEN, m_calibrateOpen);
    m_calibrateWizard->setPage(WAIT_OPEN, m_calibrateOpenWait);
    m_calibrateWizard->setPage(END, m_calibrateEnd);

    connect(m_calibrateWizard, 		SIGNAL(	currentIdChanged (int) ),
    		this, 					  SLOT( wizardPageChanged (int) ) );

}

void CRfePurNetworkAnalyzer::createAmplitudePlot()
{
	m_amplitudePlot = new QwtPlot(this);
	ui.amplitudeLayout->addWidget(m_amplitudePlot);

	QPen pen;

	pen = QPen(Qt::red);
	pen.setWidthF(2);
	m_amplitudeCurve = new QwtPlotCurve("Reflected Power (dBm)");
	m_amplitudeCurve->attach(m_amplitudePlot);
	m_amplitudeCurve->setPen(pen);

	pen = QPen(Qt::darkMagenta);
	pen.setWidthF(1);
	m_amplitudeCurveOld = new QwtPlotCurve("Reflected Power (dBm)");
	m_amplitudeCurveOld->attach(m_amplitudePlot);
	m_amplitudeCurveOld->setPen(pen);

    m_amplitudePicker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft, QwtPlotPicker::CrossRubberBand, QwtPicker::ActiveOnly, m_amplitudePlot->canvas());
    m_amplitudePicker->setStateMachine(new QwtPickerDragPointMachine());
    m_amplitudePicker->setRubberBandPen(QColor(Qt::darkGreen));
    m_amplitudePicker->setRubberBand(QwtPicker::CrossRubberBand);
    m_amplitudePicker->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_amplitudePlot);

	m_amplitudePlot->insertLegend(new QwtLegend(this), QwtPlot::BottomLegend);

	m_amplitudePlot->setAxisAutoScale(0);
	m_amplitudePlot->setAxisTitle(QwtPlot::yLeft, "Reflected Power (dB)");
	m_amplitudePlot->setAxisTitle(QwtPlot::xBottom, "Frequency (MHz)");

	m_amplitudePlot->setAxisScale(2, 	ui.freqSweepStartSpinBox->value(),
										ui.freqSweepStopSpinBox->value());
	m_amplitudePlot->setAxisScale(0, 	MIN_Y_AMPL,	0);
}

void CRfePurNetworkAnalyzer::createSmithPlot()
{
	m_smithPlot = new QwtPlot(this);
	ui.smithLayout->addWidget(m_smithPlot);

	QPen pen;

	pen = QPen(Qt::red);
	pen.setWidthF(2);
	m_smithCurve = new QwtPlotCurve("Smith");
	m_smithCurve->attach(m_smithPlot);
	m_smithCurve->setPen(pen);

	pen = QPen(Qt::darkMagenta);
	pen.setWidthF(1);
	m_smithCurveOld = new QwtPlotCurve("Smith");
	m_smithCurveOld->attach(m_smithPlot);
	m_smithCurveOld->setPen(pen);

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


	pen = QPen(Qt::darkRed);
	pen.setWidthF(2);
	m_smithMarker = new QwtPlotCurve("Marker");
	m_smithMarker->setStyle( QwtPlotCurve::NoCurve );
	m_smithMarker->setSymbol( new QwtSymbol(QwtSymbol::XCross, Qt::NoBrush, pen, QSize(10, 10) ) );
	m_smithMarker->attach(m_smithPlot);

	m_smithPlot->enableAxis(0, false);
	m_smithPlot->enableAxis(2, false);

	QwtPlotItem* backgroundImage = new SmithBackgroundImage(this);
	backgroundImage->attach(m_smithPlot);

	m_smithPlot->replot();
}


void CRfePurNetworkAnalyzer::reloadMarkerList()
{
	QStringList frequList;
	foreach(double freq, m_calibration.frequencies)
		frequList << QString::number(freq) + "MHz";

	ui.marker1FrequencyComboBox->clear();
	ui.marker1FrequencyComboBox->addItems(frequList);
	ui.marker1FrequencyComboBox->setCurrentIndex(0);

	ui.marker2FrequencyComboBox->clear();
	ui.marker2FrequencyComboBox->addItems(frequList);
	ui.marker2FrequencyComboBox->setCurrentIndex(frequList.size()/2);

	ui.marker3FrequencyComboBox->clear();
	ui.marker3FrequencyComboBox->addItems(frequList);
	ui.marker3FrequencyComboBox->setCurrentIndex(frequList.size()-1);

}

void CRfePurNetworkAnalyzer::reloadLicenseData()
{

    ui.runCalibrationButton->setEnabled(true);
    ui.loadCalibrationButton->setEnabled(true);
    ui.startButton->setEnabled(m_calibrated);
    ui.continousCheckBox->setEnabled(m_calibrated);
    ui.markerGroupBox->setEnabled(m_calibrated);
    ui.exportButton->setEnabled(m_dataToExport);
}

void CRfePurNetworkAnalyzer::rescaleSmithPlot()
{
	if(m_smithPlot == 0)
		return;

	int height = m_smithPlot->canvas()->height();
	int width = m_smithPlot->canvas()->width();

	int min = qMin(width, height);

	double xDiff = ((double)width) / ((513.0 - 82.0) * (min/1026.0));
	double yDiff = ((double)height) / ((512.0 - 80.0) * (min/1024.0));

	double xMin = (xDiff/2.0) * (-1.0);
	double xMax = (xDiff/2.0);
	double yMin = (yDiff/2.0) * (-1.0);
	double yMax = (yDiff/2.0);

	m_smithPlot->setAxisScale(2, 	xMin,	xMax);
	m_smithPlot->setAxisScale(0, 	yMin,	yMax);

	m_smithPlot->replot();
}

void CRfePurNetworkAnalyzer::resizeEvent ( QResizeEvent * /*event*/ )
{
	rescaleSmithPlot();
}


bool CRfePurNetworkAnalyzer::calibrate ( const QVector< QrfeComplexNumber> & loadData, const QVector< QrfeComplexNumber > & shortData, const QVector< QrfeComplexNumber > & openData,
		QVector< QrfeComplexNumber > &err1, QVector< QrfeComplexNumber > &err2, QVector< QrfeComplexNumber > &err3)
{
	//f11<->err1
	//f21<->err2
	//f22<->err3
	QrfeComplexNumber f11;
	QrfeComplexNumber f21;
	QrfeComplexNumber f22;
	QrfeComplexNumber Mload;
	QrfeComplexNumber Mopen;
	QrfeComplexNumber Mshort;

	err1.clear();
	err2.clear();
	err3.clear();

	for (int i = 0; i < loadData.size(); i++)
	{

		Mload = loadData.at(i);
		Mopen = openData.at(i);
		Mshort = shortData.at(i);

		f11 = calculatef11(Mload, Mopen, Mshort);
		f22 = calculatef22(Mload, Mopen, Mshort, f11);
		f21 = calculatef21(Mload, Mopen, Mshort, f11, f22);

		err1 << f11;
		err2 << f21;
		err3 << f22;
	}

	return true;
}

bool CRfePurNetworkAnalyzer::calculate ( const double frequency, const double portExtension,
				 const QrfeComplexNumber &err1, const QrfeComplexNumber &err2, const QrfeComplexNumber &err3,
				 const QrfeComplexNumber M,
                 QrfeComplexNumber &reflection, QrfeComplexNumber& impedance, double &amplitude, double &phase)
{
    double pi = QrfeGlobal::PI;
    double c = QrfeGlobal::C;
    double f; // Frequency in Hz

    //f11<->err1
    //f21<->err2
    //f22<->err3
    QrfeComplexNumber f11 = err1;
    QrfeComplexNumber f21 = err2;
    QrfeComplexNumber f22 = err3;

    QrfeComplexNumber shift; //exp(-i*4*pi*L*f/c)
    QrfeComplexNumber x; //r without port extension

    f = frequency * 1000000;
    shift.setRealPart(		cos(4.0*pi*f*portExtension/c));
    shift.setImaginaryPart(	sin(4.0*pi*f*portExtension/c));
    x = (M-f11)/((f22*(M-f11))+f21);
    reflection = x*shift;

    phase = reflection.phase();

    if( reflection.absoluteValue() != 0 )
    	amplitude = 20*log10(reflection.absoluteValue());
    else
    	amplitude = MIN_AMPLITUDE;

	//QrfeComplexNumber one = QrfeComplexNumber(1.0);
	impedance = 50 * ((1.0 + reflection)/(1.0 - reflection));

    return false;
}


QrfeComplexNumber CRfePurNetworkAnalyzer::calculatef11 ( const QrfeComplexNumber& Mload, const QrfeComplexNumber& /*Mopen*/, const QrfeComplexNumber& /*Mshort*/ )
{
    return Mload;
}
QrfeComplexNumber CRfePurNetworkAnalyzer::calculatef21 ( const QrfeComplexNumber& /*Mload*/, const QrfeComplexNumber& Mopen, const QrfeComplexNumber& /*Mshort*/, const QrfeComplexNumber& f11, const QrfeComplexNumber& f22 )
{
    QrfeComplexNumber one = QrfeComplexNumber(1.0);
    return (one-f22)*(Mopen-f11);
}
QrfeComplexNumber CRfePurNetworkAnalyzer::calculatef22 ( const QrfeComplexNumber& /*Mload*/, const QrfeComplexNumber& Mopen, const QrfeComplexNumber& Mshort, const QrfeComplexNumber& f11 )
{
    QrfeComplexNumber two = QrfeComplexNumber(2.0);
    return ((two*f11)-Mopen-Mshort)/(Mshort-Mopen);
}


void CRfePurNetworkAnalyzer::loadValuesFromCache()
{
    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.antennaComboBox->setCurrentIndex( Cache::d.value(CACHE_HEADER + "Antenna", 0).toUInt() );
}

void CRfePurNetworkAnalyzer::saveValuesToCache()
{
    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 + "Antenna", ui.antennaComboBox->currentIndex() );
}
