#include "ModbusRepository.h"
#include <QByteArray>
#include <QBuffer>
#include <QDataStream>
#include "EngLog.h"

CModbusRepository::CModbusRepository()
{
}

int CModbusRepository::AddHRDataMap(quint16 StartAddress, quint16 Length)
{
    mMutex.lockForWrite();
    for(int i= 0; i < mHoldingRegisters.size(); i++)
    {
        if((StartAddress >= mHoldingRegisters.at(i).mStartAddress && StartAddress <= mHoldingRegisters.at(i).mEndAddress) ||
           (StartAddress + Length - 1 >= mHoldingRegisters.at(i).mStartAddress && StartAddress + Length - 1 <= mHoldingRegisters.at(i).mEndAddress))
        {
            mMutex.unlock();
            return RET_ERROR;   //The data map overlaps an existing map.
        }
    }

    CHRDataMap NewHRMap(StartAddress,Length);

    mHoldingRegisters.append(NewHRMap);
    mMutex.unlock();

    CEngLog::instance()->AddLogString(QString("Création d'une zone registre modbus à l'adresse: %1 de taille %2").arg(StartAddress).arg(Length));

    return RET_OK;
}

bool CModbusRepository::IsHRValid(quint16 StartAddress, quint16 Length, int *index)
{
    mMutex.lockForRead();
    for(int i= 0; i < mHoldingRegisters.size(); i++)
    {
        if((StartAddress >= mHoldingRegisters.at(i).mStartAddress && StartAddress + Length - 1 <= mHoldingRegisters.at(i).mEndAddress))
        {
            if(index != 0)
            {
                *index = i;
            }
            mMutex.unlock();
            return true;
        }
    }
    mMutex.unlock();

    return false;
}

QByteArray CModbusRepository::GetHRData(quint16 StartAddress, quint16 Length, bool *OK)
{
    QByteArray Data;
    int RegisterIndex = 0;

    if(IsHRValid(StartAddress,Length, &RegisterIndex) == false)
    {
        if(OK != 0)
        {
            *OK = false;
        }
    }
    else
    {
        mMutex.lockForRead();
        int DataIndex = StartAddress - mHoldingRegisters.at(RegisterIndex).mStartAddress;
        for(int i = 0; i < Length; i++)
        {
            quint16 CurReg = mHoldingRegisters.at(RegisterIndex).mRegistersData.at(DataIndex++);
            quint8 HighByte, LowByte;

            LowByte = CurReg & 0x00FF;
            HighByte = (CurReg >> 8) & 0x00FF;
            Data.append(HighByte);
            Data.append(LowByte);
        }
        mMutex.unlock();

        if(OK != 0)
            *OK = true;
    }

    return Data;
}

int CModbusRepository::WriteHRData(quint16 StartAddress, quint16 Length, QByteArray Data)
{
    int RegisterIndex;

    if(IsHRValid(StartAddress,Length, &RegisterIndex) == false)
    {
        return RET_ERROR;
    }

    if(Length*2 != Data.size())
    {
        return RET_ERROR;
    }

    mMutex.lockForWrite();
    int DataIndex = StartAddress - mHoldingRegisters.at(RegisterIndex).mStartAddress;

    for(int i = 0; i < Length; i++)
    {
        quint8 HighByte = Data.at(i*2);
        quint8 LowByte = Data.at(i*2 + 1);
        qint16 Word = HighByte;
        Word <<= 8;
        Word += LowByte;
        Word = Word &0xFFFF;

        mHoldingRegisters[RegisterIndex].mRegistersData[DataIndex++] = Word;
    }
    mMutex.unlock();

    emit RepoChanged(StartAddress,Length);

    return RET_OK;
}

int CModbusRepository::WriteSingleReg(quint16 Address, quint16 Value)
{
    int RegisterIndex;

    if(IsHRValid(Address,1, &RegisterIndex) == false)
    {
        return RET_ERROR;
    }

    mMutex.lockForWrite();
    int DataIndex = Address - mHoldingRegisters.at(RegisterIndex).mStartAddress;
    mHoldingRegisters[RegisterIndex].mRegistersData[DataIndex] = Value;
    mMutex.unlock();

    emit RepoChanged(Address,1);

    return RET_OK;
}

int CModbusRepository::WriteMultipleRegs(quint16 StartAddress, QList<qint16> Data)
{
    int RegisterIndex;

    if(IsHRValid(StartAddress,Data.size(), &RegisterIndex) == false)
    {
        return RET_ERROR;
    }

    mMutex.lockForWrite();
    int DataIndex = StartAddress - mHoldingRegisters.at(RegisterIndex).mStartAddress;
    for(int i = 0; i < Data.size(); i++)
    {
        mHoldingRegisters[RegisterIndex].mRegistersData[DataIndex++] = Data.at(i);
    }
    mMutex.unlock();

    emit RepoChanged(StartAddress,Data.size());
    return RET_OK;
}

QList<qint16> CModbusRepository::GetRegs(quint16 StartAddress, quint16 Length, bool *OK)
{
    int RegisterIndex;

    if(IsHRValid(StartAddress,Length, &RegisterIndex) == false)
    {
        if(OK != 0)
        {
            *OK = false;
        }
        return QList<qint16>();
    }

    if(OK != 0)
    {
        *OK = true;
    }

    int DataIndex = StartAddress - mHoldingRegisters.at(RegisterIndex).mStartAddress;
    return mHoldingRegisters[RegisterIndex].mRegistersData.mid(DataIndex,Length);
}
quint16 CModbusRepository::GetSingleReg(quint16 Address, bool *OK)
{
    int RegisterIndex;

    if(IsHRValid(Address,1, &RegisterIndex) == false)
    {
        if(OK != 0)
            *OK = false;
        return 0;
    }

    if(OK != 0)
        *OK = true;

    mMutex.lockForRead();
    int DataIndex = Address - mHoldingRegisters.at(RegisterIndex).mStartAddress;
    quint16 Data = mHoldingRegisters[RegisterIndex].mRegistersData[DataIndex];
    mMutex.unlock();

    return Data;
}


CHRDataMap::CHRDataMap(quint16 StartAddress, quint16 Length)
{
    mStartAddress = StartAddress;
    mLength = Length;
    for(int i = 0; i < Length; i++)
    {
        mRegistersData.append(0);
    }
    mEndAddress = StartAddress + Length - 1;
}



