package be.iminds.ilabt.jfed.experimenter_gui.timeline.controller.action;

import be.iminds.ilabt.jfed.experimenter_gui.timeline.model.TimelineModel;
import be.iminds.ilabt.jfed.experimenter_gui.timeline.view.TimelineView;
import be.iminds.ilabt.jfed.experimenter_gui.timeline.view.TimelineComponent;
import be.iminds.ilabt.jfed.experimenter_gui.timeline.view.dialogs.SaveOutputDialog;
import be.iminds.ilabt.jfed.experimenter_gui.util.FileUtils;
import be.iminds.ilabt.jfed.preferences.GuiPreferenceKey;
import be.iminds.ilabt.jfed.preferences.JFedGuiPreferences;
import be.iminds.ilabt.jfed.rspec.model.controller.ExperimentCommand;
import be.iminds.ilabt.jfed.rspec.model.controller.ExperimentCommandOutput;
import javafx.stage.FileChooser;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import static be.iminds.ilabt.jfed.experimenter_gui.util.FileUtils.EXPERIMENT_OUTPUT_FILE_EXTENSION;

/**
 * @author Cedric
 */
public class SaveOutputAction implements IAction {
    private final List<ExperimentCommand> preSelection;

    private final JFedGuiPreferences jFedPreferences;

    public SaveOutputAction(JFedGuiPreferences jFedPreferences) {
        this.preSelection = null;
        this.jFedPreferences = jFedPreferences;
    }
    public SaveOutputAction(List<ExperimentCommand> preSelection, JFedGuiPreferences jFedPreferences) {
        this.preSelection = preSelection;
        this.jFedPreferences = jFedPreferences;
    }

    @Override
    public boolean execute(TimelineModel model, TimelineComponent view) {

        SaveOutputDialog saveOutputDialog = new SaveOutputDialog(((TimelineView) view).getScene().getWindow(),
                model.getNodes(), preSelection);

        List<ExperimentCommand> commands = saveOutputDialog.showDialog();


        if (commands != null && commands.size() > 0) {
            FileChooser fc = new FileChooser();
            fc.setTitle("Save output");
            fc.getExtensionFilters().add(FileUtils.OUTPUT_EXTENSION_FILTER);
            fc.setInitialFileName(model.getExperiment().getSlice().getName() + EXPERIMENT_OUTPUT_FILE_EXTENSION);


            if (jFedPreferences.containsPreference(GuiPreferenceKey.PREF_RSPECFOLDER_REQUEST))
                fc.setInitialDirectory(new File(jFedPreferences.getString(GuiPreferenceKey.PREF_RSPECFOLDER_REQUEST)));
            else if (System.getProperty("user.home") != null)
                fc.setInitialDirectory(new File(System.getProperty("user.home")));


            File file = fc.showSaveDialog(((TimelineView) view).getScene().getWindow());

            if (file == null)
                return false;


            //save folder in which the file was saved for future file selector dialogs
            jFedPreferences.setString(GuiPreferenceKey.PREF_RSPECFOLDER_REQUEST,
                    file.getParentFile().getAbsolutePath());

            if (!file.getAbsolutePath().endsWith(EXPERIMENT_OUTPUT_FILE_EXTENSION))
                file = new File(file.getAbsolutePath() + EXPERIMENT_OUTPUT_FILE_EXTENSION);


            try {
                JAXBContext jaxbContext = JAXBContext.newInstance(OutputList.class);
                Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

                // output pretty printed
                jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                List<ExperimentCommandOutput> outputs = new ArrayList<>();
                for (ExperimentCommand c : commands) {
                    outputs.addAll(c.getOutputCollection());
                }

                OutputList outputList = new OutputList();
                outputList.setExperimentCommandOutputList(outputs);

                jaxbMarshaller.marshal(outputList, file);

            } catch (Exception ex) {
                ex.printStackTrace();
                return false;
            }

            return true;

        } else
            return false;
    }

    @Override
    public boolean undo(TimelineModel model, TimelineComponent view) {
        return false;
    }

    @XmlAccessorType(XmlAccessType.NONE)
    @XmlRootElement
    private static class OutputList {
        private List<ExperimentCommandOutput> experimentCommandOutputList;

        public OutputList() {
            experimentCommandOutputList = new ArrayList<>();
        }

        public List<ExperimentCommandOutput> getExperimentCommandOutputList() {
            return experimentCommandOutputList;
        }

        @XmlElement(name = "output")
        public void setExperimentCommandOutputList(List<ExperimentCommandOutput> experimentCommandOutputList) {
            this.experimentCommandOutputList = experimentCommandOutputList;
        }
    }

}
