/*
 * JobCenter.cpp
 *
 *  Created on: 25.11.2009
 *      Author: stefan.detter
 */

#include "JobCenter.h"

#include <QrfeProgressDialog>

#include <QTimer>

#include <QrfeTrace>
#include <QrfeSleeper>

#include <QrfeReaderManager>

#include "../gui/GuiController.h"
#include "../control/ReaderControll.h"
#include "../update/FirmwareUpdateManager.h"
#include "../trace/TraceWindowManager.h"
#include "../tools/ToolController.h"

#include "../License.h"

#include <QMessageBox>

#define REBOOT_TIMEOUT_MS			2500

JobCenter::JobCenter(QrfeReaderManager* manager, GuiController* advanced, ReaderControll* controll,
		FirmwareUpdateManager* updateManager, TraceWindowManager* traceWindowManager, ToolController* toolController, QWidget* mainWindow, QObject* parent)
	: QObject(parent)
	, m_manager(manager)
	, m_guiController(advanced)
	, m_controll(controll)
	, m_updateManager(updateManager)
	, m_traceWindowManager(traceWindowManager)
	, m_toolController(toolController)
	, m_mainWindow(mainWindow)
{
	QTimer::singleShot(100, this, SLOT(processJobs()));
}

JobCenter::~JobCenter()
{
}

void JobCenter::appendJop(JobType type, const QList<QVariant>& parameters)
{
	Job j;
	j.jobType 		= type;
	j.parameters 	= parameters;
	m_jobList.enqueue(j);
}

void JobCenter::processJobs()
{
	while(m_jobList.size() != 0)
	{
		Job j = m_jobList.dequeue();
		switch(j.jobType)
		{
		case JOB_ShowHideTraceWindow:
			showHideTraceWindow(j.parameters);
			break;

		case JOB_WaitForSpeciifedTime:
			waitForSpecifiedTime(j.parameters);
			break;
		case JOB_WaitForSpeciifedTimeWithDialog:
			waitForSpecifiedTimeWithDialog(j.parameters);
			break;

		case JOB_AddReader:
			addReader(j.parameters);
			break;
		case JOB_CheckReaderForUpdates:
			checkReaderForUpdates(j.parameters);
			break;

		case JOB_SwitchReaderToBootloader:
			switchReaderToBootloader(j.parameters);
			break;
		case JOB_SwitchReaderToBootloaderAndShowDialog:
			switchReaderToBootloaderAndShowDialog(j.parameters);
			break;
		case JOB_SwitchReaderToFirmware:
			switchReaderToFirmware(j.parameters);
			break;
		case JOB_SwitchReaderSystemWithoutCommand:
			switchReaderSystemWithoutCommand(j.parameters);
			break;
		case JOB_SwitchReaderSystemWithoutCommandAndShowSettings:
			switchReaderSystemWithoutCommandAndShowSettings(j.parameters);
			break;

		case JOB_StartScan:
			startScan(j.parameters);
			break;
		case JOB_StopScan:
			stopScan(j.parameters);
			break;

		case JOB_ShowApplicationSettings:
			showApplicationSettings(j.parameters);
			break;

		case JOB_ShowSettingsOfReader:
			showSettingsOfReader(j.parameters);
			break;
		case JOB_ShowAppSettingsOfReader:
			showAppSettingsOfReader(j.parameters);
			break;
		case JOB_ShowEngineeringForReader:
			showEngineeringForReader(j.parameters);
			break;

		case JOB_ShowSettingsOfTag:
			showSettingsOfTag(j.parameters);
			break;
		case JOB_ShowEngineeringForTag:
			showEngineeringForTag(j.parameters);
			break;

		case JOB_StartTool:
			startTool(j.parameters);
			break;

		default:
			break;
		}
	}

	QTimer::singleShot(100, this, SLOT(processJobs()));
}


void JobCenter::showHideTraceWindow(QList<QVariant> &params)
{
	if(params.size() != 2)
		return;
	if(params.at(0).type() != QVariant::Bool)
		return;
	if(params.at(1).type() != QVariant::Int)
		return;

	bool 		show 	= params.at(0).toBool();
	int 		level 	= params.at(1).toInt();

	m_traceWindowManager->showTraceWindow(show);
	if(show)
		QrfeTrace::setTrcLevel(level, QrfeTrace::Trace2Signal);
	else
		QrfeTrace::setTrcLevel(-1, QrfeTrace::Trace2Signal);
}

