/*
 * Copyright (c) 2011, Patrik Dufresne. All rights reserved.
 * Patrik Dufresne PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.planimod.ui;

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

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.StatusHandlerDialog;
import com.patrikdufresne.managers.DatabaseUrl;
import com.patrikdufresne.util.Localized;
import com.planimod.core.PlanimodManagers;
import com.planimod.ui.preference.PlanimodPreferences;
import com.planimod.ui.theme.Resources;
import com.planimod.ui.views.admin.AboutDialog;

public class Main {
	/**
	 * Define the application data directory name.
	 */
	private static final String APP_USER_DATA = "planimod"; //$NON-NLS-1$

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

	/**
	 * Define the preference file's name.
	 */
	private static final String PREF_FILENAME = "preferences"; //$NON-NLS-1$

	/**
	 * Open the preference files.
	 */
	public static void initPreference() {
		String osName = System.getProperty("os.name"); //$NON-NLS-1$
		String homeDir = System.getProperty("user.home"); //$NON-NLS-1$
		File prefFile;
		if (osName.equals("Linux")) { //$NON-NLS-1$
			File configDir = new File(homeDir, ".config/" + APP_USER_DATA); //$NON-NLS-1$
			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) {
			// Nothing to do
		} catch (IOException e) {
			// Display error
			e.printStackTrace();
		}

		PlanimodPreferences.setPreferenceStore(pref);
	}

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

		// Set the default locale to french
		Locale.setDefault(Locale.CANADA_FRENCH);
		localized = Localized.load(Main.class);

		// Init preferences
		initPreference();

		Display.setAppName(Localized.get(Main.class, "applicationName")); //$NON-NLS-1$

		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_64),
								Resources.getImage(Resources.APP_ICON_48),
								Resources.getImage(Resources.APP_ICON_32),
								Resources.getImage(Resources.APP_ICON_24),
								Resources.getImage(Resources.APP_ICON_16) });

						WindowManager winManager = new WindowManager();
						PlanimodManagers managers = null;
						try {
							if ((managers = openDatabase()) == null) {
								// 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) {
							e.printStackTrace();
							MessageUtils.openWarning(null,
									localized.get("fatalError"), null, e); //$NON-NLS-1$
						} finally {
							if (managers != null) {
								managers.dispose();
							}

							winManager.close();
							display.dispose();
						}
					}
				});
	}

	/**
	 * Open a database. Returns True if a database got open. False if the
	 * operation have been cancel.
	 */
	private static PlanimodManagers openDatabase() {

		// Open DB selector
		PlanimodManagers managers = null;
		DatabaseSelectorDialog dlg = new DatabaseSelectorDialog(null);
		Exception exception = null;
		DatabaseUrl url = null;
		do {
			if (exception != null) {
				if (url != null && url.isRemote()) {
					MessageUtils.openWarning(null,
							localized.get("openDatabaseError"), //$NON-NLS-1$
							localized.get("localDatabaseConnectionError"), //$NON-NLS-1$
							exception);
				} else {
					MessageUtils.openWarning(null,
							localized.get("openDatabaseError"), //$NON-NLS-1$
							localized.get("remoteDatabaseConnectionError"), //$NON-NLS-1$
							exception);
				}
			}
			dlg.open();
			url = dlg.getDatabaseUrl();
			if (url == null) {
				return null;
			}

			exception = null;
			try {
				// Open the database
				managers = new PlanimodManagers(url);
			} catch (Exception e) {
				e.printStackTrace();
				exception = e;
			}

		} while (exception != null);

		return managers;
	}

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

	/**
	 * This function sets the status handler.
	 */
	protected static void updateJFacePolicy() {
		Policy.setLog(new ILogger() {

			final transient Logger logger = LoggerFactory.getLogger(getClass());

			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;
				}

				System.err.println(status.getMessage());
				if (status.getException() != null) {
					status.getException().printStackTrace(System.err);
				}
			}
		});
		Policy.setStatusHandler(StatusHandlerDialog.getStatusHandler());
	}
}
