package TestingSystem.Common;
import Common.Constants;
import Common.Utils.Utils;
import Repository.EmailMessage;
import Repository.Server.ServerCode;
import Repository.Server.ServerExchangeUnit_2021;
import TestingSystem.Common.TestingPackage.TestingPackage;
import Visual_DVM_2021.Passes.PassException;
import Visual_DVM_2021.Passes.Server.TestingSystemPass;

import java.io.FileWriter;
import java.io.Serializable;
import java.util.Date;
public abstract class TestingPlanner<P extends TestingPackage> {
    protected P testingPackage;
    protected int getSleepMillis() {
        return 2000;
    }
    //---
    protected Object ServerCommand(ServerCode code_in, String arg, Serializable object_in) throws Exception {
        TestingSystemPass<Object> pass = new TestingSystemPass<Object>() {
            @Override
            public String getDescription() {
                return "";
            }
            @Override
            protected void ServerAction() throws Exception {
                Command(new ServerExchangeUnit_2021(code_in, arg, object_in));
                target = response.object;
            }
        };
        if (!pass.Do()) throw new PassException("Ошибка взаимодействия с сервером " + code_in);
        return pass.target;
    }
    protected Object ServerCommand(ServerCode code_in, Serializable object_in) throws Exception {
        return ServerCommand(code_in, "", object_in);
    }
    protected Object ServerCommand(ServerCode code_in) throws Exception {
        return ServerCommand(code_in, "", null);
    }
    //---
    protected boolean isPrintOn() {
        return true;
    }
    protected void Print(String message) {
        try {
            if (isPrintOn()) {
                FileWriter testLog = new FileWriter(getClass().getSimpleName() + "_Log.txt", true);
                String dmessage = Utils.Brackets(new Date()) + " " + message;
                System.out.println(dmessage);
                testLog.write(dmessage + "\n");
                testLog.close();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    //---
    void UpdatePackageState(TasksPackageState state_in) throws Exception {
        testingPackage.state = state_in;
        testingPackage.ChangeDate = new Date().getTime();
        ServerCommand(ServerCode.EditObject, testingPackage);
    }
    void UpdatePackage() throws Exception {
        testingPackage.ChangeDate = new Date().getTime();
        ServerCommand(ServerCode.EditObject, testingPackage);
    }
    void EmailPackage() throws Exception {
        if (testingPackage.needsEmail == 1) {
            EmailMessage message = new EmailMessage();
            message.subject = "Состояние пакета задач " + Utils.Brackets(testingPackage) + " изменилось на " + Utils.Brackets(testingPackage.state.getDescription());
            message.text = testingPackage.description;
            message.targets.add(testingPackage.sender_address);
            ServerCommand(ServerCode.Email, message);
        }
    }
    //---
    protected abstract ServerCode getActivePackageCode();
    protected abstract ServerCode getCheckIfNeedsKillCode();
    protected abstract TasksPackageState getStateAfterStart();
    protected void InitSessionCredentials() {
    }
    protected abstract void TestsSynchronize() throws Exception;
    protected abstract void PackageWorkspaceCreation() throws Exception;
    protected abstract void AnalyseResults() throws Exception;
    protected abstract void PackageStart() throws Exception;
    protected abstract boolean CheckNextState() throws Exception;
    protected abstract void DownloadResults() throws Exception;
    protected abstract void Kill() throws Exception;
    protected boolean Connect() {
        return true;
    }
    protected void Disconnect() {
    }
    //жизненный цикл планировщика
    protected void Session() throws Exception {
        switch (testingPackage.state) {
            case TestsSynchronize:
                TestsSynchronize();
                UpdatePackageState(TasksPackageState.PackageWorkspaceCreation);
                Disconnect();
                break;
            case PackageWorkspaceCreation:
                PackageWorkspaceCreation();
                UpdatePackageState(TasksPackageState.PackageStart);
                Disconnect();
                break;
            case PackageStart:
                PackageStart();
                EmailPackage();
                testingPackage.StartDate = new Date().getTime();
                UpdatePackageState(getStateAfterStart());
                Disconnect();
                break;
            case RunningEnd:
                DownloadResults();
                UpdatePackageState(TasksPackageState.Analysis);
                Disconnect();
                break;
            default:
                if (CheckNextState()) UpdatePackage();
                break;
        }
    }
    // ---
    public void Perform() {
        try {
            testingPackage = null;
            testingPackage = (P) ServerCommand(getActivePackageCode());
            if (testingPackage != null) {
                Print(testingPackage.id + ":" + testingPackage.state.getDescription());
                //--
                InitSessionCredentials();
                if (testingPackage.state.equals(TasksPackageState.Analysis)) {
                    AnalyseResults();
                    UpdatePackageState(TasksPackageState.Done);
                    EmailPackage();
                } else {
                    try {
                        if (Connect()) {
                            int ptk_id = (int) ServerCommand(getCheckIfNeedsKillCode(), testingPackage.id);
                            if (ptk_id != Constants.Nan) {
                                Print("package " + testingPackage.id + " NEEDS TO KILL");
                                Kill();
                                UpdatePackageState(TasksPackageState.Aborted);
                                EmailPackage();
                                ServerCommand(ServerCode.DeleteObjectByPK, ptk_id);
                            } else {
                                Session();
                            }
                        }
                    } catch (Exception ex) {
                        Print("Ошибка сеанса. Соединение будет разорвано.");
                        Print(ex.getMessage());
                        Disconnect();
                    } finally {
                    }
                }
                //--
                testingPackage.destructor();
                testingPackage = null;
                System.gc();
                //--
            }
            //else Print(this.getClass().getSimpleName()+": no active package found");
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            Utils.sleep(getSleepMillis());
        }
    }
}
