/**
 * 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.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.patrikdufresne.jface.preference.PreferenceConverter;
import com.patrikdufresne.ui.BTabFolder;
import com.patrikdufresne.ui.BTabItem;
import com.planimod.ui.preference.PlanimodPreferences;
import com.planimod.ui.theme.Resources;

/**
 * This dialog is used to allow the user to select a database.
 * 
 * @author Patrik Dufresne
 * 
 */
public class DatabaseSelectorDialog extends Dialog {
    /**
     * Standard return code constant (value 1) indicating that the window was canceled.
     *
     * @see #open
     */
    public static final int CANCEL = Window.CANCEL;
    /**
     * return code constant (value 2) indicating to create a database.
     */
    public static final int CREATE = 3;
    /**
     * return code constant (value 2) indicating to open a database.
     *
     * @see #open
     */
    public static final int OPEN = 2;

    /**
     * Default value.
     */
    protected static final int PREF_MAX_RECENT_FILES_DEFAULT = 5;
    /**
     * Preference key to access the files list.
     */
    protected static final String PREFKEY_FILES_LIST = "DatabaseSelectorDialog.files";
    /**
     * Preference key to define the number of files to keep in preferences.
     */
    protected static final String PREFKEY_MAX_RECENT_FILES = "DatabaseSelectorDialog.max_recent.files";

    private static final int TAB_IDX_CREATE = 1;

    private static final int TAB_IDX_OPEN = 0;

    /**
     * Add the given url to the recent list.
     * 
     * @param url
     */
    public static void addToRecentList(String url) {
        // Set default and get value of the maximum number a file in the recent
        // list
        IPreferenceStore preferenceStore = PlanimodPreferences.getPreferenceStore();
        preferenceStore.setDefault(PREFKEY_MAX_RECENT_FILES, PREF_MAX_RECENT_FILES_DEFAULT);
        int maxNumberOfFile = preferenceStore.getInt(PREFKEY_MAX_RECENT_FILES);

        // Get previous recent list from preferences
        List<String> list = Arrays.asList(PreferenceConverter.getStringArray(preferenceStore, PREFKEY_FILES_LIST));
        list = new ArrayList<String>(list);

        // Add current selection to the recent list
        if (list.contains(url)) {
            list.remove(url);
        }
        list.add(url);

        // Reduce the size of the list
        while (list.size() > maxNumberOfFile)
            list.remove(0);

        // Save recent file list in preferences
        String[] array = new String[list.size()];
        list.toArray(array);
        PreferenceConverter.setValue(preferenceStore, PREFKEY_FILES_LIST, array);
    }

    /**
     * Return the list of recent database file.
     * 
     * @return
     */
    public static String[] getRecentList() {
        return PreferenceConverter.getStringArray(PlanimodPreferences.getPreferenceStore(), PREFKEY_FILES_LIST);
    }

    private Button createBrowseButton;
    private Text createText;

    private boolean demo;

    private Button demoButton;
    /**
     * Listen to browser button selection.
     */
    private Listener listener = new Listener() {
        @Override
        public void handleEvent(Event event) {
            if (event.widget == openBrowseButton) {
                handleOpenBrowse();
            } else if (event.widget == createBrowseButton) {
                handleCreateBrowse();
            }
        }
    };
    /**
     * The browse button
     */
    protected Button openBrowseButton;

    private Combo openCombo;

    private BTabFolder tabFolder;

    private String url;

    /**
     * Create a new dialog to select the database to open.
     * 
     * @param parentShell
     */
    public DatabaseSelectorDialog(Shell parentShell) {
        super(parentShell);
    }

    /**
     * This implementation set the windows title
     */
    @Override
    protected void configureShell(Shell shell) {
        super.configureShell(shell);
    }

