/*
 * QrfeReaderInterfaceGlobal.cpp
 *
 *  Created on: 02.12.2009
 *      Author: stefan.detter
 */

#include "QrfeReaderInterfaceGlobal.h"

#include <QMetaType>
#include <QStringList>

QMap<uint, QMap<uint,QString> >		_availableMemoryBanks;
static __init_QrfeReaderInterfaceGlobal	__init;

QString QrfeGlobal::tagTypeToString( const TagType t )
{
	switch(t)
	{
	case QrfeGlobal::TAG_GEN2:
		return "Gen2";
	case QrfeGlobal::TAG_GEN2_NXP_READPROTECTED:
		return "Gen2 - NXP ReadProtected";
	case QrfeGlobal::TAG_ISO6B:
		return "ISO6b";
	default:
		return "Unknown";
	}
}


QString QrfeGlobal::readerModuleToString( const ReaderModule rm )
{
	switch(rm)
	{
	case QrfeGlobal::VERSION_RFE_PUR_RM1:
		return "PUR RM1";
	case QrfeGlobal::VERSION_RFE_PUR_RM2:
		return "PUR RM2";
	default:
		return "Unknown";
	}
}

QString QrfeGlobal::stateToString( const HandlerState state )
{
	// return the state as human readable string
	switch(state){
	case QrfeGlobal::STATE_ONLINE:
		return "Online";
	case QrfeGlobal::STATE_OFFLINE:
		return "Offline";
	case QrfeGlobal::STATE_RESTARTING:
		return "Restarting";
	case QrfeGlobal::STATE_NOTRESPONDING:
		return "Not Responding";
	case QrfeGlobal::STATE_UNKOWN_ERROR:
		return "Unknown Error";
	default:
		return "Unknown";
	}
}


QString QrfeGlobal::actionToString( const HandlerAction action )
{
	// return the state as human readable string
	switch(action){
	case QrfeGlobal::ACTION_OFFLINE:
		return "Offline";
	case QrfeGlobal::ACTION_IDLE:
		return "Idle";
	case QrfeGlobal::ACTION_SCANNING:
		return "Scanning";
	case QrfeGlobal::ACTION_WAITING:
		return "Waiting";
	default:
		return "Unknown";
	}
}

bool QrfeGlobal::isPUR(const ulong readerType)
{
	switch( (uchar)(readerType >> 24) )
	{
	case 0x80:
	case 0x81:
	case 0x82:
	case 0x83:
    case 0x84:
	case 0xFF:
		return true;
	default:
		return false;
	}
}

bool QrfeGlobal::isAUR(const ulong readerType)
{
	switch( (uchar)(readerType >> 24) )
	{
	case 0x01:
	case 0x02:
		return true;
	default:
		return false;
	}
}

QrfeGlobal::ReaderModule QrfeGlobal::getReaderModule(const ulong readerType)
{
    switch( (uchar)(readerType >> 24) )
    {
    case 0x81:
        return VERSION_RFE_PUR_RM1;
    case 0x82:
        return VERSION_RFE_PUR_RM2;
    default:
        return VERSION_RFE_PUR_RM1;
    }
}

ulong QrfeGlobal::getApplicationId(const ulong readerType)
{
	return 0x000000FF & readerType;
}

ulong QrfeGlobal::readerTypeWithApplication (const ulong readerType, const ulong application)
{
	return (readerType & 0xFFFFFF00) | (application & 0x000000FF);
}



QString QrfeGlobal::readerTypeToString( const ulong readerType )
{
    uchar* p = (uchar*) &readerType;
    return QString("%1-%2-%3-%4")
			      .arg((uchar)p[3], 2, 16, QChar('0'))
			      .arg((uchar)p[2], 2, 16, QChar('0'))
			      .arg((uchar)p[1], 2, 16, QChar('0'))
			      .arg((uchar)p[0], 2, 16, QChar('0'));
}

