package be.iminds.ilabt.jfed.experimenter_gui.gts_editor;

import be.iminds.ilabt.jfed.experimenter_gui.editor.views.EditorViewType;
import be.iminds.ilabt.jfed.experimenter_gui.gts_editor.actions.GTSEditorActionsFactory;
import be.iminds.ilabt.jfed.experimenter_gui.gts_editor.views.EditableGtsDslView;
import be.iminds.ilabt.jfed.experimenter_gui.gts_editor.views.GTSViewsFactory;
import be.iminds.ilabt.jfed.groovy_dsl.DSLStreamException;
import be.iminds.ilabt.jfed.ui.javafx.dialogs.JFDialogs;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.Alert;
import javafx.scene.layout.BorderPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * User: twalcari
 * Date: 5/18/2015
 * Time: 10:37
 */
public class GTSEditor extends BorderPane {
    private static final Logger LOG = LoggerFactory.getLogger(GTSEditor.class);

    private final EditableGtsDsl editableGtsDsl;

    private final GTSViewsFactory gtsViewsFactory;
    private final GTSEditorActionsFactory gtsEditorActionsFactory;

    private EditableGtsDslView currentView;

    private final StringProperty status = new SimpleStringProperty();

    public GTSEditor(EditableGtsDsl editableGtsDsl, GTSViewsFactory gtsViewsFactory,
                     GTSEditorActionsFactory gtsEditorActionsFactory) {
        this.editableGtsDsl = editableGtsDsl;

        this.gtsViewsFactory = gtsViewsFactory;
        this.gtsEditorActionsFactory = gtsEditorActionsFactory;

        //try to open in canvas editor
        if (editableGtsDsl.tryConvertToModel()) {
            setEditorView(gtsViewsFactory.createEditableGTSCanvasEditorView(new GTSModelEditor(editableGtsDsl.getModel())));
        } else {
            LOG.error("Could not parse GTS DSL! Reverting to raw view");
            setEditorView(gtsViewsFactory.createRawGtsDslEditor(editableGtsDsl.getDsl(), false));
        }
    }

    public String getStatus() {
        return status.get();
    }

    public StringProperty statusProperty() {
        return status;
    }


    public void save() {
        try {
            editableGtsDsl.save();

            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("GTS DSL saved");
            alert.setContentText("Your GTS DSL was successfully saved.");
            alert.showAndWait();
        } catch (DSLStreamException ex) {
            LOG.error("Error while saving DSL: {}", ex.getMessage(), ex);

            JFDialogs.create()
                    .title("Saving GTS DSL failed")
                    .message("An error occured while saving your GTS DSL")
                    .showException(ex);
        }
    }
   /*
    private void setEditorViewByType(EditorViewType type) {
        if (currentView != null)
            currentView.dispose();

        if (type == EditorViewType.CANVAS) {
            setEditorView();
            GTSModelEditor modelEditor = new GTSModelEditor(editableGtsDsl);
            currentView = gtsViewsFactory.createEditableGTSCanvasEditorView(modelEditor);
        } else if (type == EditorViewType.RAW) {
            currentView = gtsViewsFactory.createRawGtsDslEditor(editableGtsDsl.getDsl(), false);
        }


        assert (currentView != null);
        setCenter(currentView.getView());

        status.unbind();
        status.bind(currentView.statusProperty());
    } */

    private void setEditorView(EditableGtsDslView view) {
        if (currentView != null)
            currentView.dispose();

        setCenter(view.getView());

        status.unbind();
        status.bind(view.statusProperty());

        currentView = view;
    }

    /**
     * Tries to the view to the requested type, without losing any data during the switch.
     * <p/>
     * Before making the switch, this method will first check if data will be lost.
     * If so, the user will be warned, and can abort the process.
     *
     * @param type new EditorViewType to switch to
     * @return If switch was a success
     */
    public boolean trySwitchToEditorViewByType(EditorViewType type) {
        assert (currentView != null);

        synchronized (this) {
            if (currentView.getType() == type)
                return true; //we are already in the correct mode

            if (type == EditorViewType.CANVAS) {
                assert currentView.getType() == EditorViewType.RAW;
                //force save of current raw view
                editableGtsDsl.setDsl(editableGtsDsl.getName(), currentView.getResultDsl());

                if (editableGtsDsl.tryConvertToModel()) {
                    setEditorView(gtsViewsFactory.createEditableGTSCanvasEditorView(new GTSModelEditor(editableGtsDsl.getModel())));
                    return true;
                } else {
                    Alert dialog = new Alert(Alert.AlertType.ERROR);
                    dialog.setTitle("Invalid GTS DSL");
                    dialog.setContentText("jFed could not parse the given GTS DSL. Please edit it manually.");
                    dialog.showAndWait();

                    return false;
                }
            } else {
                assert type == EditorViewType.RAW;
                assert currentView.getType() == EditorViewType.CANVAS;

                editableGtsDsl.convertToDsl();
                setEditorView(gtsViewsFactory.createRawGtsDslEditor(editableGtsDsl.getDsl(), false));
                return true;
            }
        }
    }

    public void export() {
        gtsEditorActionsFactory.createExportGtsDslAction(editableGtsDsl, getScene().getWindow()).call();
    }


    public EditableGtsDsl getEditableGtsDsl() {
        return editableGtsDsl;
    }

    public boolean revert() {
        return editableGtsDsl.revert();
    }

    public EditorViewType getCurrentEditorViewType() {
        return currentView.getType();
    }

    public EditableGtsDslView getCurrentEditorView() {
        return currentView;
    }
}
