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

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

import java.util.Date;

import org.eclipse.core.databinding.BindingProperties;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.ObservablesManager;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ObservableSetContentProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

import com.patrikdufresne.jface.databinding.viewers.PropertyViewerComparator;
import com.patrikdufresne.jface.resource.OverlayImageDescriptor;
import com.planimod.core.PlanimodManagers;
import com.planimod.core.comparators.ProductionEventComparators;
import com.planimod.ui.databinding.ObservableWeekEnd;
import com.planimod.ui.databinding.ObservableWeekStart;
import com.planimod.ui.theme.Resources;
import com.planimod.ui.viewers.ProductionEventViewerUtils;

/**
 * This dialog is used to allow the user to select the week to copie data from.
 * 
 * @author Patrik Dufresne
 * 
 */
public class DuplicateProductionEventDialog extends TitleAreaDialog {

    /**
     * Resource id for title image.
     */
    private static final String TITLE_IMAGE = "DuplicateProductionEventDialog.titleImage";

    /**
     * Return the title image
     * 
     * @return
     */
    private static Image getTitleImage() {
        Image image = JFaceResources.getImage(TITLE_IMAGE);
        if (image == null) {
            OverlayImageDescriptor icon = new OverlayImageDescriptor(JFaceResources.getImageRegistry().getDescriptor(DLG_IMG_TITLE_BANNER), Resources
                    .getImageDescriptor(Resources.ICON_DUPLICATE_48), SWT.LEFT, SWT.CENTER);
            JFaceResources.getImageRegistry().put(TITLE_IMAGE, icon);
            image = JFaceResources.getImage(TITLE_IMAGE);
        }
        return image;
    }

    /**
     * The currently selected date.
     */
    private WritableValue date = new WritableValue(new Date(), Date.class);

    private DataBindingContext dbc;

    private PlanimodManagers managers;

    private ObservablesManager om;

    /**
     * The viewer used to display the production events.
     */
    private TableViewer prodEventViewer;

    /**
     * Widget used to select the week.
     */
    private DateTime weekDateTime;

    public DuplicateProductionEventDialog(Shell parentShell, PlanimodManagers managers) {
        super(parentShell);
        if (managers == null) {
            throw new NullPointerException();
        }
        this.managers = managers;
    }

    protected void bindValues() {

        /*
         * Bind the date value to the calendar widget
         */
        this.dbc.bindValue(SWTObservables.observeSelection(this.weekDateTime), this.date);
        IObservableValue start = new ObservableWeekStart(this.managers, this.date);
        IObservableValue end = new ObservableWeekEnd(this.managers, this.date);

        /*
         * Bind viewer
         */
        IObservableSet productionEvents = new ProductionEventComputedSet(this.managers, start, end);
        this.prodEventViewer.setContentProvider(new ObservableSetContentProvider());
        this.prodEventViewer.setLabelProvider(new ObservableMapLabelProvider(BindingProperties
                .convertedValue(ProductionEventViewerUtils.labelConverter())
                .observeDetail(productionEvents)));
        this.prodEventViewer.setComparator(new PropertyViewerComparator(ProductionEventComparators.byDate()));
        this.prodEventViewer.setInput(productionEvents);

    }

    /**
     * This implementation free allocated resources.
     */
    @Override
    public boolean close() {
        if (super.close()) {
            // Dispose the allocated resource
            if (this.om != null) {
                this.om.dispose();
                this.om = null;
            }
            if (this.dbc != null) {
                this.dbc.dispose();
                this.dbc = null;
            }
            return true;
        }
        return false;
    }

    /**
     * This implementation sets the binding.
     */
    @Override
    protected Control createContents(Composite parent) {
        Control control = super.createContents(parent);

        /*
         * Bind widgets
         */
        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);
        return control;

    }

    /**
     * This implementation create required widgets to edit a calendar event.
     * 
     * @param parent
     * @return
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite composite = (Composite) super.createDialogArea(parent);

        getShell().setText(_("Recopier"));
        setMessage(_("Sélectionnez la semaine dont vous désirez recopier les événements."));
        setTitle(_("Recopier les événements de production"));
        setTitleImage(getTitleImage());

        GridLayout layout = new GridLayout(2, false);
        Composite comp = new Composite(composite, SWT.NONE);
        comp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        comp.setLayout(layout);

        this.weekDateTime = new DateTime(comp, SWT.BORDER | SWT.CALENDAR);
        this.weekDateTime.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
        this.prodEventViewer = new TableViewer(comp, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
        GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
        data.heightHint = 350;
        this.prodEventViewer.getControl().setLayoutData(data);

        // Build the separator line
        Label separator = new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR);
        separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        return composite;
    }

    /**
     * Returns the currently selected date.
     * 
     * @return the date value or null.
     */
    public Date getDate() {
        return (Date) this.date.getValue();
    }

    /**
     * Sets the selected date.
     * 
     * @param date
     *            the new date value.
     */
    public void setDate(Date date) {
        if (date == null) {
            this.date.setValue(new Date());
        } else {
            this.date.setValue(date);
        }
    }

}
