// ****************************************************************************
// INCLUDE FILES: Header files of modules referenced by this module
// ****************************************************************************
#include <ConfigFileFormater.h>
#include <string.h>
#include <stdio.h>

// ****************************************************************************
// PRIVATE TYPES: Private types used by this module only
// ****************************************************************************


// ****************************************************************************
// PRIVATE MACROS: Private #define directives used by this module only
// ****************************************************************************
#define CFF_CFG_START_DELIMITER '#'
#define CFF_CFG_STANDARD_DELIMITER '%' //0x25
#define CFF_CFG_SENS_NUM_DELIMITER ','
#define CFF_CFG_SECTION_DELIMITER '$' //0x24
#define CFF_CFG_SECTION_START_DELIMITER '&' //0x26




// ****************************************************************************
// PRIVATE VARIABLES: Variables used by this module only (static)
// ****************************************************************************


// ****************************************************************************
// PRIVATE FUNCTIONS PROTOTYPES: Functions used by this module only (static)
// ****************************************************************************
//---------------------------------------------------------------------
//! @brief Creates ISTP configuration file header
//!
//! Configuration file consists of several sections. This function
//! creates the "header" section based on the sensor board config
//! structure and stores encoded header into cfgFileOutput buffer. 
//!
//! @param[in]  sensorBoardCfg - sensor board configuration structure
//! @param[out] cfgFileOutput - provided buffer where the
//!                             generated configuration file header 
//!                             will be stored. Buffer space is allocated by
//!                             the caller.
//! @return size of the generated config file header in bytes
//---------------------------------------------------------------------
static uint16_t CFFcreateBoardHeader( uint8_t * cfgFileOutput, CFFSensorBoardCfg_t * sensorBoardCfg );

//---------------------------------------------------------------------
//! @brief Creates ISTP configuration file sensor's config section
//!
//! Configuration file consists of several sections. This function
//! creates the "sensor's config" section based on the sensor board
//! config structure and stores encoded config into cfgFileOutput
//! buffer.
//!
//! @param[in]  sensorBoardCfg - sensor board configuration structure
//! @param[out] cfgFileOutput - provided buffer where the
//!                             generated configuration file sensor's
//!                             config section will be stored.
//!                             Buffer space is allocated by the
//!                             caller.
//! @return size of the generated config file sensor's config section
//!         in bytes
//---------------------------------------------------------------------
static uint16_t CFFcreateSensorConfigs( uint8_t * cfgFileOutput, CFFSensorBoardCfg_t * sensorBoardCfg );

//---------------------------------------------------------------------
//! @brief Creates ISTP configuration file parameter's config section
//!
//! Configuration file consists of several sections. This function
//! creates the "parameter's config" section based on the sensor board
//! config structure and stores encoded config into cfgFileOutput
//! buffer.
//!
//! @param[in]  sensorBoardCfg - sensor board configuration structure
//! @param[out] cfgFileOutput - provided buffer where the
//!                             generated configuration file param's
//!                             config section will be stored.
//!                             Buffer space is allocated by the
//!                             caller.
//! @return size of the generated config file param's config section
//!         in bytes
//---------------------------------------------------------------------
static uint16_t CFFcreateParameterConfigs( uint8_t * cfgFileOutput, CFFSensorBoardCfg_t * sensorBoardCfg );

//---------------------------------------------------------------------
//! @brief Creates ISTP configuration file final section
//!
//! Configuration file consists of several sections. This function
//! creates the "final" section and stores encoded config into
//! cfgFileOutput buffer.
//!
//! @param[in]  N/A
//! @param[out] cfgFileOutput - provided buffer where the
//!                             generated configuration file final
//!                             section will be stored.
//!                             Buffer space is allocated by the
//!                             caller.
//! @return size of the generated config file final section in bytes
//---------------------------------------------------------------------
static uint16_t CFFfinalizeFile( uint8_t * cfgFileOutput );

// ****************************************************************************
// PUBLIC VARIABLES: Public variables shared with other modules
// ****************************************************************************
// General strings
/*char const * const CFFstringBoard = "board";
// Quantity name strings
char const * const CFFstringAcc = "acc";
char const * const CFFstringTemp = "temp";
char const * const CFFstringRate = "rate";
char const * const CFFstringRateAnalog = "rate_analog";
char const * const CFFstringStatus = "status";
char const * const CFFstringErrorType = "error_type";
// Parameter name strings

// Parameter unit strings
char const * const CFFAccRangeG = "G";
char const * const CFFGyroRangeDpS = "d/s";
char const * const CFFSampleRateHz = "Hz";*/