QString QrfeGlobal::readerSerialToString( const ulong readerSerial )
{
    uchar* p = (uchar*) &readerSerial;
    return QString("%1-%2-%3-%4")
			      .arg((uchar)p[3], 2, 16, QChar('0'))
			      .arg((uchar)p[2], 2, 16, QChar('0'))
			      .arg((uchar)p[1], 2, 16, QChar('0'))
			      .arg((uchar)p[0], 2, 16, QChar('0'));
}

QString QrfeGlobal::hardwareRevisionToString( const ulong hardwareRevision )
{
    QString hardwareRev;
    hardwareRev = "Rev. " + QString::number(hardwareRevision);
//    hardwareRev.clear();
//    hardwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(hardwareRevision >> 0)) ) );
//    hardwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(hardwareRevision >> 4)) ) );
//    hardwareRev.prepend( "." );
//    hardwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(hardwareRevision >> 8)) ) );
//    hardwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(hardwareRevision >> 12)) ) );
//    hardwareRev.prepend( "v" );

    return hardwareRev;
}

QString QrfeGlobal::softwareRevisionToString( const ulong softwareRevision )
{
	bool testVersion = false;
	ulong usedSoftwareRevision = softwareRevision;

    if(softwareRevision == 0xFFFFFFFF)
	return "No software installed";

    if( (softwareRevision&0x00008000) > 0){
    	testVersion = true;
    	usedSoftwareRevision &= ~0x00008000;
    }


    QString softwareRev;
    softwareRev.clear();
    softwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(usedSoftwareRevision >> 0)) ) );
    softwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(usedSoftwareRevision >> 4)) ) );
    softwareRev.prepend( "." );
    softwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(usedSoftwareRevision >> 8)) ) );
    softwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(usedSoftwareRevision >> 12)) ) );
    softwareRev.prepend( "Kernel - v" );

    if( (softwareRevision&0xFFFF0000) > 0 )
    {
	softwareRev.prepend( " " );
	softwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(usedSoftwareRevision >> 16)) ) );
	softwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(usedSoftwareRevision >> 20)) ) );
	softwareRev.prepend( "." );
	softwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(usedSoftwareRevision >> 24)) ) );
	softwareRev.prepend( QChar( 0x30 + (0x0F & (uchar)(usedSoftwareRevision >> 28)) ) );
	softwareRev.prepend( "Appl - v" );
    }

    if( testVersion )
    {
    	softwareRev.prepend( "Test - " );
    }

    return softwareRev;
}

QString QrfeGlobal::bootloaderRevisionToString( const ulong bootloaderRevision )
{
    if(bootloaderRevision == 0xFFFFFFFF)
	return "No bootloader installed";

    QString bootloaderRev;
    bootloaderRev.clear();
    bootloaderRev.prepend( QChar( 0x30 + (0x0F & (uchar)(bootloaderRevision >> 0)) ) );
    bootloaderRev.prepend( QChar( 0x30 + (0x0F & (uchar)(bootloaderRevision >> 4)) ) );
    bootloaderRev.prepend( "." );
    bootloaderRev.prepend( QChar( 0x30 + (0x0F & (uchar)(bootloaderRevision >> 8)) ) );
    bootloaderRev.prepend( QChar( 0x30 + (0x0F & (uchar)(bootloaderRevision >> 12)) ) );
    bootloaderRev.prepend( "v" );

    return bootloaderRev;
}

QString QrfeGlobal::applicationToString(const ulong readerType)
{
	if(QrfeGlobal::isAUR(readerType))
	{
		switch( QrfeGlobal::getApplicationId(readerType) )
		{
		case AUR_APP_STANDARD:			return "Standard";
		case AUR_APP_TAG:				return "Tag";
		case AUR_APP_DIRECT_MODE:		return "Direct-Mode";
		case AUR_APP_WLAN_CONTROL:		return "WLAN";
		case AUR_APP_HYCAT:				return "HYCAT";
		default:					return "";
		}
	}

	if(QrfeGlobal::isPUR(readerType))
	{
		switch( QrfeGlobal::getApplicationId(readerType) )
		{
        case PUR_APP_STANDARD:              return "Standard";
        case PUR_APP_HID_KEYBOARD:          return "HID-Keyboard";
        case PUR_APP_IDTRONIC_RUSSIA:       return "iDTRONIC - Russia";
        default:                            return "";
		}
	}

	return "";
}


