/*
 * 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.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import ilog.views.IlvGraphic;
import ilog.views.IlvManagerView;
import ilog.views.maps.IlvAttributeInfoProperty;
import ilog.views.maps.IlvAttributeProperty;
import ilog.views.maps.IlvFeatureAttributeProperty;
import ilog.views.maps.IlvMapLayerTreeProperty;
import ilog.views.maps.IlvMapUtil;
import ilog.views.maps.beans.IlvFeatureSelectorPanel;
import ilog.views.maps.beans.IlvMapLayer;
import ilog.views.maps.beans.IlvMapLayerTreeModel;
import ilog.views.maps.datasource.DataSourceEvent;
import ilog.views.maps.datasource.DataSourceListener;
import ilog.views.maps.datasource.IlvMapDataSource;
import ilog.views.maps.format.IlvDefaultTilableDataSource;
import ilog.views.maps.raster.datasource.IlvThreadMonitoringData;
import ilog.views.maps.theme.IlvMapStyleController;
import ilog.views.maps.theme.IlvMapStyleControllerProperty;
import nodefense.S57DefLess;

/**
 * Class that manages S57 import action.
 * 
 * @since JViews 8.0
 */
public class S57LoadAction extends ImportAction {
  // JV-4113
  /* deal with the scale minimum data */
  private static final class ScaleMimimumManager implements DataSourceListener {
    Override
    public void dataSourceLoaded(DataSourceEvent event) {
      IlvMapDataSource ds = event.getDataSource();
      // The main S57 layer
      IlvMapLayer ml = ds.getInsertionLayer();
      IlvMapLayerTreeModel model = IlvMapLayerTreeProperty.GetMapLayerTreeModel(ml.getManager());
      // The layer style controller
      IlvMapStyleController themeControl = IlvMapStyleControllerProperty.GetMapStyleController(ml.getManager());
      // Get all the layers created
      IlvMapLayer layers[] = model.getChildren(ml);
      String invisible = IlvMapUtil.getString(S57LoadAction.class, "S57LoadAction.InvisibleStyleName"); //$NON-NLS-1$
      String visible = IlvMapUtil.getString(S57LoadAction.class, "S57LoadAction.VisibleStyleName"); //$NON-NLS-1$
      for (int il = 0; il < layers.length; il++) {
        IlvAttributeInfoProperty p = layers[il].getStyle().getAttributeInfo();
        String scaleMinAttributeName = "Scale minimum"; //$NON-NLS-1$
        String scaleMaxAttributeName = "Scale maximum"; //$NON-NLS-1$
        if (hasAttribute(p, scaleMinAttributeName) || hasAttribute(p, scaleMaxAttributeName)) {
          // yes - get the first graphic in the layer
          if (layers[il].getManagerLayer() != null && layers[il].getManagerLayer().getCardinal() > 0) {
            IlvGraphic g = layers[il].getManagerLayer().getObject(0);
            // get its attributes
            IlvFeatureAttributeProperty att = (IlvFeatureAttributeProperty) g
                .getNamedProperty(IlvAttributeProperty.NAME);
            if (p != null) {
              String smin = getAttributeValue(att, scaleMinAttributeName);
              String smax = getAttributeValue(att, scaleMaxAttributeName);
              double scalemin = (smin == null) ? 0 : Double.parseDouble(smin);
              double scalemax = (smax == null) ? 0 : Double.parseDouble(smax);
              if (scalemin != 0 || scalemax != 0) {
                if (scalemin != 0) {
                  themeControl.addTheme(1f / scalemin, layers[il], invisible);
                  themeControl.getStyle(layers[il], 1f / scalemin).setVisibleInView(false);
                }
                if (scalemax != 0) {
                  themeControl.addTheme(1f / scalemax, layers[il], visible);
                  themeControl.getStyle(layers[il], 1f / scalemax).setVisibleInView(true);
                  themeControl.getStyle(layers[il], 1).setVisibleInView(false);
                } else {
                  themeControl.getStyle(layers[il], 1).setVisibleInView(true);
                }
              }
            }
          }
        }
      }
    }

