/*
 * Licensed Materials - Property of Perforce Software, Inc. 
 * © Copyright Perforce Software, Inc. 2014, 2021 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */
package utils;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.HeadlessException;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Vector;

import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileFilter;

import ilog.views.IlvManager;
import ilog.views.IlvManagerLayer;
import ilog.views.IlvManagerView;
import ilog.views.io.IlvReadFileException;
import ilog.views.io.IlvSingleValueNamedProperty;
import ilog.views.maps.IlvAreaOfInterest;
import ilog.views.maps.IlvAreasOfInterestProperty;
import ilog.views.maps.IlvCoordinateSystemProperty;
import ilog.views.maps.IlvDisplayPreferences;
import ilog.views.maps.IlvDisplayPreferencesProperty;
import ilog.views.maps.IlvMapInputStream;
import ilog.views.maps.IlvMapLayerTreeProperty;
import ilog.views.maps.IlvMapOutputStream;
import ilog.views.maps.IlvMapTileGeneratorConstants;
import ilog.views.maps.IlvMapUtil;
import ilog.views.maps.beans.IlvExceptionMessage;
import ilog.views.maps.beans.IlvJAreaOfInterestPanel;
import ilog.views.maps.beans.IlvMapAnnotationProperty;
import ilog.views.maps.beans.IlvMapLayerTreeModel;
import ilog.views.maps.datasource.IlvMapDataSourceProperty;
import ilog.views.maps.format.IlvDefaultDataPathResolver;
import ilog.views.maps.format.IlvMapDataPathManager;
import ilog.views.maps.format.IlvMapDataPathResolver;
import ilog.views.maps.label.IlvMapLabelerProperty;
import ilog.views.maps.raster.IlvRasterTemporaryFileManager;
import ilog.views.maps.srs.coordsys.IlvCoordinateSystem;
import ilog.views.maps.theme.IlvMapStyleControllerProperty;
import ilog.views.tiling.IlvThreadedTileLoader;
import ilog.views.tiling.IlvTileLoader;
import ilog.views.tiling.IlvTiledLayer;
import ilog.views.util.swing.layout.IlvVerticalFlowLayout;
import plugins.ImportAction;
import shared.BaseDemo;
import shared.MapBuilder;

/** management of save/load actions */
public class IvlFileManager {
  // Since JViews 8.7, we store the last visible area and try to apply it when
  // the file is loaded in the map builder.
  private static final String LAST_AREA = "LastAOE"; //$NON-NLS-1$

  static String description;

  /**
   * Sets the description of the files able to be loaded in the MapBuilder. This
   * is the descrition that appears in the file selector.
   * 
   * @return The String describing the map files.
   */
  public static String getDescription() {
    return description != null ? description : IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.FileType"); //$NON-NLS-1$
  }

  /**
   * Sets the description of the maps files.
   * 
   * @param d
   */
  public static void setDescription(String d) {
    description = d;
  }

  // final static String MODE_PROPERTY = "mode"; //$NON-NLS-1$
  static JFileChooser makeFileChooser() {
    final JFileChooser fileChooser = new JFileChooser();
    fileChooser.setFileFilter(new FileFilter() {
      Override
      public boolean accept(File f) {
        return (f.isDirectory() || f.getName().toLowerCase().endsWith(IlvMapOutputStream.getFileSuffix()));
      }

      Override
      public String getDescription() {
        return IvlFileManager.getDescription();
      }
    });
    fileChooser.removeChoosableFileFilter(fileChooser.getAcceptAllFileFilter());
    return fileChooser;
  }

  // JV-1725
  /**
   * Shows a save dialog if necessary.
   * 
   * @param app
   *          application to check for modification
   * @param view
   *          component to use as dialog root
   * @return JOptionPane.YES_OPTION or NO_OPTION or CANCEL_OPTION.
   * @see SaveIvlActionListener
   */
  public static int askSave(BaseDemo app, IlvManagerView view) {
    if (app.isModified()) {
      int ans = JOptionPane.showConfirmDialog(view,
          IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.MessageConfirmSave"), //$NON-NLS-1$
          IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.TitleConfirmSave"), //$NON-NLS-1$
          JOptionPane.YES_NO_CANCEL_OPTION);
      if (ans == JOptionPane.YES_OPTION) {
        IvlFileManager.SaveIvlActionListener p = new IvlFileManager.SaveIvlActionListener(app, true);
        p.actionPerformed(null);
        if (!p.isSaved()) {
          ans = JOptionPane.CANCEL_OPTION;
        }
      }
      return ans;
    }
    return JOptionPane.YES_OPTION;
  }