void JobCenter::waitForSpecifiedTime(QList<QVariant> &params)
{
	if(params.size() != 1)
		return;
	if(params.at(0).type() != QVariant::UInt)
		return;

	uint 		msecs 	= params.at(0).toUInt();

	QrfeSleeper::MSleepAlive(msecs);
}

void JobCenter::waitForSpecifiedTimeWithDialog(QList<QVariant> &params)
{
	if(params.size() != 3)
		return;
	if(params.at(0).type() != QVariant::String)
		return;
	if(params.at(1).type() != QVariant::UInt)
		return;
	if(!params.at(2).canConvert<QWidget*>())
		return;

	QString 	title 	= params.at(0).toString();
	uint 		msecs 	= params.at(1).toUInt();
	QWidget* 	parent 	= params.at(2).value<QWidget*>();

	uint steps = (msecs / 100);
	steps += (msecs%100 > 0)?1:0;

	QrfeProgressDialog* pb = new QrfeProgressDialog(title, steps, parent);
	pb->show();
	for(uint i = 0; i < steps; i ++){
		pb->increasePorgressBar(); 
		QrfeSleeper::MSleepAlive(100);
	}
	pb->hide();
	delete pb;
}

void JobCenter::addReader(QList<QVariant> &params)
{
	if(params.size() != 2)
		return;
	if(!params.at(0).canConvert<uint>())
		return;
	if(params.at(1).type() != QVariant::String)
		return;

	QrfeGlobal::DeviceType	deviceType 	= (QrfeGlobal::DeviceType) params.at(0).value<uint>();
	QString 				deviceName	= params.at(1).toString();

	m_manager->addReader(deviceType, deviceName);
}

void JobCenter::checkReaderForUpdates(QList<QVariant> &params)
{
	if(params.size() != 1)
		return;

	if(params.at(0).type() != QVariant::String)
		return;

	QString 	readerId	= params.at(0).toString();

	QrfeReaderInterface* reader = m_manager->readerInterface(readerId);
	if(reader == 0)
		return;

	m_updateManager->checkReaderForUpdates(reader);
}


void JobCenter::switchReaderToBootloader(QList<QVariant> &params)
{
	if(params.size() != 1)
		return;
	if(params.at(0).type() != QVariant::String)
		return;

	QString 	readerId	= params.at(0).toString();

	QrfeReaderInterface* reader = m_manager->readerInterface(readerId);
	if(reader == 0)
		return;

	if(reader->currentSystem() == QrfeGlobal::BOOTLOADER)
		return;

	QrfeGlobal::DeviceType	deviceType 	= reader->deviceType();
	QString 				deviceName 	= reader->deviceName();
	ulong					readerCaps	= reader->readerCaps();

	if(reader->switchSystem() == QrfeGlobal::RES_OK)
	{
		reader->destroy();

		ulong waitTime = REBOOT_TIMEOUT_MS;
		if( (readerCaps & QrfeGlobal::PLUG_OFF_REQUIRED) != 0 )
		{
			QMessageBox::information(m_mainWindow, "Switch to bootloader", "Switched to bootloader. Please unplug and replug the device now and then press OK.");
		}

		QList<QVariant> params;
		params.append(QString("Switching to bootloader..."));
		params.append((uint)waitTime);
		params.append(QVariant::fromValue(m_mainWindow));
		appendJop(JOB_WaitForSpeciifedTimeWithDialog, params);

		params.clear();
		params.append(deviceType);
		params.append(deviceName);
		appendJop(JOB_AddReader, params);
	}
	else
	{
		QMessageBox::warning(m_mainWindow, "Switch to bootloader", "Could not switch to the bootloader");
	}
}

