#include "eccbaseclass.h"

tlm::tlm_sync_enum ECCBaseClass::nb_transport_fw( int id,
                                                  tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_time &delay )
{
    if (trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_REQ) {
        // Allocate memory for encoded data using the size provided by AllocationEncode
        unsigned nEncodedDataSize = AllocationSize(trans.get_data_length());
        assert(nEncodedDataSize != 0);
        unsigned char *pEncodedData = new unsigned char[nEncodedDataSize];

        // Save memory pointer and size
        m_mDataPointer[pEncodedData].pData = trans.get_data_ptr();
        m_mDataPointer[pEncodedData].nDataSize = trans.get_data_length();

        // Data Encoding
        Encode(trans.get_data_ptr(), trans.get_data_length(), pEncodedData,
               nEncodedDataSize);

        // Change transport data length and pointer
        trans.set_data_length(nEncodedDataSize);
        trans.set_data_ptr(pEncodedData);
    } else if (trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_REQ) {
        // Allocate memory for reading data using the size provided by AllocationEncode
        unsigned nReadDataSize = AllocationSize(trans.get_data_length());
        assert(nReadDataSize != 0);
        unsigned char *pReadData = new unsigned char[nReadDataSize];

        // Save memory pointer and size
        m_mDataPointer[pReadData].pData = trans.get_data_ptr();
        m_mDataPointer[pReadData].nDataSize = trans.get_data_length();

        // Change transport data length and pointer
        trans.set_data_length(nReadDataSize);
        trans.set_data_ptr(pReadData);
    }

    return i_socket[id]->nb_transport_fw( trans, phase, delay );
}


// Backward interface
tlm::tlm_sync_enum ECCBaseClass::nb_transport_bw( int id,
                                                  tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_time &delay )
{
    if (trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_RESP) {
        //Look for the corresponding data pointer for decoding
        auto it = m_mDataPointer.find(trans.get_data_ptr());
        assert(it != m_mDataPointer.end());

        // Data Decoding
        Decode(trans.get_data_ptr(), trans.get_data_length(), it->second.pData,
               it->second.nDataSize);

        // delete data pointer from map
        m_mDataPointer.erase(it);

        // Delete data pointer used for encoded data
        delete[] trans.get_data_ptr();

        // Set data pointer and size for decoded data
        trans.set_data_ptr(it->second.pData);
        trans.set_data_length(it->second.nDataSize);
    } else if (trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_RESP) {
        //Look for the corresponding data pointer for decoding
        auto it = m_mDataPointer.find(trans.get_data_ptr());
        assert(it != m_mDataPointer.end());

        // delete data pointer from map
        m_mDataPointer.erase(it);

        // Delete data pointer used for encoded data
        delete[] trans.get_data_ptr();

        // Set data pointer and size for decoded data
        trans.set_data_ptr(it->second.pData);
        trans.set_data_length(it->second.nDataSize);
    }

    return t_socket[id]->nb_transport_bw( trans, phase, delay );
}
