/*
 * QrfeGlobal.cpp
 *
 *  Created on: 28.07.2011
 *      Author: stefan.detter
 */

#include "../inc/QrfeGlobal.h"

#include <QStringList>

QString QrfeGlobal::bytesToString ( const QByteArray& epc )
{
	if(epc.size() == 0)
		return "<zero>";

	QString epcString;
	for(int i = 0; i < epc.size(); i++)
	{
		if(i != 0)
			epcString += "-";
		epcString += QString("%1").arg((unsigned char)epc.at(i), 2, 16, QChar('0'));
	}
	return epcString.toUpper();
}

QByteArray QrfeGlobal::stringToBytes ( const QString& epcString, bool * ok )
{
	QByteArray epc;

	if(epcString == "<zero>")
	{
		if(ok)
			(*ok) = true;
		return epc;
	}

	QStringList bytes = epcString.split(QChar('-'));
	bool local_ok = false;
	if(!ok)
		ok = &local_ok;
	for(int i = 0; i < bytes.size(); i++)
	{
		(*ok) = false;
		epc.append((uchar) bytes.at(i).toUShort(ok, 16 ) );
		if(!(*ok))
			return QByteArray();
	}
	return epc;
}


QByteArray QrfeGlobal::appendBits(const QByteArray& base, int targetBitPos, quint64 value, int valueBitCount)
{
    int targetIndex = targetBitPos/8;
    int targetBitOffset = targetBitPos%8;
    uchar mask1 = (0xFF) >> targetBitOffset;
    uchar mask2 = (0xFF) << (8 - targetBitOffset);

    int byteCount = valueBitCount/8;
    byteCount += ((valueBitCount%8) > 0) ? 1 : 0;

    int targetSize = (targetBitPos + valueBitCount)/8;
    targetSize += (((targetBitPos + valueBitCount)%8) > 0) ? 1 : 0;

    QByteArray ba;
    ba.fill(0, targetSize);
    ba.replace(0, base.size(), base);

    for(int i = 0; i < byteCount; i++)
    {
        uchar byte = 0;
        // Get byte
        int shift = (valueBitCount - ((i+1) * 8));
        int bitCount = 8;
        if(shift < 0){
            byte = (uchar) (value << ( shift * (-1) ));
            bitCount = (8 + shift);
        }
        else
            byte = (uchar) (value >> shift);


        // Clear target values
        ba[targetIndex] = ba[targetIndex] & ~mask1;
        if(targetBitOffset != 0 && ((targetBitOffset + bitCount) > 8))
            ba[targetIndex+1] = ba[targetIndex+1] & ~mask2;

        // Write target bits
        ba[targetIndex] = ba[targetIndex] | (byte >> targetBitOffset);
        if(targetBitOffset != 0 && ((targetBitOffset + bitCount) > 8))
            ba[targetIndex+1] = ba[targetIndex+1] | (byte << (8 - targetBitOffset));

        targetIndex++;
    }

    return ba;
}

quint64 QrfeGlobal::extractValue(const QByteArray& base, int targetBitPos, int valueBitCount)
{
    quint64 res = 0;

    int targetIndex = targetBitPos/8;
    int targetBitOffset = targetBitPos%8;
    uchar mask1 = (0xFF) >> targetBitOffset;
    uchar mask2 = (0xFF) << (8 - targetBitOffset);

    int byteCount = valueBitCount/8;
    byteCount += ((valueBitCount%8) > 0) ? 1 : 0;

    for(int i = 0; i < byteCount; i++)
    {
        uchar byte = 0;
        byte = (base[targetIndex] & mask1);
        byte <<= targetBitOffset;

        uchar followByte = 0;
        if(targetBitOffset != 0 && base.size() > (targetIndex+1))
        {
            followByte |= (base[targetIndex+1] & mask2);
            followByte >>= 8 - targetBitOffset;
        }
        byte |= followByte;

        int shift = (valueBitCount > 8) ? 8 : valueBitCount;

        res <<= shift;

        if(shift == 8)
            res |= byte;
        else
            res |= (byte >> (8-shift)) & (0xFF >> (8-shift));

        valueBitCount -= shift;
        targetIndex++;

    }

    return res;
}


QByteArray QrfeGlobal::xorByteArray ( const QByteArray& data, const QByteArray& xdata)
{
	QByteArray result;
	result.resize(data.size());
	for(int i = 0; i < data.size(); i++)
	{
		result[i] = data.at(i) ^ xdata.at( i % xdata.size());
	}
	return result;
}


QString QrfeGlobal::getWrappedString ( const QString& string, int wrapAfterCount )
{
	QString result = string;

	int size = result.size();
	int wrap = size / wrapAfterCount;
	for(int i = 1; i <= wrap; i++)
	{
		result.insert((i*wrapAfterCount) + (i-1), '\n');
	}

	return result;
}


ulong QrfeGlobal::bitCountTobyteCount( const ulong bitCount )
{
	if(bitCount == 0)
		return 0;
	ulong byteCount = bitCount >> 3;
	byteCount += ((bitCount&0x7) != 0) ? 1 : 0;
	return byteCount;
}
