/* Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
 *
 * NVIDIA CORPORATION and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA CORPORATION is strictly prohibited.
 */

#include "cmdline.h"

static void
_PrintCaptureParamSets(TestArgs *args)
{
    uint32_t j;

    LOG_MSG("Capture parameter sets (%d):\n", args->captureConfigSetsNum);
    for (j = 0; j < args->captureConfigSetsNum; j++) {
        LOG_MSG("\n%s: ", args->captureConfigCollection[j].name);
        LOG_MSG("%s\n", args->captureConfigCollection[j].description);
    }
    LOG_MSG("\n");
}

static int32_t
_GetParamSetID(void *configSetsList,
              uint32_t paramSets,
               char *paramSetName)
{
    uint32_t i;
    char *name = NULL;

    for (i = 0; i < paramSets; i++) {
        name = ((CaptureConfigParams *)configSetsList)[i].name;

        if (!strcasecmp(name, paramSetName)) {
            LOG_DBG("%s: Param set found (%d)\n", __func__, i);
            return i;
        }
    }
    return -1;
}

NvMediaStatus
ParseArgs(int argc,
          char *argv[],
          TestArgs *allArgs)
{
    int32_t i = 0;
    NvMediaBool bLastArg = NVMEDIA_FALSE;
    NvMediaBool bDataAvailable = NVMEDIA_FALSE;

    if (argc < 2) {
        PrintUsage();
        return NVMEDIA_STATUS_ERROR;
    }

    if (argc >= 2) {
        for (i = 1; i < argc; i++) {
            // Check if this is the last argument
            bLastArg = ((argc - i) == 1);

            // Check if there is data available to be parsed
            bDataAvailable = (!bLastArg) && !(argv[i+1][0] == '-');

            if (!strcasecmp(argv[i], "-h")) {
                PrintUsage();
                return NVMEDIA_STATUS_ERROR;
            } else if (!strcasecmp(argv[i], "-v")) {
                allArgs->logLevel = LEVEL_DBG;
                if (bDataAvailable) {
                    allArgs->logLevel = atoi(argv[++i]);
                    if (allArgs->logLevel > LEVEL_DBG) {
                        printf("Invalid logging level chosen (%d)\n",
                               allArgs->logLevel);
                        printf("Setting logging level to LEVEL_ERR (0)\n");
                        allArgs->logLevel = LEVEL_ERR;
                    }
                }
                SetLogLevel((enum LogLevel)allArgs->logLevel);
            } else if (!strcasecmp(argv[i], "-cf")) {
                if (argv[i + 1] && argv[i + 1][0] != '-') {
                    strncpy(allArgs->configFile.stringValue, argv[++i],
                            MAX_STRING_SIZE);
                    allArgs->configFile.isUsed = NVMEDIA_TRUE;
                } else {
                    LOG_ERR("-cf must be followed by configuration file name\n");
                    return NVMEDIA_STATUS_ERROR;
                }
            }
        }
    }

    // Default config file
    if (!allArgs->configFile.isUsed) {
        strcpy(allArgs->configFile.stringValue,
               "configs/default.conf");
        allArgs->configFile.isUsed = NVMEDIA_TRUE;
    }

    // Parse config file here
    if (NVMEDIA_STATUS_OK != ParseConfigFile(allArgs->configFile.stringValue,
                                &allArgs->captureConfigSetsNum,
                                &allArgs->captureConfigCollection)) {
        LOG_ERR("Failed to parse config file %s\n",
                allArgs->configFile.stringValue);
        return NVMEDIA_STATUS_ERROR;
    }

    if (argc >= 2) {
        for (i = 1; i < argc; i++) {
            // Check if this is the last argument
            bLastArg = ((argc - i) == 1);

            // Check if there is data available to be parsed
            bDataAvailable = (!bLastArg) && !(argv[i+1][0] == '-');

            if (!strcasecmp(argv[i], "-h")) {
                PrintUsage();
                return NVMEDIA_STATUS_ERROR;
            } else if (!strcasecmp(argv[i], "-v")) {
                if (bDataAvailable)
                    ++i; // Was already parsed at the beginning. Skipping.
            } else if (!strcasecmp(argv[i], "-cf")) {
                ++i; // Was already parsed at the beginning. Skipping.
            }  else if (!strcasecmp(argv[i], "-lc")) {
                _PrintCaptureParamSets(allArgs);
                return NVMEDIA_STATUS_ERROR;
            } else if (!strcasecmp(argv[i], "-if")) {
                if (bDataAvailable) {
                    strncpy(allArgs->inputFile.stringValue, argv[++i],
                            MAX_STRING_SIZE);
                    allArgs->inputFile.isUsed = NVMEDIA_TRUE;
                } else {
                    LOG_ERR("-if must be followed by a filename\n");
                    return NVMEDIA_STATUS_ERROR;
                }
            } else if (!strcasecmp(argv[i], "-of")) {
                if (bDataAvailable) {
                    strncpy(allArgs->outputFile.stringValue, argv[++i],
                            MAX_STRING_SIZE);
                    allArgs->outputFile.isUsed = NVMEDIA_TRUE;
                } else {
                    LOG_ERR("-of must be followed by a filename\n");
                    return NVMEDIA_STATUS_ERROR;
                }
            } else if (!strcasecmp(argv[i], "-p")) {
                if (bDataAvailable) {
                    strncpy(allArgs->paramFile.stringValue, argv[++i],
                            MAX_STRING_SIZE);
                    allArgs->paramFile.isUsed = NVMEDIA_TRUE;
                } else {
                    LOG_ERR("-p must be followed by a filename\n");
                    return NVMEDIA_STATUS_ERROR;
                }
            } else if (!strcasecmp(argv[i], "-n")) {
                if (bDataAvailable) {
                    allArgs->numSensors.isUsed = NVMEDIA_TRUE;
                    if ((sscanf(argv[++i], "%u", &allArgs->numSensors.uIntValue) != 1) ||
                        (allArgs->numSensors.uIntValue >= NVMEDIA_ICP_MAX_VIRTUAL_GROUPS) ||
                        (allArgs->numSensors.uIntValue == 0) ) {
                        LOG_ERR("Invalid number of sensors: %s\n", argv[i]);
                        return NVMEDIA_STATUS_ERROR;
                    }
                } else {
                    LOG_ERR("-n must be followed by a number from 1-%d\n",NVMEDIA_ICP_MAX_VIRTUAL_GROUPS);
                    return NVMEDIA_STATUS_ERROR;
                }
            } else if (!strcasecmp(argv[i], "-c")) {
                if (bDataAvailable) {
                    ++i;
                    int32_t paramSetId = 0;
                    paramSetId = _GetParamSetID(allArgs->captureConfigCollection,
                                               allArgs->captureConfigSetsNum,
                                               argv[i]);
                    if (paramSetId == -1) {
                        LOG_ERR("Params set name '%s' wasn't found\n",
                                argv[i]);
                        return NVMEDIA_STATUS_ERROR;
                    }
                    allArgs->config.isUsed = NVMEDIA_TRUE;
                    allArgs->config.uIntValue = paramSetId;
                    LOG_INFO("Using params set: %s for capture\n",
                             allArgs->captureConfigCollection[paramSetId].name);
                } else {
                    LOG_ERR("-c must be followed by capture parameters set name\n");
                    return NVMEDIA_STATUS_ERROR;
                }
            } else if (!strcasecmp(argv[i], "-a")) {
                if (bDataAvailable) {
                    allArgs->eepromAddress.isUsed = NVMEDIA_TRUE;
                    if ((sscanf(argv[++i], "%i", &allArgs->eepromAddress.uIntValue) != 1) ||
                        (allArgs->eepromAddress.uIntValue >= 0x7F) ||
                        (allArgs->eepromAddress.uIntValue <= 0) ) {
                        LOG_ERR("Invalid EEPROM Address: \'%s\'\n", argv[i]);
                        return NVMEDIA_STATUS_ERROR;
                    }
                } else {
                    LOG_ERR("-a must be followed by the eeprom address\n");
                    return NVMEDIA_STATUS_ERROR;
                }
            } else if (!strcasecmp(argv[i], "--all")) {
                allArgs->longPrint.isUsed = NVMEDIA_TRUE;
            } else {
                LOG_ERR("Unsupported option encountered: %s\n", argv[i]);
                return NVMEDIA_STATUS_ERROR;
            }
        }
    }

    return NVMEDIA_STATUS_OK;
}
