package _VisualDVM.GlobalData.Tasks.Supervisor;
import Common.Passes.Pass;
import Common.Utils.Utils_;
import _VisualDVM.Global;
import _VisualDVM.GlobalData.Tasks.Task;
import _VisualDVM.GlobalData.Tasks.TaskState;
import _VisualDVM.ProjectData.Project.db_project_info;

import java.util.Date;
public abstract class TaskSupervisor<T extends Task, P extends Pass> {
    public T task; //задача
    protected db_project_info project; //проект к которому относится задача
    protected P pass; //проход отвечающий за задачу
    protected int performanceTime; //сколько задача уже выполняется.
    public void ShowTaskState() {
        Global.mainModule.getDb().getTable(task.getClass()).ShowUI(task.getPK());
    }
    public void Init(T task_in, P pass_in, db_project_info project_in) {
        task = task_in;
        pass = pass_in;
        project = project_in;
        try {
            project.CleanInterruptFile();
        } catch (Exception ex) {
            Utils_.MainLog.PrintException(ex);
        }
    }
    protected void PrepareWorkspace() throws Exception {
        Utils_.CheckAndCleanDirectory(task.getLocalWorkspace());
    }
    protected abstract void StartTask() throws Exception;
    protected boolean isTaskActive() {
        return task.state.equals(TaskState.Running);
    }
    //периодичность проверки состояния задачи (с)
    protected int getTaskCheckPeriod() {
        return 1;
    }
    public int getMaxtime() {
        return task.maxtime;
    }
    protected void RefreshProgress() {
        pass.ShowProgress2(getMaxtime(), performanceTime, task.state.getDescription() + ", прошло секунд");
    }
    //проверка состояния задачи
    protected void CheckTask() throws Exception {
    }
    protected void CheckIfNeedAbort() {
        if (project.getInterruptFile().exists()) {
            task.state = TaskState.AbortingByUser;
            ShowTaskState();
        }
    }
    //досрочное прерывание задачи
    protected void AbortTask() throws Exception {
    }
    protected String getCoupDeGrace() {
        return "";
    }
    //добивание задачи после ее завершения по таймауту. не всегда нужно
    // protected void CoupDeGraceTask() throws Exception {}
    //получить результаты выполнения задачи. в случае локальной машины, очевидно, пустая функция
    protected void AchieveResults() throws Exception {
    }
    protected abstract void ValidateTaskResults() throws Exception;
    //получить время выполнения задачи. по умолчанию самый грубый метод.
    protected void CalculatePerformanceTime() throws Exception {
        task.Time = performanceTime;
    }
    //рабочий цикл задачи.
    public void PerformTask() throws Exception {
        if (task.hasProgress())
            pass.ShowProgressTextOnly(task.progressAll, task.progressStep, "задача");
        //сброс
        performanceTime = 0;
        task.Reset();
        ShowTaskState();
        pass.ShowMessage1("Подготовка рабочего пространства задачи..");
        PrepareWorkspace();
        ShowTaskState();
        pass.ShowMessage1("Старт задачи..");
        //запуск задачи
        StartTask();
        ShowTaskState();
        WaitForTask();
        //маловероятно, но в теории задача может оказаться выполненной сразу после команды выполнения
        //например если запуск шел через систему очередей.
        //анализируем состояние.
        //если приказано убить задачу. убиваем.
        if (task.state == TaskState.AbortingByUser) {
            pass.ShowMessage1("Принудительная остановка задачи..");
            AbortTask();
            task.state = TaskState.AbortedByUser;
            ShowTaskState();
        }
        pass.ShowMessage1("Задача " + Utils_.Brackets(task.state.getDescription()));
        task.EndDate = (new Date()).getTime();
        pass.ShowMessage2("Получение результатов");
        AchieveResults();
        pass.ShowMessage2("Анализ результатов");
        switch (task.state) {
            case Finished:
                ValidateTaskResults();
                CalculatePerformanceTime();
                break;
            case AbortedByTimeout:
                task.MaximizeTime();
                pass.ShowMessage2("Добивание задачи..");
                break;
            default:
                break;
        }
    }
    public void WaitForTask() throws Exception {
        if (isTaskActive()) {
            //  if (task.PID.isEmpty())
            //     throw new PassException("Ошибка при старте : идентификатор задачи не определен.");
            task.StartDate = (new Date()).getTime();
            pass.ShowMessage1("Задача активна");//, идентификатор " + Utils_.Brackets(task.PID));
            RefreshProgress();
            do {
                Thread.sleep(getTaskCheckPeriod() * 1000);
                performanceTime += getTaskCheckPeriod();
                CheckTask();
                if (isTaskActive()) CheckIfNeedAbort();
                RefreshProgress();
            } while (isTaskActive());
            ShowTaskState();
        }
    }
    public void UpdateTask() throws Exception {
        Global.mainModule.getDb().Update(task);
    }
}
