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

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

import ilog.views.IlvManagerView;
import ilog.views.maps.IlvCoordinate;
import ilog.views.maps.IlvMapUtil;
import ilog.views.maps.beans.IlvJCoordinateSystemEditorPanel;
import ilog.views.maps.datasource.IlvMapDataSource;
import ilog.views.maps.datasource.IlvShapeDataSource;
import ilog.views.maps.datasource.IlvTiledShapeDataSource;
import ilog.views.maps.format.shapefile.IlvDBFReader;
import ilog.views.maps.format.shapefile.IlvSHPReader;
import ilog.views.maps.format.shapefile.IlvShapeFileIndex;
import ilog.views.maps.format.shapefile.IlvShapeFileTiler;
import ilog.views.maps.raster.datasource.IlvThreadMonitoringData;
import ilog.views.maps.srs.coordsys.IlvCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.maps.srs.wkt.IlvWKTCoordinateSystemFactory;
import shared.JLayerSplitPanel;

/**
 * Class that manages ESRI/Shape import action.
 */
public class ShapeLoadAction extends ImportAction {
  JCheckBox tiled;
  IlvJCoordinateSystemEditorPanel panel;
  JTabbedPane tp;
  JLayerSplitPanel filterPanel;
  JCheckBox filterButton;

  /**
   * Creates an action for the specified view
   * 
   * @param view
   *          view to add map data to.
   */
  public ShapeLoadAction(IlvManagerView view) {
    super(view);
  }

  /**
   * @see plugins.ImportAction#getSubDirectory()
   */
  Override
  protected String getSubDirectory() {
    return IlvMapUtil.getString(getClass(), "ShapeLoadAction.CDDirectory"); //$NON-NLS-1$
  }

  /**
   * @see plugins.ImportAction#getDataSources(java.lang.String[])
   */
  Override
  public Enumeration<IlvMapDataSource> getDataSources(String fileNames[]) throws IOException {
    Vector<IlvMapDataSource> src = new Vector<IlvMapDataSource>();
    for (int i = 0; i < fileNames.length; i++) {
      IlvMapDataSource source;
      if (tiled.isSelected()) {
        IlvTiledShapeDataSource tiledSource = new IlvTiledShapeDataSource(fileNames[i], true);
        if (filterButton.isSelected()) {
          tiledSource.setFilter(filterPanel.createFilter());
        }
        boolean created = false;
        if (tiledSource.getIdxFilename() == null) {
          // offer to create an index file
          int res = JOptionPane.showConfirmDialog(getView(),
              IlvMapUtil.getString(ShapeLoadAction.class, "ShapeLoadAction.CreateIndexMessage"), //$NON-NLS-1$
              IlvMapUtil.getString(ShapeLoadAction.class, "ShapeLoadAction.CreateIndexTitle"), //$NON-NLS-1$
              JOptionPane.YES_NO_OPTION);
          if (res == JOptionPane.YES_OPTION) {
            String idxFileName = tiledSource.getShpFilename().substring(0, tiledSource.getShpFilename().length() - 4)
                + ".idx"; //$NON-NLS-1$
            created = createIndex(tiledSource.getShpFilename(), idxFileName, tiledSource.getShxFilename());
            tiledSource.setIdxFilename(idxFileName);
          }
        } else {
          created = true;
        }
        if (!created) {
          continue;
        }
        source = tiledSource;
      } else {
        source = new IlvShapeDataSource(fileNames[i], true);
        if (filterButton.isSelected()) {
          ((IlvShapeDataSource) source).setFilter(filterPanel.createFilter());
        }
      }
      if (panel != null && panel.isVisible())
        source.setCoordinateSystem(panel.getCoordinateSystem());
      source.setManager(view.getManager());
      source.setName(getFormatName() + " (" + new File(fileNames[i]).getName() + ")"); //$NON-NLS-1$//$NON-NLS-2$
      src.add(source);
    }
    return src.elements();
  }

