/******************************************************************************
* Copyright 1996-2014 United States Government as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
******************************************************************************/

import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.*;
import java.lang.reflect.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.JTable;

import gsfc.nssdc.cdf.*;
import gsfc.nssdc.cdf.util.*;

/**
 *  This class creates the table showing all entries for a given variable 
 *  from a CDF to allow user to edit
 */

public class EditvVarEntryTableScrollPane extends JScrollPane implements CDFConstants {

    private Variable var;

    private EditvVarEntryTableScrollPane aTableScrollPane;
    private MYEditor myEditor;

    private CDF cdf;
    private JTable table;
    private MyTableModel myModel;
    private Vector attrs;

    private Object[][] dataObject = null;

    private static String[] headcol = {	"Attribute Name", "Data Type",
					"Entry Data" };

    static final long serialVersionUID = 1L;

    EditvVarEntryTableScrollPane(VariablePanel varPanel) {

	super(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
              ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
	aTableScrollPane = this;
	myEditor = varPanel.getMyEditor();
	cdf = myEditor.theCDF;
	attrs = cdf.getAttributes();
	setVisible(false);

    }

    public void buildTable(Variable var) {

	this.var = var;
	table = null;
	if (var != null) buildDataTable();
	else {
//	  aTableScrollPane.removeAll();
          aTableScrollPane.setVisible(false);
	  aTableScrollPane.validate();
	}
	if (dataObject != null) {
	  aTableScrollPane.setVisible(true);
          myModel = new MyTableModel();
          table = new JTable(myModel);
//          myModel.addTableModelListener(this);
          table.setPreferredScrollableViewportSize(new Dimension(670, 420));
          table.setRowSelectionAllowed(false);
          table.sizeColumnsToFit(JTable.AUTO_RESIZE_ALL_COLUMNS);

          TableColumn column = null;
          for (int i = 0; i < headcol.length; i++) {
             column = table.getColumnModel().getColumn(i);
             column.setResizable(true);
             if (i == 0) column.setPreferredWidth(100);
             if (i == 1) column.setPreferredWidth(110);
             if (i == 2) column.setPreferredWidth(460);
          }

	  aTableScrollPane.setViewportView(table);
          aTableScrollPane.setVisible(true);
        } else {
	  aTableScrollPane.setVisible(false);
	  aTableScrollPane.revalidate();
          aTableScrollPane.repaint();
	}
    }

    public void setTable(Object[][] data) {
        dataObject = data;
        myModel.fireTableChanged(new TableModelEvent(myModel));

    }

    public Object[][] getTable() {

        return (Object[][]) dataObject;

    }

    public void setColumnNames(String[] columnNames) {

        headcol = columnNames;

    }

    public String[] getColumnNames() {

        return (String[]) headcol;

    }
/*
    public void tableChanged(TableModelEvent tme) {

//        aTableScrollPane.pack();
    }
*/

    public void setUpDataTypeColumn(TableColumn dataTypeColumn) {
        //Set up the editor for the dataType cells.
        JComboBox comboBox = new JComboBox();
        comboBox.addItem("CDF_BYTE");
        comboBox.addItem("CDF_INT1");
        comboBox.addItem("CDF_UINT1");
        comboBox.addItem("CDF_INT2");
        comboBox.addItem("CDF_UINT2");
        comboBox.addItem("CDF_INT4");
        comboBox.addItem("CDF_UINT4");
        comboBox.addItem("CDF_INT8");
        comboBox.addItem("CDF_REAL4");
        comboBox.addItem("CDF_FLOAT");
        comboBox.addItem("CDF_REAL8");
        comboBox.addItem("CDF_DOUBLE");
        comboBox.addItem("CDF_EPOCH");
	comboBox.addItem("CDF_EPOCH16");
	comboBox.addItem("CDF_TIME_TT2000");
        comboBox.addItem("CDF_CHAR");
        comboBox.addItem("CDF_UCHAR");

        dataTypeColumn.setCellEditor(new DefaultCellEditor(comboBox));

        //Set up tool tips for the dataType cells.
        DefaultTableCellRenderer renderer =
                new DefaultTableCellRenderer();
        renderer.setToolTipText("Click for valid data types");
        dataTypeColumn.setCellRenderer(renderer);

        //Set up tool tip for the dataType column header.
        TableCellRenderer headerRenderer = dataTypeColumn.getHeaderRenderer();
        if (headerRenderer instanceof DefaultTableCellRenderer) {
            ((DefaultTableCellRenderer)headerRenderer).setToolTipText(
                     "Click the dataType to see a list of choices");
        }
    }

    class MyTableModel extends AbstractTableModel {

        static final long serialVersionUID = 1L;

        public int getColumnCount() {
            return headcol.length;
        }

        public int getRowCount() {
	  if (dataObject != null)
            return dataObject.length;
	  else
	    return 0;
        }

        public String getColumnName(int col) {
            return headcol[col];
        }

        public Object getValueAt(int row, int col) {
	  if (dataObject != null)
            return dataObject[row][col];
	  else
	    return null;
        }

        /*
         * Don't need to implement this method unless your table's
         * editable.
         */
        public boolean isCellEditable(int row, int col) {
            //Note that the data/cell address is constant,
            //no matter where the cell appears onscreen.
            if (col < 2)
                return false;
            else
                return true;
//		return false;
        }

        /*
         * JTable uses this method to determine the default renderer/
         * editor for each cell.  If we didn't implement this method,
         * then a Boolean column would contain text ("true"/"false"),
         * rather than a check box.
         */
        // public Class getColumnClass(int c) {
        //    return getValueAt(0, c).getClass();
        // }

        /*
         * Don't need to implement this method unless your table's
         * data can change.
         */
        public void setValueAt(Object value, int row, int col) {

            Object oldone = getValueAt(row, col);
            dataObject[row][col] = value;
            fireTableCellUpdated(row, col);
            String attrName = (String) getValueAt(row, 0);
            String dataTypeStr = (String) getValueAt(row, 1);
            int index = dataTypeStr.indexOf("/");
            String forDataType = dataTypeStr.substring(0, index);
            String forElems = dataTypeStr.substring(index+1);
            int numElemsx, isChar;
            long dataTypeNum = CDFUtils.getDataTypeValue(forDataType);
            Object value2 = null;
            if (dataTypeStr.indexOf("CHAR") != -1) {
              isChar = 1;
              numElemsx = ((String)value).length();
            } else {
              String[] tokens = ((String)value).split(",");
              numElemsx = tokens.length;
              isChar = 0;
              value2 = CDFToolUtils.parseContents ((String)value, dataTypeNum);
            }
            String newDataType = new StringBuffer(forDataType).append("/").
                                                  append(numElemsx).toString();
            dataObject[row][1] = newDataType;
            fireTableCellUpdated(row, 1);
            try {
              long entryID = cdf.getVariableID(var.getName());
              Attribute attr = cdf.getAttribute(attrName);
              attr.deleteEntry(entryID);
              Entry.create(attr, entryID, dataTypeNum, (isChar==1?value:value2));
            } catch (Exception ex) {
              JOptionPane.showMessageDialog(myEditor.frame,
                                               "The change failed... "+ex);
            }

        }

        void applyValue(Object origin, Object newone, int row, int col) {
            if (!((String)origin).equals((String)newone)) {
              if (((String)newone).equals("CDF_CHAR") ||
                  ((String)newone).equals("CDF_UCHAR"))
                JOptionPane.showMessageDialog(myEditor.frame,
                    "The data type changed from " + origin
                    + " to " + newone + ". Please change entry value accordingly.");
            }
        }

    }

/**
  * Build the data and columns that are used for the tables.
 */

    private void buildDataTable() {

        dataObject = null;

        if (attrs != null) {
          Attribute attr;

          int attrNum = attrs.size();
          int inum = 0;
          for (int ii = 0; ii < attrNum; ii++) {
            attr = (Attribute) attrs.elementAt(ii);
            if (attr.getScope() == VARIABLE_SCOPE) inum++;
          }
          if (inum > 0) {
            dataObject = new Object[inum][headcol.length];

            Entry en = null;
            long dataType;
            long length;
            Object value = null;
            int jj = -1;

            for (int ii = 0; ii < attrNum; ii++) {

              attr = (Attribute) attrs.elementAt(ii);
              if (attr.getScope() == VARIABLE_SCOPE) {
                try {
                  en = attr.getEntry(var);
                } catch (CDFException ex) {
                  en = null;
                }
                jj++;
                if (en == null) {
                  dataObject[jj][0] = attr.toString();
                  dataObject[jj][1] = " ";
                  dataObject[jj][2] = " ";
                } else {
                  dataType = en.getDataType();
                  try {
                    value = en.getData();
                  } catch (CDFException ex) {}
		  length = en.getNumElements();
                  dataObject[jj][0] = attr.toString();
                  dataObject[jj][1] = CDFUtils.getStringDataType(dataType) + "/" +
                                        length;
                  if (dataType == CDF_EPOCH) {
                    if (value.getClass().getName().indexOf('[') == 0) { // an array
                      StringBuffer tmpStr = new StringBuffer();
                      for (int i = 0; i < ((double[])value).length; i++) {
                        if (i > 0) tmpStr.append(", ");
                        String tmp = Epoch.encode4(((double[])value)[i]);
                        tmpStr.append(tmp);
                      }
//                      tmpStr.setLength(tmpStr.length()-2);
                      dataObject[jj][2] = tmpStr.toString();
                    } else {
                      dataObject[jj][2] = Epoch.encode4(((Double)value).doubleValue());
		    }
                  } else if (dataType == CDF_EPOCH16) {
                    if (value.getClass().getName().indexOf('[') == 0) { // an array
                      StringBuffer tmpStr = new StringBuffer();
		      double[] aaa = new double[2];
                      for (int i = 0; i < ((double[])value).length; i=i+2) {
                        if (i > 0) tmpStr.append(", ");
			aaa[0] = ((double[])value)[i];
			aaa[1] = ((double[])value)[i+1];
                        String tmp = Epoch16.encode4(aaa);
                        tmpStr.append(tmp);
                      }
//                      tmpStr.setLength(tmpStr.length()-2);
                      dataObject[jj][2] = tmpStr.toString();
                    } 
                  } else if (dataType == CDF_TIME_TT2000) {
                    if (value.getClass().getName().indexOf('[') == 0) { // an array
                      StringBuffer tmpStr = new StringBuffer();
                      for (int i = 0; i < ((long[])value).length; i++) {
                        if (i > 0) tmpStr.append(", ");
                        String tmp = CDFTT2000.toUTCstring(((long[])value)[i]);
                        tmpStr.append(tmp);
                      }
//                      tmpStr.setLength(tmpStr.length()-2);
                      dataObject[jj][2] = tmpStr.toString();
                    } else 
                      dataObject[jj][2] = CDFTT2000.toUTCstring(((Long)value).longValue());
                  } else {
                    if (dataType == CDF_REAL4 || dataType == CDF_REAL8 ||
                        dataType == CDF_FLOAT || dataType == CDF_DOUBLE) {
                      String format;
                      try {
                        format = (String) var.getEntryData("FORMAT");
                      } catch (CDFException ce) { format = null; }
                      dataObject[jj][2] = CDFUtils.getStringFloatingData (value, format, ", ").trim();
                    } else
                      dataObject[jj][2] = CDFUtils.getStringData(value, ",");
                  }
//                    dataObject[jj][2] = CDFUtils.getStringData(value, ",");
                }
              }
            }
          }

        }

    }

    public void reset() {
	dataObject = null;
        aTableScrollPane.setVisible(false);
    }

}
