#include "leak_detector.h"

#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <string>

#include "dvm.h"
#include "verifications.h"
#include "utils.h"
#include "SgUtils.h"
#include "errors.h"
#include "../Distribution/DvmhDirective.h"

using std::vector;
using std::string;
using std::wstring;
using std::set;
using std::pair;

static bool check(SgStatement* st, const string& fileName, const int lastLine, vector<Messages>& currMessages)
{
    if (isSgExecutableStatement(st) && !isSPF_stat(st) && !isDVM_stat(st))
    {
        if (st->fileName() != fileName)
        {
            __spf_print(1, "  ERROR: include '%s' at line %d has executable operators\n", st->fileName(), lastLine);

            wstring currE, currR;
            __spf_printToLongBuf(currE, L"Include '%s' has executable operators", to_wstring(st->fileName()).c_str());
            __spf_printToLongBuf(currR, R52, to_wstring(st->fileName()).c_str());

            currMessages.push_back(Messages(ERROR, lastLine, currR, currE, 1019));
            return false;
        }
    }

    return true;
}

bool IncludeChecker(SgFile *file, const string &fileName, vector<Messages> &currMessages)
{
    int funcNum = file->numberOfFunctions();
    bool checkOK = true;

    for (int i = 0; i < funcNum; ++i)
    {
        SgStatement *st = file->functions(i);
        SgStatement *lastNode = st->lastNodeOfStmt();
        int lastLine = 1;
        while (st != lastNode)
        {            
            if (st == NULL)
            {
                __spf_print(1, "internal error in analysis, parallel directives will not be generated for this file!\n");
                break;
            }

            if (st->variant() == CONTAINS_STMT)
                break;

            if (st->fileName() == fileName)
            {
                lastLine = st->lineNumber();
                auto next = st->lexNext();
                if (next && next->comments() && next->fileName() != fileName)
                {
                    string comm(next->comments());
                    int countLines = 0;
                    for (auto& elem : comm)
                        if (elem == '\n')
                            ++countLines;
                    lastLine += countLines;
                }
                lastLine++;
            }

            auto res = check(st, fileName, lastLine, currMessages);
            checkOK = checkOK && res;
            st = st->lexNext();
        }
    }

    vector<SgStatement*> modules;
    findModulesInFile(file, modules);

    for (auto& module : modules)
    {
        SgStatement* st = module;
        SgStatement* lastNode = module->lastNodeOfStmt();

        if (st->fileName() != fileName)
            continue;

        int lastLine = 1;
        while (st != lastNode)
        {
            if (st->fileName() == fileName)
                lastLine = st->lineNumber();
            else
            {
                auto res = check(st, fileName, lastLine, currMessages);
                checkOK = checkOK && res;
            }
            
            if (st->variant() == FUNC_HEDR || st->variant() == PROC_HEDR)
                st = st->lastNodeOfStmt();

            st = st->lexNext();
        }
    }
    return checkOK;
}