package _VisualDVM.ProjectData.Project;
import Common.CommonConstants;
import Common.Database.Objects.DBObject;
import Common.MainModule_;
import Common.Passes.PassException;
import Common.Utils.*;
import Common.Visual.UI;
import _VisualDVM.Constants;
import _VisualDVM.Current;
import _VisualDVM.Global;
import _VisualDVM.GlobalData.DBLastProject.DBLastProject;
import _VisualDVM.GlobalData.SapforProfile.SapforProfile;
import _VisualDVM.GlobalData.SapforProfileSetting.SapforProfileSetting;
import _VisualDVM.Passes.PassCode;
import _VisualDVM.ProjectData.DBArray.DBArray;
import _VisualDVM.ProjectData.Files.DBProjectFile;
import _VisualDVM.ProjectData.Files.FileState;
import _VisualDVM.ProjectData.Files.FileType;
import _VisualDVM.ProjectData.Files.LanguageStyle;
import _VisualDVM.ProjectData.LanguageName;
import _VisualDVM.ProjectData.Messages.Errors.MessageError;
import _VisualDVM.ProjectData.Messages.FileMessagesJson;
import _VisualDVM.ProjectData.Messages.Message;
import _VisualDVM.ProjectData.Messages.MessagesJson;
import _VisualDVM.ProjectData.Messages.Notes.MessageNote;
import _VisualDVM.ProjectData.Messages.Recommendations.MessageRecommendation;
import _VisualDVM.ProjectData.Messages.Warnings.MessageWarning;
import _VisualDVM.ProjectData.ProjectDatabase;
import _VisualDVM.ProjectData.SapforData.Arrays.ProjectArray;
import _VisualDVM.ProjectData.SapforData.Arrays.ProjectArraysSet;
import _VisualDVM.ProjectData.SapforData.Functions.FuncCall;
import _VisualDVM.ProjectData.SapforData.Functions.FuncCallH;
import _VisualDVM.ProjectData.SapforData.Functions.FuncInfo;
import _VisualDVM.ProjectData.SapforData.Functions.UI.Graph.GraphInfo;
import _VisualDVM.ProjectData.SapforData.Includes.Analysis.FileInfo;
import _VisualDVM.ProjectData.SapforData.Regions.ParallelRegion;
import _VisualDVM.ProjectData.SapforData.Regions.ParallelRegionsSet;
import _VisualDVM.ProjectData.SapforData.SapforProperties;
import _VisualDVM.ProjectData.SapforData.Variants.ParallelVariant;
import _VisualDVM.ProjectData.SapforData.Variants.ParallelVariantsSet;
import _VisualDVM.Utils;
import com.mxgraph.swing.mxGraphComponent;
import com.sun.org.glassfish.gmbal.Description;
import org.apache.commons.io.FileUtils;

