/* ----------------------------------------
 * Origin  : GFI INFORMATIQUE 
 * Project : CDPP Propagation Tool 
 * ----------------------------------------
 * History 
 * Version : 01/05/2015 : SCA : V2.1
 * Version : 07/04/2016 : SCA : V2.2 (PSWS-H2020)
 *  Add comets
 * Version : 17/10/2018 : SCA : V2.2.5
 *  Redmine #6119 
 * Version : 27/06/2022 : LBE : V2.5
 * DM-ID : Redmine #7279 : 27/06/2022 : save xml files
 * ----------------------------------------
 */
package fr.tlse.irap.pt.client.controller.tools.timetable;

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.tlse.irap.pt.client.component.CustomComponent;
import fr.tlse.irap.pt.client.component.ICustomComponent;
import fr.tlse.irap.pt.client.controller.RootController;
import fr.tlse.irap.pt.client.controller.dialogbox.DialogBox;
import fr.tlse.irap.pt.client.controller.tools.common.DesktopBrowser;
import fr.tlse.irap.pt.client.controller.tools.jmap.ClickPointsFileHandler;
import fr.tlse.irap.pt.client.controller.tools.samp.JSampController;
import fr.tlse.irap.pt.client.services.constant.CONFIG;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Cursor;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableView;
import javafx.scene.layout.GridPane;
import javafx.stage.FileChooser;
import org.apache.commons.io.FileUtils;

public abstract class TimeTableController extends GridPane implements ICustomComponent {

    protected static final Logger log = LoggerFactory.getLogger(TimeTableController.class);

    protected static final String EXPORT_HDR = ""
            + "Computation done by CDPP/CNES Propagation Tool " + CONFIG.PROJECT_VERSION + " available at http://propagationtool.cdpp.eu";
    protected static final String XML_HDR = ""
            + "<?xml version=\"1.0\"?>\n"
            + "<VOTABLE version=\"1.3\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
            + "xmlns=\"http://www.ivoa.net/xml/VOTable/v1.3\"\n"
            + "xmlns:stc=\"http://www.ivoa.net/xml/STC/v1.30\" >\n";

    protected static double WS_COL = 60;
    protected static double WM_COL = 90;
    protected static double WL_COL = 160;

    protected static final String UNIT_LONG = "(°)";
    protected static final String UNIT_TIME = "(hrs)";
    protected static final String UNIT_TIME_MIN = "(min)";
    protected static final String UNIT_DIST = "(AU)";
    protected static final String UNIT_ENERGY = "(Mev)";

    @FXML
    protected GridPane rootTimetable;
    @FXML
    protected TableView<?> tableViewRoot;

    public TimeTableController() {
        super();
        CustomComponent.initCustomComponent(this);
        loadMenu();
    }

    protected abstract File tableToAscii() throws IOException;

    protected abstract File tableToXml() throws IOException;

    protected abstract void filterAll();

    protected abstract void filterImpacted();

    protected void endCursor() {
        rootTimetable.setDisable(false);
        rootTimetable.setCursor(null);
    }

    protected void waitCursor() {
        rootTimetable.setDisable(true);
        rootTimetable.setCursor(Cursor.WAIT);
    }

