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