View Javadoc
1   package nom.tam.fits;
2   
3   import java.util.NoSuchElementException;
4   
5   import nom.tam.fits.header.GenericKey;
6   import nom.tam.fits.header.IFitsHeader;
7   import nom.tam.fits.header.Standard;
8   
9   import static nom.tam.fits.header.Standard.NAXISn;
10  import static nom.tam.fits.header.Standard.TFIELDS;
11  import static nom.tam.fits.header.Standard.TFORMn;
12  import static nom.tam.fits.header.Standard.TTYPEn;
13  
14  /*
15   * #%L
16   * nom.tam FITS library
17   * %%
18   * Copyright (C) 2004 - 2024 nom-tam-fits
19   * %%
20   * This is free and unencumbered software released into the public domain.
21   *
22   * Anyone is free to copy, modify, publish, use, compile, sell, or
23   * distribute this software, either in source code form or as a compiled
24   * binary, for any purpose, commercial or non-commercial, and by any
25   * means.
26   *
27   * In jurisdictions that recognize copyright laws, the author or authors
28   * of this software dedicate any and all copyright interest in the
29   * software to the public domain. We make this dedication for the benefit
30   * of the public at large and to the detriment of our heirs and
31   * successors. We intend this dedication to be an overt act of
32   * relinquishment in perpetuity of all present and future rights to this
33   * software under copyright law.
34   *
35   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
36   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
38   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
39   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
40   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
41   * OTHER DEALINGS IN THE SOFTWARE.
42   * #L%
43   */
44  
45  /**
46   * Base class for binary and ASCII table implementations.
47   *
48   * @param <T> the generic type of table data contained in this HDU instance.
49   */
50  @SuppressWarnings("deprecation")
51  public abstract class TableHDU<T extends AbstractTableData> extends BasicHDU<T> {
52  
53      /**
54       * Returns the default name for a columns with the specified index, to use if no column name was explicitly defined
55       * 
56       * @param  col The zero-based Java index of the column
57       * 
58       * @return     The default column name to use if no other name was defined.
59       * 
60       * @since      1.20
61       * 
62       * @see        #setColumnName(int, String, String)
63       */
64      public static String getDefaultColumnName(int col) {
65          return "Column " + (col + 1);
66      }
67  
68      /**
69       * Create the TableHDU. Note that this will normally only be invoked by subclasses in the FITS package.
70       *
71       * @deprecated     intended for internal use. Its visibility should be reduced to package level in the future.
72       * 
73       * @param      hdr the header
74       * @param      td  The data for the table.
75       */
76      @Deprecated
77      protected TableHDU(Header hdr, T td) {
78          super(hdr, td);
79      }
80  
81      /**
82       * Add a column to the table without any associated header information.
83       *
84       * @param  newCol        the new column information. the newCol should be an Object[] where type of all of the
85       *                           constituents is identical. The length of data should match the other columns. <b>
86       *                           Note:</b> It is valid for data to be a 2 or higher dimensionality primitive array. In
87       *                           this case the column index is the first (in Java speak) index of the array. E.g., if
88       *                           called with int[30][20][10], the number of rows in the table should be 30 and this
89       *                           column will have elements which are 2-d integer arrays with TDIM = (10,20).
90       *
91       * @return               the number of columns in the adapted table
92       *
93       * @throws FitsException if the operation failed
94       */
95      public int addColumn(Object newCol) throws FitsException {
96          int nCols = getNCols();
97          myHeader.findCard(TFIELDS).setValue(nCols);
98          return nCols;
99      }
100 
101     /**
102      * Add a row to the end of the table. If this is the first row, then this will add appropriate columns for each of
103      * the entries. The rows to add must be supplied as column based array of arrays.
104      *
105      * @return               the number of rows in the adapted table
106      *
107      * @param  newRows       rows to add to the table
108      *
109      * @throws FitsException if the operation failed
110      */
111     public int addRow(Object[] newRows) throws FitsException {
112         int row = myData.addRow(newRows);
113         myHeader.findCard(NAXISn.n(2)).setValue(getNRows());
114         return row;
115     }
116 
117     /**
118      * Returns the list of column description keyword stems that descrive this column in the FITS header.
119      * 
120      * @return the stems of the keywords that are associated with table columns. Users can supplement this with their
121      *             own and call the appropriate deleteColumns fields.
122      */
123     protected abstract IFitsHeader[] columnKeyStems();
124 
125     /**
126      * Delete a set of columns from a table.
127      *
128      * @param      column        The one-indexed start column.
129      * @param      len           The number of columns to delete.
130      *
131      * @throws     FitsException if the operation failed
132      * 
133      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
134      *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
135      *                               HDU and editing the header as necessary to incorporate custom entries. May be
136      *                               removed from the API in the future.
137      */
138     @Deprecated
139     public void deleteColumnsIndexOne(int column, int len) throws FitsException {
140         deleteColumnsIndexZero(column - 1, len);
141     }
142 
143     /**
144      * Delete a set of columns from a table.
145      *
146      * @param      column        The one-indexed start column.
147      * @param      len           The number of columns to delete.
148      * @param      fields        Stems for the header fields to be removed for the table.
149      *
150      * @throws     FitsException if the operation failed
151      * 
152      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
153      *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
154      *                               HDU and editing the header as necessary to incorporate custom entries. May be
155      *                               removed from the API in the future.
156      */
157     @Deprecated
158     public void deleteColumnsIndexOne(int column, int len, String[] fields) throws FitsException {
159         deleteColumnsIndexZero(column - 1, len, GenericKey.create(fields));
160     }
161 
162     /**
163      * Delete a set of columns from a table.
164      *
165      * @param      column        The one-indexed start column.
166      * @param      len           The number of columns to delete.
167      *
168      * @throws     FitsException if the operation failed
169      * 
170      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
171      *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
172      *                               HDU and editing the header as necessary to incorporate custom entries. May be
173      *                               removed from the API in the future.
174      */
175     @Deprecated
176     public void deleteColumnsIndexZero(int column, int len) throws FitsException {
177         deleteColumnsIndexZero(column, len, columnKeyStems());
178     }
179 
180     /**
181      * Delete a set of columns from a table.
182      *
183      * @param      column        The zero-indexed start column.
184      * @param      len           The number of columns to delete.
185      * @param      fields        Stems for the header fields to be removed for the table.
186      *
187      * @throws     FitsException if the operation failed
188      * 
189      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
190      *                               {@link TableData#deleteColumns(int, int)} to edit tables before wrapping them in an
191      *                               HDU and editing the header as necessary to incorporate custom entries. May be
192      *                               removed from the API in the future.
193      */
194     @Deprecated
195     public void deleteColumnsIndexZero(int column, int len, IFitsHeader[] fields) throws FitsException {
196 
197         if (column < 0 || len < 0 || column + len > getNCols()) {
198             throw new FitsException("Illegal columns deletion request- Start:" + column + " Len:" + len
199                     + " from table with " + getNCols() + " columns");
200         }
201 
202         if (len == 0) {
203             return;
204         }
205 
206         int ncol = getNCols();
207         myData.deleteColumns(column, len);
208 
209         // Get rid of the keywords for the deleted columns
210         for (int col = column; col < column + len; col++) {
211             for (IFitsHeader field : fields) {
212                 myHeader.deleteKey(field.n(col + 1));
213             }
214         }
215 
216         // Shift the keywords for the columns after the deleted columns
217         for (int col = column + len; col < ncol; col++) {
218             for (IFitsHeader field : fields) {
219                 IFitsHeader oldKey = field.n(col + 1);
220                 IFitsHeader newKey = field.n(col + 1 - len);
221                 if (myHeader.containsKey(oldKey)) {
222                     myHeader.replaceKey(oldKey, newKey);
223                 }
224             }
225         }
226         // Update the number of fields.
227         myHeader.getCard(TFIELDS).setValue(getNCols());
228 
229         // Give the data sections a chance to update the header too.
230         myData.updateAfterDelete(ncol, myHeader);
231     }
232 
233     /**
234      * Remove all rows from the table starting at some specific index from the table. Inspired by a routine by R. Mathar
235      * but re-implemented using the DataTable and changes to AsciiTable so that it can be done easily for both Binary
236      * and ASCII tables.
237      *
238      * @param      row           the (0-based) index of the first row to be deleted.
239      *
240      * @throws     FitsException if an error occurs.
241      * 
242      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
243      *                               {@link TableData#deleteRows(int, int)} to edit tables before wrapping them in an
244      *                               HDU and editing the header as necessary to incorporate custom entries. May be
245      *                               removed from the API in the future.
246      */
247     @Deprecated
248     public void deleteRows(final int row) throws FitsException {
249         deleteRows(row, getNRows() - row);
250     }
251 
252     /**
253      * Remove a number of adjacent rows from the table. This routine was inspired by code by R.Mathar but re-implemented
254      * using changes in the ColumnTable class abd AsciiTable so that we can do it for all FITS tables.
255      *
256      * @param      firstRow      the (0-based) index of the first row to be deleted. This is zero-based indexing:
257      *                               0&lt;=firstrow&lt; number of rows.
258      * @param      nRow          the total number of rows to be deleted.
259      *
260      * @throws     FitsException If an error occurs in the deletion.
261      * 
262      * @deprecated               It is not entirely foolproof for keeping the header in sync -- it is better to use
263      *                               {@link TableData#deleteRows(int, int)} to edit tables before wrapping them in an
264      *                               HDU and editing the header as necessary to incorporate custom entries. May be
265      *                               removed from the API in the future.
266      */
267     @Deprecated
268     public void deleteRows(final int firstRow, int nRow) throws FitsException {
269 
270         // Just ignore invalid requests.
271         if (nRow <= 0 || firstRow >= getNRows() || firstRow <= 0) {
272             return;
273         }
274 
275         /* correct if more rows are requested than available */
276         if (nRow > getNRows() - firstRow) {
277             nRow = getNRows() - firstRow;
278         }
279 
280         myData.deleteRows(firstRow, nRow);
281         myHeader.setNaxis(2, getNRows());
282     }
283 
284     /**
285      * Find the 0-based column index corresponding to a particular column name.
286      *
287      * @return         index of the column
288      *
289      * @param  colName the name of the column
290      */
291     public int findColumn(String colName) {
292         for (int i = 0; i < getNCols(); i++) {
293             String val = myHeader.getStringValue(TTYPEn.n(i + 1));
294             if (val != null && val.trim().equals(colName)) {
295                 return i;
296             }
297         }
298         return -1;
299     }
300 
301     /**
302      * <p>
303      * Returns the data for a particular column in as an array of elements. See {@link TableData#addColumn(Object)} for
304      * more information about the format of data elements in general.
305      * </p>
306      * 
307      * @param  col           The 0-based column index.
308      * 
309      * @return               an array of primitives (for scalar columns), or else an <code>Object[]</code> array, or
310      *                           possibly <code>null</code>
311      * 
312      * @throws FitsException if the table could not be accessed
313      *
314      * @see                  TableData#getColumn(int)
315      * @see                  #setColumn(int, Object)
316      * @see                  #getElement(int, int)
317      * @see                  #getNCols()
318      */
319     public Object getColumn(int col) throws FitsException {
320         return myData.getColumn(col);
321     }
322 
323     /**
324      * <p>
325      * Returns the data for a particular column in as an array of elements. See {@link TableData#addColumn(Object)} for
326      * more information about the format of data elements in general.
327      * </p>
328      * 
329      * @param  colName       The name or ID of the column as stored by the <code>TTYPE</code><i>n</i> FITS header
330      *                           keyword.
331      * 
332      * @return               an array of primitives (for scalar columns), or else an <code>Object[]</code> array, or
333      *                           <code>null</code> if there is no column by that name.
334      * 
335      * @throws FitsException if the table could not be accessed
336      *
337      * @see                  TableData#getColumn(int)
338      * @see                  #setColumn(int, Object)
339      * @see                  #getElement(int, int)
340      * @see                  #getNCols()
341      */
342     public Object getColumn(String colName) throws FitsException {
343         int col = findColumn(colName);
344         return col < 0 ? null : getColumn(col);
345     }
346 
347     /**
348      * Get the FITS type of a column in the table.
349      *
350      * @param  index0        The 0-based index of the column.
351      *
352      * @return               The FITS type.
353      *
354      * @throws FitsException if the index is less than 0 or greater than or equals to the number of columns in the
355      *                           table.
356      */
357     public String getColumnFormat(int index0) throws FitsException {
358         if (index0 < 0 || index0 >= getNCols()) {
359             throw new FitsException("Bad column index " + index0 + " (only " + getNCols() + " columns)");
360         }
361 
362         return myHeader.getStringValue(TFORMn.n(index0 + 1)).trim();
363     }
364 
365     /**
366      * Convenience method for getting column metadata, as a string. Note, that the return value is always a string even
367      * if the underlying metadata is some other type in the FITS header. For accessing column descriptions specified via
368      * standard FITS keywords, you should prefer using `{@link #getColumnMeta(int, IFitsHeader)}. And, to get metadata
369      * of known other types (e.g. integers), you may use one of the type-specific getter methods of {@link Header}, such
370      * as <code>getHeader().getIntValue(...)</code>.
371      *
372      * @param  index0                    zero-based index index of the colum
373      * @param  keyBase                   the base header keyword of the descriptor, without the column index, e.g.
374      *                                       `"TTYPE"`.
375      *
376      * @return                           column meta data as a string, or <code>null</code> if there is no such metadata
377      *                                       in the header.
378      * 
379      * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of columns
380      *                                       in the table.
381      *
382      * @see                              #getColumnMeta(int, IFitsHeader)
383      * @see                              #getHeader()
384      */
385     public String getColumnMeta(int index0, String keyBase) throws IndexOutOfBoundsException {
386         if (index0 < 0 || index0 >= getNCols()) {
387             throw new IndexOutOfBoundsException("Zero-based column index " + index0 + " is out of range");
388         }
389 
390         HeaderCard c = myHeader.getCard(keyBase + (index0 + 1));
391         return c == null ? null : c.getValue();
392     }
393 
394     /**
395      * Convenience method for getting column metadata, as a string. Note, that the return value is always a string even
396      * if the underlying metadata is some other type@throws IndexOutOfBoundsException if the index is less than 0 or
397      * greater than or equals to the number of columns in the table. in the FITS header. To get metadata of known other
398      * types (e.g. integers), you may use one of the type-specific getter methods of {@link Header}, such as
399      * <code>getHeader().getIntValue(...)</code>.
400      * 
401      * @param  index0                    zero-based index index of the colum
402      * @param  keyBase                   the standard FITS key to get, without the column indexing, e.g.
403      *                                       `Standard.TTYPEn`.
404      * 
405      * @return                           column meta data as a string, or <code>null</code> if there is no such metadata
406      *                                       in the header.
407      * 
408      * @throws IndexOutOfBoundsException if the index is less than 0, or greater than or equals to the number of columns
409      *                                       in the table.
410      * @throws HeaderCardException       if the resulting indexed keyword exceeds the maximum 8-bytes allowed for
411      *                                       standard FITS keywords.
412      * @throws NoSuchElementException    If more indices were supplied than can be filled for this keyword.
413      * 
414      * @since                            1.22.3
415      * 
416      * @see                              #getHeader()
417      */
418     public String getColumnMeta(int index0, IFitsHeader keyBase)
419             throws IndexOutOfBoundsException, HeaderCardException, NoSuchElementException {
420         if (index0 < 0 || index0 >= getNCols()) {
421             throw new IndexOutOfBoundsException("Zero-based column index " + index0 + " is out of range");
422         }
423 
424         HeaderCard c = myHeader.getCard(keyBase.n(index0 + 1));
425         return c == null ? null : c.getValue();
426     }
427 
428     /**
429      * Gets the name of a column in the table, as it appears in this HDU's header. It may differ from a more currently
430      * assigned name of the binary table data column after the HDU creation or reading.
431      *
432      * @param  index0                    The 0-based column index.
433      *
434      * @return                           The column name, or <code>null</code> if it was undefined.
435      *
436      * @throws IndexOutOfBoundsException if the index is less than 0, or greater than or equals to the number of columns
437      *                                       in the table.
438      * 
439      * @see                              BinaryTable.ColumnDesc#name()
440      */
441     public String getColumnName(int index0) throws IndexOutOfBoundsException {
442         return getColumnMeta(index0, Standard.TTYPEn);
443     }
444 
445     /**
446      * <p>
447      * Returns the data for all columns in as an array. See {@link TableData#addColumn(Object)} for more information
448      * about the column format of each element in the returned array.
449      * </p>
450      * 
451      * @return               An array containing the column data for all columns. Each entry in the returned array is
452      *                           itself an array of primitives (for scalar columns), or else an <code>Object[]</code>
453      *                           array, or possibly <code>null</code>.
454      * 
455      * @throws FitsException if the table could not be accessed
456      *
457      * @see                  TableData#getColumn(int)
458      * @see                  #setColumn(int, Object)
459      * @see                  #getElement(int, int)
460      * @see                  #getNCols()
461      */
462     public Object[] getColumns() throws FitsException {
463         Object[] result = new Object[getNCols()];
464         for (int i = 0; i < result.length; i++) {
465             result[i] = getColumn(i);
466         }
467         return result;
468     }
469 
470     /**
471      * Returns a specific element from this table
472      * 
473      * @return               a specific element of the table using 0-based indices.
474      *
475      * @param  row           the row index of the element
476      * @param  col           the column index of the element
477      *
478      * @throws FitsException if the operation failed
479      * 
480      * @see                  #getElement(int, int)
481      */
482     public Object getElement(int row, int col) throws FitsException {
483         return myData.getElement(row, col);
484     }
485 
486     /**
487      * Get the number of columns for this table
488      *
489      * @return The number of columns in the table.
490      */
491     public int getNCols() {
492         return myData.getNCols();
493     }
494 
495     /**
496      * Get the number of rows for this table
497      *
498      * @return The number of rows in the table.
499      */
500     public int getNRows() {
501         return myData.getNRows();
502     }
503 
504     /**
505      * Returns a specific row from this table
506      * 
507      * @return               a specific row of the table.
508      *
509      * @param  row           the index of the row to retreive
510      *
511      * @throws FitsException if the operation failed
512      * 
513      * @see                  #setRow(int, Object[])
514      */
515     public Object[] getRow(int row) throws FitsException {
516         return myData.getRow(row);
517     }
518 
519     /**
520      * Update a column within a table. The new column should have the same format ast the column being replaced. See
521      * {@link TableData#addColumn(Object)} for more information about the column data format.
522      *
523      * @param  col           index of the column to replace
524      * @param  newCol        the replacement column
525      *
526      * @throws FitsException if the operation failed
527      * 
528      * @see                  #getColumn(int)
529      * @see                  #setColumn(String, Object)
530      * @see                  TableData#addColumn(Object)
531      */
532     public void setColumn(int col, Object newCol) throws FitsException {
533         myData.setColumn(col, newCol);
534     }
535 
536     /**
537      * Update a column within a table. The new column should have the same format as the column being replaced. See
538      * {@link TableData#addColumn(Object)} for more information about the column data format.
539      *
540      * @param  colName       name of the column to replace
541      * @param  newCol        the replacement column
542      *
543      * @throws FitsException if the operation failed
544      * 
545      * @see                  #getColumn(String)
546      * @see                  #setColumn(int, Object)
547      * @see                  TableData#addColumn(Object)
548      */
549     public void setColumn(String colName, Object newCol) throws FitsException {
550         setColumn(findColumn(colName), newCol);
551     }
552 
553     /**
554      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
555      * be organized together.
556      *
557      * @param  index0                    The 0-based index of the column
558      * @param  key                       The column key. I.e., the keyword will be key+(index+1)
559      * @param  value                     The value to be placed in the header.
560      * @param  comment                   The comment for the header
561      * @param  after                     Should the header card be after the current column metadata block
562      *                                       (<code>true</code>), or immediately before the TFORM card
563      *                                       (<code>false</code>).
564      *
565      * @throws HeaderCardException       if the header could not be updated, or if the indexed FITS keyword is too long
566      *                                       (exceeds the maximum 8 bytes allowed by the FITS standard).
567      * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of columns
568      *                                       in t@throws IndexOutOfBoundsException if the index is less than 0 or
569      *                                       greater than or equals to the number of columns in the table.
570      */
571     public void setColumnMeta(int index0, IFitsHeader key, String value, String comment, boolean after)
572             throws IndexOutOfBoundsException, HeaderCardException {
573         setCurrentColumn(index0, after);
574         myHeader.addLine(new HeaderCard(key.n(index0 + 1).key(), value, comment));
575     }
576 
577     /**
578      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
579      * be organized together.
580      *
581      * @param  index0                    The 0-based index of the column
582      * @param  key                       The column key. I.e., the keyword will be key+(index+1)
583      * @param  value                     The value to be placed in the header.
584      * @param  comment                   The comment for the header
585      * @param  after                     Should the header card be after the current column metadata block
586      *                                       (<code>true</code>), or immediately before the TFORM card
587      *                                       (<code>false</code>).
588      *
589      * @throws HeaderCardException       if the header could not be updated, or if the indexed FITS keyword is too long
590      *                                       (exceeds the maximum 8 bytes allowed by the FITS standard).
591      * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of columns
592      *                                       in t@throws IndexOutOfBoundsException if the index is less than 0 or
593      *                                       greater than or equals to the number of columns in the table.
594      *
595      * @since                            1.16
596      */
597     public void setColumnMeta(int index0, IFitsHeader key, Number value, String comment, boolean after)
598             throws IndexOutOfBoundsException, HeaderCardException {
599         setCurrentColumn(index0, after);
600         myHeader.addLine(new HeaderCard(key.n(index0 + 1).key(), value, comment));
601     }
602 
603     /**
604      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
605      * be organized together.
606      *
607      * @param  index0                    The 0-based index of the column
608      * @param  key                       The column key. I.e., the keyword will be key+(index+1)
609      * @param  value                     The value to be placed in the header.
610      * @param  comment                   The comment for the header
611      * @param  after                     Should the header card be after the current column metadata block
612      *                                       (<code>true</code>), or immediately before the TFORM card
613      *                                       (<code>false</code>).
614      *
615      * @throws HeaderCardException       if the header could not be updated, or if the indexed FITS keyword is too long
616      *                                       (exceeds the maximum 8 bytes allowed by the FITS standard).
617      * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of columns
618      *                                       in t@throws IndexOutOfBoundsException if the index is less than 0 or
619      *                                       greater than or equals to the number of columns in the table.
620      */
621     public void setColumnMeta(int index0, String key, Boolean value, String comment, boolean after)
622             throws IndexOutOfBoundsException, HeaderCardException {
623         setCurrentColumn(index0, after);
624         myHeader.addLine(new HeaderCard(key + (index0 + 1), value, comment));
625     }
626 
627     /**
628      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
629      * be organized together.
630      *
631      * @param  index0                    The 0-based index of the column
632      * @param  key                       The column key. I.e., the keyword will be key+(index+1)
633      * @param  value                     The value to be placed in the header.
634      * @param  comment                   The comment for the header
635      * @param  after                     Should the header card be after the current column metadata block
636      *                                       (<code>true</code>), or immediately before the TFORM card
637      *                                       (<code>false</code>).
638      *
639      * @throws HeaderCardException       if the header could not be updated, or if the indexed FITS keyword is too long
640      *                                       (exceeds the maximum 8 bytes allowed by the FITS standard).
641      * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of columns
642      *                                       in t@throws IndexOutOfBoundsException if the index is less than 0 or
643      *                                       greater than or equals to the number of columns in the table.
644      */
645     public void setColumnMeta(int index0, String key, Number value, String comment, boolean after)
646             throws IndexOutOfBoundsException, HeaderCardException {
647         setCurrentColumn(index0, after);
648         myHeader.addLine(new HeaderCard(key + (index0 + 1), value, comment));
649     }
650 
651     /**
652      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
653      * be organized together.
654      *
655      * @param  index0                    The 0-based index of the column
656      * @param  key                       The column key. I.e., the keyword will be key+(index+1)
657      * @param  value                     The value to be placed in the header.
658      * @param  precision                 The maximum number of decimal places to show after the leading figure.
659      *                                       (Trailing zeroes will be ommitted.)
660      * @param  comment                   The comment for the header
661      * @param  after                     Should the header card be after the current column metadata block
662      *                                       (<code>true</code>), or immediately before the TFORM card
663      *                                       (<code>false</code>).
664      *
665      * @throws HeaderCardException       if the header could not be updated, or if the indexed FITS keyword is too long
666      *                                       (exceeds the maximum 8 bytes allowed by the FITS standard).
667      * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of columns
668      *                                       in t@throws IndexOutOfBoundsException if the index is less than 0 or
669      *                                       greater than or equals to the number of columns in the table.
670      */
671     public void setColumnMeta(int index0, String key, Number value, int precision, String comment, boolean after)
672             throws IndexOutOfBoundsException, HeaderCardException {
673         setCurrentColumn(index0, after);
674         myHeader.addLine(new HeaderCard(key + (index0 + 1), value, precision, comment));
675     }
676 
677     /**
678      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
679      * be organized together.
680      *
681      * @param  index0                    The 0-based index of the column
682      * @param  key                       The column key. I.e., the keyword will be key+(index+1)
683      * @param  value                     The value to be placed in the header.
684      * @param  comment                   The comment for the header
685      *
686      * @throws HeaderCardException       if the header could not be updated, or if the indexed FITS keyword is too long
687      *                                       (exceeds the maximum 8 bytes allowed by the FITS standard).
688      * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of columns
689      *                                       in t@throws IndexOutOfBoundsException if the index is less than 0 or
690      *                                       greater than or equals to the number of columns in the table.
691      */
692     public void setColumnMeta(int index0, String key, String value, String comment)
693             throws IndexOutOfBoundsException, HeaderCardException {
694         setColumnMeta(index0, key, value, comment, true);
695     }
696 
697     /**
698      * Specify column metadata for a given column in a way that allows all of the column metadata for a given column to
699      * be organized together.
700      *
701      * @param      index0                    The 0-based index of the column
702      * @param      key                       The column key. I.e., the keyword will be key+(index+1)
703      * @param      value                     The value to be placed in the header.
704      * @param      comment                   The comment for the header
705      * @param      after                     Should the header card be after the current column metadata block (true),
706      *                                           or immediately before the TFORM card (false). @throws FitsException if
707      *                                           the operation failed
708      *
709      * @throws     HeaderCardException       if the header could not be updated, or if the indexed FITS keyword is too
710      *                                           long (exceeds the maximum 8 bytes allowed by the FITS standard).
711      * @throws     IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of
712      *                                           columns in t@throws IndexOutOfBoundsException if the index is less than
713      *                                           0 or greater than or equals to the number of columns in the table.
714      *
715      * @deprecated                           use {@link #setColumnMeta(int, IFitsHeader, String, String, boolean)}
716      */
717     @Deprecated
718     public void setColumnMeta(int index0, String key, String value, String comment, boolean after)
719             throws IndexOutOfBoundsException, HeaderCardException {
720         setCurrentColumn(index0, after);
721         myHeader.addLine(new HeaderCard(key + (index0 + 1), value, comment));
722     }
723 
724     /**
725      * Sets the name / ID of a specific column in this table. Naming columns is generally a good idea so that people can
726      * figure out what sort of data actually appears in specific table columns.
727      * 
728      * @param  index0                    the 0-based column index
729      * @param  name                      the name or ID we want to assing to the column
730      * @param  comment                   Any additional comment we would like to store alongside in the FITS header.
731      *                                       (The comment may be truncated or even ommitted, depending on space
732      *                                       constraints in the FITS header.
733      * 
734      * @throws HeaderCardException       if there was a problem wil adding the associated descriptive FITS header
735      *                                       keywords to this table's header.
736      * @throws IndexOutOfBoundsException if the table has no column matching the index
737      * 
738      * @see                              #getColumnName(int)
739      * @see                              #getDefaultColumnName(int)
740      */
741     public void setColumnName(int index0, String name, String comment)
742             throws IndexOutOfBoundsException, HeaderCardException {
743         setColumnMeta(index0, TTYPEn, name, comment, true);
744     }
745 
746     /**
747      * Set the cursor in the header to point after the metadata for the specified column
748      *
749      * @param      col                       The 0-based index of the column
750      * 
751      * @throws     IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of
752      *                                           columns in t@throws IndexOutOfBoundsException if the index is less than
753      *                                           0 or greater than or equals to the number of columns in the table.
754      * 
755      * @deprecated                           (<i>for internal use</i>) Will be removed int the future (no longer used).
756      */
757     @Deprecated
758     public void setCurrentColumn(int col) throws IndexOutOfBoundsException {
759         setCurrentColumn(col, true);
760     }
761 
762     /**
763      * Set the cursor in the header to point either before the TFORMn value or after the column metadata
764      *
765      * @param      col0                      The 0-based index of the column
766      * @param      after                     True if the cursor should be placed after the existing column metadata or
767      *                                           false if the cursor is to be placed before the TFORM value. If no
768      *                                           corresponding TFORM is found, the cursor will be placed at the end of
769      *                                           current header.
770      * 
771      * @throws     IndexOutOfBoundsException if the index is less than 0 or greater than or equals to the number of
772      *                                           columns in t@throws IndexOutOfBoundsException if the index is less than
773      *                                           0 or greater than or equals to the number of columns in the table.
774      * 
775      * @deprecated                           (<i>for internal use</i>) Will have private access in the future.
776      */
777     @Deprecated
778     public void setCurrentColumn(int col0, boolean after) throws IndexOutOfBoundsException {
779         if (col0 < 0 || col0 >= getNCols()) {
780             throw new IndexOutOfBoundsException("Zero-based column index " + col0 + " is out of range");
781         }
782 
783         if (after) {
784             myHeader.positionAfterIndex(TFORMn, col0 + 1);
785         } else {
786             myHeader.findCard(TFORMn.n(col0 + 1));
787         }
788     }
789 
790     /**
791      * Update a single element within the table.
792      *
793      * @param  row           the row index
794      * @param  col           the column index
795      * @param  element       the replacement element
796      *
797      * @throws FitsException if the operation failed
798      * 
799      * @see                  #getElement(int, int)
800      */
801     public void setElement(int row, int col, Object element) throws FitsException {
802         myData.setElement(row, col, element);
803     }
804 
805     /**
806      * Update a row within a table.
807      *
808      * @param  row           row index
809      * @param  newRow        the replacement row
810      *
811      * @throws FitsException if the operation failed
812      * 
813      * @see                  #getRow(int)
814      */
815     public void setRow(int row, Object[] newRow) throws FitsException {
816         myData.setRow(row, newRow);
817     }
818 }