  /**
   * @see plugins.ImportAction#getDataSources(java.lang.String[])
   */
  Override
  public Enumeration<IlvMapDataSource> getDataSources(URL urls[]) {
    Vector<IlvMapDataSource> src = new Vector<IlvMapDataSource>();
    for (int i = 0; i < urls.length; i++) {
      IlvShapeDataSource source = new IlvShapeDataSource(urls[i], true);
      if (panel != null && panel.isVisible())
        source.setCoordinateSystem(panel.getCoordinateSystem());
      if (filterButton.isSelected()) {
        source.setFilter(filterPanel.createFilter());
      }
      source.setManager(view.getManager());
      source.setName(getFormatName() + " (" + urls[i].toString() + ")"); //$NON-NLS-1$//$NON-NLS-2$
      src.add(source);
    }
    return src.elements();
  }

  private static String INDEXING = IlvMapUtil.getString(ShapeLoadAction.class, "ShapeLoadAction.IndexingTask"); //$NON-NLS-1$

  /**
   * Creates the index file.
   * 
   * @param shpFileName
   *          shape file name to read.
   * @param indexFileName
   *          index file name to create.
   * @param shxFileName
   *          SHX file name to read.
   * @return <code>true</code> if the index file has been created successfully.
   * @throws IOException
   */
  public boolean createIndex(String shpFileName, String indexFileName, String shxFileName) throws IOException {
    if (shxFileName == null) {
      JOptionPane.showMessageDialog(getView(),
          IlvMapUtil.getString(ShapeLoadAction.class, "ShapeLoadAction.MissingSHXFile")); //$NON-NLS-1$
      return false;
    }
    IlvShapeFileIndex index = new IlvShapeFileIndex(shxFileName);
    IlvCoordinate UL = index.getUpperLeftCorner();
    IlvCoordinate LR = index.getLowerRightCorner();
    index.dispose();
    Frame f = null;
    if (SwingUtilities.windowForComponent(getView()) instanceof Frame) {
      f = (Frame) SwingUtilities.windowForComponent(getView());
    }
    TilingParameterDialog dial = new TilingParameterDialog(f,
        IlvMapUtil.getString(ShapeLoadAction.class, "ShapeLoadAction.TilingParametersTitle"), UL, LR); //$NON-NLS-1$
    // SetLocation(dial, this);
    dial.setVisible(true);
    if (!dial.isOk())
      return false;
    IlvSHPReader shpReader = new IlvSHPReader(shpFileName);
    IlvCoordinate ul = shpReader.getUpperLeftCorner();
    IlvCoordinate lr = shpReader.getLowerRightCorner();
    shpReader.dispose();
    double width = lr.x - ul.x;
    double height = ul.y - lr.y;
    int tileColumns = dial.getTileColumns();
    int tileRows = dial.getTileRows();
    double tileWidth = width / tileColumns;
    double tileHeight = height / tileRows;
    IlvShapeFileTiler tiler = new IlvShapeFileTiler(shpFileName, shxFileName, indexFileName, tileWidth, tileHeight);
    Object activity = new Object();
    IlvThreadMonitoringData monitorData = new IlvThreadMonitoringData(getMonitor(), activity,
        INDEXING + " " + new File(shpFileName).getName(), 0, 100); //$NON-NLS-1$
    // pbar.setMaximum(tiler.getFeatureCount());
    // waitCursor();k
    int totalCount = tiler.getFeatureCount();
    while (tiler.getNextFeature() != null) {
      // updateProgressBar(tiler.getCurrentCount());
      monitorData.updateProgress((int) (tiler.getCurrentCount() / (double) totalCount * 100));
      tiler.addInfo();
    }
    monitorData.updateProgress(100);
    tiler.close();
    // defaultCursor();
    return true;
  }

  /**
   * @see plugins.ImportAction#getExtensions()
   */
  Override
  public String[] getExtensions() {
    return new String[] { ".shp" }; //$NON-NLS-1$
  }

