/*
 * Copyright (c) 1998-2019 University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */

package ucar.nc2.ui.op;

import ucar.ma2.Array;
import ucar.ma2.DataType;
import ucar.nc2.VariableSimpleIF;
import ucar.nc2.ui.image.ImageViewPanel;
import ucar.ui.widget.BAMutil;
import ucar.ui.widget.IndependentWindow;
import ucar.ui.widget.PopupMenu;
import ucar.ui.widget.TextHistoryPane;
import ucar.nc2.dt.RadialDatasetSweep;
import ucar.nc2.dt.image.ImageArrayAdapter;
import ucar.util.prefs.PreferencesExt;
import ucar.ui.prefs.BeanTable;
import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Formatter;
import java.util.List;
import java.lang.invoke.MethodHandles;
import javax.swing.AbstractAction;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;

/**
 * A Swing widget to examine a RadialDataset.
 *
 * @author caron
 */

public class RadialDatasetTable extends JPanel {

  private static final org.slf4j.Logger logger =
      org.slf4j.LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

  private PreferencesExt prefs;
  private RadialDatasetSweep radialDataset;

  private BeanTable varTable, sweepTable;
  private JSplitPane split;
  private TextHistoryPane infoTA;
  private IndependentWindow infoWindow;

  public RadialDatasetTable(PreferencesExt prefs) {
    this.prefs = prefs;

    varTable = new BeanTable(VariableBean.class, (PreferencesExt) prefs.node("VariableBeans"), false);
    varTable.addListSelectionListener(e -> {
      VariableBean vb = (VariableBean) varTable.getSelectedBean();
      if (vb != null)
        setVariable(vb);
    });

    JTable jtable = varTable.getJTable();

    PopupMenu csPopup = new PopupMenu(jtable, "Options");
    csPopup.addAction("Show Declaration", new AbstractAction() {
      public void actionPerformed(ActionEvent e) {
        VariableBean vb = (VariableBean) varTable.getSelectedBean();
        if (vb == null)
          return;
        VariableSimpleIF v = radialDataset.getDataVariable(vb.getName());
        if (v == null)
          return;
        infoTA.clear();
        infoTA.appendLine(v.toString());
        infoTA.gotoTop();
        infoWindow.show();
      }
    });
    csPopup.addAction("Show Info", new AbstractAction() {
      public void actionPerformed(ActionEvent e) {
        VariableBean vb = (VariableBean) varTable.getSelectedBean();
        if (vb == null)
          return;
        Formatter f = new Formatter();
        showInfo(radialDataset, vb.getName(), f);
        infoTA.clear();
        infoTA.appendLine(f.toString());
        infoTA.gotoTop();
        infoWindow.show();
      }
    });

    // the info window
    infoTA = new TextHistoryPane();
    infoWindow = new IndependentWindow("Variable Information", BAMutil.getImage("nj22/NetcdfUI"), infoTA);
    infoWindow.setBounds((Rectangle) prefs.getBean("InfoWindowBounds", new Rectangle(300, 300, 500, 300)));

    sweepTable = new BeanTable(SweepBean.class, (PreferencesExt) prefs.node("SweepBean"), false);

    PopupMenu sweepPopup = new PopupMenu(sweepTable.getJTable(), "Options");
    sweepPopup.addAction("Show Image", new AbstractAction() {
      public void actionPerformed(ActionEvent e) {
        showImage((SweepBean) sweepTable.getSelectedBean());
      }
    });

    split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, varTable, sweepTable);
    split.setDividerLocation(prefs.getInt("splitPos", 500));

