package _VisualDVM.TestingSystem.DVM;
import Common.Utils.Utils_;
import _VisualDVM.Global;
import _VisualDVM.ProjectData.Files.ProjectFile;
import _VisualDVM.ProjectData.LanguageName;
import _VisualDVM.Repository.Server.ServerCode;
import _VisualDVM.TestingSystem.Common.TasksPackageState;
import _VisualDVM.TestingSystem.Common.TestingPlanner;
import _VisualDVM.TestingSystem.DVM.DVMPackage.DVMPackage;
import _VisualDVM.TestingSystem.DVM.DVMTasks.DVMCompilationTask;
import _VisualDVM.Utils;

import java.io.File;
import java.io.FileFilter;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Vector;
public abstract class DVMTestingPlanner extends TestingPlanner<DVMPackage> {
    public DVMTestingPlanner(String[] args) {
        super(args);
    }
    static LinkedHashMap<LanguageName, Vector<ProjectFile>> getTestPrograms(File test) {
        LinkedHashMap<LanguageName, Vector<ProjectFile>> res = new LinkedHashMap<>();
        //--
        res.put(LanguageName.fortran, new Vector<>());
        res.put(LanguageName.c, new Vector<>());
        res.put(LanguageName.cpp, new Vector<>());
        //--
        File[] files = test.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isFile();
            }
        });
        if (files != null) {
            for (File file : files) {
                ProjectFile projectFile = new ProjectFile(new File(file.getName()));
                if (projectFile.isNotExcludedProgram()) res.get(projectFile.languageName).add(projectFile);
            }
        }
        return res;
    }
    static void generateForLanguage(String dvm_drv, LanguageName language, Vector<ProjectFile> language_programs, Vector<String> titles, Vector<String> objects, Vector<String> bodies, String flags) {
        if (!language_programs.isEmpty()) {
            String LANG_ = language.toString().toUpperCase() + "_";
            Vector<String> module_objects = new Vector<>();
            String module_body = "";
            int i = 1;
            for (ProjectFile program : language_programs) {
                //--
                String object = Utils_.DQuotes(language + "_" + i + ".o");
                module_objects.add(object);
                module_body += object + ":\n" + "\t" + String.join(" ", Utils.MFVar(LANG_ + "COMMAND"), Utils.MFVar(LANG_ + "FLAGS"), program.getStyleOptions(), "-c", program.getQSourceName(), "-o", object + "\n\n");
                ++i;
            }
            titles.add(String.join("\n", LANG_ + "COMMAND=" + Utils_.DQuotes(dvm_drv) + " " + language.getDVMCompile(), LANG_ + "FLAGS=" + flags, LANG_ + "OBJECTS=" + String.join(" ", module_objects), ""));
            objects.add(Utils.MFVar(LANG_ + "OBJECTS"));
            bodies.add(module_body);
        }
    }
    static String generateMakefile(File test, LanguageName test_language, String dvm_drv, String flags) {
        //----->>
        LinkedHashMap<LanguageName, Vector<ProjectFile>> programs = getTestPrograms(test);
        Vector<String> titles = new Vector<>();
        Vector<String> objects = new Vector<>();
        Vector<String> bodies = new Vector<>();
        String binary = Utils_.DQuotes("0");
        //----->>
        for (LanguageName languageName : programs.keySet()) {
            generateForLanguage(dvm_drv, languageName, programs.get(languageName), titles, objects, bodies, flags);
        }
        //----->>
        return String.join("\n", "LINK_COMMAND=" + Utils_.DQuotes(dvm_drv) + " " + test_language.getDVMLink(), "LINK_FLAGS=" + flags + "\n", String.join("\n", titles), "all: " + binary, binary + " : " + String.join(" ", objects), "\t" + Utils.MFVar("LINK_COMMAND") + " " + Utils.MFVar("LINK_FLAGS") + " " + String.join(" ", objects) + " -o " + binary, String.join(" ", bodies));
    }
    LinkedHashMap<Integer, File> getTestsFromJson() {
        LinkedHashMap<Integer, File> res = new LinkedHashMap<>();
        for (DVMCompilationTask task : testingPackage.package_json.compilationTasks) {
            if (!res.containsKey(task.test_id)) {
                res.put(task.test_id, Paths.get(Global.TestsDirectory.getAbsolutePath(), String.valueOf(task.test_id)).toFile());
            }
        }
        return res;
    }
    @Override
    protected void Print(String message) {
        try {
            if (isPrintOn()) {
                System.out.println(message);
                Utils_.MainLog.Print(message);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    @Override
    protected ServerCode getActivePackagesCode() {
        return ServerCode.GetFirstActiveDVMPackageForMachineURL;
    }
    @Override
    protected ServerCode getCheckIfNeedsKillCode() {
        return ServerCode.DVMPackageNeedsKill;
    }
    @Override
    protected TasksPackageState getStateAfterStart() {
        return TasksPackageState.CompilationWorkspacesCreation;
    }
    @Override
    protected void ServerConnectionError(ServerCode code_in, String logText) throws Exception {
        Finalize("Не удалось выполнить команду " + code_in + " на сервере тестирования\n" + logText);
    }
    protected abstract boolean CheckModules() throws Exception;
    @Override
    public void perform() throws Exception {
        Print("Проверка сервера...");
        String currentServerName = (String) ServerCommand(ServerCode.GetServerName);
        Print("имя текущего сервера " + Utils_.Brackets(currentServerName));
        Print("имя сервера, создавшего нить " + Utils_.Brackets(serverName));
        if (!serverName.equals(currentServerName)) {
            Finalize("Несоответствующий сервер");
        }
        Print("Запрос активных пакетов для машины " + Utils_.Brackets(machine.getURL()));
        testingPackage = null;
        Vector<DVMPackage> activePackages = (Vector<DVMPackage>) ServerCommand(getActivePackagesCode(), machine.getURL(), null);
        if (activePackages.isEmpty())
            Finalize("Не найдено активных пакетов для машины " + Utils_.Brackets(machine.getURL()));
        for (DVMPackage activePackage : activePackages)
            PerformPackage(activePackage);
    }
}
