package _VisualDVM.TestingSystem.Common;
import Common.CommonConstants;
import Common.Database.SQLITE.SQLiteDatabase;
import Common.Utils.TextLog;
import Common.Utils.Utils_;
import _VisualDVM.Constants;
import _VisualDVM.Global;
import _VisualDVM.GlobalData.Account.Account;
import _VisualDVM.Passes.All.ZipFolderPass;
import _VisualDVM.Passes.PassCode;
import _VisualDVM.Repository.Component.Sapfor.Sapfor;
import _VisualDVM.Repository.RepositoryRefuseException;
import _VisualDVM.TestingSystem.Common.Group.Group;
import _VisualDVM.TestingSystem.Common.Group.GroupsDBTable;
import _VisualDVM.TestingSystem.Common.Test.Test;
import _VisualDVM.TestingSystem.Common.Test.TestDBTable;
import _VisualDVM.TestingSystem.Common.TestingPackageToKill.TestingPackagesToKillDBTable;
import _VisualDVM.TestingSystem.DVM.DVMConfiguration.DVMConfigurationDBTable;
import _VisualDVM.TestingSystem.DVM.DVMPackage.DVMPackage;
import _VisualDVM.TestingSystem.DVM.DVMPackage.DVMPackageDBTable;
import _VisualDVM.TestingSystem.DVM.DVMSettings.DVMSettingsDBTable;
import _VisualDVM.TestingSystem.DVM.DVMTasks.DVMRunTasksSet;
import _VisualDVM.TestingSystem.SAPFOR.SapforConfiguration.SapforConfigurationDBTable;
import _VisualDVM.TestingSystem.SAPFOR.SapforPackage.SapforPackage;
import _VisualDVM.TestingSystem.SAPFOR.SapforPackage.SapforPackageDBTable;
import _VisualDVM.TestingSystem.SAPFOR.SapforSettings.SapforSettingsDBTable;
import _VisualDVM.TestingSystem.SAPFOR.SapforSettingsCommand.SapforSettingsCommandsDBTable;
import _VisualDVM.TestingSystem.SAPFOR.ServerSapfor.ServerSapfor;
import _VisualDVM.TestingSystem.SAPFOR.ServerSapfor.ServerSapforState;
import _VisualDVM.TestingSystem.SAPFOR.ServerSapfor.ServerSapforsDBTable;
import _VisualDVM.Utils;
import javafx.util.Pair;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Vector;
public class TestsDatabase extends SQLiteDatabase {
    public DVMConfigurationDBTable dvm_configurations;
    public TestDBTable tests;
    public GroupsDBTable groups;
    public DVMPackageDBTable dvmPackages;
    public SapforPackageDBTable sapforPackages;
    //--
    public TestingPackagesToKillDBTable testingPackagesToKill;
    //--
    public SapforConfigurationDBTable sapforConfigurations;
    //----
    public ServerSapforsDBTable serverSapfors;
    //---
    public DVMRunTasksSet dvmRunTasks = new DVMRunTasksSet(); //задачи текущего пакета тестирования DVM
    public SapforSettingsDBTable sapforSettings;
    public SapforSettingsCommandsDBTable sapforSettingsCommands;
    //--
    public DVMSettingsDBTable dvmSettings;
    public TestsDatabase() {
        super(Paths.get(System.getProperty("user.dir"), "Data", Constants.tests_db_name + ".sqlite").toFile());
    }
    @Override
    protected void initAllTables() throws Exception {
        addTable(dvm_configurations = new DVMConfigurationDBTable());
        addTable(groups = new GroupsDBTable());
        addTable(tests = new TestDBTable());
        addTable(dvmPackages = new DVMPackageDBTable());
        addTable(sapforPackages = new SapforPackageDBTable());
        addTable(testingPackagesToKill = new TestingPackagesToKillDBTable());
        //-
        addTable(sapforConfigurations = new SapforConfigurationDBTable());
        addTable(serverSapfors = new ServerSapforsDBTable());
        addTable(sapforSettings = new SapforSettingsDBTable());
        addTable(sapforSettingsCommands = new SapforSettingsCommandsDBTable());
        addTable(dvmSettings = new DVMSettingsDBTable());
    }
    @Override
    public PassCode getSynchronizePassCode() {
        return PassCode.SynchronizeTests;
    }
    public Vector<SapforPackage> getFirstActiveSapforPackagesCopies() {
        Vector<SapforPackage> res = new Vector<>();
        Vector<SapforPackage> packages = new Vector<>();
        SapforPackage activePackage = null;
        //1. получить активные пакеты.
        for (SapforPackage p : sapforPackages.Data.values()) {
            switch (p.state) {
                case Done:
                case Aborted:
                case Draft:
                case ConnectionError:
                case DoneWithErrors:
                    break;
                default:
                    packages.add(p);
                    break;
            }
        }
        //2. отсортировать по приоритету.
        packages.sort(new Comparator<SapforPackage>() {
            @Override
            public int compare(SapforPackage o1, SapforPackage o2) {
                return Integer.compare(o1.state.ordinal(), o2.state.ordinal());
            }
        });
        if (!packages.isEmpty()) {
            activePackage = packages.lastElement();
            if (activePackage.state.equals(TasksPackageState.Queued)) {
                activePackage.state = TasksPackageState.TestsSynchronize;
                try {
                    Update(activePackage);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            res.add(new SapforPackage(activePackage));
            ; //копия чтобы не было конфликта доступа с нитью планировщика.
        }
        return res;
    }
    public Vector<DVMPackage> getFirstActiveDVMPackagesCopies() {
        Vector<DVMPackage> res = new Vector<>();
        //--
        LinkedHashMap<String, Vector<DVMPackage>> packagesByMachines = new LinkedHashMap<>();
        //----
        //1. Получить список активных пакетов по машинам.
        for (DVMPackage dvmPackage : dvmPackages.Data.values()) {
            switch (dvmPackage.state) {
                case Done:
                case DoneWithErrors:
                case Aborted:
                case Draft:
                case ConnectionError:
                    break;
                default:
                    //активен.
                    Vector<DVMPackage> packages = null;
                    //--
                    if (packagesByMachines.containsKey(dvmPackage.machine_address)) {
                        packages = packagesByMachines.get(dvmPackage.machine_address);
                    } else {
                        packages = new Vector<>();
                        packagesByMachines.put(dvmPackage.machine_address, packages);
                    }
                    packages.add(dvmPackage);
                    break;
            }
        }
        //2. Выбрать для каждой машины наиболее приоритетный пакет.
        for (String machine : packagesByMachines.keySet()) {
            Vector<DVMPackage> packages = packagesByMachines.get(machine);
            if (!packages.isEmpty()) {
                packages.sort(new Comparator<DVMPackage>() {
                    @Override
                    public int compare(DVMPackage o1, DVMPackage o2) {
                        return Integer.compare(o1.state.ordinal(), o2.state.ordinal());
                    }
                });
                //-
                DVMPackage activePackage = packages.lastElement();
                if (activePackage.state.equals(TasksPackageState.Queued)) {
                    activePackage.state = TasksPackageState.TestsSynchronize;
                    try {
                        Update(activePackage);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                res.add(new DVMPackage(activePackage)); //копия чтобы не было конфликта доступа с нитью планировщика.
            }
        }
        return res;
    }
    //--
    public void SaveTestFromSingleFile(ServerSapfor sapfor, Group group, Test test, File file) throws Exception {
        File testDirectory = new File(Global.TestsDirectory, String.valueOf(test.id));
        Utils_.CheckAndCleanDirectory(testDirectory);
        File testFile = Paths.get(testDirectory.getAbsolutePath(), file.getName()).toFile();
        FileUtils.copyFile(file, testFile);
        //----
        //архивация.
        File archive = test.getArchive();
        if (archive.exists())
            FileUtils.forceDelete(archive);
        //----------->>
        ZipFolderPass zip = new ZipFolderPass();
        zip.Do(testDirectory.getAbsolutePath(), archive.getAbsolutePath());
        //---
        //Определение размерности
        switch (group.language) {
            case fortran:
                // временная папка для анализа. чтобы не засорять нормальную.
                File tempProject = Utils.getTempFileName("test");
                FileUtils.forceMkdir(tempProject);
                FileUtils.copyDirectory(testDirectory, tempProject);
                //--
                if (Sapfor.getMinMaxDim(Sapfor.getTempCopy(new File(sapfor.call_command)), tempProject, test)) {
                    Update(test);
                } else
                    throw new RepositoryRefuseException("Не удалось определить размерность теста " + Utils_.Brackets(test.description));
                break;
            case c:
                test.max_dim = Utils.getCTestMaxDim(testFile);
                Update(test);
                break;
        }
    }
    //---
    public void CreateTestFromSingleFile(Account account, ServerSapfor sapfor, Group group, File file, String testDescription) throws Exception {
        Test test = new Test();
        test.description = testDescription;
        test.sender_name = account.name;
        test.sender_address = account.email;
        test.group_id = group.id;
        test.files = file.getName();
        Insert(test);
        //->>
        SaveTestFromSingleFile(sapfor, group, test, file);
    }
    public void RefreshGroup(Account account, ServerSapfor sapfor, Pair<Group, Vector<File>> groupData) throws Exception {
        Group group = groupData.getKey();
        Vector<File> files = groupData.getValue();
        //--
        Group oldGroup = groups.getGroupByDescription(group.language, group.description);
        if (oldGroup == null) {
            Insert(group);
            for (File file : files) {
                String testDescription = Utils_.getNameWithoutExtension(file.getName()) + "_" + group.language.getDVMCompile();
                CreateTestFromSingleFile(account, sapfor, group, file, testDescription);
            }
        } else {
            for (File file : files) {
                String testDescription = Utils_.getNameWithoutExtension(file.getName()) + "_" + group.language.getDVMCompile();
                Test oldTest = tests.getTestByDescription(oldGroup.id, testDescription);
                if (oldTest == null) {
                    CreateTestFromSingleFile(account, sapfor, oldGroup, file, testDescription);
                } else {
                    SaveTestFromSingleFile(sapfor, group, oldTest, file);
                }
            }
        }
    }
    public Vector<DVMPackage> getFirstActiveDVMPackageCopyForMachineURL(String arg) {
        Vector<DVMPackage> res = new Vector<>();
        Vector<DVMPackage> machinePackages = new Vector<>();
        //--
        //1. Получить список активных пакетов для машины.
        for (DVMPackage dvmPackage : dvmPackages.Data.values()) {
            switch (dvmPackage.state) {
                case Done:
                case DoneWithErrors:
                case Aborted:
                case Draft:
                case ConnectionError:
                    break;
                default:
                    if (dvmPackage.getMachine().getURL().equals(arg))
                        machinePackages.add(dvmPackage);
                    break;
            }
        }
        if (!machinePackages.isEmpty()) {
            machinePackages.sort(new Comparator<DVMPackage>() {
                @Override
                public int compare(DVMPackage o1, DVMPackage o2) {
                    return Integer.compare(o1.state.ordinal(), o2.state.ordinal());
                }
            });
            //-
            DVMPackage activePackage = machinePackages.lastElement();
            if (activePackage.state.equals(TasksPackageState.Queued)) {
                activePackage.state = TasksPackageState.TestsSynchronize;
                try {
                    Update(activePackage);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            res.add(new DVMPackage(activePackage));
        }
        return res;
    }
    public ServerSapfor getSapforCopyForCompilation() {
        for (ServerSapfor serverSapfor : serverSapfors.Data.values()) {
            if (serverSapfor.state.equals(ServerSapforState.Queued)) {
                return new ServerSapfor(serverSapfor);
            }
        }
        return null;
    }
    public Integer getInstalledSapforMaxVersion() {
        int max_version = CommonConstants.Nan;
        for (ServerSapfor sapfor : serverSapfors.Data.values()) {
            if (sapfor.state.equals(ServerSapforState.Done)) {
                int version = CommonConstants.Nan;
                try {
                    version = Integer.parseInt(sapfor.version);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                if (version > max_version) max_version = version;
            }
        }
        return max_version;
    }
    public boolean hasActiveSapfors() {
        for (ServerSapfor serverSapfor : serverSapfors.Data.values()) {
            if (serverSapfor.state.isActive())
                return true;
        }
        return false;
    }
    public void UnselectAllGTC() {
        groups.CheckAll(false);
        tests.CheckAll(false);
        dvm_configurations.CheckAll(false);
    }
    public void CheckTestsPackagesDependencies(Vector<Integer> testsIds, TextLog Log) {
        //определить есть ли активные пакеты в которые входят упомянутые тесты
        //если есть выписать группа/тест причина - находится в активном пакете
    }
    public void RefreshTestNameInConfigurations(Integer testId) {
        //обновить имя теста во всех конфигурация
    }
    public void DeleteTestFromConfigurations(Integer testId) {
        //обновить имя теста во всех конфигурация
    }
    //todo возможно рассмотреть вариант с синхроннизацией тестов для пакетов через команду серверу а не в нити
    //во избежание конфликта доступа,или удалением тестов во время копирования(?)
}