  /**
   * Action listener that loads an ivl file.
   */
  public static class LoadIvlActionListener implements ActionListener {
    // JViews Bug Report #2005.245
    /**
     * An improved data path resolver that tries all possible relative paths
     * that can be made from a file name: for example, for
     * "//C/dir1/dir2/file.shp", we will try : basename//C/dir1/dir2/file.shp
     * basename/dir1/dir2/file.shp basename/dir2/file.shp basename/file.shp
     */
    private static class ImprovedDataPathResolver extends IlvDefaultDataPathResolver {
      private ImprovedDataPathResolver(String basename) {
        super(basename);
      }

      /**
       * @see ilog.views.maps.format.IlvDefaultDataPathResolver#resolvePath(java.lang.String)
       */
      Override
      public String resolvePath(String filename) {
        String s = super.resolvePath(filename);
        // if we did not find "filename" (perhaps because it is not a relative
        // path)
        if (s == null) {
          // lets try with any relative path that can be constructed from the
          // file name
          File f = new File(filename);
          String curString = null;
          Vector<String> parents = new Vector<String>();
          while (f != null) {
            String name = f.getName();
            if (name != null && name.length() > 0) {
              if (curString == null) {
                curString = name;
              } else {
                curString = name + File.separator + curString;
              }
              parents.insertElementAt(curString, 0);
            }
            f = f.getParentFile();
          }
          for (int i = 0; i < parents.size() && s == null; i++) {
            s = super.resolvePath(parents.get(i).toString());
          }
        }
        return s;
      }

      Override
      public URL resolveURL(String urlname) {
        URL url = super.resolveURL(urlname);
        try {
          if ("file".equals(url.getProtocol())) {// lets check if //$NON-NLS-1$
                                                 // the file exists
            InputStream i = url.openStream();
            i.close();
          }
        } catch (Exception se) {
          url = null;
        }
        // we did not find "urlname" (perhaps because the basename is a file)
        if (url == null) {
          String p = resolvePath(urlname);
          try {
            if (p != null && new File(p).exists()) {
              url = new File(p).toURI().toURL();
            }
          } catch (Exception se) {
            // ignore
          }
        }
        return url;
      }
    }

    JFileChooser fChooser;
    private final BaseDemo demo;
    private final IlvManagerView view;
    // JV-1725
    private boolean shouldAskSave;

    /**
     * Creates a loader for the specified view.
     * 
     * @param demo
     */
    public LoadIvlActionListener(BaseDemo demo) {
      this.demo = demo;
      this.view = demo.getView();
      // JV-1725
      shouldAskSave = true;
    }

    /**
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    Override
    public void actionPerformed(ActionEvent e) {
      // JV-1725
      if (askSave(demo, view) == JOptionPane.CANCEL_OPTION) {
        return;
      }
      if (fChooser == null) {
        fChooser = makeFileChooser();
      }
      boolean ok = false;
      while (!ok) {
        // JViews Bug Report 2005.189
        int result = fChooser.showDialog(view, IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.Title")); //$NON-NLS-1$
        if (result != JFileChooser.APPROVE_OPTION) {
          return;
        }
        if (fChooser.getSelectedFile().exists()) {
          ok = true;
        } else {
          JOptionPane.showMessageDialog(fChooser,
              IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.ErrorMessage"), //$NON-NLS-1$
              IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.ErrorTitle"), //$NON-NLS-1$
              JOptionPane.ERROR_MESSAGE);
        }
      }
      shouldAskSave = false;
      doLoad(fChooser.getSelectedFile());
      shouldAskSave = true;
    }

    IlvMapDataPathResolver dpr;

    /**
     * Loads the selected ivl file.
     * 
     * @param file
     *          selected file.
     */
    public void doLoad(File file) {
      // JV-1725
      if (shouldAskSave && askSave(demo, view) == JOptionPane.CANCEL_OPTION) {
        return;
      }
      String ilvFilename = file.getPath();
      // JViews Bug Report 2005.218
      if (dpr != null) {// remove old datapath resolver
        IlvMapDataPathManager.RemoveDataPathResolver(dpr);
      }
      // JViews Bug Report #2005.218
      // JViews Bug Report #2005.245
      dpr = new ImprovedDataPathResolver(new File(ilvFilename).getParent());
      IlvMapDataPathManager.AddDataPathResolver(dpr);
      doLoad(demo, file);
    }