// ****************************************************************************
// PRIVATE FUNCTIONS: Private functions used by this module only
// ****************************************************************************
uint16_t CFFcreateBoardHeader( uint8_t * cfgFileOutput, CFFSensorBoardCfg_t * sensorBoardCfg )
{
    uint8_t brdHeaderIndex = 0;
    uint8_t sensorNumberIterator;
    
    // Start of sensor board configuration header
    cfgFileOutput[brdHeaderIndex++] = CFF_CFG_START_DELIMITER;
    // Unused fields
    cfgFileOutput[brdHeaderIndex++] = 0x00;
    cfgFileOutput[brdHeaderIndex++] = 0x00;
    cfgFileOutput[brdHeaderIndex++] = 0x00;
    // Sensor board driver number
    cfgFileOutput[brdHeaderIndex++] = sensorBoardCfg->BoardDriverNumber;
    // % end of this part
    cfgFileOutput[brdHeaderIndex++] = CFF_CFG_STANDARD_DELIMITER; 
    
    // Identification of number of sensors present on the board
    for( sensorNumberIterator = 1; sensorNumberIterator <= (sensorBoardCfg->SensorsAssembled); sensorNumberIterator++ )
    {
            cfgFileOutput[brdHeaderIndex++] = 0x30 + sensorNumberIterator; // sensors number
            cfgFileOutput[brdHeaderIndex++] = CFF_CFG_SENS_NUM_DELIMITER;  // Delimiter 
    }
        
    cfgFileOutput[brdHeaderIndex++] = CFF_CFG_STANDARD_DELIMITER; 
    
    // Total number of data provided (in data units, currently number of floats)
    // Tens
    cfgFileOutput[brdHeaderIndex++] = ( sensorBoardCfg->TotalQuantities / 10 ); 
    // Ones
    cfgFileOutput[brdHeaderIndex++] = ( sensorBoardCfg->TotalQuantities % 10 ); 
        
    cfgFileOutput[brdHeaderIndex++] = CFF_CFG_STANDARD_DELIMITER;
    
    return brdHeaderIndex;
}

uint16_t CFFcreateSensorConfigs( uint8_t * cfgFileOutput, CFFSensorBoardCfg_t * sensorBoardCfg )
{
    char uniqueBoardString[200];
    char uniqueSensorString[200];
    char uniqueQuantityString[200];

    uint8_t totalSensorsAssembled = sensorBoardCfg->SensorsAssembled;
    uint8_t iterator;
    uint16_t stringSize; 
    uint16_t totalIterator = 0;
    uint16_t quantitiesIterator;
    
    // String for unique board identification is prepared just once
    sprintf(uniqueBoardString, "%s-%s%.2u",
                                sensorBoardCfg->BoardName,
                                CFFstringBoard,
                                sensorBoardCfg->BoardNumber);
    
    for( iterator = 0; iterator < totalSensorsAssembled; iterator++ )
    {
        // Function for printing unique sensor string.
        stringSize = sprintf(uniqueSensorString, "%s-%s-%s%.2u",
                                                  uniqueBoardString,
                                                  sensorBoardCfg->SensorConfig[iterator].SensorName,
                                                  sensorBoardCfg->SensorConfig[iterator].OnBoardChipName,
                                                  sensorBoardCfg->SensorConfig[iterator].OnBoardChipNumber);
        
        // Write unique sensor string to the config file
        memcpy( &cfgFileOutput[totalIterator], uniqueSensorString, stringSize );
        totalIterator += stringSize;
        
        // Delimiter
        cfgFileOutput[totalIterator++] = CFF_CFG_STANDARD_DELIMITER;

        for( quantitiesIterator = 0; quantitiesIterator < sensorBoardCfg->SensorConfig[iterator].NumOfQuantities; quantitiesIterator++ )
        {
            // Write the quantity string
            stringSize = sprintf(uniqueQuantityString, "%s%u",
                                                       sensorBoardCfg->SensorConfig[iterator].Quantities[quantitiesIterator].QuantityName,
                                                       sensorBoardCfg->SensorConfig[iterator].Quantities[quantitiesIterator].QuantityNumber);
            memcpy( &cfgFileOutput[totalIterator], uniqueQuantityString, stringSize );
            totalIterator += stringSize;
            
            // Write delimiter
            cfgFileOutput[totalIterator++] = CFF_CFG_STANDARD_DELIMITER;
        }

        // Write delimiter
        cfgFileOutput[totalIterator++] = CFF_CFG_STANDARD_DELIMITER;
    }
    
    cfgFileOutput[totalIterator++] = CFF_CFG_SECTION_DELIMITER;
    
    return totalIterator;

}