ulong QrfeGlobal::readerCaps ( const ulong readerType, const ulong /*hardwareRevision*/, const ulong softwareRevision, const ReaderSystem currentSystem )
{
	ulong caps = 0;


	switch( ((readerType & 0x000F0000) >> 16))
	{
	case 0x02:
	case 0x04:
	case 0x05:
	case 0x06:
	case 0x07:
    case 0x0A:
        caps |= EEPROM_AVAILABLE;
		break;
	case 0x03:
		caps |= EEPROM_AVAILABLE;
		caps |= PLUG_OFF_REQUIRED;
		break;
	}

	if(currentSystem == BOOTLOADER){
		caps |= UPDATE_DIALOG;
		return caps;
	}

	switch( ((readerType & 0xFF000000) >> 24))
	{
	case 0x02:
		caps |= READER_SETTINGS;
		caps |= ENGINEERING;

		if( (readerType & 0x000000FF) == 0x00000003)
			caps |= APPLICATION_SETTINGS;

		break;

	case 0x81:
	case 0x82:
	case 0x83:
		caps |= READER_SETTINGS;
		if( (softwareRevision & 0x0000FFFF) > 0x0026)
			caps |= ENGINEERING;

		switch( (readerType & 0x000000FF) )
		{
		case PUR_APP_HID_KEYBOARD:
            caps |= APPLICATION_SETTINGS;
			break;
		default:
			break;
		}
		break;
    case 0x84:
        caps |= READER_SETTINGS;
        caps |= ENGINEERING;
        break;

	default:
		break;
	}


	return caps;
}

ulong QrfeGlobal::tagFunctionCaps ( const ulong readerType, const ulong /*hardwareRevision*/, const ulong softwareRevision, const ReaderSystem currentSystem )
{
	ulong caps = 0;

	if(currentSystem == BOOTLOADER)
		return 0;

	switch( ((readerType & 0xFF000000) >> 24))
	{
	case 0x02:
		caps |= READ_FROM_TAG;
		caps |= WRITE_TO_TAG;
		break;

	case 0x81:
	case 0x82:
	case 0x83:
		caps |= READ_FROM_TAG;
		caps |= WRITE_TO_TAG;
		caps |= LOCK_TAG;
		caps |= KILL_TAG;
		caps |= READ_MULTIPLE_FROM_TAG;
		caps |= NXP_SET_READ_PROTECT;
		caps |= NXP_RESET_READ_PROTECT;

		if( (softwareRevision & 0x0000FFFF) >= 0x0031)
			caps |= NXP_SEND_CMD_TO_CONTOLER;
		break;
    case 0x84:
        caps |= READ_FROM_TAG;
        caps |= WRITE_TO_TAG;
        caps |= LOCK_TAG;
        caps |= KILL_TAG;
        break;
	default:
		break;
	}

	return caps;
}


QMap<uint,QString> QrfeGlobal::availableMemoryBanks(TagType tagType)
{
	return _availableMemoryBanks.value(tagType);
}



__init_QrfeReaderInterfaceGlobal::__init_QrfeReaderInterfaceGlobal()
{
	qRegisterMetaType<QrfeGlobal::TagReadEvent>("QrfeGlobal::TagReadEvent");

	QMap<uint,QString> gen2;
	gen2.insert(0, "Reserved");
	gen2.insert(1, "EPC");
	gen2.insert(2, "TID");
	gen2.insert(3, "User");
	_availableMemoryBanks.insert( (uint)QrfeGlobal::TAG_GEN2, gen2);
}