    /**
     * Loads a map file in the specified application.
     * 
     * @param demo
     *          The application.
     * @param selected
     *          The file lot load.
     */
    public static void doLoad(final BaseDemo demo, File selected) {
      try {
        if (demo == null)
          return;
        if (!IlvMapInputStream.isIVL(selected.getAbsolutePath())) {
          String msg = "<html> " + selected.getName() + "<br> " + //$NON-NLS-1$//$NON-NLS-2$
              IlvMapUtil.getString(BaseDemo.class, "BaseDemo.NotAIVLFile") + " <br>" + //$NON-NLS-1$//$NON-NLS-2$
              IlvMapUtil.getString(BaseDemo.class, "BaseDemo.LoadAnyway") + " <br>" + //$NON-NLS-1$ //$NON-NLS-2$
              " </html>"; //$NON-NLS-1$
          JLabel label = new JLabel(msg);
          int rep = JOptionPane.showConfirmDialog(demo, label,
              IlvMapUtil.getString(BaseDemo.class, "BaseDemo.NotAIVLFileTitle"), //$NON-NLS-1$
              JOptionPane.YES_NO_OPTION);
          if (rep != JOptionPane.YES_OPTION)
            return;
        }
        IlvManagerView view = demo.getView();
        IlvManager manager = view.getManager();
        clearManager(view, true);
        String ilvFilename = selected.getPath();
        IlvMapInputStream input = new IlvMapInputStream(ilvFilename);
        input.setDocumentBase(selected.toURI().toURL());
        input.read(manager);
        // restore the visible area (Since JViews 8.7)
        boolean fit = true;
        Object o = manager.getNamedProperty(LAST_AREA);
        if (o instanceof IlvSingleValueNamedProperty) {
          Object a = ((IlvSingleValueNamedProperty) o).getValue();
          if (a instanceof IlvAreaOfInterest) {
            ((IlvAreaOfInterest) a).zoomTo(view);
            fit = false;
          }
        }
        if (fit) {
          view.fitTransformerToContent();
        }
        demo.setCurrentFile(ilvFilename);
        demo.setLoading(true);
        IlvCoordinateSystem cs = IlvCoordinateSystemProperty.GetCoordinateSystem(view.getManager());
        demo.getCoordinateSystemEditorPanel().setCoordinateSystem(cs);
        IlvDisplayPreferences pref = IlvDisplayPreferencesProperty.GetDisplayPreferences(view.getManager());
        demo.getDisplayPreferencesEditorPanel().setDisplayPreferences(pref);
        demo.setLoading(false);
        SwingUtilities.invokeLater(new Runnable() {
          Override
          public void run() {
            demo.setModified(false);
          }
        });
        view.repaint();
      } catch (IOException e1) {
        new IlvExceptionMessage(e1, e1.getMessage());
      } catch (IlvReadFileException e2) {
        new IlvExceptionMessage(e2, e2.getMessage());
      }
    }
  }