    String getAttributeValue(IlvFeatureAttributeProperty a, String attributeName) {
      try {
        return a.getValue(attributeName).toString();
      } catch (IllegalArgumentException e) {
        // this means that the property is not there.
      }
      return null;
    }

    boolean hasAttribute(IlvAttributeInfoProperty p, String attributeName) {
      try {
        // does this layer define that attribute ?
        if (p.getAttributeIndex(attributeName) > -1) {
          return true;
        }
      } catch (IllegalArgumentException e) {
        // this means that the property is not there.
      }
      return false;
    }
  }

  static class ColorSetDisplayItem {
    final String value;
    String label;

    public ColorSetDisplayItem(String value) {
      this.value = value;
    }

    Override
    public String toString() {
      if (label == null) {
        label = IlvMapUtil.getString(S57LoadAction.class, "S57LoadAction.ColorSet" + value);//$NON-NLS-1$
      }
      return label;
    }

    public String getValue() {
      return value;
    }
  }

  // JV-4656
  ColorSetDisplayItem S52Colorsets[] = { new ColorSetDisplayItem("DAY"), //$NON-NLS-1$ //
                                                                         // (defined
                                                                         // by
                                                                         // S52)
      new ColorSetDisplayItem("DUSK"), //$NON-NLS-1$ //(defined by S52)
      new ColorSetDisplayItem("NIGHT") //$NON-NLS-1$ //(defined by S52)
  };
  IlvFeatureSelectorPanel panel;
  TilingParameterPanel tilingPanel;
  JPanel compositePanel;
  JCheckBox useScaleLimits;
  JCheckBox simplified;
  JCheckBox showDescriptionText;
  JComboBox<ColorSetDisplayItem> colorset;

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

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

  /**
   * @see plugins.ImportAction#getDataSources(URL[])
   */
  Override
  public Enumeration<IlvMapDataSource> getDataSources(URL urls[]) {
    return null;
  }

