/*
 * =================================================================================================
 *
 *       Filename:  test-driver.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  21/10/2011 01:48:23 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Maciej Lipinski (based on code from Cesar Prados Boda (cp), c.prados@gsi.de)
 *        Company:  CERN
 *
 * =================================================================================================
 */

#include "fec.h"
#include <stdio.h>
#include <stdint.h>


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>

#define MAX_MSG_SIZE 1024
#define MAX_NR_EN_MSGs 8

#define MSG_SIZE 501   
			  // (x + 1)  ->> because if we have text, we need to cut the end char
			  
/*
 * Control Debugging
 */
//#define DBG_SHOW_ORIG_MSG

/*
 * The encoder receives message of some size from somewhere, this 
 * function simulates it, in the function you decide on the 
 * message content and size.
 * So, the function basically only outputs data (msg and size)
 */
int createOriginalMsg(unsigned char msg[], unsigned int* size, unsigned int* etherType)
{
    // decode on message size
    unsigned int msgSize = MSG_SIZE; // 500 bytes
    
    *size 	= msgSize;                 
    *etherType	= 0xABCD;
    // decider on message content
    unsigned char nasty_data_filler = 0x0;
    for (int i=0; i<msgSize;i++)
      if(i%2==0) msg[i] = nasty_data_filler++;
      else       msg[i] = 0x0;

    #ifdef DBG_SHOW_ORIG_MSG
    // print the result
    printf("\n********************** message to be encoded (payload of %3d bytes) ***************************", msgSize);
    for (int i = 0; i < msgSize; ++i)
    {
 	if(i % 16 == 0) printf("\n");
        printf("0x%2x, ", msg[i]);
    }
    printf("\n***********************************************************************************************\n");
    #endif
}

int show_encoded_msgs(const unsigned char** encodedMsgs,unsigned int* encodedMsgLen, unsigned int msg_number)
{
    printf("FEC encoded into %d Ethernet frames\n",msg_number);
    for(unsigned int i = 0; i< msg_number; i++)
    {
      printf("MSG_%d [payload size(with FEC header): %d]:\n",i,encodedMsgLen[i]);
      printf("HEADER: ");
      for(unsigned int j = 0; j< encodedMsgLen[i]; j++)
      {
	if(j > 7 && (j-8) % 18 == 0) printf("\n");
	printf("0x%2x, ", encodedMsgs[i][j]);
	if(j==7) printf("\nPAYLOAD:"); //end of header
      }
      printf("\n");
    }
}

int compare_results(const unsigned char* origMsg, unsigned int origMsgSize, 
		    const unsigned char* recoveredMsg,	int recoveredMsgSize)
{
  int ret = 0;
  
  if(origMsgSize != recoveredMsgSize)
  {
    printf("FEC FAILED: wrong size of recovered message. origMsgSize=%d  recoveredMsgSize = %d\n",
	   origMsgSize, recoveredMsgSize);
    return -1;
  }
  
  for (int i = 0; i< origMsgSize; i++)
  {
    if(origMsg[i] != recoveredMsg[i]) 
    {
	printf("Error in byte %d, original data: 0x%x, recovered data: 0x%x\n", origMsg[i], recoveredMsg[i] );
	ret = -1;
    }
    
    return ret;
  }
  
}


int main()
{

    int ret = 0;

    //init FEC (bullshit)
    fec_open();
    
    /***************************************************************************************
    /*					Creating message
     ***************************************************************************************/   
    unsigned int  origMessageSize;
    unsigned int  origEtherType;
    unsigned char origMessage[MAX_MSG_SIZE];    
    //create a message
    createOriginalMsg(origMessage, &origMessageSize, &origEtherType);
    
    /***************************************************************************************
    /*					Encoding
     ***************************************************************************************/  
    const unsigned char* encodedMessages[MAX_NR_EN_MSGs];
    unsigned int 	 encoded_msgs_len[MAX_NR_EN_MSGs];
    unsigned int 	 encoded_msgs_number;    
    
    //encode original message into a number of ethernet frames
    ret = fec_encoder(origMessage,origMessageSize, origEtherType, encodedMessages, 
		      encoded_msgs_len, &encoded_msgs_number);
    
    if(ret < 0 ) printf("fec_encoder error\n");
    
    /***************************************************************************************
    /*				"Sending [erasure channel]
     ***************************************************************************************/      
    const unsigned char* erroredMessages[MAX_NR_EN_MSGs];
    
    //show the effect 
    //show_encoded_msgs(encodedMessages, encoded_msgs_len,encoded_msgs_number);    
    
    erasure_channel(erroredMessages, encodedMessages, encoded_msgs_len, encoded_msgs_number);
        
    /***************************************************************************************
    /*					Decoding
     ***************************************************************************************/    
    const unsigned char* recoveredMessage;
    int  recoveredMsgSize = 0;
    unsigned int  recoveredEtherType;
    ret = 0;
    
    printf("\n-----------------------------  FEC_DECODER  ----------------------------\n");
    
    for(int i =0; i < encoded_msgs_number; i++)
    {
	if(recoveredMsgSize == 0) //not recovered the frame yet
	{
	    recoveredMessage = fec_decode(erroredMessages[i], encoded_msgs_len[i] /*I dont like this*/, 
					  &ret, &recoveredEtherType);
	    if(ret > 0)	//record the size
		recoveredMsgSize = ret;
	}
	else //go through the unnecessary fragments
	    fec_decode(erroredMessages[i], encoded_msgs_len[i], &ret, &recoveredEtherType);
    }
    printf("------------------------------------------------------------------------\n");
    ret = -1;
    if(recoveredMsgSize > 0)
      ret=compare_results(origMessage, origMessageSize, recoveredMessage,recoveredMsgSize);
      
    if(ret==0 && recoveredMsgSize > 0) 
      printf("\n\n\n \t\t CONGRATULATIONS ! \n \t   message recovered succesfully \n\n\n ");
    else
      printf("\n\n\n \t\t Message not recovered\n\n\n");
    
    fec_decoder_report();
    
    return 0;//below is the shity code provided by CESAR and modified by me
  
}
