#include "lib_neoNet_prot_IP.h"

#include <string.h>
#include <stdio.h>


int32_t neoNet_P_IP_prepRead(neoNet_utils_DevInfo* in_dev, neoNet_P_IP_Frame* in_fr, uint16_t in_fr_len){
    // NOTE: in_fr_len must c <0; INT16_MAX>

    if(in_fr_len < 20){ return -(NEONET_PROT_IP_ERR_MASTER+1); } // TODO: prep a distinct ret code

    if(in_fr_len < ((uint16_t)neoNet_P_IP_frame_GET_intntHdrLen(in_fr))*4){ return -(NEONET_PROT_IP_ERR_MASTER+2); } // TODO: prep a distinct ret code
    // NOTE: if the options fields are detected you may need to byte-swap them - that depends on what opts are passed

    printf("dstAddr:%d.%d.%d.%d\r\n",((uint8_t*)in_fr->dstAddr32b)[0],((uint8_t*)in_fr->dstAddr32b)[1],((uint8_t*)in_fr->dstAddr32b)[2],((uint8_t*)in_fr->dstAddr32b)[3]);
    if(memcmp(&in_fr->dstAddr32b, in_dev->ipAddr, 4) != 0){ return -(NEONET_PROT_IP_ERR_MASTER+3); } // TODO: prep a distinct ret code
    
    if(neoNet_utils_calcChecksum((uint8_t*) in_fr, ((uint16_t)neoNet_P_IP_frame_GET_intntHdrLen(in_fr))*4) != 0){ return -(NEONET_PROT_IP_ERR_MASTER+4); } // TODO: prep a distinct ret code

    in_fr->wholeFrameLenBytes16b = ntohs(in_fr->wholeFrameLenBytes16b);
    in_fr->fragmId16b = ntohs(in_fr->fragmId16b);
    in_fr->fragmFlags3b_fragmOffset13b = ntohs(in_fr->fragmFlags3b_fragmOffset13b);
    //in_fr->hdrChksm16b = ntohs(in_fr->hdrChksm16b); // actually we don't need this
    //in_fr->srcAddr32b = ntohl(in_fr->srcAddr32b);
    //in_fr->dstAddr32b = ntohl(in_fr->dstAddr32b);

    return in_fr_len - (((uint16_t)neoNet_P_IP_frame_GET_intntHdrLen(in_fr))*4);
}

int16_t neoNet_P_IP_prepResp(neoNet_utils_DevInfo* in_dev, neoNet_P_IP_Frame* in_fr, neoNet_P_IP_Frame* out_fr){
    // NOTE: this func must work also if in_fr==out_fr
    // NOTE: this func must not rely on the fr.data 's length

    if(out_fr != in_fr){ memcpy(out_fr, in_fr, 10); }
    memcpy(&out_fr->dstAddr32b, &in_fr->srcAddr32b, 4);
    memcpy(&out_fr->srcAddr32b, in_dev->ipAddr, 4);
    neoNet_P_IP_frame_SET_intntHdrLen(out_fr, 5);

    return 0;
}

int16_t neoNet_P_IP_prepSend(neoNet_utils_DevInfo* in_dev, neoNet_P_IP_Frame* out_fr, uint16_t out_fr_dataLen){
    out_fr->wholeFrameLenBytes16b = ((uint16_t)neoNet_P_IP_frame_GET_intntHdrLen(out_fr))*4 + out_fr_dataLen;

    out_fr->hdrChksm16b = 0;

    out_fr->wholeFrameLenBytes16b = htons(out_fr->wholeFrameLenBytes16b);
    out_fr->fragmId16b = htons(out_fr->fragmId16b);
    out_fr->fragmFlags3b_fragmOffset13b = htons(out_fr->fragmFlags3b_fragmOffset13b);
    //in_fr->srcAddr32b = htonl(in_fr->srcAddr32b);
    //in_fr->dstAddr32b = htonl(in_fr->dstAddr32b);

    out_fr->hdrChksm16b = neoNet_utils_calcChecksum((uint8_t*) out_fr, ((uint16_t)neoNet_P_IP_frame_GET_intntHdrLen(out_fr))*4);

    return out_fr_dataLen + ((uint16_t)neoNet_P_IP_frame_GET_intntHdrLen(out_fr))*4;
}