  /**
   * @see plugins.ImportAction#getDataSources(java.lang.String[])
   */
  Override
  public Enumeration<IlvMapDataSource> getDataSources(String fileNames[]) {
    Vector<IlvMapDataSource> src = new Vector<IlvMapDataSource>();
    IlvFeatureSelectorPanel.Feature[] features = panel.getSelectedFeatures();
    // String[] faccCodes = new String[features.length];
    List<String> ccodes = new ArrayList<String>();
    if (features != null) {
      for (int j = 0; j < features.length; j++) {
        IlvFeatureSelectorPanel.Feature currentFeature = features[j];
        IlvFeatureSelectorPanel.Feature currentChild;
        int nChildren = currentFeature.getChildCount();
        if (nChildren != 0) {// major
          for (int i = 0; i < currentFeature.getChildCount(); i++) {
            currentChild = (IlvFeatureSelectorPanel.Feature) currentFeature.getChildAt(i);
            ccodes.add(currentChild.getMajorCode() + currentChild.getMinorCode());
          }
        } else {
          ccodes.add(currentFeature.getMajorCode() + currentFeature.getMinorCode());
        }
      }
    }
    IlvThreadMonitoringData monitorData = new IlvThreadMonitoringData(getMonitor(), fileNames,
        getActivityDescription(RENDERING), 0, 100);
    for (int i = 0; i < fileNames.length; i++) {
      IlvDefaultTilableDataSource source = S57DefLess.newIlvS57DataSource(fileNames[i]);
      ColorSetDisplayItem item = (ColorSetDisplayItem) (colorset.getSelectedItem());
      S57DefLess.setRenderingParameters(source, simplified.isSelected(), showDescriptionText.isSelected(),
          item.getValue());
      source.setAcceptedCodeList((String[]) ccodes.toArray(new String[0]));
      if (simplified.isSelected()) {
        /// S57 must be simplified to use tiling
        source.setTilingParameters(tilingPanel.isTiling(), tilingPanel.getRows(), tilingPanel.getColumns());
      }
      source.setAreaOfinterest(tilingPanel.getLonMin(), tilingPanel.getLatMin(), tilingPanel.getLonMax(),
          tilingPanel.getLatMax());
      source.setManager(getView().getManager());
      source.setName(getFormatName() + " (" + new File(fileNames[i]).getName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
      source.setMonitoringData(monitorData);
      // make use of scale minimum when the data is loaded.
      if (useScaleLimits.isSelected()) {
        source.addDataSourceListener(new ScaleMimimumManager());
      }
      src.add(source);
    }
    return src.elements();
  }

  /**
   * @see plugins.ImportAction#approveSelection(File [])
   */
  Override
  public boolean approveSelection(File selection[]) {
    IlvFeatureSelectorPanel.Feature[] features = panel.getSelectedFeatures();
    if (features == null || features.length == 0) {
      JOptionPane.showMessageDialog(getView(),
          IlvMapUtil.getString(S57LoadAction.class, "S57LoadAction.NoFeatureMessage"), //$NON-NLS-1$
          IlvMapUtil.getString(S57LoadAction.class, "S57LoadAction.NoFeatureTitle"), //$NON-NLS-1$
          JOptionPane.ERROR_MESSAGE);
      return false;
    }
    return super.approveSelection(selection);
  }

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

  /**
   * Returns an IlvFeatureSelectorPanel
   * 
   * @see plugins.ImportAction#getAccessory()
   */
  Override
  public JComponent getAccessory() {
    String filename = "S57FeaturesEN.xml"; //$NON-NLS-1$
    if (compositePanel == null) {
      compositePanel = new JPanel(new BorderLayout());
      panel = new IlvFeatureSelectorPanel(null, filename, "S57");//$NON-NLS-1$
      JScrollPane sp = new JScrollPane(panel);
      compositePanel.add(sp, BorderLayout.CENTER);
      tilingPanel = new TilingParameterPanel(getView(), false);
      simplified = new JCheckBox(IlvMapUtil.getString(getClass(), "S57LoadAction.Simplified"), false); //$NON-NLS-1$
      // Limitation: Prevent using tiling when using non-simplified rendering
      tilingPanel.useTilingBox.setEnabled(simplified.isSelected());
      showDescriptionText = new JCheckBox(IlvMapUtil.getString(getClass(), "S57LoadAction.ShowDescriptionText"), false); //$NON-NLS-1$
      colorset = new JComboBox<S57LoadAction.ColorSetDisplayItem>(S52Colorsets);
      simplified.addChangeListener(new ChangeListener() {
        Override
        public void stateChanged(ChangeEvent e) {
          colorset.setEnabled(!simplified.isSelected());
          tilingPanel.useTilingBox.setEnabled(simplified.isSelected());
          // Limitation: Prevent using tiling when using non-simplified
          // rendering
          if (!simplified.isSelected()) {
            tilingPanel.useTilingBox.setSelected(false);
          }
          showDescriptionText.setEnabled(!simplified.isSelected());
        }
      });
      JPanel hintsPanel = new JPanel(new BorderLayout());
      JPanel optionPanel = new JPanel();
      hintsPanel.setBorder(
          BorderFactory.createTitledBorder(IlvMapUtil.getString(getClass(), "S57LoadAction.RenderingOptions"))); //$NON-NLS-1$
      hintsPanel.add(simplified, BorderLayout.NORTH);
      useScaleLimits = new JCheckBox(IlvMapUtil.getString(getClass(), "S57LoadAction.UseS52ScaleLimits"), false); //$NON-NLS-1$
      hintsPanel.add(useScaleLimits, BorderLayout.SOUTH);
      optionPanel.add(showDescriptionText);
      optionPanel.add(new JLabel(IlvMapUtil.getString(getClass(), "S57LoadAction.Colorset"))); //$NON-NLS-1$
      optionPanel.add(colorset);
      hintsPanel.add(optionPanel, BorderLayout.CENTER);
      compositePanel.add(hintsPanel, BorderLayout.NORTH);
      compositePanel.add(tilingPanel, BorderLayout.SOUTH);
    }
    return compositePanel;
  }

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

  /**
   * @see plugins.ImportAction#isAvailable()
   */
  Override
  public boolean isAvailable() {
    return super.isAvailable() && S57DefLess.isAvailable();
  }
}