/**
 * Copyright (C) 2019 Patrik Dufresne Service Logiciel <info@patrikdufresne.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package com.planimod.ui;

import static com.planimod.ui.Localized._;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.jface.util.ILogger;
import org.eclipse.jface.util.Policy;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.window.WindowManager;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.patrikdufresne.jface.dialogs.DetailMessageDialog;
import com.patrikdufresne.jface.dialogs.StatusHandlerDialog;
import com.planimod.core.PlanimodManagers;
import com.planimod.ui.preference.PlanimodPreferences;
import com.planimod.ui.theme.Resources;

public class Main {

    /**
     * Define the application data directory name.
     */
    private static final String APP_USER_DATA = "planimod";

    private static Logger logger = LoggerFactory.getLogger(Main.class);

    /**
     * Preference store of the application.
     */
    private static PreferenceStore pref;

    /**
     * Define the preference file's name.
     */
    private static final String PREF_FILENAME = "preferences";

    /**
     * Open the preference files.
     */
    public static void initPreference() {
        String osName = System.getProperty("os.name");
        String homeDir = System.getProperty("user.home");
        File prefFile;
        if (osName.equals("Linux")) {
            File configDir = new File(homeDir, ".config/" + APP_USER_DATA);
            configDir.mkdirs();
            prefFile = new File(configDir, PREF_FILENAME);
        } else {
            File configDir = new File(homeDir, APP_USER_DATA);
            configDir.mkdirs();
            prefFile = new File(configDir, PREF_FILENAME);
        }

        pref = new PreferenceStore(prefFile.getPath());
        try {
            pref.load();
        } catch (FileNotFoundException e) {
            // Swallow
        } catch (IOException e) {
            // Display error
            logger.error("Can't load the preferences.", e);
        }

        PlanimodPreferences.setPreferenceStore(pref);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        logger.info("Planimod is starting...");

        // Init preferences
        initPreference();

        Display.setAppName(_("Planimod"));

        final Display display = new Display();
        Realm.runWithDefault(SWTObservables.getRealm(Display.getCurrent()), new Runnable() {
            @Override
            public void run() {

                updateJFacePolicy();

                // Set default application image to be use by all JFace
                // Window
                Window.setDefaultImages(new Image[] { Resources.getImage(Resources.APP_ICON_128), Resources.getImage(Resources.APP_ICON_48) });

                WindowManager winManager = new WindowManager();
                PlanimodManagers managers = null;
                try {
                    managers = new DatabaseSelector().selectDatabase();
                    if (managers == null) {
                        // Operation cancel by user - exit application
                        savePreference();
                        return;
                    }

                    // Open Main Window
                    PlanimodMainWindow win = new PlanimodMainWindow(null);
                    win.setManagers(managers);
                    win.setWindowManager(winManager);
                    win.open();

                    // Event loop
                    while (winManager.getWindowCount() > 0) {
                        try {
                            if (!display.readAndDispatch()) display.sleep();
                        } catch (RuntimeException e) {
                            PlanimodPolicy.showException(e);
                        }
                    }

                    savePreference();

                } catch (Throwable e) {
                    logger.error("fatal error", e);
                    DetailMessageDialog.openDetailWarning(null, Display.getAppName(), _("Une erreur fatale s'est produite."), null, e);
                } finally {
                    if (managers != null) {
                        managers.dispose();
                    }
                    winManager.close();
                    display.dispose();
                }
            }
        });
    }

    /**
     * Save the preferences.
     */
    public static void savePreference() {
        if (pref != null) {
            try {
                pref.save();
            } catch (IOException e) {
                // Print the error into logs
                logger.error("Can't save preferences.", e);
            }
        }
    }

    /**
     * This function sets the status handler.
     */
    protected static void updateJFacePolicy() {
        /**
         * Redirect all the Jface logger into SLF4J logger.
         */
        Policy.setLog(new ILogger() {

            /**
             * Create a default logger for ILogger.
             */
            final transient Logger logger = LoggerFactory.getLogger(getClass());

            /**
             * This implementation is logging the status object using the logger.
             */
            @Override
            public void log(IStatus status) {
                switch (status.getSeverity()) {
                case IStatus.OK:
                case IStatus.INFO:
                    if (status.getException() == null) {
                        logger.info(status.getMessage());
                    } else {
                        logger.info(status.getMessage(), status.getException());
                    }
                    break;
                case IStatus.WARNING:
                    if (status.getException() == null) {
                        logger.warn(status.getMessage());
                    } else {
                        logger.warn(status.getMessage(), status.getException());
                    }
                    break;
                case IStatus.ERROR:
                    if (status.getException() == null) {
                        logger.error(status.getMessage());
                    } else {
                        logger.error(status.getMessage(), status.getException());
                    }
                    break;
                }
            }
        });
        /**
         * Redirect all the JFace exception to our status dialog.
         */
        Policy.setStatusHandler(StatusHandlerDialog.getStatusHandler());
    }
}