    /**
     * Load context menu
     */
    private void loadMenu() {
        final ContextMenu tableMenu = new ContextMenu();
        final Menu filterItem = new Menu("Filter");
        final MenuItem filterAllItem = new MenuItem("All targets");
        final MenuItem filterImpactedItem = new MenuItem("Impacted targets");
        final Menu exportItem = new Menu("Export");
        final MenuItem exportXmlItem = new MenuItem("VOTABLE");
        final MenuItem exportAsciiItem = new MenuItem("ASCII");
        final MenuItem exportSAMPItem = new MenuItem("Send via SAMP");

        filterAllItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                filterAll();
            }
        });
        filterImpactedItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                filterImpacted();
            }
        });
        filterItem.getItems().addAll(filterAllItem, filterImpactedItem);
        tableMenu.getItems().add(filterItem);

        exportXmlItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                exportXml();
            }
        });
        exportAsciiItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                exportAscii();
            }
        });
        exportItem.getItems().addAll(exportXmlItem, exportAsciiItem);
        tableMenu.getItems().add(exportItem);

        exportSAMPItem.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                exportSamp();
            }
        });
        tableMenu.getItems().add(exportSAMPItem);

        tableViewRoot.setContextMenu(tableMenu);
    }

    /**
     * Export table of arrival times to ascii format and open it with the current editor
     */
    private void exportAscii() {
        try {
            openFile(tableToAscii());

        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e.getMessage());
            DialogBox.error(" Error while exporting table of arrival times.\n");
        }
    }

    /**
     * Export table of arrival times to xml format (VOTABLE) and open it with the current editor
     */
    private void exportXml() {
        try {
            saveFile(tableToXml());

        } catch (IOException e) {
            e.printStackTrace();
            log.warn(e.getMessage());
            DialogBox.error(" Error while exporting table of arrival times.\n");
        }
    }

    /**
     * Export table of arrival times to SAMP hub using xml votable format
     */
    private void exportSamp() {
        try {
            sendToSamp(tableToXml());

        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e.getMessage());
            DialogBox.error(" Error while exporting table of arrival times to SAMP.\n");
        }
    }

    private void openFile(final File tmpFile) {
        final Task<Object> openFileWorker = openFileWorker(tmpFile);

        openFileWorker.stateProperty().addListener(
                new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends Worker.State> observableValue, Worker.State oldState, Worker.State newState) {
                if (newState == Worker.State.SUCCEEDED) {
                    endCursor();
                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                    endCursor();
                    DialogBox.error(" Error while exporting table of arrival times.\n");
                    if (openFileWorker.getException() != null) {
                        log.warn(openFileWorker.getException().getMessage());
                    }
                }
            }
        });
        new Thread(openFileWorker).start();
        waitCursor();
    }

    private Task<Object> openFileWorker(final File file) {
        return new Task<Object>() {
            @Override
            protected Object call() throws Exception {
                try {
                    Desktop.getDesktop().edit(file);
                } catch (Exception e) {
                    DesktopBrowser.openURL("File://" + file.getPath());
                }
                return true;
            }
        };
    }

    
    
    private void saveFile(final File tmpFile) throws IOException {
 
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Choose file name");
        fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
        fileChooser.getExtensionFilters().addAll(
                new FileChooser.ExtensionFilter("All files", "*.*"),
                new FileChooser.ExtensionFilter("XML", "*.xml")
        );
        //        if (userDir != null) {
        //            fileChooser.setInitialDirectory(userDir);
        //        }
        File file = fileChooser.showSaveDialog(RootController.stage);
        if (file != null) {
            if (!file.getName().contains(".")) {
                file = new File(file.getAbsolutePath() + ".xml");
            }
            //copy tmpFile in file
            FileUtils.copyFile(tmpFile, file);
        }
        
        
//        final Task<Object> saveFileWorker = saveFileWorker(tmpFile);

//        saveFileWorker.stateProperty().addListener(
//                new ChangeListener<Worker.State>() {
//            @Override
//            public void changed(ObservableValue<? extends Worker.State> observableValue, Worker.State oldState, Worker.State newState) {
//                if (newState == Worker.State.SUCCEEDED) {
//                    endCursor();
//                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
//                    endCursor();
//                    DialogBox.error(" Error while exporting table of arrival times.\n");
//                    if (saveFileWorker.getException() != null) {
//                        log.warn(saveFileWorker.getException().getMessage());
//                    }
//                }
//            }
//        });
//        new Thread(saveFileWorker).start();
//        waitCursor();
    }

//    private Task<Object> saveFileWorker(final File file) {
//        return new Task<Object>() {
//            @Override
//            protected Object call() throws Exception {
//                try {
//                    Desktop.getDesktop().edit(file);
//                } catch (Exception e) {
//                    DesktopBrowser.openURL("File://" + file.getPath());
//                }
//                return true;
//            }
//        };
//    }
    
    
    /**
     * Send XML VoTable file to SAMP
     *
     * @param xmlFile
     */
    private void sendToSamp(final File xmlFile) {
        final Task<Object> sendToSampWorker = sendToSampWorker(xmlFile);

        sendToSampWorker.stateProperty().addListener(
                new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends Worker.State> observableValue, Worker.State oldState, Worker.State newState) {
                if (newState == Worker.State.SUCCEEDED) {
                    endCursor();
                } else if (newState == Worker.State.FAILED || newState == Worker.State.CANCELLED) {
                    endCursor();
                    DialogBox.error(" Error while exporting table of arrival times to SAMP.\n");
                    if (sendToSampWorker.getException() != null) {
                        log.warn(sendToSampWorker.getException().getMessage());
                    }
                }
            }
        });
        new Thread(sendToSampWorker).start();
        waitCursor();
    }

    private Task<Object> sendToSampWorker(final File xmlFile) {
        return new Task<Object>() {
            @Override
            protected Object call() throws Exception {
                // Export via SAMP hub
                JSampController.getJSampFrame().sendVOTable("File://" + xmlFile.getPath());
                return true;
            }
        };
    }

}