    setLayout(new BorderLayout());
    add(split, BorderLayout.CENTER);
  }

  public PreferencesExt getPrefs() {
    return prefs;
  }

  public void save() {
    varTable.saveState(false);
    prefs.putBeanObject("InfoWindowBounds", infoWindow.getBounds());
    if (split != null)
      prefs.putInt("splitPos", split.getDividerLocation());
    if (sweepTable != null)
      sweepTable.saveState(false);
  }

  public void clear() {
    varTable.setBeans(new ArrayList());
    sweepTable.setBeans(new ArrayList());
  }

  public void setDataset(RadialDatasetSweep rds) {
    this.radialDataset = rds;
    // dateUnit = rds.getTimeUnits();

    varTable.setBeans(getVariableBeans(rds));
    sweepTable.setBeans(new ArrayList());
  }

  public RadialDatasetSweep getRadialDataset() {
    return radialDataset;
  }

  public List<VariableBean> getVariableBeans(RadialDatasetSweep rds) {
    List<VariableBean> vlist = new ArrayList<>();
    List list = rds.getDataVariables();
    for (Object aList : list) {
      RadialDatasetSweep.RadialVariable v = (RadialDatasetSweep.RadialVariable) aList;
      vlist.add(new VariableBean(v));
    }
    return vlist;
  }

  public void setVariable(VariableBean vb) {
    List<SweepBean> sweeps = new ArrayList<>();
    int n = vb.v.getNumSweeps();
    for (int i = 0; i < n; i++) {
      RadialDatasetSweep.Sweep sweep = vb.v.getSweep(i);
      sweeps.add(new SweepBean(sweep));
    }
    sweepTable.setBeans(sweeps);
  }

  private void showInfo(RadialDatasetSweep rds, String varName, Formatter f) {
    f.format("Radial Dataset %s%n", rds.getLocation());

    /* radar information */
    // String stationID = rds.getRadarID();
    String stationName = rds.getRadarName();
    boolean isVolume = rds.isVolume();
    f.format("  stationName = %s%n", stationName);
    f.format("  isVolume = %s%n", isVolume);

    /* radial variable */
    RadialDatasetSweep.RadialVariable v = (RadialDatasetSweep.RadialVariable) rds.getDataVariable(varName);
    if (v == null)
      return;

    f.format("  info for variable = %s%n", varName);
    f.format("  number of sweeps = %d%n", v.getNumSweeps());

    // loop over sweeps
    for (int sweep = 0; sweep < v.getNumSweeps(); sweep++) {
      RadialDatasetSweep.Sweep sw = v.getSweep(sweep);
      float me = sw.getMeanElevation();
      int nrays = sw.getRadialNumber();
      int ngates = sw.getGateNumber();
      f.format("    %d : elev=%f nrays=%d ngates=%d%n", sweep, me, nrays, ngates);

      try {
        for (int j = 0; j < nrays; j++) {
          float azi = sw.getAzimuth(j);
          float ele = sw.getElevation(j);
          float[] data = sw.readData(j);
          f.format("      %d : azimuth=%f elev=%f data len=%d%n", j, azi, ele, data.length);
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }


  public static class VariableBean {
    // static public String editableProperties() { return "title include logging freq"; }

    RadialDatasetSweep.RadialVariable v;

    private String name, desc, units, dataType;
    String dims, r, t;
    // private boolean isCoordVar, isRadial, axis;

    // no-arg constructor
    public VariableBean() {}

    // create from a dataset
    public VariableBean(RadialDatasetSweep.RadialVariable v) {
      this.v = v;

      setName(v.getShortName());
      setDescription(v.getDescription());
      setUnits(v.getUnitsString());
      dataType = v.getDataType().toString();

      // collect dimensions
      StringBuilder buff = new StringBuilder();
      int[] shape = v.getShape();
      for (int j = 0; j < shape.length; j++) {
        if (j > 0)
          buff.append(",");
        buff.append(shape[j]);
      }
      dims = buff.toString();
    }

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public String getDescription() {
      return desc;
    }

    public void setDescription(String desc) {
      this.desc = desc;
    }

    public String getUnits() {
      return units;
    }

    public void setUnits(String units) {
      this.units = units;
    }

    public String getDataType() {
      return dataType;
    }

    public String getDims() {
      return dims;
    }

  }

  public static class SweepBean {
    // static public String editableProperties() { return "title include logging freq"; }

    RadialDatasetSweep.Sweep sweep;

    // no-arg constructor
    public SweepBean() {}

    // create from a dataset
    public SweepBean(RadialDatasetSweep.Sweep sweep) {
      this.sweep = sweep;

    }

    public String getType() {
      RadialDatasetSweep.Type type = sweep.getType();
      return (type == null) ? "" : type.toString();
    }

    public int getNumRadial() {
      return sweep.getRadialNumber();
    }

    public int getNumGates() {
      return sweep.getGateNumber();
    }

    public float getBeamWidth() {
      return sweep.getBeamWidth();
    }

    public float getNyqFreq() {
      return sweep.getNyquistFrequency();
    }

    public float getFirstGate() {
      return sweep.getRangeToFirstGate();
    }

    public float getGateSize() {
      return sweep.getGateSize();
    }

    public float getMeanElevation() {
      return sweep.getMeanElevation();
    }

    public float getMeanAzimuth() {
      return sweep.getMeanAzimuth();
    }

    public Date getStartingTime() {
      return sweep.getStartingTime();
    }

    public Date getEndingTime() {
      return sweep.getEndingTime();
    }
  }

  // show image
  private static final String ImageViewer_WindowSize = "RadialImageViewer_WindowSize";
  private IndependentWindow imageWindow;
  private ImageViewPanel imageView;

  private void showImage(SweepBean bean) {
    if (bean == null)
      return;

    if (imageWindow == null) {
      imageWindow = new IndependentWindow("Image Viewer", BAMutil.getImage("nj22/ImageData"));
      imageView = new ImageViewPanel(null);
      imageWindow.setComponent(new JScrollPane(imageView));
      // imageWindow.setComponent( imageView);
      Rectangle b = (Rectangle) prefs.getBean(ImageViewer_WindowSize, new Rectangle(99, 33, 700, 900));
      // System.out.println("bounds in = "+b);
      imageWindow.setBounds(b);
    }

    float[] data;
    try {
      data = bean.sweep.readData();
      int[] shape = {bean.getNumRadial(), bean.getNumGates()};
      Array arrData = Array.factory(DataType.FLOAT, shape, data);

      imageView.setImage(ImageArrayAdapter.makeGrayscaleImage(arrData, null));
      imageWindow.show();

    } catch (IOException e) {
      logger.warn("sweep read data failed", e);
    }
  }
}