/*******************************************************************************
 * JMMC project ( http://www.jmmc.fr ) - Copyright (C) CNRS.
 ******************************************************************************/
/**
 * @file
 * Functions to handle instrumental configuration.
 *
 */

/* 
 * System Headers
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 
 * Local Headers
 */
#include "amdlib.h"
#include "amdlibProtected.h"

/*
 * Local function declaration
 */
static amdlibCOMPL_STAT amdlibSplitHeaderKeyword(amdlibKEYW_LINE keywLine,
                                        amdlibKEYWORD   *keyword);

/*
 * Protected function definition
 */
/**
 * Add / Modify a keyword to an instrumental configuration array. 
 *
 * This function inserts a new keyword in the specified instrumental
 * configuration array if it is not already stored in the array. This keyword is
 * given as a line read on headers (ie from type "@e name = @e value [ / 
 * @e comment ]" ).
 * 
 * @param insCfg instrumental configuration array.
 * @param keywLine the data to insert.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibAddInsCfgKeyword(amdlibINS_CFG   *insCfg, 
                                        amdlibKEYW_LINE keywLine,
                                        amdlibERROR_MSG errMsg)
{ 
    int i;
    amdlibKEYWORD keyword;
    char name[amdlibKEYW_NAME_LEN+1];
    char currentName[amdlibKEYW_NAME_LEN+1];

    /* Split the keyword line in its components */
    if (amdlibSplitHeaderKeyword(keywLine, &keyword) != amdlibSUCCESS)
    {
        amdlibSetErrMsg("Impossible to split the input line");
        return amdlibFAILURE;
    }

    strcpy(name, keyword.name);
    amdlibStripBlanks(name);
    /* Look for keyword in table */
    for (i = 0; i < insCfg->nbKeywords; i++)
    {
        strcpy(currentName, insCfg->keywords[i].name);
        amdlibStripBlanks(currentName);
        if (strcmp(currentName, name) == 0)
        {
            /* If found, returns error */
            amdlibSetErrMsg("%s keyword to add is already present in insCfg "
                            "array", keyword.name);
            return amdlibFAILURE;
        }
    }
    
    /* Insert it if array is not full */
    if (i < amdlibNB_INS_CFG_KEYW)
    {
        strcpy(insCfg->keywords[i].name, keyword.name);
        strcpy(insCfg->keywords[i].value, keyword.value);
        strcpy(insCfg->keywords[i].comment, keyword.comment);
        insCfg->nbKeywords++;
        return amdlibSUCCESS;
    }
    
    amdlibSetErrMsg("insCfg array is full - impossible to insert it");
    return amdlibFAILURE;
}

/**
 * Remove keyword(s) containing string in an instrumental configuration array. 
 * The keywords removed contain at least one instance of the string.
 *
 * @param insCfg instrumental configuration array.
 * @param keyword the string to which compare the keyword to remove.
 *
 */
void amdlibRemoveInsCfgKeyword(amdlibINS_CFG   *insCfg, 
                               char            *keyword)
{
    int i,j;
    char name[amdlibKEYW_NAME_LEN+1];
    char currentName[amdlibKEYW_NAME_LEN+1];

    strcpy(name, keyword);
    /* Look for keyword in table */
    i=0;

    while (i < insCfg->nbKeywords)
    {
        strcpy(currentName, insCfg->keywords[i].name);
        if (strstr(currentName, name) != NULL)
        {
            /* found, at location I */
            for (j=i+1;j<insCfg->nbKeywords;j++)
            {
                strcpy(insCfg->keywords[j-1].name, insCfg->keywords[j].name);
                strcpy(insCfg->keywords[j-1].value, insCfg->keywords[j].value);
                strcpy(insCfg->keywords[j-1].comment, insCfg->keywords[j].comment);
            }
            insCfg->nbKeywords--;
        }
        else
        {
            i++;
        }
    }

    return;
}

/**
 * Get the value of a given keyword from an instrumental configuration array. 
 *
 * This function finds the value corresponding to the given keyword name in the
 * given instrumental configuration array.
 *   
 * @param insCfg instrumental configuration array.
 * @param keywName name of the keyword to find.
 * @param keywValue value of the found keyword.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibGetInsCfgKeyword(amdlibINS_CFG   *insCfg, 
                                        char            *keywName,
                                        char    keywValue[amdlibKEYW_VAL_LEN+1],
                                        amdlibERROR_MSG errMsg)
{
    int i;
    char name[amdlibKEYW_NAME_LEN+1];
    char currentName[amdlibKEYW_NAME_LEN+1];

    strcpy(name, keywName);
    amdlibStripBlanks(name);
    /* Look for keyword in table */
    for (i = 0; i < insCfg->nbKeywords; i++)
    {
        strcpy(currentName, insCfg->keywords[i].name);
        amdlibStripBlanks(currentName);
        if (strcmp(currentName, name) == 0)
        {
            /* If found, store it */
            strcpy((char *)keywValue, insCfg->keywords[i].value);
            return amdlibSUCCESS;
        }
    }
    amdlibSetErrMsg("Keyword %s has not been found in input list of keywords",
                    keywName);
    return amdlibFAILURE;
}