void JobCenter::switchReaderToBootloaderAndShowDialog(QList<QVariant> &params)
{
	if(params.size() != 1)
		return;
	if(params.at(0).type() != QVariant::String)
		return;

	QString 	readerId	= params.at(0).toString();

	QrfeReaderInterface* reader = m_manager->readerInterface(readerId);
	if(reader == 0)
		return;

	if(reader->currentSystem() == QrfeGlobal::BOOTLOADER)
		return;

	QrfeGlobal::DeviceType	deviceType 	= reader->deviceType();
	QString 				deviceName 	= reader->deviceName();
	ulong					readerCaps	= reader->readerCaps();

	if(reader->switchSystem() == QrfeGlobal::RES_OK)
	{
		reader->destroy();

		ulong waitTime = REBOOT_TIMEOUT_MS;
		if( (readerCaps & QrfeGlobal::PLUG_OFF_REQUIRED) != 0 )
		{
			QMessageBox::information(m_mainWindow, "Switch to bootloader", "Switched to bootloader. Please unplug and replug the device now and then press OK.");
		}

		QList<QVariant> params;
		params.append(QString("Switching to bootloader..."));
		params.append((uint)waitTime);
		params.append(QVariant::fromValue(m_mainWindow));
		appendJop(JOB_WaitForSpeciifedTimeWithDialog, params);

		params.clear();
		params.append(deviceType);
		params.append(deviceName);
		appendJop(JOB_AddReader, params);

		params.clear();
		params.append(readerId);
		appendJop(JOB_ShowSettingsOfReader, params);
	}
	else
	{
		QMessageBox::warning(m_mainWindow, "Switch to bootloader", "Could not switch to the bootloader.");
	}
}

void JobCenter::switchReaderToFirmware(QList<QVariant> &params)
{
	if(params.size() != 1)
		return;
	if(params.at(0).type() != QVariant::String)
		return;

	QString 	readerId	= params.at(0).toString();

	QrfeReaderInterface* reader = m_manager->readerInterface(readerId);
	if(reader == 0)
		return;

	if(reader->currentSystem() == QrfeGlobal::FIRMWARE)
		return;

	QrfeGlobal::DeviceType	deviceType 	= reader->deviceType();
	QString 				deviceName 	= reader->deviceName();
	ulong					readerCaps	= reader->readerCaps();

	if(reader->switchSystem() == QrfeGlobal::RES_OK)
	{
		reader->destroy();

		ulong waitTime = REBOOT_TIMEOUT_MS;
		if( (readerCaps & QrfeGlobal::PLUG_OFF_REQUIRED) != 0 )
		{
			QMessageBox::information(m_mainWindow, "Switch to firmware", "Switched to firmware. Please unplug and replug the device now and then press OK.");
		}

		QList<QVariant> params;
		params.append(QString("Switching to firmware..."));
		params.append((uint)waitTime);
		params.append(QVariant::fromValue(m_mainWindow));
		appendJop(JOB_WaitForSpeciifedTimeWithDialog, params);

		params.clear();
		params.append(deviceType);
		params.append(deviceName);
		appendJop(JOB_AddReader, params);
	}
	else
	{
		QMessageBox::warning(m_mainWindow, "Switch to firmware", "Could not switch to the firmware.");
	}
}

void JobCenter::switchReaderSystemWithoutCommand(QList<QVariant> &params)
{
	if(params.size() != 4)
		return;
	if(params.at(0).type() != QVariant::String)
		return;
	if(params.at(1).type() != QVariant::UInt)
		return;
	if(params.at(2).type() != QVariant::String)
		return;
	if(params.at(3).type() != QVariant::UInt)
		return;

	QString 				readerId	= params.at(0).toString();
	QrfeGlobal::DeviceType	deviceType 	= (QrfeGlobal::DeviceType)params.at(1).toUInt();
	QString 				deviceName 	= params.at(2).toString();
	ulong 					readerCaps 	= params.at(3).toUInt();

	ulong waitTime = REBOOT_TIMEOUT_MS;
	if( (readerCaps & QrfeGlobal::PLUG_OFF_REQUIRED) != 0 )
	{
		QMessageBox::information(m_mainWindow, "Switch to firmware", "Switched to firmware. Please unplug and replug the device now and then press OK.");
	}

	{
		QList<QVariant> params;
		params.append(QString("Switching to firmware..."));
		params.append((uint)waitTime);
		params.append(QVariant::fromValue(m_mainWindow));
		appendJop(JOB_WaitForSpeciifedTimeWithDialog, params);

		params.clear();
		params.append(deviceType);
		params.append(deviceName);
		appendJop(JOB_AddReader, params);
	}
}

