package _VisualDVM.Passes.All;
import Common.CommonConstants;
import Common.Passes.Pass;
import Common.Utils.Index;
import Common.Utils.Utils_;
import Common.Visual.UI;
import Common.Visual.Windows.Dialog.VDirectoryChooser;
import _VisualDVM.Global;
import _VisualDVM.GlobalData.Tasks.TaskState;
import _VisualDVM.Passes.PassCode;
import _VisualDVM.TestingSystem.DVM.DVMPackage.DVMPackage;
import _VisualDVM.TestingSystem.DVM.DVMTasks.DVMCompilationTask;
import _VisualDVM.TestingSystem.DVM.DVMTasks.DVMRunTask;
import _VisualDVM.Utils;
import org.apache.commons.io.FileUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Vector;
public class ExportDVMPackageToExcel extends Pass<Vector<DVMPackage>> {
    //---
    final int max_columns = 16;
    //https://tproger.ru/translations/how-to-read-write-excel-file-java-poi-example
    File dir;
    File res;
    VDirectoryChooser directoryChooser = new VDirectoryChooser("Выбор папки для сохранения таблицы Excel");
    Vector<CellStyle> styles;
    //--
    Workbook book = null;
    Sheet sheet = null;
    //--
    int total_tasks_count = 0;
    long total_time = 0;
    //--
    @Override
    public String getIconPath() {
        return "/Common/icons/Excel.png";
    }
    @Override
    public String getButtonText() {
        return "";
    }
    @Override
    protected boolean needsAnimation() {
        return true;
    }
    @Override
    protected boolean canStart(Object... args) throws Exception {
        book = null;
        sheet = null;
        styles = null;
        target = null;
        //--
        if (Global.testingServer.db.dvmPackages.getUI().getSelectedCount() > 0) {
            target = Global.testingServer.db.dvmPackages.getUI().getSelectedItems();
        } else {
            if (Global.testingServer.db.dvmPackages.getUI().CheckCurrent(Log)) {
                target = new Vector<>();
                target.add(
                        Global.testingServer.db.dvmPackages.getUI().getCurrent()
                );
            } else return false;
        }
        Vector<Integer> packagesToDownload = new Vector<>();
        for (DVMPackage dvmPackage : target) {
            if (!dvmPackage.state.isDone()) {
                Log.Writeln_("Пакет " + dvmPackage.id + " не завершен.");
            } else {
                if (!new File(dvmPackage.getLocalWorkspace(), CommonConstants.LOADED).exists()) {
                    packagesToDownload.add(dvmPackage.id);
                }
            }
        }
        if (!Global.mainModule.getPass(PassCode.DownloadDVMPackages).Do(packagesToDownload)) {
            return false;
        }
        if (!Log.isEmpty())
            return false;
        Utils.ChooseDocumentsDirectory(directoryChooser);
        dir = directoryChooser.ShowDialog();
        if (dir == null) {
            Log.Writeln_("Папка не выбрана.");
            return false;
        }
        Global.mainModule.getPass(PassCode.UpdateProperty).Do("DocumentsDirectory", dir.getAbsolutePath());
        res = new File(dir, Utils_.getDateName("packages") + ".xls");
        return true;
    }
    //---
    String getPackageInfo(DVMPackage object) {
        Vector<String> lines = new Vector<>();
        lines.add("задач " + object.tasksCount);
        lines.add("машина " + object.machine_address + ":" + object.machine_port);
        lines.add("ядер " + object.kernels);
        lines.add("DVM-система " + object.version);
        //--
        total_tasks_count += object.tasksCount;
        //--
        long milliseconds = object.ChangeDate - object.StartDate;
        total_time += milliseconds;
        //--
        lines.add("время выполнения " + Utils_.printSplittedDateInterval(milliseconds));
        return String.join("; ", lines);
    }
    //---
    protected void addInfoRow(int row_num, String value) {
        Row row = sheet.createRow(row_num);
        String cell_text = value.toString();
        Cell cell = row.createCell(0);
        cell.setCellValue(cell_text);
        cell.setCellStyle(styles.get(1));
        //https://translated.turbopages.org/proxy_u/en-ru.ru.f85b6508-657377d3-df23bc2d-74722d776562/https/stackoverflow.com/questions/23533381/creating-the-border-for-the-merged-cells-in-poi
        sheet.addMergedRegion(new CellRangeAddress(row_num, row_num, 0, max_columns - 1));
        for (int i = 1; i < max_columns; ++i) {
            Cell blankCell = row.createCell(i);
            blankCell.setCellStyle(styles.get(1));
        }
    }
    protected void addHeaderRow(int row_num, Object... values) {
        Row row = sheet.createRow(row_num);
        int i = 0;
        for (Object value : values) {
            String cell_text = value.toString();
            Cell cell = row.createCell(i);
            cell.setCellStyle(styles.get(0));
            cell.setCellValue(cell_text);
            //--
            ++i;
        }
    }
    protected void addTaskRow(int row_num, Object... values) {
        Row row = sheet.createRow(row_num);
        int i = 0;
        for (Object value : values) {
            //   String cell_text = value.toString();
            Cell cell = row.createCell(i);
            int style_index = 1;
            switch (i) {
                /*
                 addTaskRow(offset.getValue(),
                    task.group_description, //0
                    task.test_description,//1
                    task.language.getDescription(), //2
                    task.flags, //3
                    task.compilation_state, //4
                    task.state, //5
                    num_threads, //6
                    num_cudas, //7
                    total_threads, //8
                    formatMatrix(task.matrix), //9
                    task.environments, //10
                    task.usr_par, //11
                    task.compilation_time, //12
                    task.Time,//13
                    task.CleanTime, //14
                    task.progress //15
            );
                */
                case 4:
                case 5:
                    TaskState state = (TaskState) value;
                    switch (state) {
                        case FailedToQueue:
                        case NoSuchTask:
                        case AbortedByUser:
                        case AbortedByTimeout:
                        case DoneWithErrors:
                        case WrongTestFormat:
                        case InternalError:
                        case Canceled:
                            style_index = 3;
                            break;
                        case Queued:
                        case Running:
                            style_index = 5;
                            break;
                        case Done:
                            style_index = 2;
                            break;
                        case Crushed:
                            style_index = 4;
                            break;
                        case Finished:
                            style_index = 6;
                            break;
                    }
                    cell.setCellValue(state.getDescription());
                    break;
                case 6:
                case 7:
                case 8:
                    style_index = 7;
                    cell.setCellValue((int) value);
                    break;
                case 9:
                    style_index = 7;
                    cell.setCellValue(value.toString());
                    break;
                case 15:
                    cell.setCellValue((int) value);
                    break;
                case 12:
                case 13:
                case 14:
                    cell.setCellValue((double) value);
                    break;
                default:
                    cell.setCellValue(value.toString());
                    break;
            }
            cell.setCellStyle(styles.get(style_index));
            //--
            ++i;
        }
    }
    protected void setBorder(CellStyle style, short border) {
        style.setBorderBottom(border);
        style.setBorderLeft(border);
        style.setBorderRight(border);
        style.setBorderTop(border);
    }
    protected String extractEnvironmentValue(String environmentsSet, String name) {
        if (environmentsSet.contains(name)) {
            int index = environmentsSet.lastIndexOf(name);
            if (index >= 0) {
                String s1 = environmentsSet.substring(index + name.length() + 1);
                String[] data = s1.split("\"");
                if (data.length > 0) {
                    return data[1];
                }
            }
        }
        return null;
    }
    protected Integer extractIntegerEnvironmentValue(String environmentsSet, String name) {
        Integer res = null;
        String s = extractEnvironmentValue(environmentsSet, name);
        if (s != null) {
            try {
                res = Integer.parseInt(s);
            } catch (NumberFormatException ex) {
                ex.printStackTrace();
            }
        }
        return res;
    }
    String formatMatrix(String matrix) {
        return Utils_.DQuotes(matrix.trim());
    }
    void createStyles() {
        styles = new Vector<>();
        //0 - заголовок
        //1 - черный
        //2 - зеленый
        //3 - красный
        //4 - темно красный
        //5 - оранжевый
        //6 - серый
        //7 - черный выровненный по центру.
        for (int i = 0; i < 8; ++i) {
            CellStyle style = book.createCellStyle();
            Font font = book.createFont();
            switch (i) {
                case 0:
                    font.setBold(true);
                    setBorder(style, CellStyle.BORDER_THICK);
                    break;
                default:
                    setBorder(style, CellStyle.BORDER_THIN);
                    switch (i) {
                        case 1:
                            font.setColor(HSSFColor.BLACK.index);
                            break;
                        case 2:
                            font.setColor(HSSFColor.GREEN.index);
                            break;
                        case 3:
                            font.setColor(HSSFColor.RED.index);
                            break;
                        case 4:
                            font.setColor(HSSFColor.DARK_RED.index);
                            break;
                        case 5:
                            font.setColor(HSSFColor.ORANGE.index);
                            break;
                        case 6:
                            font.setColor(HSSFColor.GREY_40_PERCENT.index);
                            break;
                        case 7:
                            font.setColor(HSSFColor.BLACK.index);
                            style.setAlignment(CellStyle.ALIGN_CENTER);
                            break;
                    }
                    break;
            }
            style.setFont(font);
            styles.add(style);
        }
    }
    void exportPackageTasks(DVMPackage dvmPackage, Index offset) throws Exception {
        dvmPackage.readJson();
        for (DVMCompilationTask compilationTask : dvmPackage.package_json.compilationTasks) {
            for (DVMRunTask task : compilationTask.runTasks) {
                ShowMessage2(task.test_description);
                //---
                Integer NUM_THREADS = extractIntegerEnvironmentValue(task.environments, "DVMH_NUM_THREADS");
                if (NUM_THREADS != null && NUM_THREADS == 0) NUM_THREADS = 1;
                Integer NUM_CUDAS = extractIntegerEnvironmentValue(task.environments, "DVMH_NUM_CUDAS");
                //--
                int num_threads = (NUM_THREADS != null) ? NUM_THREADS : 1;
                int num_cudas = (NUM_CUDAS != null) ? NUM_CUDAS : 0;
                int total_threads = num_threads * Utils.getMatrixProcessors(task.matrix);
                //--
                addTaskRow(offset.getValue(),
                        task.group_description, //0
                        task.test_description,//1
                        task.language.getDescription(), //2
                        task.flags, //3
                        task.compilation_state, //4
                        task.state, //5
                        num_threads, //6
                        num_cudas, //7
                        total_threads, //8
                        formatMatrix(task.matrix), //9
                        task.environments, //10
                        task.usr_par, //11
                        task.compilation_time, //12
                        task.Time,//13
                        task.CleanTime, //14
                        task.progress //15
                );
                offset.Inc();
            }
        }
    }
    @Override
    protected void body() throws Exception {
        File file = Utils.getTempFileName("table");
        //--
        book = new HSSFWorkbook();
        sheet = book.createSheet("Результаты тестирования");
//        format = book.createDataFormat();
        //--
        createStyles();
        //--
        Index offset = new Index();
        for (DVMPackage dvmPackage : target) {
            addInfoRow(offset.getValue(), getPackageInfo(dvmPackage));
            offset.Inc();
        }
        if (target.size() > 1) {
            addInfoRow(offset.getValue(), "всего задач " + total_tasks_count + "; общее время выполнения " + Utils_.printSplittedDateInterval(total_time));
            offset.Inc();
        }
        addHeaderRow(offset.getValue(),
                "Группа",
                "Тест",
                "Язык",
                "Флаги",
                "Компиляция",
                "Запуск",
                "NUM_THREADS",
                "NUM_CUDAS",
                "TOTAL_THREADS",
                "Матрица",
                "Окружение",
                "usr.par",
                "Время компиляции (с)",
                "Время запуска (с)",
                "Чистое время (с)",
                "Прогресс (%)");
        //--
        offset.Inc();
        for (DVMPackage dvmPackage : target) {
            exportPackageTasks(dvmPackage, offset);
        }
        //--
        for (int i = 0; i < max_columns; ++i)
            sheet.autoSizeColumn(i);
        // Записываем всё в файл
        FileOutputStream stream = new FileOutputStream(file);
        book.write(stream);
        book.close();
        stream.close();
        ///--
        FileUtils.copyFile(file, res);
        book = null;
        stream = null;
        file = null;
    }
    @Override
    protected void performDone() throws Exception {
        super.performDone();
        if (Desktop.isDesktopSupported()) {
            if (UI.Question("Таблица сформирована в файле\n" + Utils_.DQuotes(res.getAbsolutePath()) + ".\nОткрыть её"
            )) {
                Desktop.getDesktop().open(res);
            }
        }
    }
}
