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

 Copyright 2023 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 <stdlib.h>
#include <cassert>
#include <iostream>

#include "Metview.h"
#include "MvException.h"
#include "MvService.h"
#include "Path.h"
#include "MacroToPythonConvert.h"
#include "MvLog.h"
#include "MvMiscellaneous.h"


// Globals
int ac;
char** av;

namespace metview {
namespace macroconvert {

class MvMacroToPython : public MvService
{
public:
    MvMacroToPython(const char* name) :
        MvService(name) {}
    void serve(MvRequest&, MvRequest&) override;

private:
    void checkSyntax(const std::string& inPath);
    void convert(const std::string& inPath, std::string& outPath);
    const std::string moduleLabel_{"MvMacroToPython-> "};
};


void MvMacroToPython::checkSyntax(const std::string& inPath)
{
    auto mPath = MacroToPythonConvert::resolveMacroPath(inPath);

    MvRequest r("MACRO");
    r("PATH") = mPath.c_str();                                    // path to macro
    r("_NAME") = mPath.c_str();                                       // path to macro
    r("_CLASS") = "MACRO";      // class name
    r("_ACTION") = "syntax";
    r("_SERVICE") = "macro";

    std::cout << "Send request" << std::endl;
    r.print();

    MvRequest outR;
    int ret = MvService::callService("macro", r, outR);
    if (ret != 0) {
        std::cout << "Received request" << std::endl;
        outR.print();
        std::string msg;
        outR.getValue("TEXT", msg, true);
        if (msg.empty()) {
            msg = "Syntax error in macro";
        }
        throw MvException(msg);
    }
}

void MvMacroToPython::convert(const std::string& inPath, std::string& outPath)
{
    checkSyntax(inPath);

    MacroToPythonConvert converter;
    int ret = converter.convert(inPath, true, outPath);
    if (ret != 0) {
        throw MvException(converter.errText());
    }
}

void MvMacroToPython::serve(MvRequest& in, MvRequest& out)
{
    std::cout << "--------------MvConvert::serve()--------------" << std::endl;
    in.print();

    bool hasError = false;
    std::string errMsg;
    out = MvRequest("MESSAGE");
    int totalCnt = 0;
    int failedCnt = 0;

    try {
        std::string verb;
        auto *verbCh = in.getVerb();
        if (verbCh != nullptr) {
            verb = std::string(verbCh);
        } else {
            std::string msg= "Invalid input request! No verb found.";
            throw MvException(msg);
        }

        if (verb == "MACRO") {
            std::string inPath, outPath;
            in.getValue("PATH", inPath);
            convert(inPath, outPath);

            out = MvRequest("PYTHON");
            out("PATH") = outPath.c_str();

        } else if (verb == "CONVERT") {
            std::vector<std::string> vals;
            if (!in.getValue("ITEMS", vals)) {
                std::string msg = "Invalid input request! No ITEMS found.";
                throw MvException(msg);
            }

            for (auto inPath: vals) {
                std::string outPath;
                try {
                    totalCnt++;
                    convert(inPath, outPath);
                } catch (MvException(e)) {
                    failedCnt++;
                    out.addValue("FAILED_ITEMS", inPath.c_str());
                    out.addValue("ITEM_ERRORS", e.what());
                    hasError = true;
//                    f (errMsg.empty()) {
//                        errMsg = moduleLabel_ + "Error: failed to convert the following Macros:";
//                    }
                    if (errMsg.empty()) {
                        errMsg = moduleLabel_ + "Error: Macro to Python conversion failed for the following files:";
                    }
                    errMsg += "\n " + inPath;
                }
            }
        }
    } catch (MvException(e)) {
        errMsg = moduleLabel_ + "Error: " + e.what();
        hasError = true;
    }

    out("STATUS") = (hasError)?"ERROR":"OK";
    if (hasError) {
        if (errMsg.empty()) {
            errMsg = moduleLabel_ + "Error: Macro to Python conversion failed";
        }
        out("TEXT") = errMsg.c_str();
        setError(1, errMsg.c_str());
    }
}

} // namespace macroconvert
} // namespace metview

int main(int argc, char** argv)
{
    ac = argc;
    av = argv;

    MvApplication theApp(argc, argv, "MvMacroToPython");

    metview::macroconvert::MvMacroToPython conv1("MACRO");
    metview::macroconvert::MvMacroToPython conv2("CONVERT");

    theApp.run();
}
