package Visual_DVM_2021.Passes.All;
import Common.Constants;
import Common.Current;
import Common.Database.Database;
import Common.Global;
import Common.UI.UI;
import Common.Utils.Index;
import ProjectData.LanguageName;
import TestingSystem.Common.Group.Group;
import TestingSystem.Common.Test.Test;
import TestingSystem.Common.TasksPackageState;
import TestingSystem.SAPFOR.Json.SapforConfiguration_json;
import TestingSystem.SAPFOR.Json.SapforTasksPackage_json;
import TestingSystem.SAPFOR.Json.SapforTest_json;
import TestingSystem.SAPFOR.SapforConfiguration.SapforConfiguration;
import TestingSystem.SAPFOR.SapforConfigurationCommand.SapforConfigurationCommand;
import TestingSystem.SAPFOR.SapforPackage.SapforPackage;
import Visual_DVM_2021.Passes.AddObjectPass;
import Visual_DVM_2021.Passes.PassCode_2021;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Vector;
public class AddSapforPackage extends AddObjectPass<SapforPackage> {
    //--
    protected int allTasksCount = 0;
    protected LinkedHashMap<Integer, Vector<Integer>> groupsTests = null;
    protected LinkedHashMap<String, Test> testsByDescriptions = null;
    protected Vector<String> testsNames_lower = null; //все тесты что участвуют здесь
    protected Vector<LanguageName> groupsLanguages = null;
    protected Vector<String> testsIds = null;
    protected Vector<String> configurationsIds = null;
    protected File sapfor = null;
    //---
    protected boolean checkTestName(Test test) {
        String name = test.description.toLowerCase();
        if (testsNames_lower.contains(name)) {
            Log.Writeln_("В пакет не могут входить тесты с одинаковыми именами (без учета регистра):" + test.description.toLowerCase());
            return false;
        }
        testsNames_lower.add(name);
        return true;
    }
    protected boolean getGroupTests(int groupId) {
        Vector<Integer> groupTests = new Vector<>();
        Vector<Integer> selectedGroupTests = new Vector<>();
        //---
        for (Test test : Global.testingServer.db.tests.Data.values()) {
            if (test.group_id==groupId) {
                groupTests.add(test.id);
                if (test.isSelected())
                    selectedGroupTests.add(test.id);
            }
        }
        if (!groupTests.isEmpty() && !selectedGroupTests.isEmpty())
            groupTests = selectedGroupTests;
        //---
        if (groupTests.isEmpty()) {
            Log.Writeln_("Пустая группа тестов: " + groupId);
            return false;
        }
        //--
        for (int testId : groupTests) {
            Test test = Global.testingServer.db.tests.get(testId);
            if (!checkTestName(test))
                return false;
            else
                testsByDescriptions.put(test.description, test);
        }
        //--
        groupsTests.put(groupId, groupTests);
        //--
        return true;
    }
    boolean checkTerminalCode(SapforConfiguration sapforConfiguration, PassCode_2021 code, int count, Vector<PassCode_2021> codes) {
        if (count > 2) {
            Log.Writeln_("Неверная конфигурация:" + sapforConfiguration.id + ": " +
                    code.getDescription() +
                    " возможно только один раз.");
            return false;
        }
        //--
        if ((count == 1) && codes.size() > 1) {
            if (!codes.lastElement().equals(code)) {
                Log.Writeln_("Неверная конфигурация:" + sapforConfiguration.id + ": " +
                        code.getDescription() +
                        " может быть только завершающей командой!");
                return false;
            }
        }
        return true;
    }
    public boolean getConfigurationCommands(SapforConfiguration sapforConfiguration) {
        int headers_count = 0;
        //1. получить список всех команд.
        Vector<PassCode_2021> codes = new Vector<>();
        //-- счетчик завершающих команд.
        LinkedHashMap<PassCode_2021, Index> terminalCodesCount = new LinkedHashMap<>();
        for (PassCode_2021 code : Constants.terminalSapforTestingCodes)
            terminalCodesCount.put(code, new Index());
        //--
        for (SapforConfigurationCommand command : Global.testingServer.db.sapforConfigurationCommands.Data.values()) {
            if (command.sapforconfiguration_id==sapforConfiguration.id) {
                codes.add(command.passCode);
                //---
                for (PassCode_2021 t_code : Constants.terminalSapforTestingCodes) {
                    if (command.passCode.equals(t_code))
                        terminalCodesCount.get(t_code).Inc();
                }
                //---
            }
        }
        //--
        if (codes.size() == 0) {
            Log.Writeln_("Пустая конфигурация:" + sapforConfiguration.id);
            return false;
        }
        for (PassCode_2021 t_code : Constants.terminalSapforTestingCodes) {
            if (!checkTerminalCode(sapforConfiguration, t_code,
                    terminalCodesCount.get(t_code).getValue(), codes
            ))
                return false;
        }


        //--
        return true;
    }
    //временный вариант. в дальнейшем, следует сделать возможность формирования.(?)
    public AddSapforPackage() {
        super(SapforPackage.class);
    }
    @Override
    protected Database getDb() {
        return Global.testingServer.db;
    }
    @Override
    protected boolean canStart(Object... args) throws Exception {
        if (!Current.getAccount().CheckRegistered(Log)) {
            return false;
        }
        if (Current.Check(Log, Current.ServerSapfor)) {
            for (SapforPackage sapforPackage : Global.testingServer.db.sapforPackages.Data.values()) {
                if (sapforPackage.state.equals(TasksPackageState.Draft)) {
                    Log.Writeln_("Может существовать только один пакет, готовящийся к публикации.");
                    return false;
                }
            }
            //--
            allTasksCount = 0;
            groupsTests = new LinkedHashMap<>();
            testsNames_lower = new Vector<>();
            testsByDescriptions = new LinkedHashMap<>();
            groupsLanguages = new Vector<>();
            testsIds =new Vector<>();
            configurationsIds = new Vector<>();
            //--
            if (Global.testingServer.db.sapforConfigurations.getCheckedCount() == 0) {
                Log.Writeln_("Не отмечено ни одной конфигурации SAPFOR.");
                return false;
            }
            //-
            for (SapforConfiguration configuration : Global.testingServer.db.sapforConfigurations.getCheckedItems()) {
                if (!getConfigurationCommands(configuration))
                    return false;
            }
            //--
            if (Global.testingServer.db.groups.getCheckedCount() == 0) {
                Log.Writeln_("Не отмечено ни одной группы тестов");
                return false;
            }
            //--
            for (Group group : Global.testingServer.db.groups.getCheckedItems()) {
                //---
                if (!groupsLanguages.contains(group.language))
                    groupsLanguages.add(group.language);
                //-
                if (groupsLanguages.get(0) != LanguageName.fortran) {
                    Log.Writeln_("Поддерживается пакетный режим только для языка Fortran!");
                    return false;
                }
                if (groupsLanguages.size() > 1) {
                    Log.Writeln_("Запуск тестов на разных языках в рамках одного пакета запрещен!");
                    return false;
                }
                //---
                if (!getGroupTests(group.id))
                    return false;
            }
            //--
            for (int i = 0; i < Global.testingServer.db.sapforConfigurations.getCheckedCount(); ++i) {
                for (Vector<Integer> tests : groupsTests.values())
                    allTasksCount += tests.size();
            }
            //--
            for (Test test : testsByDescriptions.values())
                testsIds.add(String.valueOf(test.id));
            //--
            for (SapforConfiguration configuration : Global.testingServer.db.sapforConfigurations.getCheckedItems())
                configurationsIds.add(String.valueOf(configuration.id));
            //--
            target = new SapforPackage();
            target.id = Constants.Nan;
            //-
            target.sender_name = Current.getAccount().name;
            target.sender_address = Current.getAccount().email;
            //-
            target.drv = Current.getServerSapfor().call_command;
            target.version = Current.getServerSapfor().version;
            target.kernels = Global.properties.TestingKernels;
            target.needsEmail = Global.properties.EmailOnTestingProgress ? 1 : 0;
            //--
            target.tasksCount = allTasksCount;
            target.testsIds = String.join("\n", testsIds);
            target.configurationsIds = String.join("\n", configurationsIds);
            //--
            target.sapforId = Current.getServerSapfor().id;
            target.testsNames = String.join(";", testsNames_lower);
            //
            SapforTasksPackage_json package_json = new SapforTasksPackage_json();
            target.package_json = package_json;
            ///-------------------------------
            package_json.kernels = target.kernels;
            for (Test test : testsByDescriptions.values()) {
                SapforTest_json test_json = new SapforTest_json();
                test_json.id = test.id;
                test_json.description = test.description;
                test_json.group_description = Global.testingServer.db.groups.get(test.group_id).description;
                package_json.tests.add(test_json);
            }
            ///-------------------------------
            for (SapforConfiguration configuration : Global.testingServer.db.sapforConfigurations.getCheckedItems()) {
                //--
                SapforConfiguration_json configuration_json = new SapforConfiguration_json();
                configuration_json.id = configuration.id;
                configuration_json.flags = configuration.getFlags();
                configuration_json.codes.add(PassCode_2021.SPF_CorrectCodeStylePass); //всегда добавляется.
                configuration_json.codes.addAll(configuration.getPassCodes());
                //--->>
                package_json.configurations.add(configuration_json);
                //-->>
            }
            package_json.sapfor_drv = Current.getServerSapfor().call_command;
            ///-------------------------------
            return   (UI.Question("Будет добавлено:\n"
                    + allTasksCount + " задач\n" +
                    "Продолжить"));
        }
        return false;
    }
    @Override
    protected void body() throws Exception {
        //черновик не вставляется в бд. идет только как элемент списка.
        Global.testingServer.db.sapforPackages.Data.put(target.id, target);
    }
}