/*
 * Copyright
 *   2007 axYus - www.axyus.com
 *   2006 JP.Tessier- jean-philippe.tessier@axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS 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.
 *
 * XEMELIOS 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 XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package fr.gouv.finances.cp.xemelios.importers;

import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.TreeSet;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.BoundedRangeModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import org.apache.log4j.Logger;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import fr.gouv.finances.dgfip.utils.Pair;
import fr.gouv.finances.cp.utils.ui.DisplayExceptionDlg;
import fr.gouv.finances.cp.utils.ui.DlgGetPair;
import fr.gouv.finances.cp.utils.ui.IhmFactory;
import fr.gouv.finances.cp.utils.ui.InfiniteGlassPane;
import fr.gouv.finances.cp.xemelios.ui.MainWindow;
import fr.gouv.finances.dgfip.xemelios.auth.UnauthorizedException;
import fr.gouv.finances.dgfip.xemelios.common.ToolException;
import fr.gouv.finances.dgfip.xemelios.common.config.DocumentModel;
import fr.gouv.finances.dgfip.xemelios.importers.ImportServiceProvider;
import fr.gouv.finances.dgfip.xemelios.data.DataAccessException;
import fr.gouv.finances.dgfip.xemelios.data.DataConfigurationException;
import fr.gouv.finances.dgfip.xemelios.data.DataLayerManager;
import fr.gouv.finances.dgfip.xemelios.importers.EtatImporteur;

public class ImportServiceSwingProvider implements ImportServiceProvider {

    private static Logger logger = Logger.getLogger(ImportServiceSwingProvider.class);
    private MainWindow owner = null;
    private int lastReponse = -1;
    private final static boolean SHOW_CANCEL_BUTTON = true;
    protected ProgressDlg pg;
    private EtatImporteur ei;
    private boolean displayFeedback = true;
    private boolean alwaysOverwrite = false;

    public ImportServiceSwingProvider(MainWindow owner, EtatImporteur ei, int nbfiles) {
        super();
        this.owner = owner;
        //this.pg=new ProgressDlg(owner,nbfiles,ei);
        this.ei = ei;
    }

    public Pair getBudget(DocumentModel dm, Pair collectivite, String fileName, Pair budget) throws ToolException {
        Pair ret = null;
        if (ret == null) {
            TreeSet<Pair> existing = new TreeSet<Pair>();
            try {
                existing.addAll(DataLayerManager.getImplementation().getBudgets(dm, collectivite, owner.getConnectedUser()));
            } catch (UnauthorizedException ex) {
                throw new ToolException(ex, ToolException.ERROR_UNAUTHORIZED);
            } catch (DataConfigurationException e) {
                logger.error("in getBudget", e);
            } catch (DataAccessException e) {
                logger.error("in getBudget", e);
            }
            Vector<Pair> budgetsDm = dm.getDefaultBudgets();
            existing.addAll(budgetsDm);
            QueryBudget qb = new QueryBudget(fileName, existing, collectivite.libelle, budget);
            if (SwingUtilities.isEventDispatchThread()) {
                qb.run();
            } else {
                try {
                    SwingUtilities.invokeAndWait(qb);
                } catch (Throwable t) {
                }
            }
            ret = qb.getRet();
            if (ret == null) {
                throw new ToolException("Action interrompue", ToolException.ERROR_INTERRUPTED);
            }
        }
        return ret;
    }

    public Pair getCollectivite(DocumentModel dm, String fileName, Pair collectivite) throws ToolException {
        Pair ret = null;
        if (ret == null) {
            QueryCollectivite qc = new QueryCollectivite(dm, fileName, collectivite);
            if (SwingUtilities.isEventDispatchThread()) {
                qc.run();
            } else {
                try {
                    SwingUtilities.invokeAndWait(qc);
                } catch (Throwable t) {
                }
            }
            ret = qc.getRet();
            if (ret == null) {
                throw new ToolException("Import interrompu", ToolException.ERROR_INTERRUPTED);
            }
        }
        return ret;
    }

    public boolean getOverwrite(String docName) throws Exception {
        if (alwaysOverwrite) {
            return true;
        }
        if (lastReponse == 0 || lastReponse == 1) {
            return (lastReponse == 0);
        }
        QueryOverwrite qo = new QueryOverwrite(docName);
        int ret = -2;
        if (SwingUtilities.isEventDispatchThread()) {
            qo.run();
        } else {
            try {
                SwingUtilities.invokeAndWait(qo);
            } catch (Throwable t) {
            }
        }
        ret = qo.getRet();
        if (ret == JOptionPane.CLOSED_OPTION || ret == 2) {
            throw new Exception("Annuler");
        }
        lastReponse = ret;
        return ret == 0;
    }

    public void setEtatImporter(EtatImporteur ei) {
        this.ei = ei;
        ei.addPropertyChangeListener(new PropertyChangeListener() {

            public void propertyChange(PropertyChangeEvent evt) {
                String propName = evt.getPropertyName();
                logger.debug("property " + propName + " changed");
                if ("FILE_NAME".equals(propName)) {
                    pg.setCurrentFile((String) evt.getNewValue());
                } else if ("progress".equals(propName)) {
                    Integer progress = (Integer) evt.getNewValue();
                    pg.pushCurrentProgress(progress.intValue());
                } else if ("terminated".equals(propName)) {
                    pg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                    pg.setVisible(false);
                }
            }
        });
    }

    public Pair getCollectivite() {
        return ei.getCollectivite();
    }

    public Pair getBudget() {
        return ei.getBudget();
    }

    public interface ImmediatlyPaintable {

        public void paintImmediatly();
    }

    public static class PaintableProgress extends JProgressBar implements ImmediatlyPaintable {

        /**
         * Comment for <code>serialVersionUID</code>
         */
        private static final long serialVersionUID = 1L;

        public PaintableProgress() {
            super();
        }

        public PaintableProgress(int orient) {
            super(orient);
        }

        public PaintableProgress(int min, int max) {
            super(min, max);
        }

        public PaintableProgress(int orient, int min, int max) {
            super(orient, min, max);
        }

        public PaintableProgress(BoundedRangeModel newModel) {
            super(newModel);
        }

        public void paintImmediatly() {
            Runnable code = new Runnable() {

                public void run() {
                    paintImmediately(0, 0, getWidth(), getHeight());
                }
            };
            if (SwingUtilities.isEventDispatchThread()) {
                code.run();
            } else {
                try {
                    SwingUtilities.invokeAndWait(code);
                } catch (Exception ex) {
                    logger.error("tu sais ou", ex);
                }
            }
        }
    }

    public void displayProgress(final int nbFiles) {
        Runnable code = new Runnable() {

            public void run() {
                logger.debug(this.getClass().getName());
                if (pg == null) {
                    pg = new ProgressDlg(owner, nbFiles, ei);
                }
                if (ei != null) {
                    ei.addPropertyChangeListener(new PropertyChangeListener() {

                        public void propertyChange(PropertyChangeEvent evt) {
                            String propName = evt.getPropertyName();
//                            logger.debug("property "+propName+" changed");
                            if ("FILE_NAME".equals(propName)) {
                                pg.setCurrentFile((String) evt.getNewValue());
                            } else if ("progress".equals(propName)) {
                                Integer progress = (Integer) evt.getNewValue();
                                pg.pushCurrentProgress(progress.intValue());
                            } else if ("terminated".equals(propName)) {
                                pg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                                pg.setVisible(false);
                            }
                        }
                    });
                }
                pg.setVisible(true);
            }
        };
        if (SwingUtilities.isEventDispatchThread()) {
            code.run();
        } else {
            try {
                SwingUtilities.invokeAndWait(code);
            } catch (Throwable t) {
            }
        }
    }

    public void pushCurrentProgress(final int progress) {
        pg.pushCurrentProgress(progress);
    }

    public void displayMessage(String msg, int msgType) {
        if (shouldDisplayFeedback()) {
            JOptionPane.showMessageDialog(owner, msg, "Import", msgType == ImportServiceProvider.MSG_TYPE_INFORMATION ? JOptionPane.INFORMATION_MESSAGE : JOptionPane.ERROR_MESSAGE);
        }
    }

    public void displayException(Throwable t) {
        new DisplayExceptionDlg((JFrame) owner, t);
    }

    public void startLongWait() {
        pg.setUnknownEndded(true);
    }

    public void endLongWait() {
        pg.setUnknownEndded(false);
    }

    private class QueryCollectivite implements Runnable {

        private Pair ret;
        private String fileName;
        private DocumentModel dm;
        Pair collectivite;

        public QueryCollectivite(DocumentModel dm, String fileName, Pair collectivite) {
            super();
            this.fileName = fileName;
            this.dm = dm;
            this.collectivite = collectivite;
        }

        public void run() {
            DlgGetPair dlg = new DlgGetPair(owner, "Sur quel(le) " + dm.getLibelleCollectivite() + " porte ce document :\n" + fileName + " ?", null, null, collectivite);

            if (dlg.run()) {
                ret = new Pair(dlg.getCode(), dlg.getLibelle());
            }
        }

        public Pair getRet() {
            return ret;
        }
    }

    private class QueryBudget implements Runnable {

        private String fileName;
        private TreeSet<Pair> existing;
        private Pair ret;
        private String collectivite = null;
        private Pair budget;

        public QueryBudget(String fileName, TreeSet<Pair> existing, String collectivite, Pair budget) {
            super();
            this.fileName = fileName;
            this.existing = existing;
            this.collectivite = collectivite;
            this.budget = budget;
        }

        public void run() {
            DlgGetPair dlg = null;
//			if(existing.size()>0){
            dlg = new DlgGetPair(owner, "Sur quel budget porte ce document :\n" + fileName + " ?", existing, collectivite, budget);

            if (dlg.run()) {
                ret = new Pair(dlg.getCode(), dlg.getLibelle());
            }
            logger.debug("fin de QueryBudget.run()");
        }

        public Pair getRet() {
            logger.debug("QueryBudget.getRet()");
            return ret;
        }
    }

    private class QueryOverwrite implements Runnable {

        private String fileName;
        private int ret = -2;

        public QueryOverwrite(String fileName) {
            super();
            this.fileName = fileName;
        }

        public void run() {
            String msg = "Ce document existe déjà : " + fileName + "; voulez-vous l'écraser ?";
            String[] options = {"Oui", "Non", "Annuler"};
            ret = JOptionPane.showOptionDialog(owner, msg, "Confirmation", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]);
        }

        public int getRet() {
            return ret;
        }
    }

    public final class ProgressDlg extends JDialog {

        /**
         * Comment for <code>serialVersionUID</code>
         */
        private static final long serialVersionUID = 1L;
        public static final String DEFAULT_TEXT = "Import en cours : ";
        private boolean shouldContinue = true;
        private EtatImporteur ei = null;
        private int nbFilesToImport, nbFilesImported = -1;
        PaintableProgress globalProgress, currentProgress;
        JTextField currentFileName;

        public ProgressDlg(JFrame owner, int nbFilesToImport, EtatImporteur ei) {
            super(owner, "Import en cours...");
            this.nbFilesToImport = nbFilesToImport;
            this.ei = ei;
            initComponents(nbFilesToImport);
        }

        protected void initComponents(int nbFilesToImport) {
            IhmFactory iF = IhmFactory.newInstance();
            FormLayout fl = null;
            if (SHOW_CANCEL_BUTTON) {
                fl = new FormLayout("3dlu,pref,3dlu", "3dlu,pref,1dlu,pref,5dlu,pref,1dlu,pref,3dlu,pref,3dlu");
            } else {
                fl = new FormLayout("3dlu,pref,3dlu", "3dlu,pref,1dlu,pref,5dlu,pref,1dlu,pref,3dlu");
            }
            CellConstraints cc = new CellConstraints();
            PanelBuilder pb = new PanelBuilder(fl);

            pb.add(iF.newLabel("Import global", "normal"), cc.xy(2, 2));
            globalProgress = new PaintableProgress(0, 100);
            globalProgress.setStringPainted(true);
            globalProgress.setMaximum(1000);
            pb.add(globalProgress, cc.xy(2, 4));

            currentFileName = new JTextField(30);
            currentFileName.setBackground(getBackground());
            currentFileName.setBorder(BorderFactory.createEmptyBorder());
            currentFileName.setEditable(false);
            currentFileName.setText(DEFAULT_TEXT);
            pb.add(currentFileName, cc.xy(2, 6));
            currentProgress = new PaintableProgress(0, 100);
            currentProgress.setStringPainted(true);
            pb.add(currentProgress, cc.xy(2, 8));
            if (SHOW_CANCEL_BUTTON) {
                JButton pbCancel = new JButton("Annuler");
                pbCancel.addActionListener(new ActionListener() {

                    public void actionPerformed(ActionEvent evt) {
                        ei.cancel(true);
                    }
                });
                pb.add(pbCancel, cc.xy(2, 10));
                if (ei == null) {
                    pbCancel.setEnabled(false);
                }
            }

            setContentPane(pb.getPanel());
            setResizable(false);
            setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
            pack();
            setLocationRelativeTo(getOwner());
            setVisible(true);
            Graphics g = getGraphics();
            g.setClip(0, 0, getWidth(), getHeight());
            paint(g);
            setGlassPane(new InfiniteGlassPane());
        }

        public boolean setCurrentFile(String fileName) {
            nbFilesImported++;
            currentFileName.setText(DEFAULT_TEXT + fileName);
            currentProgress.setMaximum(100);
            currentProgress.setValue(0);
            return shouldContinue;
        }

        public boolean pushCurrentProgress(int value) {
            //  logger.debug("CurrentProgress: "+value);
            currentProgress.setValue(value);
            //   logger.debug(nbFilesToImport+" fichiers à importer.\n"+nbFilesImported+" fichiers importés.");
            int progress = (int) (((nbFilesImported + currentProgress.getPercentComplete()) / nbFilesToImport) * 1000);
            //   logger.debug("GlobalProgress: "+progress);
            globalProgress.setValue(progress);
            //	paintComponents(g);
            //	paintAll(g);
            repaintImmediatly();
            return shouldContinue;
        }

        public void repaintImmediatly() {
            //	logger.debug("repaintImmediatly");
            currentProgress.paintImmediatly();
            globalProgress.paintImmediatly();
            Graphics g = getGraphics();
            g.setClip(0, 0, getWidth(), getHeight());
            if (isLightweight()) {
                paint(g);
            } else {
                update(g);
            }
        }

        public void setUnknownEndded(boolean start) {
            getGlassPane().setVisible(start);
        }
    }

    public void setDisplayFeedback(boolean display) {
        displayFeedback = display;
    }

    public boolean shouldDisplayFeedback() {
        return displayFeedback;
    }

    public void setCollectivite(Pair p) {
        ei.setCollectivite(p);
    }

    public void setBudget(Pair p) {
        ei.setBudget(p);
    }

    public void setAlwaysOverwrite(boolean b) {
        alwaysOverwrite = b;
    }
}
