/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package org.esa.beam.smos.visat;
import org.esa.beam.dataio.smos.L1cSmosFile;
import org.esa.beam.dataio.smos.ProductFile;
import org.esa.beam.dataio.smos.SmosFile;
import org.esa.beam.dataio.smos.SmosProductReader;
import org.esa.beam.framework.dataio.ProductReader;
import org.esa.beam.framework.datamodel.MetadataElement;
import org.esa.beam.framework.datamodel.PixelPos;
import org.esa.beam.framework.datamodel.Placemark;
import org.esa.beam.framework.datamodel.Product;
import org.esa.beam.framework.datamodel.ProductNode;
import org.esa.beam.framework.datamodel.ProductNodeEvent;
import org.esa.beam.framework.datamodel.ProductNodeListener;
import org.esa.beam.framework.help.HelpSys;
import org.esa.beam.framework.ui.product.ProductSceneView;
import org.esa.beam.visat.VisatApp;
import javax.swing.AbstractButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import java.awt.BorderLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
public abstract class GridPointBtDataToolView extends SmosToolView {
public static final String ID = GridPointBtDataToolView.class.getName();
private static final String TAG_DS_NAME = "DS_Name";
private static final String TAG_LIST_OF_DATA_SETS = "List_of_Data_Sets";
private static final String TAG_REF_FILENAME = "Ref_Filename";
private JLabel infoLabel;
private JCheckBox snapToSelectedPinCheckBox;
private GPSL gpsl;
@Override
protected JComponent createClientComponent() {
infoLabel = new JLabel();
snapToSelectedPinCheckBox = new JCheckBox("Snap to selected pin");
snapToSelectedPinCheckBox.addItemListener(new IL());
final JPanel optionsPanel = new JPanel(new BorderLayout(6, 0));
optionsPanel.add(snapToSelectedPinCheckBox, BorderLayout.WEST);
optionsPanel.add(createGridPointComponentOptionsComponent(), BorderLayout.CENTER);
final JPanel mainPanel = new JPanel(new BorderLayout(2, 2));
mainPanel.add(infoLabel, BorderLayout.CENTER);
mainPanel.add(createGridPointComponent(), BorderLayout.CENTER);
mainPanel.add(optionsPanel, BorderLayout.SOUTH);
final AbstractButton helpButton = createHelpButton();
optionsPanel.add(helpButton, BorderLayout.EAST);
if (getDescriptor().getHelpId() != null) {
HelpSys.enableHelpOnButton(helpButton, getDescriptor().getHelpId());
HelpSys.enableHelpKey(mainPanel, getDescriptor().getHelpId());
}
return mainPanel;
}
protected JComponent createGridPointComponentOptionsComponent() {
return new JPanel();
}
boolean isSnappedToPin() {
return snapToSelectedPinCheckBox.isSelected();
}
@Override
public void componentOpened() {
super.componentOpened();
gpsl = new GPSL();
SmosBox.getInstance().getGridPointSelectionService().addGridPointSelectionListener(gpsl);
updateGridPointBtDataComponent(SmosBox.getInstance().getGridPointSelectionService().getSelectedGridPointId());
}
@Override
public void componentClosed() {
super.componentClosed();
SmosBox.getInstance().getGridPointSelectionService().removeGridPointSelectionListener(gpsl);
updateGridPointBtDataComponent(-1);
}
protected L1cSmosFile getL1cSmosFile() {
final SmosFile smosFile = getSelectedSmosFile();
if (smosFile instanceof L1cSmosFile) {
return (L1cSmosFile) smosFile;
} else if (smosFile != null) {
// find the L1c SMOS file corresponding to the selected SMOS file
final Product selectedProduct = getSelectedSmosProduct();
if (selectedProduct != null) {
final MetadataElement element = findElement(selectedProduct.getMetadataRoot(), TAG_LIST_OF_DATA_SETS);
if (element != null) {
final String referredFileName = getReferredFileName(element);
if (referredFileName != null) {
return findL1cSmosFile(referredFileName);
}
}
}
}
return null;
}
final void updateGridPointBtDataComponent() {
int id = -1;
if (!isSnappedToPin()) {
id = SmosBox.getInstance().getGridPointSelectionService().getSelectedGridPointId();
} else {
final ProductSceneView view = getSelectedSmosView();
if (view != null) {
final Placemark selectedPin = view.getSelectedPin();
if (selectedPin != null) {
final PixelPos pixelPos = selectedPin.getPixelPos();
final int x = (int) Math.floor(pixelPos.getX());
final int y = (int) Math.floor(pixelPos.getY());
id = SmosBox.getInstance().getSmosViewSelectionService().getGridPointId(x, y);
}
}
}
updateGridPointBtDataComponent(id);
}
private void updateGridPointBtDataComponent(int selectedGridPointId) {
if (selectedGridPointId == -1) {
setInfoText("No data");
clearGridPointBtDataComponent();
return;
}
final L1cSmosFile l1cSmosFile = getL1cSmosFile();
final int gridPointIndex = l1cSmosFile != null ? l1cSmosFile.getGridPointIndex(selectedGridPointId) : -1;
if (gridPointIndex >= 0) {
setInfoText("" +
"<html>" +
"SEQNUM=<b>" + selectedGridPointId + "</b>, " +
"INDEX=<b>" + gridPointIndex + "</b>" +
"</html>");
new SwingWorker<GridPointBtDataset, Void>() {
@Override
protected GridPointBtDataset doInBackground() throws ExecutionException {
try {
return GridPointBtDataset.read(l1cSmosFile, gridPointIndex);
} catch (IOException e) {
throw new ExecutionException(e);
}
}
@Override
protected void done() {
try {
updateGridPointBtDataComponent(get());
} catch (InterruptedException | ExecutionException e) {
updateGridPointBtDataComponent(new IOException(e));
}
}
}.execute();
} else {
setInfoText("No data");
clearGridPointBtDataComponent();
}
}
protected void setInfoText(String text) {
infoLabel.setText(text);
}
protected abstract JComponent createGridPointComponent();
protected abstract void updateGridPointBtDataComponent(GridPointBtDataset ds);
protected abstract void updateGridPointBtDataComponent(IOException e);
protected abstract void clearGridPointBtDataComponent();
private static MetadataElement findElement(MetadataElement element, String elementName) {
if (element.getName().equals(elementName)) {
return element;
} else {
for (final MetadataElement childElement : element.getElements()) {
MetadataElement metadataElement = findElement(childElement, elementName);
if (metadataElement != null) {
return metadataElement;
}
}
}
return null;
}
private static String getReferredFileName(MetadataElement element) {
for (final MetadataElement metadataElement : element.getElements()) {
if ("L1C_SM_FILE".equals(metadataElement.getAttributeString(TAG_DS_NAME, ""))
|| "L1C_OS_FILE".equals(metadataElement.getAttributeString(TAG_DS_NAME, ""))) {
final String name = metadataElement.getAttributeString(TAG_REF_FILENAME, "");
return trimVersionNumber(name);
}
}
return null;
}
private static String trimVersionNumber(String productName) {
if (productName.length() > 10) {
return productName.substring(0, productName.length() - 10);
}
return null;
}
private static L1cSmosFile findL1cSmosFile(String referredFileName) {
final Product[] products = VisatApp.getApp().getProductManager().getProducts();
for (final Product product : products) {
final ProductReader productReader = product.getProductReader();
if (productReader instanceof SmosProductReader) {
final ProductFile productFile = ((SmosProductReader) productReader).getProductFile();
if (productFile instanceof L1cSmosFile) {
if (referredFileName.equalsIgnoreCase(trimVersionNumber(product.getName()))) {
return (L1cSmosFile) productFile;
}
}
}
}
return null;
}
private class GPSL implements GridPointSelectionService.SelectionListener {
@Override
public void handleGridPointSelectionChanged(int oldId, int newId) {
if (!isSnappedToPin()) {
updateGridPointBtDataComponent(newId);
}
}
}
private class IL implements ItemListener {
private final PCL pcl;
private final PNL pnl;
private final VSL vsl;
private IL() {
pcl = new PCL();
pnl = new PNL();
vsl = new VSL();
}
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
updateGridPointBtDataComponent();
SmosBox.getInstance().getSmosViewSelectionService().addSceneViewSelectionListener(vsl);
getSelectedSmosView().addPropertyChangeListener(ProductSceneView.PROPERTY_NAME_SELECTED_PIN, pcl);
getSelectedSmosProduct().addProductNodeListener(pnl);
} else {
getSelectedSmosProduct().removeProductNodeListener(pnl);
getSelectedSmosView().removePropertyChangeListener(ProductSceneView.PROPERTY_NAME_SELECTED_PIN, pcl);
SmosBox.getInstance().getSmosViewSelectionService().removeSceneViewSelectionListener(vsl);
}
}
private class PCL implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateGridPointBtDataComponent();
}
}
private class PNL implements ProductNodeListener {
@Override
public void nodeChanged(ProductNodeEvent event) {
updatePin(event);
}
@Override
public void nodeDataChanged(ProductNodeEvent event) {
updatePin(event);
}
@Override
public void nodeAdded(ProductNodeEvent event) {
updatePin(event);
}
@Override
public void nodeRemoved(ProductNodeEvent event) {
updatePin(event);
}
private void updatePin(ProductNodeEvent event) {
final ProductNode sourceNode = event.getSourceNode();
if (sourceNode instanceof Placemark) {
updateGridPointBtDataComponent();
}
}
}
private class VSL implements SceneViewSelectionService.SelectionListener {
@Override
public void handleSceneViewSelectionChanged(ProductSceneView oldView, ProductSceneView newView) {
if (oldView != null) {
oldView.removePropertyChangeListener(ProductSceneView.PROPERTY_NAME_SELECTED_PIN, pcl);
}
if (newView != null) {
newView.addPropertyChangeListener(ProductSceneView.PROPERTY_NAME_SELECTED_PIN, pcl);
}
updateGridPointBtDataComponent();
}
}
}
}