/******************************************************************************
* 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 global attribute 
 *  from a CDF to allow user to edit
 */

public class EditgEntryTablePanel extends JPanel implements CDFConstants {

    static final long serialVersionUID = 1L;

    private Attribute selectedAttr;

    private EditgEntryTablePanel aTablePanel;
    private MYEditor myEditor;

    private JTable table;
    private MyTableModel myModel;
    private JScrollPane scrollPane;

    private Object[][] dataObject = null;

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

    EditgEntryTablePanel(EditAttrEntryPanel entryPanel) {

	aTablePanel = this;
	myEditor = entryPanel.getMyEditor();
	selectedAttr = entryPanel.getSelectedAttr();
	scrollPane = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
				     ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

    }

    public void buildTable(Attribute attr) {

	this.selectedAttr = attr;

	if (attr != null) buildDataTable();
	if (dataObject != null) {
          myModel = new MyTableModel();
          table = new JTable(myModel);
//          myModel.addTableModelListener(this);
          table.setPreferredScrollableViewportSize(new Dimension(520, 210));
          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(40);
             if (i == 1) column.setPreferredWidth(110);
             if (i == 2) column.setPreferredWidth(370);
          }
//          setUpDataTypeColumn(table.getColumnModel().getColumn(1));
	  table.setCellSelectionEnabled(false);

	  scrollPane.setViewportView(table);

	  aTablePanel.removeAll();
	  aTablePanel.revalidate();
	  aTablePanel.repaint();
	  aTablePanel.add(scrollPane, BorderLayout.CENTER);
	}
    }

    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) {

    }
*/

    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;
        }

        /*
         * 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, 2);
            int index = dataTypeStr.indexOf("/");
            String forDataType = dataTypeStr.substring(0, index);
            String forElems = dataTypeStr.substring(index+1);
            if (attrName == null || attrName.length() == 0) {
              int ij;
              for (ij = row-1; ij > -1; --ij) {
                attrName = (String) getValueAt(ij, 0);
                if (attrName != null && attrName.length() > 0) break;
              }
            }
            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);
            long entryID = new Long((String)dataObject[row][1]).longValue() - 1;
            try {
              selectedAttr.deleteEntry(entryID);
              Entry.create(selectedAttr, 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() {

        Vector entries;
        try {
          entries = selectedAttr.getEntries();
        } catch (CDFException ex) { entries = null;}
        
	dataObject = null;

	if (entries != null) {
	  Entry en = null;
	  int entryNum = 0;
          for (Enumeration e = entries.elements() ;
                 e.hasMoreElements() ; ) {
            en = (Entry)e.nextElement();
	    if (en != null) entryNum++;
	  } 
	  if (entryNum == 0) {
	    dataObject = null;
	    return;
	  }
	  dataObject = new Object[entryNum][headcol.length];

	  long dataType;
	  long numElem;
	  Object value = null;
	  int jj = -1;

          for (Enumeration e = entries.elements() ;
               e.hasMoreElements() ; ) {
	    en = (Entry)e.nextElement();

	    if (en != null) {
		jj++;
	     	dataType = en.getDataType();
	    	numElem = en.getNumElements();
                try {
	      	  value = en.getData();
	      	} catch (CDFException ex) {} 
                dataObject[jj][0] = "" + (en.getID() + 1);
	      	dataObject[jj][1] = CDFUtils.getStringDataType(dataType) + "/" + 
					numElem;
		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();
                    for (int i = 0; i < ((double[])value).length; i=i+2) {
                      if (i > 0) tmpStr.append(", ");
		      double[] aaa = new double[2];
		      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 
		    dataObject[jj][2] = CDFUtils.getStringData(value, ",");
	    }
	  }

        }

    }

    public void reset() {
	if (dataObject != null) {
          aTablePanel.setVisible(true);
	  setTable(dataObject);
	}
    }

    public JScrollPane getScrollPane() {
        return scrollPane;
    }

}
