/**
 * 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.views.admin;

import java.util.Iterator;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.ObservablesManager;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.observable.set.WritableSet;
import org.eclipse.core.databinding.property.value.IValueProperty;
import org.eclipse.jface.databinding.viewers.ObservableSetContentProvider;
import org.eclipse.jface.databinding.viewers.ViewerProperties;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.RowLayoutFactory;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

import com.patrikdufresne.jface.action.ActionContributionItem;
import com.patrikdufresne.jface.databinding.util.JFaceProperties;
import com.patrikdufresne.jface.databinding.viewers.ColumnSupport;
import com.patrikdufresne.managers.ManagerException;
import com.patrikdufresne.managers.databinding.ManagerUpdateValueStrategy;
import com.patrikdufresne.util.Localized;
import com.planimod.core.ApplicationSetting;
import com.planimod.core.PlanimodManagers;
import com.planimod.ui.PlanimodPolicy;
import com.planimod.ui.databinding.MotifBean;

/**
 * This dialog is used to change the Planimod Motif parameters.
 * 
 * @author Karl St-Cyr
 * 
 */
public class MotifPreferencePage extends PreferencePage {

    private AddMotifEntry addMotifEntry;
    private DataBindingContext dbc = new DataBindingContext();
    private Localized localized = Localized.load(AppearancePreferencePage.class);
    private PlanimodManagers managers;
    public WritableSet motifs;
    private ObservablesManager om;
    private RemoveMotifEntry removeMotifEntry;

    private TableViewer viewer;

    /**
     * Key to acces the non availability motif. Used to filter the non availability.
     */
    public static final String NONAVAILABILITY_REASON = "Nouveau motif,"; //$NON-NLS-1$

    
    /**
     * Create a new preference page.
     */
    public MotifPreferencePage(PlanimodManagers manager) {
        super();
        if (manager == null) {
            throw new IllegalArgumentException();
        }
        this.managers = manager;
        setTitle(this.localized.get("MotifPreferencePage.title")); //$NON-NLS-1$
    }

    /**
     * Sets the binding between the values and the page.
     */
    private void bind() {
        this.dbc = new DataBindingContext();
        this.om = new ObservablesManager();
        this.om.runAndCollect(new Runnable() {
            @Override
            public void run() {
                bindValues();
            }
        });
        this.om.addObservablesFromContext(this.dbc, true, true);
    }

    /**
     * Used to bind the widgets
     */
    protected void bindValues() {

        this.motifs = new WritableSet();
        String nAReason = null;
        try {
            nAReason = this.managers.getApplicationSettingManager().getByName(NONAVAILABILITY_REASON);

        } catch (ManagerException e) {
            PlanimodPolicy.showException(e);
        }
        if (nAReason == null) {
            nAReason = this.localized.get("AddMotifEntry.newMotif"); //$NON-NLS-1$
        }
        for (String s : nAReason.split(",")) { //$NON-NLS-1$
            MotifBean r = new MotifBean();
            r.setName(s);
            this.motifs.add(r);
        }
        ObservableSetContentProvider oscp = new ObservableSetContentProvider();
        viewer.setContentProvider(oscp);

        IValueProperty nameProperty = BeanProperties.value(MotifBean.class, MotifBean.NAME);
        ColumnSupport.create(viewer, this.localized.get("MotifPreferencePage.title"), oscp.getKnownElements(), nameProperty) //$NON-NLS-1$
                .addTextEditingSupport(this.dbc, new ManagerUpdateValueStrategy(this.managers, UpdateValueStrategy.POLICY_CONVERT), null)
                .setWeightLayoutData(1, 70)
                .setResizable(false)
                .setMoveable(false);
        viewer.setInput(this.motifs);

        /*
         * Create the binding for the action
         */
        // Bind add action
        dbc.bindSet(JFaceProperties.set(AddMotifEntry.class, AddMotifEntry.MOTIFS).observe(this.addMotifEntry), this.motifs);

        // Bind remove action
        dbc.bindSet(JFaceProperties.set(RemoveMotifEntry.class, RemoveMotifEntry.MOTIFS).observe(this.removeMotifEntry), this.motifs);
        dbc.bindValue(
                JFaceProperties.value(RemoveMotifEntry.class, RemoveMotifEntry.MOTIF, RemoveMotifEntry.MOTIF).observe(this.removeMotifEntry),
                ViewerProperties.singleSelection().observe(this.viewer));
    }

    @Override
    protected Control createContents(Composite parent) {

        // PlanimodManagers.updateDatabase(manager.getSessionFactory());

        Composite comp = new Composite(parent, SWT.NONE);
        comp.setLayout(GridLayoutFactory.fillDefaults().create());
        comp.setLayoutData(new GridData(GridData.FILL_BOTH));

        // TableViewer from Planimod
        this.viewer = new TableViewer(comp, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
        this.viewer.getTable().setHeaderVisible(false);

        // Change the editor strategy
        ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(this.viewer) {
            @Override
            protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
                return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
                        || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION
                        || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR)
                        || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
            }
        };
        TableViewerEditor.create(this.viewer, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL
                | ColumnViewerEditor.TABBING_CYCLE_IN_ROW
                | ColumnViewerEditor.TABBING_VERTICAL
                | ColumnViewerEditor.KEYBOARD_ACTIVATION);

        // Composite for the buttons (Add and Remove)
        Composite buttonsComp = new Composite(parent, SWT.NONE);
        buttonsComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        buttonsComp.setLayout(RowLayoutFactory.fillDefaults().create());

        // Add button
        (new ActionContributionItem(this.addMotifEntry = new AddMotifEntry(), true)).fill(buttonsComp);

        // Remove button
        (new ActionContributionItem(this.removeMotifEntry = new RemoveMotifEntry(), true)).fill(buttonsComp);
        bind();
        return comp;
    }

    /**
     * This implementation save the motif to the managers.
     */
    @Override
    public boolean performOk() {
        StringBuilder buf = new StringBuilder();
        if (motifs != null) {
            @SuppressWarnings("unchecked")
            Iterator<MotifBean> iter = motifs.iterator();
            try {
                while (iter.hasNext()) {
                    buf.append(iter.next().getName());
                    if (iter.hasNext()) {
                        buf.append(","); //$NON-NLS-1$
                    }
                }
                buf.append(","); //$NON-NLS-1$
                this.managers.getApplicationSettingManager().setByName(NONAVAILABILITY_REASON, buf.toString());
            } catch (ManagerException e) {
                PlanimodPolicy.showException(e);
            }
        }
        return true;
    }
}