  /**
   * Clears the manager and all its properties.
   * 
   * @param view
   *          to retrieve the manager.
   * @param clearAll
   *          if true, will also clear all layers,map layers and data sources.
   */
  public static void clearManager(IlvManagerView view, boolean clearAll) {
    IlvManager manager = view.getManager();
    IlvMapLayerTreeModel model = IlvMapLayerTreeProperty.GetMapLayerTreeModel(manager);
    /* Correction for JV-1632 */
    /*
     * Calling model.clearAllObjects() is not necessary. We do it after the
     * "regular" cleaning below.
     */
    if (clearAll) {
      while (manager.getLayersCount() > 0) {
        IlvManagerLayer layer = manager.getManagerLayer(0);
        if (layer instanceof IlvTiledLayer) {
          IlvTileLoader loader = ((IlvTiledLayer) layer).getTileLoader();
          if (loader instanceof IlvThreadedTileLoader) {
            ((IlvThreadedTileLoader) loader).dispose();
          }
        }
        manager.removeLayer(0, false);
      }
      manager.removeNamedProperty(IlvMapLayerTreeProperty.NAME);
      manager.removeNamedProperty(IlvMapDataSourceProperty.NAME);
      manager.removeNamedProperty(IlvAreasOfInterestProperty.NAME);
      manager.removeNamedProperty(IlvMapStyleControllerProperty.NAME);
      manager.removeNamedProperty(IlvMapLabelerProperty.NAME);
      manager.removeNamedProperty(IlvMapAnnotationProperty.NAME);
      manager.removeNamedProperty(IlvMapTileGeneratorConstants.TILE_SIZE_PROPERTY);
      manager.removeNamedProperty(IlvMapTileGeneratorConstants.SCALE_LEVELS_PROPERTY);
      // remove the temporary files
      String dialogTitle = IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.TitleClearingDialog"); //$NON-NLS-1$
      String dialogMessage = IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.ClearingMessageDialog"); //$NON-NLS-1$
      final Frame frame = JOptionPane.getFrameForComponent(view);
      final JDialog clearDialog = new JDialog(frame, dialogTitle, true);
      clearDialog.setUndecorated(true);
      clearDialog.getContentPane().add(new JLabel(dialogMessage));
      clearDialog.pack();
      Point loc = new Point((int) (frame.getBounds().getCenterX() - clearDialog.getWidth() / 2.),
          (int) (frame.getBounds().getCenterY() - clearDialog.getHeight() / 2.));
      clearDialog.setLocation(loc);
      clearDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
      clearDialog.setResizable(false);
      final Thread clearThread;
      clearThread = new Thread("ClearThread") { //$NON-NLS-1$
        Override
        public void run() {
          IlvRasterTemporaryFileManager.removeAllFiles();
          SwingUtilities.invokeLater(new Runnable() {
            Override
            public void run() {
              clearDialog.setVisible(false);
            }
          });
        }
      };
      clearDialog.getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
      clearThread.setPriority(Thread.MIN_PRIORITY);
      clearThread.start();
      double t0 = System.currentTimeMillis();
      while (clearThread.isAlive() && System.currentTimeMillis() < t0 + 1000) {
        try {
          Thread.sleep(250);
        } catch (InterruptedException e) {
          // empty
        }
      }
      if (clearThread.isAlive()) {
        clearDialog.setVisible(true);
      }
    }
    model.clearAllObjects();
    // clear remaining file mappings
    IlvMapUtil.freeMemoryNow(null);
  }

  static Window getWindowForComponent(Component parentComponent) throws HeadlessException {
    if (parentComponent == null)
      return null;
    if (parentComponent instanceof Frame || parentComponent instanceof Dialog)
      return (Window) parentComponent;
    return getWindowForComponent(parentComponent.getParent());
  }

  /**
   * Action listener that clears a manager.
   */
  public static class ClearManagerActionListener implements ActionListener {
    private IlvManagerView view;
    private BaseDemo demo;

    /**
     * Creates a clear listener for the specified view.
     * 
     * @param demo
     * @param view
     */
    public ClearManagerActionListener(BaseDemo demo, IlvManagerView view) {
      this.view = view;
      this.demo = demo;
    }

