package Common;
import Common.Database.DataSet;
import Common.UI.Menus_2023.ComponentsMenuBar.ComponentsMenuBar;
import Common.UI.UI;
import Common.Utils.Utils;
import GlobalData.GlobalDatabase;
import GlobalData.Settings.DBSetting;
import GlobalData.Settings.SettingName;
import ProjectData.ProjectView;
import Repository.Component.*;
import Repository.Component.PerformanceAnalyzer.PerformanceAnalyzer;
import Repository.Component.Sapfor.MessagesServer;
import Repository.Component.Sapfor.Sapfor_F;
import Repository.Component.Sapfor.TransformationPermission;
import Repository.Server.ComponentsServer;
import SapforTestingSystem.PackageModeSupervisor.PackageModeSupervisor;
import TestingSystem.TestingServer;
import Visual_DVM_2021.Passes.PassCode_2021;
import Visual_DVM_2021.Passes.Pass_2021;
import Visual_DVM_2021.UI.Interface.Loggable;
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
import org.fife.ui.rsyntaxtextarea.TokenMakerFactory;

import java.io.File;
import java.nio.file.Paths;
import java.util.Vector;
public class Global {
    //пробный коммит. изменение комментария.++
    //кронтаб и перезагрузка
    //https://snipp.ru/raznoe/crontab
    // /var/spool/cron/crontabs/testuser что менять
    //https://saribzhanov.ru/tehno/perezagruzka-ubuntu-po-cron/ //раз в сутки
    //testuser ALL=NOPASSWD:/sbin/reboot
    //0          2          2,15       *          *  reboot &>/var/log/reboot.log
    //https://unix.stackexchange.com/questions/117148/how-can-i-run-reboot-as-a-normal-user-without-needing-to-enter-a-password
    public static final String ServerAddress = "alex-freenas.ddns.net";
    public static final String dateNaN = "NaN";
    //--------------------------------------------------
    //текущая папка системы. в отличие от шарпа никогда не должна меняться.
    public static final String components = "Components";
    public static final String data = "Data";
    public static final String Bugs = "Bugs";
    public static final String BackUps = "BackUps";
    public static final String DataBackUps = "DataBackUps";
    public static final String Temp = "Temp";
    public static final String Projects = "Projects";
    public static final String CompilationTasks = "CompilationTasks";
    public static final String RunTasks = "RunTasks";
    public static final String Sts = "Sts";
    public static final String Repo = "Repo";
    public static final String Tests = "Tests";
    public static final String Packages = "Packages";
    public static final String PerformanceAnalyzer = "PerformanceAnalyzer";
    public static GlobalProperties properties = new GlobalProperties();
    //</editor-fold>
    //------------------------------------------------------
    public static boolean enable_text_changed = false;
    //---
    public static boolean files_multiselection = false;
    public static boolean versions_multiselection = false;
    //---
    public static TransformationPermission transformationPermission = TransformationPermission.None;
    //??
    public static DataSet<ComponentType, Component> Components = null;
    public static MessagesServer messagesServer = null;
    //--------------------------------------------------
    public static GlobalDatabase db = null;
    public static String[] admins_mails = new String[]{
            "vmk-post@yandex.ru",
            "79854210702@ya.ru"
    };
    //-
    public static String Home;
    public static File ComponentsDirectory;
    public static File DataDirectory;
    public static File BugReportsDirectory;
    public static File BackUpsDirectory;
    public static File TempDirectory;
    public static File ProjectsDirectory;
    public static File CompilationTasksDirectory;
    public static File RunTasksDirectory;
    public static File StsDirectory;
    public static File RepoDirectory;
    public static File TestsDirectory;
    public static File PerformanceAnalyzerDirectory;
    public static File DataBackUpsDirectory;
    public static File PackagesDirectory;
    public static File SapforsDirectory;
    public static File SapforPackagesDirectory;
    //------------------------------------------------------------------
    public static Visualiser visualiser = null;
    public static Visualizer_2 visualizer_2 = null;
    public static PerformanceAnalyzer performanceAnalyzer = null;
    //------------------------------------------------------------------
    public static ComponentsServer componentsServer = new ComponentsServer();
    public static TestingServer testingServer = new TestingServer();
    //------------------------------------------------------------------
    public static boolean isWindows;
    public static int bad_state = 0;
    public static int need_update = 0;
    public static int need_publish = 0;
    //------------------------------------------------------------------------
    public static Loggable Log;
    public static void SynschronizeProperties() {
        try {
            File new_propertiesFile = Paths.get(Home, "properties").toFile();
            if (new_propertiesFile.exists())
                properties = (GlobalProperties) Utils.jsonFromFile(new_propertiesFile, GlobalProperties.class);
            Utils.jsonToFile(properties, new_propertiesFile);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    public static void CheckVisualiserDirectories() {
        Utils.CheckDirectory(ComponentsDirectory = Paths.get(Home, components).toFile());
        Utils.CheckAndCleanDirectory(TempDirectory = Paths.get(Home, Temp).toFile());
        Utils.CheckDirectory(DataDirectory = Paths.get(Home, data).toFile());
        //-
        Utils.CheckDirectory(RepoDirectory = Paths.get(Home, Repo).toFile());
        Utils.CheckDirectory(BugReportsDirectory = Paths.get(Home, Bugs).toFile());
        Utils.CheckDirectory(BackUpsDirectory = Paths.get(Home, BackUps).toFile());
        Utils.CheckDirectory(ProjectsDirectory = Paths.get(Home, Projects).toFile());
        Utils.CheckDirectory(CompilationTasksDirectory = Paths.get(Home, CompilationTasks).toFile());
        Utils.CheckDirectory(RunTasksDirectory = Paths.get(Home, RunTasks).toFile());
        Utils.CheckDirectory(StsDirectory = Paths.get(Home, Sts).toFile());
        Utils.CheckDirectory(TestsDirectory = Paths.get(Home, Tests).toFile());
        Utils.CheckDirectory(PerformanceAnalyzerDirectory = Paths.get(Home, PerformanceAnalyzer).toFile());
        Utils.CheckDirectory(SapforPackagesDirectory = Paths.get(Home, "SapforPackages").toFile());
    }
    public static void CheckServerDirectories() {
        Utils.CheckDirectory(ComponentsDirectory = Paths.get(Home, components).toFile());
        Utils.CheckAndCleanDirectory(TempDirectory = Paths.get(Home, Temp).toFile());
        Utils.CheckDirectory(DataDirectory = Paths.get(Home, data).toFile());
        //-
        Utils.CheckDirectory(BugReportsDirectory = Paths.get(Home, Bugs).toFile());
        Utils.CheckDirectory(DataBackUpsDirectory = Paths.get(Home, DataBackUps).toFile());
    }
    public static void CheckTestingSystemDirectories() {
        Utils.CheckDirectory(ComponentsDirectory = Paths.get(Home, components).toFile());
        Utils.CheckAndCleanDirectory(TempDirectory = Paths.get(Home, Temp).toFile());
        Utils.CheckDirectory(DataDirectory = Paths.get(Home, data).toFile());
        //-
        Utils.CheckDirectory(TestsDirectory = Paths.get(Home, Tests).toFile());
        Utils.CheckDirectory(RepoDirectory = Paths.get(Home, Repo).toFile());
        Utils.CheckDirectory(PackagesDirectory = Paths.get(Home, Packages).toFile());
        Utils.CheckDirectory(SapforsDirectory = Paths.get(Home, "Sapfors").toFile());
        Utils.CheckDirectory(SapforPackagesDirectory = Paths.get(Home, "SapforPackages").toFile());
    }
    public static void CreateLog() {
        Log = new Loggable() {
            @Override
            public String getLogHomePath() {
                return Paths.get(Home, "Components").toString();
            }
            @Override
            public String getLogName() {
                return "VisualDVM";
            }
        };
        Log.ClearLog();
    }
    //-
    public static void FinishApplication() {
        try {
            if (db != null) db.Disconnect();
            if (componentsServer.db != null)
                componentsServer.db.Disconnect();
            if (testingServer.db != null)
                testingServer.db.Disconnect();
            if (visualizer_2 != null)
                visualizer_2.Shutdown();
            if (messagesServer != null)
                messagesServer.Shutdown();
            if (performanceAnalyzer != null)
                performanceAnalyzer.Shutdown();
        } catch (Exception ex) {
            if (Log != null) {
                Log.PrintException(ex);
            } else {
                ex.printStackTrace();
            }
        }
        System.exit(0);
    }
    public static void ActivateDB() throws Exception {
        db = new GlobalDatabase();
        db.Connect();
        db.CreateAllTables();
        db.prepareTablesStatements();
        db.Synchronize();
    }
    public static void RefreshUpdatesStatus() {
        Components.RefreshUI();
        ValidateComponentsStates();
        if (UI.HasNewMainWindow())
            UI.getMainWindow().ShowUpdatesIcon();
    }
    public static boolean ValidateComponentsStates() {
        bad_state = need_update = need_publish = 0;
        for (Component component : Components.Data.values()) {
            if (component.isVisible()) {
                switch (component.getState()) {
                    case Not_found:
                    case Unknown_version:
                    case Old_version:
                        if (component.isNecessary())
                            bad_state++;
                        component.Select(true);
                        break;
                    case Needs_update:
                        need_update++;
                        component.Select(true);
                        break;
                    case Needs_publish:
                        need_publish++;
                        break;
                    default:
                        component.Select(false);
                        break;
                }
            }
        }
        return (bad_state == 0);
    }
    //возможно заменить settings на properties
    public static DBSetting getSetting(SettingName settingName) throws Exception {
        switch (Current.mode) {
            case Normal:
                return db.settings.get(settingName);
            default:
                return null;
        }
    }
    public static void changeSetting(SettingName settingName, Object new_value) throws Exception {
        Pass_2021.passes.get(PassCode_2021.UpdateSetting).Do(settingName, new_value);
    }
    public static String packSapforSettings() {
        Vector<String> res_ = new Vector<>();
        Vector<SettingName> forbidden = new Vector<>();
        forbidden.add(SettingName.GCOVLimit);
        forbidden.add(SettingName.Precompilation);
        forbidden.add(SettingName.DVMConvertationOptions);
        forbidden.add(SettingName.SaveModifications);
        for (DBSetting setting : db.settings.getSettingsByOwner(ComponentType.SapforOptions)) {
            if (!forbidden.contains(setting.Name))
                res_.add(setting.Value);
        }
        return String.join("|", res_);
    }
    //--
    public static void NormalMode(int port) throws Exception {
        isWindows = System.getProperty("os.name").startsWith("Windows");
        CheckVisualiserDirectories();
        CreateLog();
        //-
        visualizer_2 = new Visualizer_2(port);
        visualizer_2.Connect();
        visualizer_2.refreshPid();
        //если делать раньше, то не удастся убить сервер.
        if (Utils.ContainsCyrillic(Global.Home)) {
            UI.Info("В пути к корневой папке " + Utils.DQuotes(Global.Home) + "\n" +
                    "Найдены русские буквы.\n" +
                    "Визуализатор завершает работу."); //
            FinishApplication();
        }
        messagesServer = new MessagesServer();
        messagesServer.Start();
        //создание списков служебных объектов
        Current.CreateAll();
        UI.CreateAll();
        Pass_2021.CreateAll();
        Utils.init();
        //единственное меню до остальных.
        UI.menuBars.put(ComponentsSet.class, new ComponentsMenuBar());
        Components = new ComponentsSet();
        Current.set(Current.ProjectView, ProjectView.Files);
        Components.put(ComponentType.Visualiser, visualiser = new Visualiser());
        Components.put(ComponentType.Sapfor_F, (Component) Current.set(Current.Sapfor, new Sapfor_F()));
        Components.put(ComponentType.Visualizer_2, visualizer_2);
        Components.put(ComponentType.PerformanceAnalyzer, performanceAnalyzer = new PerformanceAnalyzer());
        Components.put(ComponentType.Instruction, new Instruction());
        //-
        for (Component component : Components.Data.values())
            if (component.isVisible()) component.InitialVersionCheck();
        //-
        UI.CreateComponentsForm();
        AbstractTokenMakerFactory atmf = (AbstractTokenMakerFactory) TokenMakerFactory.getDefaultInstance();
        atmf.putMapping("text/FortranSPF", "Common.UI.Themes.FortranSPFTokenMaker");
        atmf.putMapping("text/FreeFortranSPF", "Common.UI.Themes.FreeFortranSPFTokenMaker");
        //  FoldParserManager.get().addFoldParserMapping("text/FortranSPF", new FortranFolder()); блоки кода. todo
        //-------->>
        //-------->>
        if (properties.AutoUpdateSearch)
            Pass_2021.passes.get(PassCode_2021.GetComponentsActualVersions).Do();
        ValidateComponentsStates();
        if ((need_update > 0) || (bad_state > 0)) {
            boolean flag = true;
            do {
                UI.ShowComponentsWindow();
                if (flag = (!ValidateComponentsStates())) {
                    if (!UI.Question("Найдено " + bad_state + " некорректных необходимых компонент.Работа визуализатора невозможна.\n" +
                            "Вернуться к окну компонент"
                    )) {
                        UI.Info("Визуализатор завершает работу.");
                        FinishApplication();
                    }
                }
            } while (flag);
        }
        //---
        ActivateDB();  //тут current getAccount; роль по умолчанию всегда неизвестна.
        ///--------------
        Pass_2021.passes.get(PassCode_2021.CheckAccount).Do();
        //---------------
        componentsServer.ActivateDB();
        testingServer.ActivateDB();
        //-- чисто чтобы создать таблицы. соединения на стороне клиента не предвидится.
        testingServer.SetCurrentAccountDB(Current.getAccount().email);
        //--->>>
        if (db.settings.get(SettingName.AutoBugReportsLoad).toBoolean())
            Pass_2021.passes.get(PassCode_2021.SynchronizeBugReports).Do();
        //--
        if (db.settings.get(SettingName.AutoTestsLoad).toBoolean())
            Pass_2021.passes.get(PassCode_2021.SynchronizeTests).Do();
        Pass_2021.CheckAllStats();
        Current.getSapfor().refreshPid(); //без сапфора сюда это все равно не дойдет.
        UI.CreateMenus();
        UI.CreateWindows();
    }
    public static void ServerMode() throws Exception {
        isWindows = false;
        CheckServerDirectories();
        CreateLog();
        componentsServer = new ComponentsServer();
        componentsServer.ActivateDB();
        componentsServer.Start();
        System.exit(0);
    }
    public static void TestingSystemMode() throws Exception {
        isWindows = false;
        CheckTestingSystemDirectories();
        CreateLog();
        testingServer = new TestingServer();
        testingServer.ActivateDB();
        testingServer.Start();
        System.exit(0);
    }
    public static void PackageMode() throws Exception {
        isWindows = System.getProperty("os.name").startsWith("Windows");
        Log = new Loggable() {
            @Override
            public String getLogHomePath() {
                return Home;
            }
            @Override
            public String getLogName() {
                return "Package";
            }
        };
        Log.ClearLog();
        PackageModeSupervisor planner = new PackageModeSupervisor();
        planner.Start();
    }
    //---
    public static void Init(String... args) {
        System.out.println("VisualSapfor.jar started..");
        Home = System.getProperty("user.dir"); //если Linux, дает без слеша в конце !!!
        System.out.println("home directory is" + Utils.Brackets(Home));
        //---
        SynschronizeProperties();
        Current.mode = properties.Mode;
        System.out.println("mode is " + Current.mode);
        try {
            switch (Current.mode) {
                case Normal:
                    NormalMode(Integer.parseInt(args[1]));
                    break;
                case Server:
                    ServerMode();
                    break;
                case Testing:
                    TestingSystemMode();
                    break;
                case Package:
                    PackageMode();
                    break;
                case Undefined:
                    break;
            }
        } catch (Exception ex) {
            System.out.println("VISUALISER FAILED");
            ex.printStackTrace();
            if (Global.Log != null)
                Global.Log.PrintException(ex);
            FinishApplication();
        }
    }
}
