/*
 * 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.
 */
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.filechooser.FileFilter;

import ilog.views.IlvRect;
import ilog.views.io.IlvReadFileException;
import ilog.views.maps.IlvDMSCoordinateFormatter;
import ilog.views.maps.beans.editor.IlvCoordinatePanelFactory;
import ilog.views.maps.servlet.IlvManagerTiler;
import ilog.views.maps.srs.coordtrans.IlvCoordinateTransformationException;
import ilog.views.util.IlvProductUtil;
import ilog.views.util.servlet.tiling.IlvFileTileManager;

/**
 * Code sample to show how to use the <code>IlvManagerTiler</code> class to
 * generate tiled images of a map for thin client use.
 * 
 * @author eaullas
 * 
 */
public class TileGenerator extends JFrame {
  JTextField mapFilenameField;
  JTextField outputDirField;
  JTextField diskSizeField;
  JCheckBox specifyArea;
  IlvManagerTiler managerTiler;
  JFileChooser mapFileChooser;
  JFileChooser outputDirChooser;
  JComboBox<String> formatCombo;
  private IlvCoordinatePanelFactory.CoordRectangleInputPanel coordPanel;

  /**
   * Creates a tile generator
   * 
   * @param outputDir
   *          default output directory(or null)
   * @param map
   *          default map name (or null)
   * @param diskLimit
   *          disk limit in MB.
   * @throws HeadlessException
   */
  public TileGenerator(String outputDir, String map, int diskLimit) throws HeadlessException {
    super();
    initGUI(outputDir, map, diskLimit);
    setTitle("Thin client tile generator"); //$NON-NLS-1$
    setResizable(false);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pack();
  }

