/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <string>

#include <MvRequest.h>
#include <MvRequestUtil.hpp>

namespace metview
{

void copyParam(const MvRequest& inRequest, MvRequest& outRequest,
               const std::string& oldName, const std::string& newName)
{
    int n = inRequest.countValues(oldName.c_str());
    outRequest.unsetParam(oldName.c_str());
    for (int j = 0; j < n; j++) {
        const char* value = nullptr;
        inRequest.getValue(value, oldName.c_str(), j);
        outRequest.addValue(newName.c_str(), value);
    }
}

//
// FUNCTION: CopyAndRemoveParameters
//
// PURPOSE : To copy a request into another removing all
//           parameters that start with a certain "prefix"
//
// INPUT   : - A request
//           - Prefix to be used for removing parameters
//
// OUTPUT  : - A request which does not contain the desired params
//

void CopyAndRemoveParameters(const MvRequest& inRequest,
                             MvRequest& outRequest,
                             const char* prefix)
{
    int length = strlen(prefix);

    int count = inRequest.countParameters();

    for (int i = 0; i < count; i++) {
        const char* param = inRequest.getParameter(i);
        if (strncmp(param, prefix, length) != 0) {
            int n = inRequest.countValues(param);
            outRequest.unsetParam(param);
            for (int j = 0; j < n; j++) {
                const char* value = nullptr;
                inRequest.getValue(value, param, j);
                outRequest.addValue(param, value);
            }
        }
    }
}

//
// FUNCTION: CopySomeParameters
//
// PURPOSE : To copy the Parameters which start with a certain prefix
//           from one request to another
//
// INPUT   : - A request
//           - Prefix to be used for copy parameters
//           - Option to overwrite existing output parameters
//
// OUTPUT  : - A request which contain the desired params
//
void CopySomeParameters(const MvRequest& inRequest,
                        MvRequest& outRequest,
                        const char* prefix,
                        bool overwrite)
{
    int length = strlen(prefix);

    int count = inRequest.countParameters();

    for (int i = 0; i < count; i++) {
        const char* param = inRequest.getParameter(i);
        if (strncmp(param, prefix, length) == 0) {
            if (!overwrite && IsParameterSet(outRequest, param))
                continue;
            int n = inRequest.countValues(param);
            for (int j = 0; j < n; j++) {
                const char* value = nullptr;
                inRequest.getValue(value, param, j);
                if (j == 0)
                    outRequest.setValue(param, value);
                else
                    outRequest.addValue(param, value);
            }
        }
    }
}

//
// FUNCTION: CopySomeParameters
//
// PURPOSE : To copy the Parameters which start with a certain prefix
//           from one request to another changing prefix by a new prefix
//
// INPUT   : - A request
//           - Prefix to be used for copy parameters
//           - New prefix to be used instead of prefix
//
// OUTPUT  : - A request which contain the desired params
//
void CopySomeParameters(const MvRequest& inRequest,
                        MvRequest& outRequest,
                        const char* prefix,
                        const char* newPrefix)
{
    int length = strlen(prefix);

    int count = inRequest.countParameters();
    for (int i = 0; i < count; i++) {
        const char* param = inRequest.getParameter(i);
        if (strncmp(param, prefix, length) == 0) {
            int n = inRequest.countValues(param);
            Cached auxPar((const char*)(param + length));
            Cached newparam = Cached(newPrefix) + auxPar;
            for (int j = 0; j < n; j++) {
                const char* value = nullptr;
                inRequest.getValue(value, param, j);
                outRequest.addValue(newparam, value);
            }
        }
    }
}

//
// FUNCTION: CopySomeParameters
//
// PURPOSE : To copy the Parameters which finish with a certain suffix
//           from one request to another
//
// INPUT   : - A request
//           - Sufix to be used for copy parameters
//
// OUTPUT  : - A request which contain the desired params
//
void CopySomeParameters(const MvRequest& inRequest,
                        MvRequest& outRequest,
                        const std::string& sufix)
{
    unsigned int length = sufix.size();
    int count = inRequest.countParameters();
    for (int i = 0; i < count; i++) {
        std::string param = (const char*)inRequest.getParameter(i);
        if (param.size() < length)  // no need to compare
            continue;

        if (param.compare(param.size() - length, length, sufix) == 0) {
            const char* cparam = param.c_str();
            int n = inRequest.countValues(cparam);
            for (int j = 0; j < n; j++) {
                const char* value = nullptr;
                inRequest.getValue(value, cparam, j);
                if (j == 0)
                    outRequest.setValue(cparam, value);
                else
                    outRequest.addValue(cparam, value);
            }
        }
    }
}

//
// FUNCTION: RemoveParameters
//
// PURPOSE : Remove all parameters that start with a certain "prefix"
//
// INPUT   : - A request
//           - Prefix to be used for removing parameters
//
// OUTPUT  : - A request which does not contain the desired params
//
void RemoveParameters(MvRequest& req, const char* prefix)
{
    MvRequest aux = req;
    int length = strlen(prefix);
    int count = req.countParameters();
    for (int i = 0; i < count; i++) {
        const char* param = aux.getParameter(i);
        if (strncmp(param, prefix, length) == 0)
            req.unsetParam(param);
    }
}

//
// FUNCTION: AreEqualRequests
//
// PURPOSE : Compare two requests.
//
// INPUT   : - Two requests
//
// OUTPUT  : - true: If the input requests have the same number of parameters and
//                   the parameters names and values are equal.
//           - false: otherwise
//
// OBS     : Comparison only between parameter values, if there are subrequests
//           the result is unpredictable
bool AreEqualRequests(MvRequest& req1, MvRequest& req2)
{
    int count = req1.countParameters();
    int i = -1;
    if (count == req2.countParameters()) {
        for (i = 0; i < count; i++) {
            const char* param = req1.getParameter(i);
            int n = req1.countValues(param);
            int j;
            for (j = 0; j < n; j++) {
                const char* value2 = nullptr;
                req2.getValue(value2, param, j);
                if (!value2)
                    return false;  //-- 'param' missing from req2!

                const char* value1 = nullptr;
                req1.getValue(value1, param, j);
                if (strcmp(value1, value2))
                    break;
            }
            if (j != n)
                break;
        }
    }
    if (i != count)
        return false;
    else
        return true;
}

bool IsParameterSet(MvRequest& request, const char* paramSought)
{
    int count = request.countParameters();

    for (int i = 0; i < count; i++) {
        const char* paramFound = (const char*)request.getParameter(i);

        if (strcmp(paramFound, paramSought) == 0)
            return true;
    }

    return false;
}

bool SetIfValue(MvRequest& targetReq, const char* targetParam, const char* val)
{
    if (val) {
        targetReq(targetParam) = val;
        return true;
    }

    return false;
}

void MergeTextParameters(MvRequest& inRequest,
                         MvRequest& outRequest,
                         bool overwrite)
{
    int i;

    // Move output TEXT_LINE_* forward according to
    // input TEXT_LINE_COUNT
    int inCount = inRequest("TEXT_LINE_COUNT");
    int outCount = outRequest("TEXT_LINE_COUNT");
    if (inCount) {
        // Define constants
        char saux[13];  // TEXT_LINE_*
        int MAXCOUNT = 10;
        int size;

        strcpy(saux, "TEXT_LINE_");
        size = strlen(saux);

        // Check maximum number of merged lines
        int maxline = ((inCount + outCount) > MAXCOUNT) ? MAXCOUNT : (inCount + outCount);

        // Move texts
        for (i = maxline; i > inCount; i--) {
            sprintf(saux + size, "%d", i - inCount);
            const char* text = outRequest(saux);
            sprintf(saux + size, "%d", i);
            if (text)
                outRequest(saux) = text;
            else
                outRequest.unsetParam(saux);
        }

        // Clear initial TEXT_LINE_* from the output request
        for (i = 1; i <= inCount; i++) {
            sprintf(saux + size, "%d", i);
            outRequest.unsetParam(saux);
        }

        // Update output TEXT_LINE_COUNT
        outRequest("TEXT_LINE_COUNT") = maxline;
    }

    // Copy remaining parameters
    CopySomeParameters(inRequest, outRequest, "TEXT_", overwrite);
}

void CopyParametersAndStackingOrder(const MvRequest& inRequestOld, const MvRequest& inRequestNew, int index, MvRequest& outRequest)
{
    // Create a new request based on inRequestNew and taking into consideration the
    // drawing order info. If there is a new drawing order info then update it too;
    // otherwise, keep the previous one (if it exists).
    outRequest = inRequestNew;
    if (index != -1 || !inRequestOld)
        outRequest("_STACKING_ORDER") = index;
    else {
        const char* corder = (const char*)inRequestOld("_STACKING_ORDER");
        outRequest("_STACKING_ORDER") = (int)(corder ? atoi(corder) : -1);
    }

    return;
}

}  // namespace metview
