#include "dlgstp.h"
#include "ui_dlgstp.h"
#include <QHostAddress>
#include <QListView>
#include <QSettings>
#include <QDateTime>
#define MAX_ROWS_LSTV 256
DlgSTP::DlgSTP(QWidget *parent)
	: QDialog(parent)
	, ui(new Ui::DlgSTP)
	, m_pMsgMod(new QStandardItemModel(this))
	, m_psock(new QUdpSocket(this))
	, m_pstream(new QTcpSocket(this))
{
	ui->setupUi(this);
	ui->listView_msg->setModel(m_pMsgMod);
	showMaximized();
	//Open GPS Device
	openGPS();
	//Enum all sensors
	EnumSensors();
	loadSettings();
	m_nTimer = startTimer(20);
	m_lastGpsTime = QDateTime::currentDateTime();
}

DlgSTP::~DlgSTP()
{
	delete ui;
}

void  DlgSTP::timerEvent(QTimerEvent * evt)
{
	if (evt->timerId()==m_nTimer)
	{
		++m_clk;
		//UDP Send
		const int updateITV = ui->horizontalSlider_freq->value();
		const int updateGUI = (50 / (updateITV>50?50:updateITV) )* updateITV;
		if (m_clk % updateITV ==0 )
		{
			//Call Update functions
			foreach(auto fn, m_sensorUpdaters)
				fn();
			if (ui->checkBox_udp->isChecked())
			{
				//Send Current Data
				QHostAddress addr (ui->lineEdit_ip_udp->text());
				int port = ui->spinBox_port_udp->value();
				foreach(QString i, m_listInfo)
					m_psock->writeDatagram(i.toLocal8Bit(),addr,port);
				m_nTotalSent += m_listInfo.size();
			}
			if (ui->checkBox_tcp->isChecked())
			{
				if (m_pstream->state()==QTcpSocket::ConnectedState)
				{
					QTextStream stm(m_pstream);
					stm<<"\n======\n";
					stm<<QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm:ss");
					stm<<"\n";
					foreach(QString i, m_listInfo)
					{
						stm<<i<<"\n";
					}
					m_nTotalSent += m_listInfo.size();
				}
				else if (m_pstream->state()==QTcpSocket::UnconnectedState)
				{
					m_pstream->connectToHost(QHostAddress(ui->lineEdit_ip_tcp->text()),ui->spinBox_port_tcp->value());
				}

			}

			m_listInfo.clear();
			if (m_clk % updateGUI==0)
			{
				m_pMsgMod->appendRow(new QStandardItem(QString("%1>%2 items sent.")
													   .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
													   .arg(m_nTotalSent)));
				if (m_pMsgMod->rowCount()>MAX_ROWS_LSTV)
					m_pMsgMod->removeRows(0,m_pMsgMod->rowCount()-MAX_ROWS_LSTV);
				ui->listView_msg->scrollToBottom();
			}
		}
		if(m_clk%50==0 && m_pos_source && m_lastGpsTime.secsTo(QDateTime::currentDateTime())>10)
		{
			m_pos_source->startUpdates();
			m_lastGpsTime = QDateTime::currentDateTime();
		}
	}
}
void DlgSTP::openGPS()
{
	m_pos_source = QGeoPositionInfoSource::createDefaultSource(0);
	if (m_pos_source)
	{
		//Add Tab
		QListView * lstView = new QListView(this);
		lstView->setAlternatingRowColors(true);
		lstView->setWordWrap(true);
		QStandardItemModel * m_pMod = new QStandardItemModel(this);
		lstView->setModel(m_pMod);
		ui->tabWidget->addTab(lstView,"GPS");
		//slots for pos update
		connect (m_pos_source,
				 &QGeoPositionInfoSource::positionUpdated,
				 [lstView,m_pMod,this](const QGeoPositionInfo &update)->void
		{
			double lat = update.coordinate().latitude();
			double lon = update.coordinate().longitude();
			double alt = update.coordinate().altitude();
			double course = update.attribute(QGeoPositionInfo::Direction);
			double speed = update.attribute(QGeoPositionInfo::GroundSpeed);
			QDateTime dtm = update.timestamp();
			QString str = QString("SENSOR=GPS;\nGMT_TIME=%1;\nLAT=%2;\nLON=%3;\nALT=%4;\nANGLE=%5;\nGROUNDSPEED=%6;\n")
					.arg(dtm.toString("yyyy-MM-dd HH:mm:ss"))
					.arg(lat,0,'f',7)
					.arg(lon,0,'f',7)
					.arg(alt,0,'f',7)
					.arg(course,0,'f',7)
					.arg(speed,0,'f',7);
			str = QString("LOCALTIME=%1;\n").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))+str;
			m_listInfo << str;
			m_pMod->appendRow(new QStandardItem(str));
			if (m_pMod->rowCount()>MAX_ROWS_LSTV)
				m_pMod->removeRows(0,m_pMsgMod->rowCount()-MAX_ROWS_LSTV);
			lstView->scrollToBottom();
			m_lastGpsTime = QDateTime::currentDateTime();
		});
		//Slot for err
		connect (m_pos_source,
				 &QGeoPositionInfoSource::errorOccurred,
				 [this](QGeoPositionInfoSource::Error pe)->void{
			m_pos_source->startUpdates();
			m_pMsgMod->appendRow(new QStandardItem(QString("GPS Err Code %1.").arg(int(pe))));
		});
		//Start
		m_pos_source->setUpdateInterval(ui->horizontalSlider_gps->value());
		m_pos_source->setPreferredPositioningMethods(QGeoPositionInfoSource::AllPositioningMethods);
		m_pos_source->startUpdates();
		m_lastGpsTime = QDateTime::currentDateTime();
	}
	else
		m_pMsgMod->appendRow(new QStandardItem("No GPS Found!"));
}
void DlgSTP::EnumSensors()
{
	QList<QByteArray> sensors = QSensor::sensorTypes();
	QString strSensors = "Sensors:\n";
	for (QByteArray stp : sensors)
	{
		strSensors += "\t"+stp + "\n";
		QSensor * sensor = new QSensor(stp);
		if (!sensor)
			continue;
		sensor->start();
		sensor->setAlwaysOn(true);
		//Add Tab
		QListView * lstView = new QListView(this);
		lstView->setAlternatingRowColors(true);
		lstView->setWordWrap(true);
		QStandardItemModel * m_pMod = new QStandardItemModel(this);
		lstView->setModel(m_pMod);
		QString name = stp;
		ui->tabWidget->addTab(lstView,name);
		//Refresh Function
		m_sensorUpdaters<<[sensor,m_pMod,this,lstView,name](void)->void
		{
			QSensorReading *reading = sensor->reading();
			if (!reading)
				return;
			const int updateITV = ui->horizontalSlider_freq->value();
			const int updateGUI = (50 / (updateITV>50?50:updateITV) )* updateITV;
			QString str = "SENSOR="+name + ";\n";
			int n = reading->valueCount();
			qint64 tsp = reading->timestamp();
			str += QString("LOCALTIME=%1;\n").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"));
			str += QString("TIMESTAMP=%1;\n").arg(tsp);
			for (int i=0;i<n;++i)
			{
				str += QString("V%1=").arg(i);
				QVariant vt = reading->value(i);
				str += QString("%1").arg(vt.toString());
				str+=";\n";
			}
			m_listInfo << str;
			if (m_clk % updateGUI==0)
			{
				m_pMod->appendRow(new QStandardItem(str));
				if (m_pMod->rowCount()>MAX_ROWS_LSTV)
					m_pMod->removeRows(0,m_pMsgMod->rowCount()-MAX_ROWS_LSTV);
				lstView->scrollToBottom();
			}
		};
	}
	m_pMsgMod->appendRow(new QStandardItem(strSensors));
}
void DlgSTP::on_pushButton_left_clicked()
{
	ui->tabWidget->setCurrentIndex(ui->tabWidget->currentIndex()-1);
	ui->label_page->setText(ui->tabWidget->tabText(ui->tabWidget->currentIndex()));
}
void DlgSTP::on_pushButton_right_clicked()
{
	ui->tabWidget->setCurrentIndex(ui->tabWidget->currentIndex()+1);
	ui->label_page->setText(ui->tabWidget->tabText(ui->tabWidget->currentIndex()));
}