void JobCenter::switchReaderSystemWithoutCommandAndShowSettings(QList<QVariant> &params)
{
	if(params.size() != 4)
		return;
	if(params.at(0).type() != QVariant::String)
		return;
	if(params.at(1).type() != QVariant::UInt)
		return;
	if(params.at(2).type() != QVariant::String)
		return;
	if(params.at(3).type() != QVariant::UInt)
		return;

	QString 				readerId	= params.at(0).toString();
	QrfeGlobal::DeviceType	deviceType 	= (QrfeGlobal::DeviceType)params.at(1).toUInt();
	QString 				deviceName 	= params.at(2).toString();
	ulong 					readerCaps 	= params.at(3).toUInt();

	ulong waitTime = REBOOT_TIMEOUT_MS;
	if( (readerCaps & QrfeGlobal::PLUG_OFF_REQUIRED) != 0 )
	{
		QMessageBox::information(m_mainWindow, "Switch to firmware", "Switched to firmware. Please unplug and replug the device now and then press OK.");
	}

	{
		QList<QVariant> params;
		params.append(QString("Switching to firmware..."));
		params.append((uint)waitTime);
		params.append(QVariant::fromValue(m_mainWindow));
		appendJop(JOB_WaitForSpeciifedTimeWithDialog, params);

		params.clear();
		params.append(deviceType);
		params.append(deviceName);
		appendJop(JOB_AddReader, params);

		params.clear();
		params.append(readerId);
		appendJop(JOB_ShowSettingsOfReader, params);
	}
}

void JobCenter::startScan(QList<QVariant> &params)
{
	if(params.size() != 0)
		return;

	if(!m_controll->inventoryActive())
		m_controll->startInventory();
}

void JobCenter::stopScan(QList<QVariant> &params)
{
	if(params.size() != 0)
		return;

	if(m_controll->inventoryActive())
		m_controll->stopInventory();
}



void JobCenter::showApplicationSettings(QList<QVariant> &/*params*/)
{
	m_guiController->showApplicationSettings();
}

void JobCenter::showSettingsOfReader(QList<QVariant> &params)
{
	if(params.size() < 1)
		return;
	if(params.at(0).type() != QVariant::String)
		return;

	if(params.size() > 1 && params.at(1).type() != QVariant::Bool)
		return;

	QString 	readerId		= params.at(0).toString();
	bool 		fullFunction 	= (params.size() > 1)?params.at(1).toBool():true;

	m_guiController->showReaderSettings(readerId, fullFunction);
}

void JobCenter::showAppSettingsOfReader(QList<QVariant> &params)
{
	if(params.size() != 1)
		return;
	if(params.at(0).type() != QVariant::String)
		return;

	QString 	readerId	= params.at(0).toString();

	m_guiController->showReaderAppSettings(readerId);
}


void JobCenter::showEngineeringForReader(QList<QVariant> &params)
{
	if(params.size() != 1)
		return;
	if(params.at(0).type() != QVariant::String)
		return;

	QString 	readerId	= params.at(0).toString();

	m_guiController->showReaderEngineering(readerId);
}


void JobCenter::showSettingsOfTag(QList<QVariant> &params)
{
	if(params.size() != 3)
		return;
	if(params.at(0).type() != QVariant::String)
		return;
	if(params.at(1).type() != QVariant::String)
		return;
	if(params.at(2).type() != QVariant::UInt)
		return;

	QString 	readerId	= params.at(0).toString();
	QString 	tagId		= params.at(1).toString();
	uint 		antennaId	= params.at(2).toUInt();

	m_guiController->showTagSettings(readerId, tagId, antennaId);
}

void JobCenter::showEngineeringForTag(QList<QVariant> &params)
{
	if(params.size() != 3)
		return;
	if(params.at(0).type() != QVariant::String)
		return;
	if(params.at(1).type() != QVariant::String)
		return;
	if(params.at(2).type() != QVariant::UInt)
		return;

	QString 	readerId	= params.at(0).toString();
	QString 	tagId		= params.at(1).toString();
	uint 		antennaId	= params.at(2).toUInt();

	m_guiController->showTagEngineering(readerId, tagId, antennaId);
}


void JobCenter::startTool(QList<QVariant> &params)
{
	if(params.size() != 1)
		return;
	if(params.at(0).type() != QVariant::String)
		return;

	QString 	name 		= params.at(0).toString();

	if(!m_toolController->availableTools().contains(name))
		return;

	m_toolController->executeTool(name);
}