import javax.swing.tree.DefaultMutableTreeNode;
import java.io.File;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
public class db_project_info extends DBObject {
    public static Vector<db_project_info> newVersions = new Vector<>();
    //--
    public DefaultMutableTreeNode align_rules_root = new DefaultMutableTreeNode("");
    public DefaultMutableTreeNode includes_root = new DefaultMutableTreeNode("");
    //-
    public DefaultMutableTreeNode inline_root = new DefaultMutableTreeNode("");
    public DefaultMutableTreeNode inline_root2 = new DefaultMutableTreeNode("");
    //<editor-fold desc="Хранимые в бд поля">
    @Description("PRIMARY KEY,NOT NULL")
    public String name = "";
    public String original = "";
    public String description = "";
    public LanguageName languageName = LanguageName.fortran;
    @Description("DEFAULT 'fixed'")
    public LanguageStyle style = LanguageStyle.fixed;
    public String Log = "";//текст выдаваемый сапфором
    //-----------------------------------------------
    @Description("DEFAULT -1")
    public long creationDate = CommonConstants.Nan; //--------------------------------------------------NEW.
    @Description("DEFAULT ''")
    public String compilation_output = "";
    @Description("DEFAULT ''")
    public String compilation_errors = "";
    @Description("DEFAULT ''")
    public String run_output = "";
    @Description("DEFAULT ''")
    public String run_errors = "";
    @Description("DEFAULT ''")
    public String Scenario = "";//трассировка вызываемых визуализатором проходов.
    @Description("DEFAULT ''")
    public String VersionBuilding = "";
    public int filter_distributed = 0;
    public int filter_multiplied = 0;
    @Description("DEFAULT 40")
    public int compilation_maxtime = 40;
    @Description("DEFAULT 120")
    public int run_maxtime = 120;
    @Description("DEFAULT 0")
    public int maxdim = 0;
    //<editor-fold desc="Метрика">
    @Description("DEFAULT -1")
    public int numLines = CommonConstants.Nan;
    @Description("DEFAULT -1")
    public int numSPF = CommonConstants.Nan;
    @Description("DEFAULT -1")
    public int numDVM = CommonConstants.Nan;
    @Description("DEFAULT -1")
    public int numArrays = CommonConstants.Nan;
    @Description("DEFAULT -1")
    public int numLoops = CommonConstants.Nan;
    @Description("DEFAULT -1")
    public int numFunctions = CommonConstants.Nan;
    @Description("DEFAULT -1")
    public int numAddicted = CommonConstants.Nan;
    //-------------------------------------
    //параметры графа функций. храним для каждого проекта.
    @Description("DEFAULT 500")
    public int fgIterations = 500;
    @Description("DEFAULT 300")
    public int fgResistance = 300;
    @Description("DEFAULT 1.0")
    public double fgScreen = 1.0;
    //------------------------------------
    @Description("IGNORE")
    public int testMaxDim = 0;
    @Description("IGNORE")
    public boolean isNew = false; //для выделения только что построенных версий.
    //------------------------------------
    //тут ключ - идентификатор. не меняем.
    public ProjectArraysSet declaratedArrays = new ProjectArraysSet();
    //new - все объявленные в проекте функции.
    public FuncInfo main_function = null;
    public FuncCallH main_functionH = null;
    //-
    public LinkedHashMap<String, FuncInfo> allFunctions = new LinkedHashMap<>();
    //-
    public LinkedHashMap<String, FileInfo> addictedFiles = new LinkedHashMap<>();
    //тут ключ -адрес. меняем
    public Vector<ProjectArray> templates = new Vector<>();
    public ParallelRegionsSet parallelRegions = new ParallelRegionsSet();
    public ParallelVariantsSet parallelVariants = new ParallelVariantsSet();
    public GraphInfo functionsGraph = new GraphInfo();
    public Vector<String> files_order = new Vector<>();
    public db_project_info last_modification = null;
    public db_project_info last_version = null;
    //-------------------------------------------------------------------------------------->>>>>
    public DefaultMutableTreeNode node = null;
    public db_project_info parent = null; //родительская версия.
    public LinkedHashMap<String, db_project_info> versions = new LinkedHashMap<>(); //подверсии.
    public Vector<File> subdirectories = new Vector();///подпапки.
    public File Home = null;
    public DefaultMutableTreeNode filesTreeRoot = null;
    public ProjectDatabase db = null;
    public Vector<String> allIncludes = new Vector<>();
    public SapforProperties sapforProperties = null;
    DBLastProject info = null; //обновляется при открытии проекта.
    public db_project_info() {
    }
    //----------------------------------
    //конструктор для пустой версии (cо структурой папок)
    public db_project_info(db_project_info parent_in,
                           String letter_in,
                           String description_in,
                           String original_in) throws Exception {
        parent = parent_in;
        name = parent.GenerateVersionName(letter_in);
        languageName = parent.languageName;
        style = (parent_in.sapforProperties.FREE_FORM ? LanguageStyle.free : LanguageStyle.fixed);
        description = description_in;
        original = original_in;
        Home = Paths.get(parent_in.Home.getAbsolutePath(), name).toFile();
        parent.SaveVersionToBuild(name);
        if (!Home.mkdir()) throw new PassException("Не удалось создать папку для версии");
        creationDate = Utils_.getDateNumber(); //----------------------------------------------------------------------------->>>
        CreateVisualiserData();
        parent.AddVersion(this);
        //если это делать раньше, папка версии учтется как подпапка.
        parent.CopySubdirectories(Home);
        FileUtils.copyFile(parent.getPropertiesFile(), getPropertiesFile());
    }
    //------------------------------
    //обычное открытие.
    public db_project_info(File dir) throws Exception {
        Home = dir;
        //-
        CheckVisualiserDirectories();
        db = new ProjectDatabase(this);
        db.Connect();
        db.CreateAllTables();
        db.prepareTablesStatements();
        db_project_info stored_info = db.LoadOnlyProjectInfo();
        if (stored_info == null) {
            name = Home.getName();
            description = "";
            creationDate = Utils_.getDateNumber();
            db.Insert(this);
        } else
            ExtractStoredInfo(stored_info);
        db.Disconnect();
    }
    //-
    public static File get_db_file(File project_home) {
        return new File(Paths.get(project_home.toString(), Constants.data,
                "new_project_base.sqlite").toString());
    }
    public static String recommendAnalysis(PassCode code_in) {
        return Constants.unknown_metric + " примените анализатор  \"" + code_in.getDescription() + "\"";
    }
    public static void ResetNewVersions() {
        for (db_project_info version : newVersions) {
            version.isNew = false;
        }
        newVersions.clear();
    }
    public static int extractVersionNumber(db_project_info version) {
        int res = 0;
        try {
            res = Integer.parseInt(version.name.substring(1));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return res;
    }
    public static void sortVersionsByNumber(Vector<db_project_info> versions) {
        versions.sort(Comparator.comparingInt(db_project_info::extractVersionNumber));
    }
    public void SynchronizeSapforProperties() throws Exception {
        if (sapforProperties == null) {
            File propertiesFile = getPropertiesFile();
            if (propertiesFile.exists()) {
                sapforProperties = Utils_.ReadProperties(propertiesFile, SapforProperties.class);
            } else {
                SapforProfile defaultProfile = Global.mainModule.getDb().getDefaultSapforProfile();
                if (defaultProfile == null) {
                    sapforProperties = new SapforProperties(propertiesFile);
                    Utils_.jsonToFile(sapforProperties, propertiesFile);
                } else {
                    sapforProperties = new SapforProperties(getPropertiesFile());
                    sapforProperties.applyProfile(Global.mainModule.getDb().getVectorByFK(defaultProfile, SapforProfileSetting.class));
                }
            }
        }
    }
    public File getPropertiesFile() {
        return new File(getDataDirectory(), "properties");
    }
    //-
    public void Open() throws Exception {
        db.Connect();
        db.prepareTablesStatements();
        db.Synchronize();
    }
    public void Close() throws Exception {
        db.Disconnect();
        dropLastModification();
    }
    //-исходная
    public void CreateVisualiserData() throws Exception {
        CheckVisualiserDirectories();
        db = new ProjectDatabase(this);
        db.Connect();
        db.CreateAllTables();
        db.prepareTablesStatements();
        db.Insert(this);
        db.Disconnect();
        //--
    }
    //------------------------------------
    public void UpdatefgIterations(int iterations_in) {
        fgIterations = iterations_in;
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    public void UpdatefgResistance(int resistance_in) {
        fgResistance = resistance_in;
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    public void UpdatefgScreen(double screen_in) {
        fgScreen = screen_in;
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    public void UpdateCompilationMaxtime(int ct_in) {
        compilation_maxtime = ct_in;
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    public void UpdateRunMaxtime(int rt_in) {
        run_maxtime = rt_in;
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    //</editor-fold>
    //</editor-fold>
    //-----------------------------------
    public boolean f_distributed() {
        return filter_distributed != 0;
    }
    public boolean f_multiplied() {
        return filter_multiplied != 0;
    }
    public void SwitchFilterDistributed() {
        filter_distributed = f_distributed() ? 0 : 1;
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    public void SwitchFilterMultiplied() {
        filter_multiplied = f_multiplied() ? 0 : 1;
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    public boolean IsMCopy() {
        String lname = name.toLowerCase();
        return (lname.startsWith("m") && Utils_.isIntegerValue(lname.substring(1)));
    }
    public String getTitle() {
        return name + " " + Utils_.DQuotes(description);
    }
    public File getProjFile() {
        return Paths.get(Home.getAbsolutePath(), Constants.data, Constants.spf).toFile();
    }
    public File getDataDirectory() {
        return Paths.get(Home.getAbsolutePath(), Constants.data).toFile();
    }
    public File getOptionsDirectory() {
        return Paths.get(Home.getAbsolutePath(), Constants.data, Constants.options).toFile();
    }
    public File getGCOVDirectory() {
        return Paths.get(Home.getAbsolutePath(), Constants.data, Constants.gcov).toFile();
    }
    public File getAttachmentsDirectory() {
        return Paths.get(Home.getAbsolutePath(), Constants.data, Constants.attachments).toFile();
    }
    public File getAnalyzerDirectory() {
        return Paths.get(Home.getAbsolutePath(), Constants.data, Constants.PerformanceAnalyzerDirectoryName).toFile();
    }
    public Vector<File> getScreenShots() {
        Vector<File> res = new Vector<>();
        File[] files = getAttachmentsDirectory().listFiles();
        if (files != null) {
            for (File file : files) {
                if (!file.isDirectory() && file.getName().startsWith("screenshot"))
                    res.add(file);
            }
        }
        return res;
    }
    public File getStatisticDirectory() {
        return Paths.get(Home.getAbsolutePath(), Constants.data, Constants.statistic).toFile();
    }
    public db_project_info find_version_r(File v_home) {
        if (Home.equals(v_home)) return this;
        for (db_project_info version : versions.values())
            if (version.Home.equals(v_home)) return version;
        for (db_project_info version : versions.values()) {
            db_project_info res = version.find_version_r(v_home);
            if (res != null) return res;
        }
        return null;
    }
    public DBProjectFile getLastOpenedFile() {
        Vector<DBProjectFile> sorted_ = new Vector<>();
        for (DBProjectFile f : db.files.Data.values()) {
            if (!f.state.equals(FileState.Excluded) && !f.fileType.equals(FileType.forbidden)) {
                sorted_.add(f);
            }
        }
        sorted_.sort(new Comparator<DBProjectFile>() {
            @Override
            public int compare(DBProjectFile o1, DBProjectFile o2) {
                return Long.compare(o1.file.lastModified(), o2.file.lastModified());
            }
        }.reversed());
        LinkedHashMap<FileType, DBProjectFile> matches = new LinkedHashMap<>();
        DBProjectFile sorceFile = null;
        DBProjectFile headerFile = null;
        for (DBProjectFile f : sorted_) {
            if (!matches.containsKey(f.fileType)) {
                matches.put(f.fileType, f);
            }
        }
        Vector<FileType> priority = new Vector_<>(FileType.program, FileType.header, FileType.data, FileType.none);
        for (FileType type : priority) {
            if (matches.containsKey(type))
                return matches.get(type);
        }
        return null;
    }
    public void CreateParserOptionsDirs() throws Exception {
        Utils_.forceDeleteWithCheck(getOptionsDirectory());
        FileUtils.forceMkdir(getOptionsDirectory());
        CopySubdirectories(getOptionsDirectory());
    }
    public void CreateGCOVDirs() throws Exception {
        Utils_.forceDeleteWithCheck(getGCOVDirectory());
        FileUtils.forceMkdir(getGCOVDirectory());
        CopySubdirectories(getGCOVDirectory());
    }
    public void ClearGCOV() throws Exception {
        CreateGCOVDirs();
        //updateGCOV_status(0);
        for (DBProjectFile file : db.files.Data.values()) {
            file.GCOVLog = "";
            db.Update(file);
        }
    }
    public DBProjectFile getFirstBadFile() {
        for (DBProjectFile f : db.files.Data.values()) {
            if (f.state.equals(FileState.HasErrors))
                return f;
        }
        return null;
    }
    public void CleanAnalyses() throws Exception {
        allIncludes.clear();
        files_order.clear();
        functionsGraph.Clear();
        numLines = CommonConstants.Nan;
        numSPF = CommonConstants.Nan;
        numDVM = CommonConstants.Nan;
        numArrays = CommonConstants.Nan;
        numFunctions = CommonConstants.Nan;
        numAddicted = CommonConstants.Nan;
        numLoops = CommonConstants.Nan;
        Log = "";
        Scenario = "";
        declaratedArrays.clear();
        main_function = null;
        main_functionH = null;
        allFunctions.clear();
        RefreshInlineRoot();
        parallelRegions.clear();
        addictedFiles.clear();
        templates.clear();
        parallelVariants.clear();
        align_rules_root.removeAllChildren();
        inline_root.removeAllChildren();
        inline_root2.removeAllChildren();
        includes_root.removeAllChildren();
        Update();
        for (DBProjectFile file : db.files.Data.values())
            file.CleanAll();
        db.DeleteAll(MessageRecommendation.class);
        //в таблице сообщений скинуть счетчик.
        db.ResetAI(MessageNote.class);
        db.ResetAI(MessageError.class);
        db.ResetAI(MessageWarning.class);
        db.ResetAI(MessageRecommendation.class);
        //-
        Global.mainModule.set(Current.Function, null);
        Global.mainModule.set(Current.SelectedFunction, null);
    }
    public void CleanVersions() throws Exception {
        node.removeAllChildren();
        for (db_project_info v : versions.values())
            Utils_.forceDeleteWithCheck(v.Home);
        versions.clear();
        dropLastModification();
    }
    public void dropLastModification() {
        last_modification = null;
    }
    public void Update() {
        try {
            db.Update(this);
        } catch (Exception ex) {
            Utils_.MainLog.PrintException(ex);
        }
    }
    public boolean UpdateLanguage(LanguageName lang_in) {
        if (!languageName.equals(lang_in)) {
            languageName = lang_in;
            Update();
            return true;
        }
        return false;
    }
    public boolean UpdateStyle(LanguageStyle s) {
        if (!style.equals(s)) {
            style = s;
            Update();
            return true;
        }
        return false;
    }
    public void UpdateMaxDim() {
        Update();
    }
    public void GenRules() {
        align_rules_root.removeAllChildren();
        maxdim = 0;
        UpdateMaxDim();
        if (templates.size() > 0) {
            for (ParallelRegion p : parallelRegions.Data.values()) {
                DefaultMutableTreeNode pn = new DefaultMutableTreeNode(p);
                p.genRules(p.arraysMap);
                for (String r : p.rules)
                    pn.add(new DefaultMutableTreeNode(r));
                maxdim = Math.max(maxdim, p.maxdim);
                align_rules_root.add(pn);
            }
            UpdateMaxDim();
            for (ProjectArray t : templates)
                t.CreateDimensions();
        }
    }
    public void gen_rec(Vector<ProjectArray> templates, Vector<Vector<BigInteger>> res, int index) {
        if (index >= 0) {
            ProjectArray current = templates.get(index);
            Vector<Vector<BigInteger>> old = new Vector<>();
            for (Vector<BigInteger> L : res)
                old.add(L);
            res.clear();
            Vector<Long> varIDs = current.get_varIDs();
            for (Long varID : varIDs) {
                for (Vector<BigInteger> L : old) {
                    for (BigInteger regID : current.regIDs) //тройки для всех областей.
                    {
                        Vector<BigInteger> buf = new Vector<>();
                        buf.add(current.address);
                        buf.add(BigInteger.valueOf(varID));
                        buf.add(regID);
                        for (BigInteger l : L)
                            buf.add(l);
                        res.add(buf);
                    }
                }
            }
            gen_rec(templates, res, index - 1);
        }
    }
    public String LinesCount() {
        return numLines == ParallelVariant.statNaN ? recommendAnalysis(PassCode.SPF_GetFileLineInfo) : String.valueOf(numLines);
    }
    public String SPFCount() {
        return numSPF == ParallelVariant.statNaN ? recommendAnalysis(PassCode.SPF_GetFileLineInfo) : String.valueOf(numSPF);
    }
    public String DVMCount() {
        return numDVM == ParallelVariant.statNaN ? recommendAnalysis(PassCode.SPF_GetFileLineInfo) : String.valueOf(numDVM);
    }
    public String ArraysCount() {
        return numArrays == ParallelVariant.statNaN ? recommendAnalysis(PassCode.SPF_GetAllDeclaratedArrays) : String.valueOf(numArrays);
    }
    public String LoopsCount() {
        return numLoops == ParallelVariant.statNaN ? recommendAnalysis(PassCode.SPF_GetGraphLoops) : String.valueOf(numLoops);
    }
    public String FunctionsCount() {
        return numFunctions == CommonConstants.Nan ? recommendAnalysis(PassCode.SPF_GetGraphFunctions) : String.valueOf(numFunctions);
    }
    public String AddictedCount() {
        return numAddicted == CommonConstants.Nan ? recommendAnalysis(PassCode.SPF_GetIncludeDependencies) : String.valueOf(numAddicted);
    }
    public boolean UpdateLinesCount() {
        try {
            db.Update(this);
            return true;
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
        return false;
    }
    public void UpdateSPFCount() {
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    public void UpdateDVMCount() {
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
    }
    public boolean UpdateAddictedCount() {
        try {
            db.Update(this);
            return true;
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
        return false;
    }
    // https://javarush.ru/groups/posts/2274-kak-ispoljhzovatjh-bigdecimal-v-java
    public BigInteger getFilteredVariantsCount() {
        if (templates.isEmpty()) return BigInteger.ZERO;
        BigInteger amount = BigInteger.ONE;
        for (ProjectArray template : templates)
            amount = amount.multiply(BigInteger.valueOf(template.get_varIDs().size()));
        return amount;
    }
    public BigInteger getTotalVariantsCount() {
        if (templates.isEmpty()) return BigInteger.ZERO;
        BigInteger amount = BigInteger.ONE;
        for (ProjectArray template : templates)
            amount = amount.multiply(BigInteger.valueOf(template.get_varIDs(false).size()));
        return amount;
    }
    //получить имя относительно папки проекта.
    public String getInnerName(File file) {
        return file.getAbsolutePath().substring(Home.getAbsolutePath().length() + 1).replace('/', '\\');
    }
    public LinkedHashMap<LanguageName, Vector<DBProjectFile>> getPrograms() {
        LinkedHashMap<LanguageName, Vector<DBProjectFile>> res = new LinkedHashMap<>();
        //-----------------------------------------------
        res.put(LanguageName.fortran, new Vector<>());
        res.put(LanguageName.c, new Vector<>());
        res.put(LanguageName.cpp, new Vector<>());
        for (DBProjectFile file : db.files.Data.values()) {
            if (!file.state.equals(FileState.Excluded) && file.fileType.equals(FileType.program) && (!file.languageName.equals(LanguageName.n)))
                res.get(file.languageName).add(file);
        }
        return res;
    }
    public String getUniqKey() {
        return Home.getAbsolutePath().replace("\\", "").replace(":", "").replace("/", "");
    }
    //получить все подпапки проекта на указанном уровне.
    public Vector<File> getSubdirectoriesSimple(File dir) {
        Vector<File> res = new Vector<>();
        for (File d : Objects.requireNonNull(dir.listFiles())) {
            if (isProjectDirectory(d))
                res.add(d);
        }
        return res;
    }
    //получить файлы относящиеся к проекту, лежащие в данной папке.
    public Vector<File> getFiles(File dir) {
        Vector<File> res = new Vector<>();
        for (DBProjectFile file : db.files.Data.values()) {
            if (file.file.getParentFile().getAbsolutePath().equals(dir.getAbsolutePath()))
                res.add(file.file);
        }
        return res;
    }
    public Vector<File> getActiveFilesForSynchronization(File dir, boolean data) {
        Vector<File> res = new Vector<>();
        for (DBProjectFile file : db.files.Data.values()) {
            if (file.file.getParentFile().getAbsolutePath().equals(dir.getAbsolutePath())
                    && (!file.state.equals(FileState.Excluded)) &&
                    !file.file.getName().equalsIgnoreCase("MAKEFILE") &&
                    (!data || file.fileType.equals(FileType.data))
            )
                res.add(file.file);
            //мейкфайлы если они есть все будут игнорироваться. имеет право на существование на машине
            //только технический мейкфайл.
        }
        return res;
    }
    public DBLastProject getInfo() {
        return info;
    }
    public void setInfo(DBLastProject info_in) {
        info = info_in;
    }
    public File getStsFile() {
        return Paths.get(getStatisticDirectory().getAbsolutePath(), "statistic.txt").toFile();
    }
    public String getStsText() {
        return getStsFile().exists() ? Utils.ReadAllText(getStsFile()) : "файла статистики не существует.\nЗапустите проект на DVM системе, чтобы его получить";
    }
    public void check_files_r(File file, Vector<DBProjectFile> res) {
        if (isProjectDirectory(file)) {
            for (File f : Objects.requireNonNull(file.listFiles()))
                check_files_r(f, res);
        } else if (file.isFile()) {
            DBProjectFile pf = new DBProjectFile(file, this);
            if (pf.fileType != FileType.forbidden)
                res.add(pf);
        }
    }
    public Vector<DBProjectFile> getFilesForComparsion() {
        Vector<DBProjectFile> res = new Vector<>();
        if (Global.mainModule.HasProject() && this.Home.equals(Global.mainModule.getProject().Home)) {
            //
            res = db.files.Data.values().stream().filter(file -> !file.state.equals(FileState.Excluded)).collect(Collectors.toCollection(Vector::new));
        } else {
            try {
                //версия для сравнения - не текущий проект. придется лезть в ее бд. Предполагаем что она всегда есть.
                Open();
                res = db.files.Data.values().stream().filter(file -> !file.state.equals(FileState.Excluded)).collect(Collectors.toCollection(Vector::new));
                Close();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return res;
    }
    public boolean FolderNotExists(File new_directory, File subdir, TextLog passLog) {
        for (File pf : getSubdirectoriesSimple(subdir)) {
            if (pf.getName().equals(new_directory.getName())) {
                passLog.Writeln("В папке " + Utils_.Brackets(subdir.getAbsolutePath()) + "\n" +
                        "уже существует папка с именем " + Utils_.Brackets(new_directory.getName()));
                return false;
            }
        }
        return true;
    }
    public File getInterruptFile() {
        return Paths.get(getDataDirectory().getAbsolutePath(), CommonConstants.INTERRUPT).toFile();
    }
    public void CleanInterruptFile() throws Exception {
        File file = getInterruptFile();
        Utils_.forceDeleteWithCheck(file);
    }
    public void CreateInterruptFile() throws Exception {
        FileUtils.write(getInterruptFile(), Global.mode.toString());
    }
    public void AppendScenario(String line_in) {
        Scenario += (line_in + "\n");
        try {
            db.Update(this);
        } catch (Exception ex) {
            Utils_.MainLog.PrintException(ex);
        }
    }
    public mxGraphComponent DrawFunctionsGraph() {
        return functionsGraph.Draw();
    }
    public DefaultMutableTreeNode getAttachmentsTree() {
        File[] attachments = getAttachmentsDirectory().listFiles();
        DefaultMutableTreeNode root = new DefaultMutableTreeNode(
                (attachments != null) ? ("Файлов: " + attachments.length) : "Файлов: 0");
        if (attachments != null) {
            for (File a : attachments)
                root.add(new DefaultMutableTreeNode(a));
        }
        return root;
    }
    public boolean CheckAttachmentFile(File f, TextLog Log) {
        Utils.validateFileShortNewName(f.getName(), Log);
        if (Utils_.getFileSizeMegaBytes(f) > 2)
            Log.Writeln_("Размер вложения " + Utils_.Brackets(f.getName()) + " превышает 2 Мb");
        return Log.isEmpty();
    }
    public boolean CheckAllAttachments(TextLog Log) {
        File[] attachments = getAttachmentsDirectory().listFiles();
        if (attachments != null) {
            for (File a : attachments)
                CheckAttachmentFile(a, Log);
        }
        return Log.isEmpty();
    }
    public void RefreshInlineRoot() {
        inline_root.setUserObject("Отметьте вызовы для подстановки");
    }
    public void RefreshInlineRoot2() {
        inline_root2.setUserObject("Отметьте полные цепочки вызовов для подстановки");
    }
    public void BuildInlineGraph() {
        Vector<FuncInfo> sortedFunctions = new Vector<>(allFunctions.values());
        sortedFunctions.sort(Comparator.comparing(o -> o.funcName));
        for (FuncInfo decl1 : sortedFunctions) {
            if (decl1.isDeclared()) {
                DefaultMutableTreeNode node = new DefaultMutableTreeNode(decl1);
                inline_root.add(node);
                //-
                for (FuncInfo decl2 : allFunctions.values()) {
                    for (FuncCall call : decl2.callsFrom) {
                        if (call.funcName.equals(decl1.funcName)) {
                            if (!decl1.ownCalls.containsKey(call.file))
                                decl1.ownCalls.put(call.file, new Vector<>());
                            if (decl1.needToInline == 1) call.Select(true);
                            call.canBeInlined = decl1.doNotInline == 0;
                            decl1.ownCalls.get(call.file).add(call);
                            node.add(new DefaultMutableTreeNode(call));
                        }
                    }
                }
            }
        }
    }
    public void BuildInlineGraph2() {
        if (main_function != null) {
            //особый случай.
            main_functionH = new FuncCallH(main_function);
            DefaultMutableTreeNode main_node = new DefaultMutableTreeNode(main_functionH);
            for (FuncCall call : main_function.callsFrom) {
                Vector<String> chain = new Vector<>();
                chain.add(main_functionH.funcName);
                // UI.Info("start new chain");
                DefaultMutableTreeNode node = BuildInlineGraph2_r(call, chain);
                if (node != null) {
                    main_node.add(node);
                    main_functionH.calls.add((FuncCallH) node.getUserObject());
                }
            }
            inline_root2.add(main_node);
        }
    }
    public DefaultMutableTreeNode BuildInlineGraph2_r(FuncCall funcCall, Vector<String> chain) {
        chain.add(funcCall.funcName);
        //--
        FuncCallH funcCallH = new FuncCallH(funcCall);
        DefaultMutableTreeNode res = null;
        FuncInfo funcInfo = allFunctions.get(funcCall.funcName);
        res = new DefaultMutableTreeNode(funcCallH);
        for (FuncCall call : funcInfo.callsFrom) {
            if (!chain.contains(call.funcName)) {
                DefaultMutableTreeNode node = BuildInlineGraph2_r(call, chain);
                if (node != null) {
                    res.add(node);
                    funcCallH.calls.add((FuncCallH) node.getUserObject());
                }
            } //else System.out.println("RECURSION " + String.join("->", chain) + "->" + call.funcName);
        }
        return res;
    }
    @Override
    public Object getPK() {
        return name;
    }
    //----------------------------------------------------
    private void CheckVisualiserDirectories() {
        Utils_.CheckDirectory(getDataDirectory());
        Utils_.CheckDirectory(getOptionsDirectory());
        Utils_.CheckDirectory(getStatisticDirectory());
        Utils_.CheckDirectory(getAttachmentsDirectory());
        Utils_.CheckDirectory(getGCOVDirectory());
        Utils_.CheckDirectory(getAnalyzerDirectory());
    }
    //загрузка инфы из бд проекта.
    private void ExtractStoredInfo(db_project_info to_restore) {
        name = to_restore.name;
        original = to_restore.original;
        description = to_restore.description;
        languageName = to_restore.languageName;
        style = to_restore.style;
        Log = to_restore.Log;
        creationDate = to_restore.creationDate;
        Scenario = to_restore.Scenario;
        filter_distributed = to_restore.filter_distributed;
        filter_multiplied = to_restore.filter_multiplied;
        compilation_maxtime = to_restore.compilation_maxtime;
        run_maxtime = to_restore.run_maxtime;
        compilation_output = to_restore.compilation_output;
        compilation_errors = to_restore.compilation_errors;
        run_output = to_restore.run_output;
        run_errors = to_restore.run_errors;
        //----------------------------------
        numLines = to_restore.numLines;
        numArrays = to_restore.numArrays;
        numFunctions = to_restore.numFunctions;
        numAddicted = to_restore.numAddicted;
        numLoops = to_restore.numLoops;
        numSPF = to_restore.numSPF;
        numDVM = to_restore.numDVM;
        ///--
        fgIterations = to_restore.fgIterations;
        fgResistance = to_restore.fgResistance;
        fgScreen = to_restore.fgScreen;
        maxdim = to_restore.maxdim;
    }
    //-
    public String GenerateVersionName(String letter) {
        String res = "";
        int max_vn = 0;
        if (versions.keySet().size() > 0) {
            for (String key_ : versions.keySet()) {
                String[] data_ = key_.split(letter);
                String last = data_[data_.length - 1];
                if (Utils_.isIntegerValue(last)) {
                    int vn = Integer.parseInt(last);
                    if (vn > max_vn)
                        max_vn = vn;
                }
            }
        }
        File version_folder = null;
        do {
            res = letter + ++max_vn;
            version_folder = Paths.get(Home.getAbsolutePath(), res).toFile();
        } while (version_folder.exists());
        return res;
    }
    public void CloneParent() throws Exception {
        for (DBProjectFile file : parent.db.files.Data.values()) {
            Files.copy(file.file.toPath(),
                    Paths.get(Home.getAbsolutePath(),
                            Utils_.isWindows() ? file.name :
                                    file.name.replace('\\', '/')));
        }
    }
    public void AddVersion(db_project_info version) throws Exception {
        version.isNew = true;
        newVersions.add(version);
        //--->>
        versions.put(version.name, version);
        Global.mainModule.getUI().getVersionsWindow().getVersionsForm().getTree().AddNode(node, version.node = new DefaultMutableTreeNode(version));
        SaveVersionToBuild("");
    }
    public void SaveVersionToBuild(String v_name) throws Exception {
        if (!v_name.equalsIgnoreCase(VersionBuilding)) {
            VersionBuilding = v_name;
            db.Update(this);
        }
    }
    public void DeleteCrushedVersionIfNeed() throws Exception {
        if (!VersionBuilding.equals("")) {
            Utils_.forceDeleteWithCheck(Paths.get(Home.getAbsolutePath(), VersionBuilding).toFile());
            SaveVersionToBuild("");
        }
    }
    public void createModification() throws Exception {
        if (last_modification == null) {
            last_modification = new db_project_info(this,
                    "m",
                    "копия от " + new Date(),
                    "");
            last_modification.CloneParent();
        }
    }
    public void createEmptyVersion(String versionLetter, String versionDescription) throws Exception {
        if (sapforProperties.SaveModifications)
            createModification();
        last_version = new db_project_info(
                this,
                versionLetter,
                versionDescription,
                sapforProperties.SaveModifications ? last_modification.name : ""
        );
    }
    public void joinExistingVersion(File versionDirectory, String description_in) throws Exception {
        last_version = new db_project_info();
        last_version.parent = this;
        last_version.name = versionDirectory.getName();
        last_version.languageName = this.languageName;
        last_version.description = description_in;
        last_version.original = last_modification.name;
        last_version.Home = versionDirectory;
        last_version.creationDate = Utils_.getDateNumber();
        last_version.CreateVisualiserData();
        FileUtils.copyFile(getPropertiesFile(), last_version.getPropertiesFile());
        this.AddVersion(last_version);
    }
    //не является ли текущая версия последней модификацией
    public void checkLastModification(db_project_info version) {
        if ((last_modification != null) && version.Home.equals(last_modification.Home))
            last_modification = null;
    }
    public boolean isProjectDirectory(File dir) {
        if (!dir.isDirectory()) return false;
        if (dir.getName().equals(Constants.data)) return false;
        for (db_project_info version : versions.values()) {
            if (version.Home.equals(dir)) return false;
        }
        return true;
    }
    private void getSubdirectoriesR(File dir) {
        File[] files_ = dir.listFiles();
        if (files_ != null)
            for (File d : files_) {
                if (isProjectDirectory(d)) {
                    subdirectories.add(d);
                    getSubdirectoriesR(d);
                }
            }
    }
    public void CopySubdirectories(File dir) throws Exception {
        subdirectories.clear();
        getSubdirectoriesR(Home);
        for (File d : subdirectories) {
            String path = d.getAbsolutePath().substring(Home.getAbsolutePath().length());
            File cd = Paths.get(dir.getAbsolutePath(), path).toFile();
            FileUtils.forceMkdir(cd);
        }
    }
    //--
    private void getLonelyM_r(Vector<db_project_info> res) {
        Vector<db_project_info> ms = new Vector<>();
        Vector<db_project_info> vs = new Vector<>();
        for (db_project_info version : versions.values()) {
            if (version.IsMCopy())
                ms.add(version);
            else vs.add(version);
        }
        for (db_project_info m : ms) {
            boolean lonely = true;
            for (db_project_info v : vs) {
                if (v.original.equalsIgnoreCase(m.name)) {
                    lonely = false;
                    break;
                }
            }
            if (lonely) {
                res.add(m);
            }
        }
        for (db_project_info version : vs) {
            version.getLonelyM_r(res);
        }
    }
    public Vector<db_project_info> getLonelyM() {
        Vector<db_project_info> res = new Vector<>();
        this.getLonelyM_r(res);
        return res;
    }
    public void cleanDepAndGCOVR() throws Exception {
        Utils_.forceDeleteWithCheck(getOptionsDirectory());
        Utils_.forceDeleteWithCheck(getGCOVDirectory());
        Utils_.forceDeleteWithCheck(getStatisticDirectory());
        for (db_project_info version : versions.values())
            version.cleanDepAndGCOVR();
    }
    //---
    public Pair<LinkedHashMap<String, DBProjectFile>, LinkedHashMap<String, DBProjectFile>> sortFiles() {
        LinkedHashMap<String, DBProjectFile> active_programs = new LinkedHashMap<>();
        LinkedHashMap<String, DBProjectFile> others = new LinkedHashMap<>();
        //---
        for (DBProjectFile file : db.files.Data.values()) {
            if (file.isActiveProgram())
                active_programs.put(file.name, file);
            else
                others.put(file.name, file);
        }
        //---
        return new Pair<>(active_programs, others);
    }
    public DBProjectFile getFileByNameIgnoreCase(String name_in) {
        for (DBProjectFile file : db.files.Data.values()) {
            if (file.name.equalsIgnoreCase(name_in)) {
                return file;
            }
        }
        return null;
    }
    public void migrateFilesSettings(db_project_info target, boolean migrate_arrays, boolean sapforStyle) throws Exception {
        Pair<LinkedHashMap<String, DBProjectFile>, LinkedHashMap<String, DBProjectFile>> sortedFiles = sortFiles();
        //--
        LinkedHashMap<String, DBProjectFile> programs = sortedFiles.getKey();
        LinkedHashMap<String, DBProjectFile> files = sortedFiles.getValue();
        //--
        target.Open();
        target.db.BeginTransaction();
        Pair<LinkedHashMap<String, DBProjectFile>, LinkedHashMap<String, DBProjectFile>> sortedVersionFiles = target.sortFiles();
        LinkedHashMap<String, DBProjectFile> version_programs = sortedVersionFiles.getKey();
        //--
        for (DBProjectFile program : programs.values()) {
            for (DBProjectFile version_program : version_programs.values()) {
                boolean same_names = program.getProjectNameWithoutExtension().equals(version_program.getProjectNameWithoutExtension());
                if (same_names) {
                    version_program.importSettings(program, sapforStyle);
                    target.db.Update(version_program);
                }
            }
        }
        for (DBProjectFile file : files.values()) {
            DBProjectFile version_file = target.getFileByNameIgnoreCase(file.name);
            if (version_file != null) {
                version_file.importSettings(file, sapforStyle);
                target.db.Update(version_file);
            } else {
                File toCopy = Paths.get(target.Home.getAbsolutePath(), file.name).toFile();
                if (!toCopy.exists())
                    Files.copy(file.file.toPath(), toCopy.toPath());
                //--
                DBProjectFile new_version_file = new DBProjectFile(toCopy, target);
                new_version_file.importSettings(file, sapforStyle);
                target.db.Insert(new_version_file);
            }
        }
        //---
        target.languageName = this.languageName;
        target.maxdim = this.maxdim;
        target.db.Update(target);
        //------------------------
        if (migrate_arrays) {
            //миграция массивов.
            for (DBArray a : db.savedArrays.Data.values())
                target.db.Insert(a);
        }
        //---
        target.db.Commit();
        target.Close();
    }
    public void undoLastTransformation() throws Exception {
        MainModule_.instance.set(Current.Version, null); //?
        //---
        Global.mainModule.getUI().getVersionsWindow().getVersionsForm().getTree().RemoveNode(last_version.node);
        Utils_.forceDeleteWithCheck(last_version.Home);
        versions.remove(last_version.name);
        last_version = null;
        //---
        if (last_modification != null) {
            Utils_.forceDeleteWithCheck(last_modification.Home);
            Global.mainModule.getUI().getVersionsWindow().getVersionsForm().getTree().RemoveNode(last_modification.node);
            versions.remove(last_modification.name);
            last_modification = null;
        }
        //---
    }
    public void Clone(File dst, boolean cloneData) throws Exception {
        CopySubdirectories(dst);
        //->
        for (DBProjectFile file : db.files.Data.values()) {
            File src_file = file.file;
            File dst_file = Paths.get(dst.getAbsolutePath(),
                    Utils_.isWindows() ? file.name :
                            file.name.replace('\\', '/')).toFile();
            Files.copy(src_file.toPath(), dst_file.toPath());
        }
        //теперь копируем инфу по файлам.
        if (cloneData) {
            db_project_info res = new db_project_info(dst);
            migrateFilesSettings(res, true, false);
            FileUtils.copyFile(getPropertiesFile(), res.getPropertiesFile());
        }
    }
    public void Clone(File dst) throws Exception {
        Clone(dst, true);
    }
    public void ResetDB() throws Exception {
        Utils.CleanDirectory(getDataDirectory());
        db_project_info to_restore = new db_project_info();
        //-
        to_restore.name = name;
        to_restore.description = description;
        to_restore.original = original;
        CheckVisualiserDirectories();
        db.Connect();
        db.CreateAllTables();
        db.prepareTablesStatements();
        db.Insert(to_restore);
        db.Disconnect();
    }
    ///------------------------------------------------------------------------------------------->>>>>
    public void unpackMessagesAndLog(String packed_messages, String log_in) throws Exception {
        if (!packed_messages.isEmpty()) {
            MessagesJson messages = Utils_.gson.fromJson(packed_messages, MessagesJson.class);
            for (FileMessagesJson fileMessages : messages.allMessages) {
                fileMessages.file = Utils_.toW(fileMessages.file);
                //--
                DBProjectFile messageFile = db.files.Data.get(fileMessages.file);
                for (Message message : fileMessages.messages) {
                    messageFile.AddNewMessage(message);
                }
                messageFile.father.db.Update(messageFile);
            }
        }
        Log = log_in;
        Update();
    }
    public boolean hasErrorMessages(String packed_messages) throws Exception {
        if (packed_messages.length() > 0) {
            int idx = 0;
            String[] splited = packed_messages.split("\\|");
            int numberOfFiles = Integer.parseInt(splited[idx++]);
            for (int i = 0; i < numberOfFiles; ++i) {
                int numberOfMessages = Integer.parseInt(splited[idx++]);
                for (int k = 0; k < numberOfMessages; ++k) {
                    String[] localSplit = splited[idx++].split(" ");
                    int m_type = Integer.parseInt(localSplit[0]);
                    if (m_type == 1) {
                        UI.Info(packed_messages);
                        return true;
                    }
                }
            }
        }
        return false;
    }
    public void updateLog(String log_in) throws Exception {
        Log = log_in;
        Update();
    }
    public void updateCompilationOut(String text_in) throws Exception {
        compilation_output = text_in;
        db.Update(this);
    }
    public void updateRunOut(String text_in) throws Exception {
        run_output = text_in;
        db.Update(this);
    }
    public boolean CheckSameStyle(TextLog log) {
        boolean res = false;
        Vector<String> fixed = new Vector<>();
        Vector<String> extended = new Vector<>();
        Vector<String> free = new Vector<>();
        for (String fileName : files_order) {
            DBProjectFile file = db.files.get(fileName);
            switch (file.style) {
                case fixed:
                    fixed.add(fileName);
                    break;
                case extended:
                    extended.add(fileName);
                    break;
                case free:
                    free.add(fileName);
                    break;
            }
        }
        res = (!fixed.isEmpty() && extended.isEmpty() && free.isEmpty()) ||
                (fixed.isEmpty() && !extended.isEmpty() && free.isEmpty()) ||
                (fixed.isEmpty() && extended.isEmpty() && !free.isEmpty());
        if (!res) {
            log.Writeln_(
                    "Найдены файлы с различным стилем Fortran:\n" +
                            "Фиксированный: " + fixed.size() + "\n" +
                            String.join("\n", fixed) + "\n" +
                            "Расширенный: " + extended.size() + "\n" +
                            String.join("\n", extended) + "\n" +
                            "Свободный: " + free.size() + "\n" +
                            String.join("\n", free)
            );
        }
        return res;
    }
    public void findVersion_r(Vector<db_project_info> res, File file) {
        for (db_project_info version : versions.values()) {
            if (version.Home.getAbsolutePath().equals(file.getAbsolutePath())) {
                res.add(version);
            } else
                version.findVersion_r(res, file);
        }
    }
    public db_project_info findVersion(File file) {
        Vector<db_project_info> res = new Vector<>();
        findVersion_r(res, file);
        return res.isEmpty() ? null : res.get(0);
    }
    //-
    public void UpdateLoopsCount() {
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
        for (ParallelRegion parallelRegion : parallelRegions.Data.values())
            parallelRegion.UpdateLoopsCount();
    }
    public void UpdateFunctionsCount() {
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
        for (ParallelRegion parallelRegion : parallelRegions.Data.values())
            parallelRegion.UpdateFunctionsCount();
    }
    public void UpdateArraysCount() {
        numArrays = declaratedArrays.size();
        try {
            db.Update(this);
        } catch (Exception e) {
            Utils_.MainLog.PrintException(e);
        }
        for (ParallelRegion parallelRegion : parallelRegions.Data.values())
            parallelRegion.UpdateArraysCount();
    }
    //имя файла: число совпадений. ( ненулевое)
    public LinkedHashMap<String, Long> getMatches(String keyword_in, boolean registerOn, boolean wholeWord) throws Exception {
        //---------------------------
        LinkedHashMap<String, Long> res = new LinkedHashMap<>();
        for (DBProjectFile file : db.files.Data.values()) {
            if (!file.state.equals(FileState.Excluded)) {
                long matches_count = Utils.findInFile(keyword_in, registerOn, wholeWord, file.file);
                if (matches_count > 0) {
                    res.put(file.name, matches_count);
                }
            }
        }
        return res;
    }
    public db_project_info CreateVersionsTree() throws Exception {
        File anchestor_file = find_anchestor();
        db_project_info root_ = createVersionsTree_r(anchestor_file);
        return root_;
    }
    public db_project_info createVersionsTree_r(File dir) throws Exception {
        db_project_info result = null;
        File[] files_ = dir.listFiles();
        if (files_ != null) {
            LinkedHashMap<String, File> subdirs = new LinkedHashMap<>();
            //определить проект ли данная папка. и выделить его подпапки.
            for (File file : files_) {
                if (file.isDirectory()) {
                    if (file.getName().equals(Constants.data)) {
                        result = dir.equals(this.Home) ? this : new db_project_info(dir);
                        result.node = new DefaultMutableTreeNode(result); //узел в древе версий.
                        //не является нарушением разделения графики и данных. за графику все равно отвечает рендерер.
                    } else
                        subdirs.put(file.getName(), file);
                }
            }
            //-
            //если проект, то рекурсивно ищем его подверсии.
            if (result != null) {
                Vector<db_project_info> sorted_versions = new Vector<>();
                for (File subdir : subdirs.values()) {
                    db_project_info v = createVersionsTree_r(subdir);
                    if (v != null) {
                        v.parent = result;
                        sorted_versions.add(v);
                    }
                }
                sorted_versions.sort((o1, o2) -> {
                    Long d1 = o1.creationDate;
                    Long d2 = o2.creationDate;
                    return d1.compareTo(d2);
                });
                //-- добавляем рассортированные версии.
                for (db_project_info version : sorted_versions) {
                    result.versions.put(version.name, version);
                    result.node.add(version.node);
                }
            }
        }
        return result;
    }
    public File find_anchestor() {
        File child = Home;
        //так как мы открыли проект, гарантированно родитель существует.
        File parent = new File(child.getParent());
        while (db_project_info.get_db_file(parent).exists()) {
            child = parent;
            parent = new File(parent.getParent());
        }
        //смягчение требования
        /*
        while (new File(parent, db_project_info.data).exists()) {
            child = parent;
            parent = new File(parent.getParent());
        }
         */
        return child;
    }
    public void PrintVersions_r() {
        System.out.println(Home.getAbsolutePath());
        for (db_project_info version : versions.values())
            version.PrintVersions_r();
        //--
    }
    public String getVersionTooltip() {
        return description;
    }
    //---
    public void gen_variants_vectors() {
        //заполнить первыми тройками чтобы рекурсия работала. берем последний шаблон.
        Vector<Vector<BigInteger>> res = templates.get(templates.size() - 1).get_triples(true);
        if (templates.size() > 1)
            gen_rec(templates, res, templates.size() - 2);
        //теперь надо создать из этого списка варианты.
        for (Vector<BigInteger> vector : res) {
            ParallelVariant variant = new ParallelVariant(this, vector);
            // if (!parallelVariants.containsKey(variant.UniqKey))
            parallelVariants.put(variant.UniqKey, variant);
        }
    }
    //---
    public int getVariantsCoverageCount() {
        if (templates.isEmpty()) return 0;
        int res = 0;
        //--
        // тут сортируем по размеру.
        Vector<ProjectArray> sortedSizeTemplates = new Vector<>(templates);
        sortedSizeTemplates.sort((o1, o2) -> o2.dimSize - o1.dimSize);
        //--
        ProjectArray mainTemplate = sortedSizeTemplates.get(0);
        for (long mVarId : mainTemplate.get_varIDs(false)) {
            String main_binary = mainTemplate.get_binary(mVarId);
            boolean variantEnabled = true;
            for (int i = 1; i < sortedSizeTemplates.size(); ++i) {
                ProjectArray template = sortedSizeTemplates.get(i);
                String template_binary = (mainTemplate.dimSize > template.dimSize) ?
                        main_binary.substring(0, template.dimSize) :
                        main_binary;
                //сконвертировать из двоичной в long, чтобы получить varId
                long varID = Long.parseLong(template_binary, 2);
                //-- проверить на пригодность этот самый varID
                if (!template.checkVarID(varID, false)) {
                    variantEnabled = false;
                    break;
                }
            }
            if (variantEnabled) res++;
        }
        return res;
    }
    //минимальное покрытие.
    public void gen_variants_coverage() {
        Vector<Vector<BigInteger>> res = new Vector<>();
        //1. найти шаблон максимального размера. для этого получаем сортировку из списка по убыванию.
        Vector<ProjectArray> sortedBySizeTemplates = new Vector<>(templates);
        sortedBySizeTemplates.sort((o1, o2) -> o2.dimSize - o1.dimSize);
        if (!sortedBySizeTemplates.isEmpty()) {
            ProjectArray mainTemplate = sortedBySizeTemplates.get(0);
            Vector<Vector<BigInteger>> main_template_triples = mainTemplate.get_triples(false);
            //для каждой тройки от главного (максимального) шаблона, берем по одной подходящей от остальных.
            for (Vector<BigInteger> triple : main_template_triples) {
                //двоичное представление максимального шаблона. 1111
                String main_binary = mainTemplate.get_binary(triple.get(1).longValueExact());
                boolean variantEnabled = true;
                Vector<BigInteger> variantVector = new Vector<>(triple);
                //перебор остальных шаблонов
                for (int i = 1; i < sortedBySizeTemplates.size(); ++i) {
                    ProjectArray template = sortedBySizeTemplates.get(i);
                    String template_binary = (mainTemplate.dimSize > template.dimSize) ?
                            main_binary.substring(0, template.dimSize) :
                            main_binary;
                    //сконвертировать из двоичной в long, чтобы получить varId
                    long varID = Long.parseLong(template_binary, 2);
                    //-- проверить на пригодность этот самый varID
                    if (template.checkVarID(varID, false)) {
                        //вар ИД подошел, составляем вектор для очередного варианта.
                        for (BigInteger regID : template.regIDs) //для всех областей
                        {
                            variantVector.add(template.address);
                            variantVector.add(BigInteger.valueOf(varID));
                            variantVector.add(regID);
                        }
                    } else {
                        //вар ид не подошел. значит. этого варианта, не будет вообще. нужно идти к следующей тройке лидера.
                        variantEnabled = false;
                        break;
                    }
                }
                if (variantEnabled) {
                    res.add(variantVector);
                }
            }
        }
        //--
        //теперь надо создать из этого списка варианты.
        for (Vector<BigInteger> vector : res) {
            ParallelVariant variant = new ParallelVariant(this, vector);
            parallelVariants.put(variant.UniqKey, variant);
        }
    }
    public ProjectArray getTemplateByAddress(BigInteger address_in) {
        for (ProjectArray template : templates) {
            if (template.address.equals(address_in))
                return template;
        }
        return null;
    }
    public void SelectAllVersions(boolean b) {
        this.Select(b && !this.IsMCopy());
        for (db_project_info version : versions.values())
            version.SelectAllVersions(b);
    }
    private void getSelectedVersionsForDeletionR(Index count, Vector<db_project_info> target, boolean needs_versions) {
        if (needs_versions) {
            if (this.isSelected()) {
                target.add(this);
                count.Inc();
                //версия отмечена. подверсии больше не нужны.
                for (db_project_info version : versions.values()) {
                    version.getSelectedVersionsForDeletionR(count, null, false);
                }
            } else {
                // не отмечена. проверяем дочерние.
                for (db_project_info version : versions.values()) {
                    version.getSelectedVersionsForDeletionR(count, target, true);
                }
            }
        } else {
            //просто считаем все без разбору, так как это подверсии уже отмеченной версии.
            count.Inc();
            for (db_project_info version : versions.values()) {
                version.getSelectedVersionsForDeletionR(count, null, false);
            }
        }
    }
    public int getSelectedVersionsForDeletion(Vector<db_project_info> target) {
        Index count = new Index();
        getSelectedVersionsForDeletionR(count, target, true);
        return count.getValue();
    }
    public void getSelectedVersions(Vector<db_project_info> target) {
        if (this.isSelected())
            target.add(this);
        for (db_project_info version : versions.values())
            version.getSelectedVersions(target);
    }
    public String getLocalName() {
        //требует отображения рута. без него работать не будет.
        if (Global.mainModule.HasRoot())
            return Home.getAbsolutePath().substring(Global.mainModule.getRoot().Home.getParentFile().getAbsolutePath().length() + 1);
        else return Home.getName();
    }
    public void SelectAllFiles(boolean b) {
        for (DBProjectFile file : db.files.Data.values())
            file.Select(b);
    }
    public boolean hasSubdirectories() {
        subdirectories.clear();
        getSubdirectoriesR(Home);
        return !subdirectories.isEmpty();
    }
    public boolean checkSubdirectories(TextLog Log) {
        if (hasSubdirectories()) {
            Log.Writeln_("Проект содержит вложенные папки!");
            return false;
        }
        return true;
    }
    public DBProjectFile getMainProgramUnit() {
        for (DBProjectFile file : db.files.Data.values()) {
            if (file.isMain != 0)
                return file;
        }
        return null;
    }
}