void DlgSTP::loadSettings()
{
	QSettings settings("ColoredEagleStudio","sensor2pc");
	ui->lineEdit_ip_udp->setText(settings.value("ui/lineEdit_ip_udp",ui->lineEdit_ip_udp->text()).toString());
	ui->spinBox_port_udp->setValue(settings.value("ui/spinBox_port_udp",ui->spinBox_port_udp->value()).toInt());
	ui->lineEdit_ip_udp->setText(settings.value("ui/lineEdit_ip_tcp",ui->lineEdit_ip_tcp->text()).toString());
	ui->spinBox_port_udp->setValue(settings.value("ui/spinBox_port_tcp",ui->spinBox_port_tcp->value()).toInt());
	ui->horizontalSlider_freq->setValue(settings.value("ui/horizontalSlider_freq",ui->horizontalSlider_freq->value()).toInt());
	ui->horizontalSlider_gps->setValue(settings.value("ui/horizontalSlider_gps",ui->horizontalSlider_gps->value()).toInt());
	ui->checkBox_tcp->setChecked(settings.value("ui/checkBox_tcp",ui->checkBox_tcp->isChecked()).toBool());
	ui->checkBox_udp->setChecked(settings.value("ui/checkBox_udp",ui->checkBox_udp->isChecked()).toBool());
}
void DlgSTP::saveSettings()
{
	QSettings settings("ColoredEagleStudio","sensor2pc");
	settings.setValue("ui/lineEdit_ip_udp",ui->lineEdit_ip_udp->text());
	settings.setValue("ui/spinBox_port_udp",ui->spinBox_port_udp->value());
	settings.setValue("ui/lineEdit_ip_tcp",ui->lineEdit_ip_udp->text());
	settings.setValue("ui/spinBox_port_tcp",ui->spinBox_port_udp->value());
	settings.setValue("ui/horizontalSlider_freq",ui->horizontalSlider_freq->value());
	settings.setValue("ui/horizontalSlider_gps",ui->horizontalSlider_gps->value());
	settings.setValue("ui/checkBox_tcp",ui->checkBox_tcp->isChecked());
	settings.setValue("ui/checkBox_udp",ui->checkBox_udp->isChecked());
}
void DlgSTP::on_horizontalSlider_gps_valueChanged(int value)
{
	if (m_pos_source)
		m_pos_source->setUpdateInterval(value);
	saveSettings();
}
void DlgSTP::on_tabWidget_currentChanged(int index)
{
	ui->label_page->setText(ui->tabWidget->tabText(index));
	saveSettings();
}


void DlgSTP::on_checkBox_udp_clicked(bool checked)
{
	saveSettings();
}


void DlgSTP::on_checkBox_tcp_clicked(bool checked)
{
	saveSettings();
}