/**
 * Insert a keyword in the given instrumental configuration array. 
 *
 * This function inserts a keyword in the given array. If a keyword with same
 * name already stays in the array, its value and comment are changed, otherwise
 * a amdlibKEYWORD object is created and inserted.
 *    
 * @param insCfg instrumental configuration array.
 * @param keywName name of the keyword to set.
 * @param keywVal value of the keyword to set.
 * @param keywCmt comment of the keyword to set.
 * @param errMsg error description message returned if function fails.
 *
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibSetInsCfgKeyword(amdlibINS_CFG   *insCfg, 
                                        char            *keywName,
                                        char            *keywVal,
                                        char            *keywCmt,
                                        amdlibERROR_MSG errMsg)
{ 
    int i;
    char name[amdlibKEYW_NAME_LEN+1];
    char currentName[amdlibKEYW_NAME_LEN+1];
    
    strcpy(name, keywName);
    amdlibStripBlanks(name);
    
    /* Look for keyword in table */
    for (i = 0; i < insCfg->nbKeywords; i++)
    {
        strcpy(currentName, insCfg->keywords[i].name);
        amdlibStripBlanks(currentName);
        /* If found, set it */
        if (strcmp(name, currentName) == 0)
        {
            memset(insCfg->keywords[i].value, '\0', 
                   sizeof(char[amdlibKEYW_VAL_LEN+1]));
            memset(insCfg->keywords[i].comment, '\0',
                   sizeof(char[amdlibKEYW_CMT_LEN+1]));
            strcpy(insCfg->keywords[i].value, keywVal);
            strcpy(insCfg->keywords[i].comment, keywCmt);
            return amdlibSUCCESS;
        }
    }
    /* If not found, insert it */
    if (i < amdlibNB_INS_CFG_KEYW)
    {
        strcpy(insCfg->keywords[i].name, keywName);
        strcpy(insCfg->keywords[i].value, keywVal);
        if (keywCmt != NULL || strlen(keywCmt) != 0)
        {
            strcpy(insCfg->keywords[i].comment, keywCmt);
        }
        insCfg->nbKeywords++;
        return amdlibSUCCESS;
    }
    
    amdlibSetErrMsg("insCfg array is full - impossible to insert %s", keywName);
    return amdlibFAILURE;
}

/**
 * Clear the given instrumental configuration array.
 *
 * This function clears the given array, ie sets all keywords to 0.
 *
 * @param insCfg instrumental configuration array to clear.
 * 
 * @return Always returns amdlibSUCCESS.
 */
amdlibCOMPL_STAT amdlibClearInsCfg(amdlibINS_CFG *insCfg)
{
    amdlibLogTrace("amdlibClearInsCfg()");
    
    memset(insCfg->keywords,'\0',amdlibNB_INS_CFG_KEYW * sizeof(amdlibKEYWORD));
    insCfg->nbKeywords = 0;

    return amdlibSUCCESS;
}



/*
 * Local function definition
 */
/**
 * Split a keyword line into name, value and comment.
 *
 * This function splits a keyword line of type "@e name = @e value [ / 
 * @e comment ]" into an amdlibKEYWORD data structure storing name, keyword 
 * and comment separately.
 *
 * @param keywLine line to split.
 * @param keyword structure where data is stored.
 * 
 * @return
 * amdlibSUCCESS on successful completion. Otherwise amdlibFAILURE is returned.
 */
amdlibCOMPL_STAT amdlibSplitHeaderKeyword(amdlibKEYW_LINE keywLine,
                                          amdlibKEYWORD   *keyword)
{
    int index = 0, index2 = 0;
    int keywLineLen;

    /* Init keyword */
    memset((char *)keyword, 0, sizeof(amdlibKEYWORD));
    keywLineLen = strlen(keywLine);
    if (keywLineLen > amdlibKEYW_LINE_LEN)
    {
        keywLineLen = amdlibKEYW_LINE_LEN;
    }

    /* Check if it is a comment line ("COMMENT / <comment>\0") */
    if (strstr(keywLine, "COMMENT ") != NULL)
    {
        index = strlen("COMMENT ");
        strncpy((char *)keyword->comment, keywLine + index,
                amdlibKEYW_CMT_LEN);
        return amdlibSUCCESS;
    }

    /* Copy out keyword name */
    while ((index < keywLineLen) && (*(keywLine + index) != '='))
    {
        *(keyword->name + index) = *(keywLine + index);
        index++;
    }
    *(keyword->name + index) = '\0';

    /* Skip the equal sign for the possible value */
    while ((index < keywLineLen) && ((*(keywLine + index) == '=')))
    {
        index++;
    }
    if (index >= keywLineLen)
    {
        /* There is no value */
        return amdlibSUCCESS;
    }

    /* Copy out keyword value */
    index2 = 0;
    while ((index < keywLineLen) && (*(keywLine + index) != '/') )
    {
        *(keyword->value + index2) = *(keywLine + index);
        index++;
        index2++;
    }
    *(keyword->value + index2) = '\0';

    /* Skip '/' for the possible comment */
    while ((index < keywLineLen) && ((*(keywLine + index) == '/')))
    {
        index++;
    }
    if (index >= keywLineLen)
    {
        /* There is no comment */
        return amdlibSUCCESS;
    }
    /* Copy out a possible comment */
    if (index < (keywLineLen - 1))
    {
        strncpy(keyword->comment, (keywLine + index),
                (size_t)(keywLineLen - index + 1));
    }
    return amdlibSUCCESS;
}

/*___oOo___*/
