/******************************************************************************
 * Copyright (c) 2020, Intel Corporation. All rights reserved.
 * 
 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception.
 * 
 *****************************************************************************/

/**
 * Author: Roman Popov
 */

#include <sc_tool/SCTool.h>
#include <sc_tool/utils/CommandLine.h>
#include <sc_tool/SCToolFrontendAction.h>
#include <rtti_sysc/SystemCRTTI.h>

#include <sc_elab.pb.h>
#include <sc_tool/ScCommandLine.h>
#include <sc_tool/utils/DebugOptions.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/raw_ostream.h>
#include <sc_elab/allocated_node.h>
#include <sc_elab/sc_tool_opts.h>
#include <fstream>
#include <stdio.h>

using namespace llvm;
using namespace clang;
using namespace clang::tooling;

// Apply a custom category to all command-line options so that they are
// the only ones displayed.
llvm::cl::OptionCategory ScToolCategory("sc_tool options");

namespace sc {

[[ noreturn ]] void runScElab(const char *commandLine)
{
    DEBUG_WITH_TYPE(DebugOptions::doElab,
        outs() << "Running sc_elab2 \n";

        if (sctool_extra_opts) {
            outs() << "EXTRA COMMAND LINE OPTS: " <<
                             *sctool_extra_opts << "\n";
        }
    );

    // Call before_end_of_elaboration callback inside DUT modules
    sc_elab::finalize_elaboration();

    // This will fill mangled names for dynamically allocated sc_objects with raw new/new[]
    sc_elab::finalize_module_allocations();

    // Generate sctool "Command line" , "sctool <options> -- <clang options>"..

    auto extCmdLine = std::string("sctool ");

    // sctool_extra_opts is present when user adds -sctool when invoking dut_sctool
    // Currently it is used to enable debug print (./dut_sctool -sctool -debug)
    if (sctool_extra_opts) {
        extCmdLine += *sctool_extra_opts;
        extCmdLine += " ";
    }

    // commandLine is generated by CMake svc_target script
    extCmdLine += std::string(commandLine);
    // Required for @SCT_PROPERTY macro, see sct_assert.h
    extCmdLine += " -D__SC_TOOL_CLANG__";

    // Print all command line options
    //llvm::outs() << extCmdLine << "\n";

    // Convert string to < argc, argv >
    auto args = sc_elab::parseToArgcArgv(extCmdLine);

    //for (int i = 0; i < args.argc; ++i) {
    //    outs() << "argv[" << i << "] = " << args.argv[i] << "\n";
    //}
    outs() << "Design unity file: " << args.argv[1] << "\n\n";
    outs().flush();

    DEBUG_WITH_TYPE(DebugOptions::doElab,
        for (int i = 0; i < args.argc; ++i) {
            outs() << "argv[" << i << "] = " << args.argv[i] << "\n";
        }
        outs().flush();
    );

    // Pass command line options to Clang tooling for parsing
    CommonOptionsParser op(args.argc, args.argv, ScToolCategory);
    ClangTool Tool(op.getCompilations(), op.getSourcePathList());

    // Run SVC
    auto factory = getNewSCElabActionFactory();
    auto exitStatus = Tool.run(factory.get());
    // We exit here, instead of returning to sc_main
    exit(exitStatus);
}


} // namespace sc_elab