    @Override
    protected Control createContents(Composite parent) {
        Control control = super.createContents(parent);
        // Fill the combo with previous database name and select default option accordingly.
        String[] files = getRecentList();
        for (int i = 0; i < files.length; i++) {
            this.openCombo.add(files[i]);
        }
        // If we have a database in the list, default to "open" otherwise, dfault to "create".
        if (files.length > 0) {
            this.openCombo.setText(files[files.length - 1]);
            this.tabFolder.setSelection(TAB_IDX_OPEN);
        } else {
            this.tabFolder.setSelection(TAB_IDX_CREATE);
        }
        return control;
    }

    /**
     * This implementation create the controsl to selecte a database file.
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite composite = (Composite) super.createDialogArea(parent);

        // Planimod Logo
        Label logo = new Label(composite, SWT.NONE);
        logo.setImage(Resources.getImage(Resources.LOGO_375));
        logo.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false));

        // Open or Create Tab Folder
        tabFolder = new BTabFolder(composite, SWT.NONE);
        tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

        // Open Database
        Composite openComp = new Composite(tabFolder, SWT.NONE);
        openComp.setLayout(new GridLayout(2, false));
        openComp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));

        Label label = new Label(openComp, SWT.NONE);
        label.setText(_("Sélectionner une base de données dans la liste ou parcourez vos fichiers."));
        label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));

        this.openCombo = new Combo(openComp, SWT.BORDER);
        this.openCombo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        this.openCombo.addListener(SWT.Modify, this.listener);

        this.openBrowseButton = new Button(openComp, SWT.PUSH);
        this.openBrowseButton.setText(JFaceResources.getString("openBrowse"));
        this.openBrowseButton.addListener(SWT.Selection, this.listener);

        // Create Database
        Composite createComp = new Composite(tabFolder, SWT.NONE);
        createComp.setLayout(new GridLayout(2, false));
        createComp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));

        label = new Label(createComp, SWT.NONE);
        label.setText(_("Donnez un nom à votre base de données."));
        label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));

        this.createText = new Text(createComp, SWT.BORDER);
        this.createText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        this.createText.addListener(SWT.Modify, this.listener);

        this.createBrowseButton = new Button(createComp, SWT.PUSH);
        this.createBrowseButton.setText(JFaceResources.getString("openBrowse"));
        this.createBrowseButton.addListener(SWT.Selection, this.listener);

        this.demoButton = new Button(createComp, SWT.CHECK);
        this.demoButton.setText(_("Populer la base de données avec des données (pour Démo)"));
        this.demoButton.setSelection(true);

        // Create TabFolder items
        BTabItem openItem = new BTabItem(tabFolder, SWT.NONE);
        openItem.setText(_("Ouvrir une base de données"));
        openItem.setControl(openComp);

        BTabItem createItem = new BTabItem(tabFolder, SWT.NONE);
        createItem.setText(_("Créer une base de données"));
        createItem.setControl(createComp);

        return composite;
    }

    /**
     * Return true if the database should be created with demo data.
     * 
     * @return
     */
    public boolean getCreateDemo() {
        return demo;
    }

    /**
     * Return the selected database URL or null if operation is cancel by user.
     * 
     * @return
     */
    public String getDatabaseUrl() {
        return url;
    }

    void handleCreateBrowse() {
        FileDialog dlg = new FileDialog(getShell(), SWT.SAVE);
        String fileSelected = dlg.open();
        if (fileSelected != null) {
            this.createText.setText(fileSelected);
        }
    }

    /**
     * Notify this class about the user selecting the browse button.
     */
    void handleOpenBrowse() {
        FileDialog dlg = new FileDialog(getShell(), SWT.OPEN);
        String fileSelected = dlg.open();
        if (fileSelected != null) {
            this.openCombo.setText(fileSelected);
        }
    }

    @Override
    protected void okPressed() {

        // Define proper return code.
        if (tabFolder.getSelectionIndex() == TAB_IDX_OPEN) {
            url = this.openCombo.getText();
            setReturnCode(OPEN);
        } else {
            url = this.createText.getText();
            demo = this.demoButton.getSelection();
            setReturnCode(CREATE);
        }
        close();

    }

}
