/*
* Copyright (C) 2015 by Array Systems Computing Inc. http://www.array.ca
*
* 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.s1tbx.insar.rcp.dialogs;
import com.bc.ceres.core.ProgressMonitor;
import com.bc.ceres.swing.progress.ProgressMonitorSwingWorker;
import org.esa.s1tbx.insar.gpf.InSARStackOverview;
import org.esa.snap.core.datamodel.MetadataElement;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.engine_utilities.datamodel.AbstractMetadata;
import org.esa.snap.engine_utilities.gpf.CommonReaders;
import org.esa.snap.engine_utilities.db.ProductEntry;
import org.esa.snap.engine_utilities.gpf.OperatorUtils;
import org.esa.snap.graphbuilder.rcp.dialogs.ProductSetPanel;
import org.esa.snap.graphbuilder.rcp.utils.DialogUtils;
import org.esa.snap.productlibrary.rcp.utils.ProductOpener;
import org.esa.snap.rcp.SnapApp;
import org.esa.snap.rcp.util.Dialogs;
import org.esa.snap.ui.AppContext;
import org.esa.snap.ui.ModalDialog;
import org.esa.snap.ui.ModelessDialog;
import org.jlinda.core.Orbit;
import org.jlinda.core.SLCImage;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Find Optimal Master product for InSAR
*/
public class InSARStackOverviewDialog extends ModelessDialog {
DecimalFormat df = new DecimalFormat("0.00");
private boolean ok = false;
private final InSARFileModel outputFileModel = new InSARFileModel();
private final AppContext appContext = SnapApp.getDefault().getAppContext();
private final ProductSetPanel inputProductListPanel = new ProductSetPanel(appContext, "Input stack");
private final ProductSetPanel outputProductListPanel = new ProductSetPanel(appContext, "Overview", outputFileModel);
private final Map<SLCImage, File> slcFileMap = new HashMap<>(10);
private JButton openBtn;
private final JCheckBox searchDBCheckBox = new JCheckBox("Search Product Library");
public InSARStackOverviewDialog() {
super(SnapApp.getDefault().getMainFrame(), "Stack Overview and Optimal InSAR Master Selection", ModalDialog.ID_OK_CANCEL_HELP, "InSARStackOverview");
getButton(ID_OK).setText("Overview");
getButton(ID_CANCEL).setText("Close");
initContent();
}
private void initContent() {
final JPanel contentPane = new JPanel(new BorderLayout());
final JPanel buttonPanel1 = new JPanel(new GridLayout(10, 1));
final JButton addAllBtn = DialogUtils.createButton("addAllBtn", "Add Opened", null, buttonPanel1, DialogUtils.ButtonStyle.Text);
addAllBtn.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
final Product[] products = SnapApp.getDefault().getProductManager().getProducts();
final List<File> fileList = new ArrayList<>(products.length);
for (Product prod : products) {
final File file = prod.getFileLocation();
if (file != null && file.exists()) {
fileList.add(file);
}
}
inputProductListPanel.setProductFileList(fileList.toArray(new File[fileList.size()]));
}
});
buttonPanel1.add(addAllBtn);
final JButton clearBtn = DialogUtils.createButton("clearBtn", "Clear", null, buttonPanel1, DialogUtils.ButtonStyle.Text);
clearBtn.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
inputProductListPanel.setProductFileList(new File[]{});
}
});
buttonPanel1.add(clearBtn);
inputProductListPanel.add(buttonPanel1, BorderLayout.EAST);
contentPane.add(inputProductListPanel, BorderLayout.NORTH);
// option pane
final JPanel optionsPane = new JPanel(new GridBagLayout());
optionsPane.setBorder(BorderFactory.createTitledBorder("Options"));
final GridBagConstraints gbc = DialogUtils.createGridBagConstraints();
gbc.gridy++;
DialogUtils.addComponent(optionsPane, gbc, "", searchDBCheckBox);
gbc.gridy++;
// not yet working
//contentPane.add(optionsPane, BorderLayout.CENTER);
final JPanel buttonPanel2 = new JPanel(new GridLayout(10, 1));
openBtn = DialogUtils.createButton("openButton", " Open ", null, buttonPanel2, DialogUtils.ButtonStyle.Text);
openBtn.setEnabled(false);
openBtn.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
File[] files = outputProductListPanel.getSelectedFiles();
if (files.length == 0) // default to get all files
files = outputProductListPanel.getFileList();
ProductOpener.openProducts(files);
}
});
buttonPanel2.add(openBtn);
outputProductListPanel.add(buttonPanel2, BorderLayout.EAST);
contentPane.add(outputProductListPanel, BorderLayout.SOUTH);
setContent(contentPane);
}
public void setInputProductList(final ProductEntry[] productEntryList) {
inputProductListPanel.setProductEntryList(productEntryList);
processStack();
}
private void validate() throws Exception {
final File[] inputFiles = inputProductListPanel.getFileList();
if (inputFiles.length < 2) {
throw new Exception("Please select at least two SLC products");
}
}
private void processStack() {
try {
validate();
final File[] inputFiles = inputProductListPanel.getFileList();
final InSARStackOverview.IfgStack[] ifgStack = findInSARProducts(inputFiles);
if (ifgStack == null) {
openBtn.setEnabled(false);
Dialogs.showWarning("Optimal master not found");
} else {
final InSARStackOverview dataStack = new InSARStackOverview();
final int masterIndex = dataStack.findOptimalMaster(ifgStack);
final InSARStackOverview.IfgPair[] slaveList = ifgStack[masterIndex].getMasterSlave();
updateData(slaveList, masterIndex);
openBtn.setEnabled(true);
ok = true;
}
} catch (Exception e) {
Dialogs.showError("Error: " + e.getMessage());
}
}
protected void onOK() {
processStack();
}
public boolean IsOK() {
return ok;
}
private void updateData(final InSARStackOverview.IfgPair[] slaveList, final int masterIndex) {
outputFileModel.clear();
final File mstFile = slcFileMap.get(slaveList[masterIndex].getMasterMetadata());
try {
final Product productMst = CommonReaders.readProduct(mstFile);
final MetadataElement absRootMst = AbstractMetadata.getAbstractedMetadata(productMst);
final String[] mstValues = new String[]{
productMst.getName(),
"Master",
OperatorUtils.getAcquisitionDate(absRootMst),
String.valueOf(absRootMst.getAttributeInt(AbstractMetadata.REL_ORBIT, 0)),
String.valueOf(absRootMst.getAttributeInt(AbstractMetadata.ABS_ORBIT, 0)),
String.valueOf(df.format(slaveList[masterIndex].getPerpendicularBaseline())),
String.valueOf(df.format(slaveList[masterIndex].getTemporalBaseline())),
String.valueOf(df.format(slaveList[masterIndex].getCoherence())),
String.valueOf(df.format(slaveList[masterIndex].getHeightAmb())),
String.valueOf(df.format(slaveList[masterIndex].getDopplerDifference()))
};
outputFileModel.addFile(mstFile, mstValues);
} catch (Exception e) {
Dialogs.showError("Unable to read " + mstFile.getName() + '\n' + e.getMessage());
}
for (InSARStackOverview.IfgPair slave : slaveList) {
final File slvFile = slcFileMap.get(slave.getSlaveMetadata());
if (!slvFile.equals(mstFile)) {
try {
final Product product = CommonReaders.readProduct(slvFile);
final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product);
final String[] slvValues = new String[]{
product.getName(),
"Slave",
OperatorUtils.getAcquisitionDate(absRoot),
String.valueOf(absRoot.getAttributeInt(AbstractMetadata.REL_ORBIT, 0)),
String.valueOf(absRoot.getAttributeInt(AbstractMetadata.ABS_ORBIT, 0)),
String.valueOf(df.format(slave.getPerpendicularBaseline())),
String.valueOf(df.format(slave.getTemporalBaseline())),
String.valueOf(df.format(slave.getCoherence())),
String.valueOf(df.format(slave.getHeightAmb())),
String.valueOf(df.format(slave.getDopplerDifference()))
};
outputFileModel.addFile(slvFile, slvValues);
} catch (Exception e) {
Dialogs.showError("Unable to read " + slvFile.getName() + '\n' + e.getMessage());
}
}
}
}
private InSARStackOverview.IfgStack[] findInSARProducts(final File[] inputFiles) {
final List<SLCImage> imgList = new ArrayList<>(inputFiles.length);
final List<Orbit> orbList = new ArrayList<>(inputFiles.length);
for (File file : inputFiles) {
try {
final Product product = CommonReaders.readProduct(file);
final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product);
final SLCImage img = new SLCImage(absRoot, product);
final Orbit orb = new Orbit(absRoot, 3);
slcFileMap.put(img, file);
imgList.add(img);
orbList.add(orb);
} catch (IOException e) {
Dialogs.showError("Error: unable to read " + file.getPath() + '\n' + e.getMessage());
} catch (Exception e) {
Dialogs.showError("Error: " + file.getPath() + '\n' + e.getMessage());
}
}
try {
final InSARStackOverview dataStack = new InSARStackOverview();
dataStack.setInput(imgList.toArray(new SLCImage[imgList.size()]), orbList.toArray(new Orbit[orbList.size()]));
final Worker worker = new Worker(SnapApp.getDefault().getMainFrame(), "Computing Optimal InSAR Master",
dataStack);
worker.executeWithBlocking();
return (InSARStackOverview.IfgStack[]) worker.get();
} catch (Throwable t) {
Dialogs.showError("Error:" + t.getMessage());
return null;
}
}
private static class Worker extends ProgressMonitorSwingWorker {
private final InSARStackOverview dataStack;
Worker(final Component component, final String title,
final InSARStackOverview optimalMaster) {
super(component, title);
this.dataStack = optimalMaster;
}
@Override
protected Object doInBackground(ProgressMonitor pm) throws Exception {
return dataStack.getCoherenceScores(pm);
}
}
}