  private void initGUI(String outputDir, String map, int diskLimit) {
    JLabel mapFilenameLabel = new JLabel("Map filename"); //$NON-NLS-1$
    JLabel outputDirLabel = new JLabel("Output directory"); //$NON-NLS-1$
    JLabel diskSizeLabel = new JLabel("Disk size limit"); //$NON-NLS-1$
    JLabel MBLabel = new JLabel("MBytes"); //$NON-NLS-1$
    mapFilenameField = new JTextField(25);
    if (map != null) {
      mapFilenameField.setText(map);
    }
    outputDirField = new JTextField(25);
    if (outputDir != null) {
      outputDirField.setText(outputDir);
    }
    diskSizeField = new JTextField(5);
    diskSizeField.setText("" + diskLimit); //$NON-NLS-1$
    Dimension buttonDimension = new Dimension(25, 20);
    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new GridBagLayout());
    mainPanel.setBorder(new CompoundBorder(new EmptyBorder(3, 3, 3, 3), new EtchedBorder()));
    mainPanel.add(mapFilenameLabel, new GridBagConstraints(0, 0, 2, 1, 0, 0, GridBagConstraints.LINE_START,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    mainPanel.add(mapFilenameField, new GridBagConstraints(2, 0, 2, 1, 0, 0, GridBagConstraints.CENTER,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    JButton filenameChooserButton = new JButton("..."); //$NON-NLS-1$
    filenameChooserButton.setPreferredSize(buttonDimension);
    filenameChooserButton.setToolTipText("Choose map file"); //$NON-NLS-1$
    filenameChooserButton.addActionListener(new ActionListener() {
      Override
      public void actionPerformed(ActionEvent e) {
        if (mapFileChooser == null) {
          mapFileChooser = new JFileChooser();
          mapFileChooser.setMultiSelectionEnabled(false);
          FileFilter filter = new FileFilter() {
            Override
            public boolean accept(File pathname) {
              boolean accept = pathname.isDirectory() || pathname.getName().endsWith("ivl") //$NON-NLS-1$
                  || pathname.getName().endsWith("IVL"); //$NON-NLS-1$
              return accept;
            }

            Override
            public String getDescription() {
              return "JViews maps .ivl file"; //$NON-NLS-1$
            }
          };
          mapFileChooser.setFileFilter(filter);
        }
        int result = mapFileChooser.showDialog(TileGenerator.this, "Open map file"); //$NON-NLS-1$
        if (result == JFileChooser.APPROVE_OPTION) {
          mapFileChooser.getSelectedFile();
          mapFilenameField.setText(mapFileChooser.getSelectedFile().getPath());
        }
      }
    });
    mainPanel.add(filenameChooserButton, new GridBagConstraints(4, 0, 1, 1, 0, 0, GridBagConstraints.CENTER,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    mainPanel.add(outputDirLabel, new GridBagConstraints(0, 1, 2, 1, 0, 0, GridBagConstraints.LINE_START,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    mainPanel.add(outputDirField, new GridBagConstraints(2, 1, 2, 1, 0, 0, GridBagConstraints.CENTER,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    JButton outputDirChooserButton = new JButton("..."); //$NON-NLS-1$
    outputDirChooserButton.setPreferredSize(buttonDimension);
    outputDirChooserButton.setToolTipText("Choose output folder"); //$NON-NLS-1$
    outputDirChooserButton.addActionListener(new ActionListener() {
      Override
      public void actionPerformed(ActionEvent e) {
        if (outputDirChooser == null) {
          outputDirChooser = new JFileChooser();
          outputDirChooser.setMultiSelectionEnabled(false);
          outputDirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        }
        int result = outputDirChooser.showDialog(TileGenerator.this, "Select output folder"); //$NON-NLS-1$
        if (result == JFileChooser.APPROVE_OPTION) {
          outputDirChooser.getSelectedFile();
          outputDirField.setText(outputDirChooser.getSelectedFile().getPath());
        }
      }
    });
    mainPanel.add(outputDirChooserButton, new GridBagConstraints(4, 1, 1, 1, 0, 0, GridBagConstraints.CENTER,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    mainPanel.add(diskSizeLabel, new GridBagConstraints(1, 2, 1, 1, 0, 0, GridBagConstraints.LINE_START,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    mainPanel.add(diskSizeField, new GridBagConstraints(2, 2, 1, 1, 0, 0, GridBagConstraints.LINE_START,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    mainPanel.add(MBLabel, new GridBagConstraints(3, 2, 1, 1, 0, 0, GridBagConstraints.LINE_START,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    specifyArea = new JCheckBox("Specify area of interest"); //$NON-NLS-1$
    mainPanel.add(specifyArea, new GridBagConstraints(1, 3, 1, 1, 0, 0, GridBagConstraints.CENTER,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    specifyArea.addActionListener(new ActionListener() {
      Override
      public void actionPerformed(ActionEvent e) {
        coordPanel.setEnabled(specifyArea.isSelected());
      }
    });
    formatCombo = new JComboBox<String>(new String[] { "JPEG", "PNG" }); //$NON-NLS-1$ //$NON-NLS-2$
    JLabel formatLabel = new JLabel("Image format"); //$NON-NLS-1$
    JPanel panel = new JPanel();
    panel.add(formatLabel);
    panel.add(formatCombo);
    mainPanel.add(panel, new GridBagConstraints(3, 3, 1, 1, 0, 0, GridBagConstraints.LINE_START,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    coordPanel = IlvCoordinatePanelFactory.createCoordRectangleInputPanel(null, new IlvDMSCoordinateFormatter());
    coordPanel.setLatLonMax(Math.PI / 2, Math.PI);
    coordPanel.setLatLonMin(-Math.PI / 2, -Math.PI);
    coordPanel.setEnabled(specifyArea.isSelected());
    mainPanel.add(coordPanel, new GridBagConstraints(0, 4, 5, 2, 0, 0, GridBagConstraints.CENTER,
        GridBagConstraints.NONE, new Insets(5, 3, 5, 3), 0, 0));
    JButton generateButton = new JButton("Generate tiles"); //$NON-NLS-1$
    generateButton.addActionListener(new ActionListener() {
      Override
      public void actionPerformed(ActionEvent e) {
        try {
          boolean result = generateTiles();
          if (result) {
            String message = "Tile generation completed."; //$NON-NLS-1$
            JOptionPane.showMessageDialog(TileGenerator.this, message, "Completed", //$NON-NLS-1$
                JOptionPane.INFORMATION_MESSAGE);
          }
        } catch (RuntimeException e1) {
          String message = "This map does not contain required thin client parameters." + //$NON-NLS-1$
          "\nPlease use JViews MapBuilder to set these parameters."; //$NON-NLS-1$
          JOptionPane.showMessageDialog(TileGenerator.this, message, "Missing parameters", JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
        }
      }
    });
    mainPanel.add(generateButton, new GridBagConstraints(0, 6, 5, 1, 0, 0, GridBagConstraints.CENTER,
        GridBagConstraints.NONE, new Insets(15, 3, 5, 3), 0, 0));
    getContentPane().add(mainPanel);
  }

  /**
   * 
   * 
   */
  private boolean generateTiles() {
    String mapFilename = mapFilenameField.getText();
    if (mapFilename == null || !(new File(mapFilename).exists())) {
      JOptionPane.showMessageDialog(this, "Map file not found. Please check filename", //$NON-NLS-1$
          "File not found", JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
      return false;
    }
    String outputFolder = outputDirField.getText();
    if (outputFolder == null || outputFolder.length() == 0) {
      JOptionPane.showMessageDialog(this, "Output folder not set. Please check output folder.", //$NON-NLS-1$
          "Output folder not set", JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
      return false;
    }
    // check if folder is not empty
    File folder = new File(outputFolder);
    if (folder.exists() && folder.listFiles().length > 0) {
      int result = JOptionPane.showConfirmDialog(this,
          "Output folder is not empty. Some files might be overwritten." + //$NON-NLS-1$
              " \nDo you want to use this folder anyway ?", //$NON-NLS-1$
          "Output folder not empty", JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
      if (!(result == JOptionPane.YES_OPTION)) {
        return false;
      }
    }
    int diskSize = 100;
    try {
      diskSize = Integer.parseInt(diskSizeField.getText());
    } catch (NumberFormatException e) {
      JOptionPane.showMessageDialog(this, "Incorrect disk size limit. Please enter a positive integer", //$NON-NLS-1$
          "Incorrect value", JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
      return false;
    }
    try {
      if (managerTiler == null) {
        managerTiler = new IlvManagerTiler();
      }
      if (formatCombo.getSelectedIndex() == 0) {
        managerTiler.setImageFormat(IlvFileTileManager.JPEG_FORMAT);
      } else {
        managerTiler.setImageFormat(IlvFileTileManager.PNG_FORMAT);
      }
      IlvRect area = null;
      if (specifyArea.isSelected()) {
        float lonMin = (float) coordPanel.getLonMin();
        float lonMax = (float) coordPanel.getLonMax();
        float latMin = (float) coordPanel.getLatMin();
        float latMax = (float) coordPanel.getLatMax();
        area = new IlvRect(lonMin, latMin, lonMax - lonMin, latMax - latMin);
      }
      try {
        managerTiler.createTiles(mapFilename, area, new File(outputFolder), diskSize * 1024 * 1024);
      } catch (IlvCoordinateTransformationException e) {
        // can not happen since no specified region
      }
    } catch (IOException e) {
      e.printStackTrace();
    } catch (IlvReadFileException e) {
      e.printStackTrace();
    }
    return true;
  }

  /**
   * Main method.
   * 
   * @param args
   *          ignored
   */
  public static void main(final String[] args) {
    // This sample uses JViews Maps features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Perforce JViews Maps Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(IlvProductUtil.JViews_Maps_Deployment);

    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      Override
      public void run() {
        String rep = null;
        String map = null;
        int diskLimit = 100;
        if (args.length > 0) {
          rep = args[0];
        }
        if (args.length > 1) {
          map = args[1];
        }
        if (args.length > 2) {
          try {
            diskLimit = Integer.parseInt(args[2]);
          } catch (NumberFormatException ex) {
            ex.printStackTrace();
          }
        }

        TileGenerator frame = new TileGenerator(rep, map, diskLimit);
        frame.setVisible(true);
      }
    });
  }
}