  /**
   * Returns a panel to select the coordinate system.
   * 
   * @see plugins.ImportAction#getAccessory()
   */
  Override
  public JComponent getAccessory() {
    // JV-3352
    if (tp == null) {
      JPanel p = new JPanel();
      panel = new IlvJCoordinateSystemEditorPanel();
      panel.setCoordinateSystem(IlvGeographicCoordinateSystem.WGS84);
      panel.setAdvancedPanelsVisible(false);
      p.setLayout(new BorderLayout());
      tiled = new JCheckBox(IlvMapUtil.getString(getClass(), "ShapeLoadAction.TileButtonLabel")); //$NON-NLS-1$
      final JCheckBox csButton = new JCheckBox(
          IlvMapUtil.getString(getClass(), "ShapeLoadAction.SetProjectionButtonLabel"), true); //$NON-NLS-1$
      panel.setVisible(csButton.isSelected());
      p.add(tiled, BorderLayout.NORTH);
      p.add(panel, BorderLayout.CENTER);
      p.add(csButton, BorderLayout.SOUTH);
      csButton.addActionListener(new ActionListener() {
        Override
        public void actionPerformed(ActionEvent e) {
          panel.setVisible(csButton.isSelected());
        }
      });
      /* NOT WORKING ATM */
      // csButton.setEnabled(false);
      // panel.setEnabled(false);
      tp = new JTabbedPane();
      JPanel filterContainer = new JPanel(new BorderLayout());
      filterPanel = new JLayerSplitPanel(false, null);
      filterButton = new JCheckBox(IlvMapUtil.getString(getClass(), "ShapeLoadAction.SetFilterButtonLabel"), false); //$NON-NLS-1$
      filterButton.setEnabled(false);
      filterContainer.add(filterButton, BorderLayout.NORTH);
      filterContainer.add(filterPanel, BorderLayout.CENTER);
      tp.addTab(IlvMapUtil.getString(getClass(), "ShapeLoadAction.GeneralParameters"), new JScrollPane(p)); //$NON-NLS-1$
      tp.addTab(IlvMapUtil.getString(getClass(), "ShapeLoadAction.FilterParameters"), filterContainer); //$NON-NLS-1$
    }
    return tp;
  }

  static final IlvWKTCoordinateSystemFactory fact = new IlvWKTCoordinateSystemFactory();

  /**
   * When selected file changes, try to see if a ".prj" file exist to read the
   * coordinate system from.
   * 
   * @param file
   */
  Override
  public void selectedFileChanged(File file) {
    super.selectedFileChanged(file);
    String prjName = null;
    if (file != null) {
      String name = file.getPath();
      if (name.endsWith(".shp")) { //$NON-NLS-1$
        prjName = name.substring(0, name.length() - 3) + "prj";//$NON-NLS-1$
      }
      if (name.endsWith(".SHP")) {//$NON-NLS-1$
        prjName = name.substring(0, name.length() - 3) + "PRJ";//$NON-NLS-1$
      }
    }
    if (prjName != null) {
      File f = new File(prjName);
      try {
        int len = (int) f.length();
        if (len < 100000 && len > 0) {
          byte b[] = new byte[len];
          FileInputStream in = new FileInputStream(f);
          try {
            in.read(b);
          } finally {
            in.close();
          }
          String projWkt = new String(b);
          IlvCoordinateSystem system = fact.fromWKT(projWkt);
          panel.setCoordinateSystem(system);
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    if (filterButton != null) {
      filterButton.setSelected(false);
    }
    if (tp != null) {
      if (file != null) {
        String dbfName = null;
        String name = file.getPath();
        if (name.endsWith(".shp")) { //$NON-NLS-1$
          dbfName = name.substring(0, name.length() - 3) + "dbf";//$NON-NLS-1$
        }
        if (name.endsWith(".SHP")) {//$NON-NLS-1$
          dbfName = name.substring(0, name.length() - 3) + "DBF";//$NON-NLS-1$
        }
        try {
          IlvDBFReader r = new IlvDBFReader(dbfName);
          try {
            filterPanel.setProperties(r.getAttributeInfo());
          } finally {
            r.dispose();
          }
          filterButton.setEnabled(true);
        } catch (IOException e) {
          filterPanel.setProperties(null);
          filterButton.setEnabled(false);
        }
      } else {
        filterPanel.setProperties(null);
        filterButton.setEnabled(false);
      }
    }
  }

  /**
   * @see plugins.ImportAction#getFormatName()
   */
  Override
  public String getFormatName() {
    return IlvMapUtil.getString(getClass(), "ShapeLoadAction.FormatName"); //$NON-NLS-1$
  }
}