uint16_t CFFcreateParameterConfigs( uint8_t * cfgFileOutput, CFFSensorBoardCfg_t * sensorBoardCfg )
{
    char helperString[100];
    uint16_t stringSize;
    uint16_t totalIterator = 0;
    uint8_t parameterIterator;
    uint8_t parameterValueIterator;

    for( parameterIterator = 0; parameterIterator < sensorBoardCfg->TotalParameters; parameterIterator++ )
    {
        cfgFileOutput[totalIterator++] = CFF_CFG_SECTION_START_DELIMITER;

        stringSize = sprintf( helperString, "%s[%s]",
        sensorBoardCfg->ParameterConfig[parameterIterator].ParameterName,
        sensorBoardCfg->ParameterConfig[parameterIterator].ParameterUnit);
        memcpy( &cfgFileOutput[totalIterator], helperString, stringSize );
        totalIterator += stringSize;

        cfgFileOutput[totalIterator++] = CFF_CFG_STANDARD_DELIMITER;

        for( parameterValueIterator = 0; parameterValueIterator < sensorBoardCfg->ParameterConfig[parameterIterator].TotalValues;parameterValueIterator++ )
        {
            stringSize = sprintf( helperString, "%d %s",
                                                parameterValueIterator,
                                                sensorBoardCfg->ParameterConfig[parameterIterator].ParameterValues[parameterValueIterator]);

            memcpy( &cfgFileOutput[totalIterator], helperString, stringSize );
            totalIterator += stringSize;

            cfgFileOutput[totalIterator++] = CFF_CFG_STANDARD_DELIMITER;
        }

        cfgFileOutput[totalIterator++] = CFF_CFG_STANDARD_DELIMITER;
    }

    cfgFileOutput[totalIterator++] = CFF_CFG_SECTION_DELIMITER;

    for( parameterIterator = 0; parameterIterator < sensorBoardCfg->TotalParameters; parameterIterator++ )
    {
        cfgFileOutput[totalIterator++] = sensorBoardCfg->ParameterConfig[parameterIterator].DefaultValue;
    }

    cfgFileOutput[totalIterator++] = CFF_CFG_SECTION_DELIMITER;

    return totalIterator;
};

uint16_t CFFfinalizeFile( uint8_t * cfgFileOutput )
{
    uint8_t numOfZeroes = 10;
    memset( cfgFileOutput, 0, numOfZeroes );
    return numOfZeroes;
}

// ****************************************************************************
// PUBLIC FUNCTIONS: Public functions shared with other modules
// ****************************************************************************
uint16_t CFFCreateConfigFile( uint8_t * cfgFileOutput, uint16_t cfgFileSize, CFFSensorBoardCfg_t * sensorBoardCfg )
{
    uint16_t cfgFileindex = 0;
    uint16_t cfgFileindexIncrement;
    
    if( cfgFileSize >= CFF_SENSOR_BOARD_EEPROM_SIZE_BYTES )
    {
        // Enough space provided, let's start creating config file
        
        // Clear the buffer
        memset(cfgFileOutput, 0, CFF_SENSOR_BOARD_EEPROM_SIZE_BYTES );

        cfgFileindexIncrement = CFFcreateBoardHeader( cfgFileOutput, sensorBoardCfg );

        cfgFileindex += cfgFileindexIncrement;

        cfgFileindexIncrement = CFFcreateSensorConfigs( &cfgFileOutput[cfgFileindex], sensorBoardCfg);

        cfgFileindex += cfgFileindexIncrement;

        cfgFileindexIncrement = CFFcreateParameterConfigs( &cfgFileOutput[cfgFileindex], sensorBoardCfg);

        cfgFileindex += cfgFileindexIncrement;

        cfgFileindexIncrement = CFFfinalizeFile( &cfgFileOutput[cfgFileindex] );

        cfgFileindex += cfgFileindexIncrement;
    }
    else
    {

    }

    return cfgFileindex; 
}