    /**
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    Override
    public void actionPerformed(ActionEvent e) {
      // JV-1725
      if (askSave(demo, view) == JOptionPane.CANCEL_OPTION) {
        return;
      }
      // stopping threads
      if (demo instanceof MapBuilder) {
        MapBuilder mb = (MapBuilder) demo;
        ImportAction[] importActions = mb.getAllImportActions();
        for (int i = 0; i < importActions.length; i++) {
          importActions[i].getStopButton().stopAllThreads();
        }
      }

      clearManager(view, true);
      demo.getCoordinateSystemEditorPanel().setCoordinateSystem(null); // fix
                                                                       // for
                                                                       // JV-1558
      view.fitTransformerToContent();
      view.getManager().reDraw();
      if (demo != null) {
        demo.setCurrentFile(null);
        SwingUtilities.invokeLater(new Runnable() {
          Override
          public void run() {
            demo.setModified(false);
          }
        });
      }
    }
  }

  /**
   * Action listener that saves an ivl file.
   */
  public static class SaveIvlActionListener implements ActionListener {
    final BaseDemo demo;
    private final IlvManagerView view;
    private boolean saved;
    JFileChooser fileChooser;
    final boolean useDemoCurrentFile;
    JCheckBox mmode = new JCheckBox(IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.ModeToggleLabel")); //$NON-NLS-1$
    JCheckBox bmode = new JCheckBox(IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.BinaryModeToggleLabel")); //$NON-NLS-1$

    /**
     * @return Returns the view.
     */
    IlvManagerView getView() {
      return view;
    }

    /**
     * @param saved
     *          The saved to set.
     */
    void setSaved(boolean saved) {
      this.saved = saved;
    }

    /**
     * @return Returns the saved.
     */
    public boolean isSaved() {
      return saved;
    }

    /**
     * Creates a save listener for the specified demo.
     * 
     * @param demo
     *          application registered.
     * @param useDemoCurrentFile
     *          indicates if saving should use the demo last opened filename.
     */
    public SaveIvlActionListener(BaseDemo demo, boolean useDemoCurrentFile) {
      this.demo = demo;
      this.view = demo.getView();
      this.useDemoCurrentFile = useDemoCurrentFile;
    }

    /**
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    boolean binary;

    /**
     * @inheritDoc
     */
    Override
    public void actionPerformed(ActionEvent e) {
      try {
        saved = false;
        String ilvFilenameTemp = null;
        boolean themeOnly = getView().getManager()
            .getNamedProperty(IlvMapOutputStream.CONTENTS_NOT_SAVED_PROPERTY_NAME) != null;
        if (useDemoCurrentFile) {
          ilvFilenameTemp = demo.getCurrentFile();
        }
        if (ilvFilenameTemp == null) {
          mmode.setSelected(themeOnly);
          bmode.setSelected(binary);
          if (fileChooser == null) {
            fileChooser = makeFileChooser();
            JPanel accessory = new JPanel();
            accessory.setLayout(new IlvVerticalFlowLayout());
            accessory.add(mmode);
            accessory.add(bmode);
            fileChooser.setAccessory(accessory);
          }
          int result = fileChooser.showSaveDialog(view);
          if (result != JFileChooser.APPROVE_OPTION) {
            return;
          }
          File selected = fileChooser.getSelectedFile();
          // long time = System.currentTimeMillis();
          ilvFilenameTemp = selected.getPath();
          themeOnly = mmode.isSelected();
          binary = bmode.isSelected();
        }
        int ans = JOptionPane.YES_OPTION;
        // JV-4849
        final String imgFilename;
        int len = IlvMapOutputStream.getFileSuffix().length();
        if (!ilvFilenameTemp.substring(ilvFilenameTemp.length() - len)
            .equalsIgnoreCase(IlvMapOutputStream.getFileSuffix())) {
          imgFilename = ilvFilenameTemp + IlvMapOutputStream.getImageFileSuffix();
          ilvFilenameTemp = ilvFilenameTemp + IlvMapOutputStream.getFileSuffix();
        } else {
          imgFilename = ilvFilenameTemp.substring(0, ilvFilenameTemp.length() - len)
              + IlvMapOutputStream.getImageFileSuffix();
        }
        if (!useDemoCurrentFile && new File(ilvFilenameTemp).exists()) {
          ans = JOptionPane.showConfirmDialog(view,
              IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.MessageConfirmOverwrite"), //$NON-NLS-1$
              IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.TitleConfirmOverwrite"), //$NON-NLS-1$
              JOptionPane.YES_NO_CANCEL_OPTION);
        }
        if (ans == JOptionPane.YES_OPTION) {
          final String ilvFilename = ilvFilenameTemp;
          final boolean writeObj = !themeOnly;
          String dialogTitle = IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.TitleSavingDialog"); //$NON-NLS-1$
          String dialogMessage = IlvMapUtil.getString(IvlFileManager.class, "IvlFileManager.SavingMessageDialog"); //$NON-NLS-1$
          final Frame frame = JOptionPane.getFrameForComponent(view);
          JLabel label = new JLabel(dialogMessage);
          label.setHorizontalAlignment(SwingConstants.CENTER);
          final JOptionPane optionPane = new JOptionPane(label, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_OPTION, null,
              new String[] { UIManager.getString("OptionPane.cancelButtonText") }); //$NON-NLS-1$
          optionPane.setBorder(new EmptyBorder(10, 10, 10, 10));
          final JDialog saveDialog = new JDialog(frame, dialogTitle, true);
          Point loc = new Point((int) (frame.getBounds().getCenterX() - saveDialog.getWidth() / 2.),
              (int) (frame.getBounds().getCenterY() - saveDialog.getHeight() / 2.));
          saveDialog.setLocation(loc);
          // saveDialog.setUndecorated(true);
          // saveDialog.setLayout(new BorderLayout());
          saveDialog.getContentPane().add(optionPane);
          saveDialog.pack();
          saveDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
          saveDialog.setResizable(false);
          final IlvMapOutputStream mapOut = new IlvMapOutputStream(ilvFilename, binary);
          mapOut.setWritingObjects(writeObj);
          // save the visible area (Since JViews 8.7)
          IlvAreaOfInterest aoe = IlvJAreaOfInterestPanel.createLocationFromView(getView(), 0, false);
          IlvSingleValueNamedProperty aoep = new IlvSingleValueNamedProperty(LAST_AREA, aoe);
          getView().getManager().setNamedProperty(aoep);
          // end
          final Thread writeThread = new Thread("WriteThread") { //$NON-NLS-1$
            Override
            public void run() {
              boolean deleteFiles = false;
              try {
                // Wait a bit before actually saving (refresh pb(?))
                Thread.sleep(500);
                mapOut.write(getView().getManager());
                //
              } catch (IOException e1) {
                // was interrupted during write
                deleteFiles = true;
                mapOut.setWritingObjects(false);
                try {
                  mapOut.closeImageStream();
                } catch (IOException exx) {
                  exx.printStackTrace();
                }
              } catch (InterruptedException e2) {
                // was interrupted during sleep
              } catch (Exception e3) {
                e3.printStackTrace();
                new IlvExceptionMessage(e3, null);
              } finally {
                try {
                  mapOut.flush();
                  mapOut.close();
                } catch (IOException e4) {
                  // ignore.
                }
                if (deleteFiles) {
                  new File(ilvFilename).delete();
                  new File(imgFilename).delete();
                }
              }
              setSaved(true);
              SwingUtilities.invokeLater(new Runnable() {
                Override
                public void run() {
                  demo.setModified(false);
                }
              });
              demo.setCurrentFile(ilvFilename);
              if (saveDialog.isVisible()) {
                saveDialog.dispose();
              }
            }
          };
          saveDialog.getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
          optionPane.addPropertyChangeListener(new PropertyChangeListener() {
            Override
            public void propertyChange(PropertyChangeEvent ev) {
              String prop = ev.getPropertyName();
              if (saveDialog.isVisible() && (ev.getSource() == optionPane)
                  && (prop.equals(JOptionPane.VALUE_PROPERTY))) {
                try {
                  // ivlFos.close();
                  mapOut.close();
                } catch (Exception e6) {
                  new IlvExceptionMessage(e6, null);
                }
                saveDialog.setVisible(false);
              }
            }
          });
          writeThread.start();
          saveDialog.setVisible(true);
        }
      } catch (IOException e1) {
        new IlvExceptionMessage(e1, null);
      }
    }
  }
}