001 package edu.nrao.sss.model.source; 002 003 import java.util.ArrayList; 004 import java.util.Collections; 005 import java.util.Comparator; 006 import java.util.HashMap; 007 import java.util.List; 008 import java.util.Map; 009 010 /** 011 * Structured representation of data from the old VLA Calibrator Manual. 012 * <p> 013 * <b>Warning:</b> This class is not expected to be used by anything other 014 * than the source catalog application under controlled circumstances. 015 * Because of this documentation herein is scanty and error handling has 016 * not been coded. If you would like to use this class in your own 017 * environment, see the author about making this class more robust.</p> 018 * <p> 019 * <b>CVS Info:</b> 020 * <table style="margin-left:2em"> 021 * <tr><td>$Revision: 760 $</td></tr> 022 * <tr><td>$Date: 2007-07-09 08:39:29 -0600 (Mon, 09 Jul 2007) $</td></tr> 023 * <tr><td>$Author: dharland $</td></tr> 024 * </table></p> 025 * 026 * @author David M. Harland 027 * @since 2006-12-13 028 */ 029 public class VlaHistoricalCalibratorData 030 { 031 //============================================================================ 032 // COLUMN HEADINGS 033 //============================================================================ 034 035 private static final ArrayList<String> NAME_LINE_COLUMN_NAMES = 036 new ArrayList<String>(); 037 038 private static final ArrayList<String> BAND_LINE_COLUMN_NAMES = 039 new ArrayList<String>(); 040 041 static 042 { 043 NAME_LINE_COLUMN_NAMES.add("IAU NAME"); 044 NAME_LINE_COLUMN_NAMES.add("EQUINOX"); 045 NAME_LINE_COLUMN_NAMES.add("PC"); 046 NAME_LINE_COLUMN_NAMES.add("RA(hh,mm,ss)"); 047 NAME_LINE_COLUMN_NAMES.add("DEC(ddd,mm,ss)"); 048 NAME_LINE_COLUMN_NAMES.add("POS.REF"); 049 NAME_LINE_COLUMN_NAMES.add("ALT.NAME"); 050 051 BAND_LINE_COLUMN_NAMES.add("BAND WAVELENGTH"); 052 BAND_LINE_COLUMN_NAMES.add("BAND CODE"); 053 BAND_LINE_COLUMN_NAMES.add("A"); 054 BAND_LINE_COLUMN_NAMES.add("B"); 055 BAND_LINE_COLUMN_NAMES.add("C"); 056 BAND_LINE_COLUMN_NAMES.add("D"); 057 BAND_LINE_COLUMN_NAMES.add("FLUX(Jy)"); 058 BAND_LINE_COLUMN_NAMES.add("UVMIN(kL)"); 059 BAND_LINE_COLUMN_NAMES.add("UVMAX(kL)"); 060 BAND_LINE_COLUMN_NAMES.add("IMAGE1"); 061 BAND_LINE_COLUMN_NAMES.add("IMAGE2"); 062 } 063 064 /** 065 * Returns a list where each entry is the name of a column in a 066 * "name" line. 067 * @return a list of name-line column names. 068 */ 069 @SuppressWarnings("unchecked") 070 public static List<String> getNameLineColumnNames() 071 { 072 return (List<String>)NAME_LINE_COLUMN_NAMES.clone(); 073 } 074 075 /** 076 * Returns a list where each entry is the name of a column in a 077 * "band" line. 078 * @return a list of band-line column names. 079 */ 080 @SuppressWarnings("unchecked") 081 public static List<String> getBandLineColumnNames() 082 { 083 return (List<String>)BAND_LINE_COLUMN_NAMES.clone(); 084 } 085 086 //============================================================================ 087 // 088 //============================================================================ 089 090 private List<List<String>> nameLines; 091 private List<List<String>> bandLines; 092 093 private VlaHistoricalCalibratorData() 094 { 095 nameLines = new ArrayList<List<String>>(); 096 bandLines = new ArrayList<List<String>>(); 097 } 098 099 /** 100 * Returns a list "name" lines for this record. There is usually one name 101 * line for J2000 and one for B1950. Each line is a list of strings. 102 * The meaning of the n<sup>th</sup> string can be found by fetching 103 * the n<sup>th</sup> element of {@link #getNameLineColumnNames()}. 104 * 105 * @return a list of name lines. 106 */ 107 public List<List<String>> getNameLines() 108 { 109 ArrayList<List<String>> lines = new ArrayList<List<String>>(); 110 111 for (int i=0; i < nameLines.size(); i++) 112 lines.add(new ArrayList<String>(nameLines.get(i))); 113 114 return lines; 115 } 116 117 /** 118 * Returns a list "band" lines for this record. 119 * Each line is a list of strings. 120 * The meaning of the n<sup>th</sup> string can be found by fetching 121 * the n<sup>th</sup> element of {@link #getBandLineColumnNames()}. 122 * 123 * @return a list of band lines. 124 */ 125 public List<List<String>> getBandLines() 126 { 127 ArrayList<List<String>> lines = new ArrayList<List<String>>(); 128 129 for (int i=0; i < bandLines.size(); i++) 130 lines.add(new ArrayList<String>(bandLines.get(i))); 131 132 return lines; 133 } 134 135 /** 136 * Returns an HTML table that contains a row for each name line. 137 * @param tableStyle text that is added to the <tt><table></tt> tag. 138 * @return an HTML table that contains a row for each name line. 139 */ 140 public String toHtmlNameTable(String tableStyle) 141 { 142 final String EOL = System.getProperty("line.separator"); 143 int colCount = NAME_LINE_COLUMN_NAMES.size(); 144 145 StringBuilder buff = new StringBuilder(); 146 147 buff.append("<table"); 148 if (tableStyle == null) 149 buff.append(">"); 150 else 151 buff.append(" ").append(tableStyle).append(">"); 152 buff.append(EOL); 153 154 //Column headings 155 buff.append(" <tr>"); 156 for (int h=0; h < colCount; h++) 157 buff.append("<th>").append(NAME_LINE_COLUMN_NAMES.get(h)).append("</th>"); 158 buff.append("</tr>").append(EOL); 159 160 //Data 161 for (List<String> nameLine : nameLines) 162 { 163 buff.append(" <tr>"); 164 for (String data : nameLine) 165 buff.append("<td>").append(data).append("</td>"); 166 buff.append("</tr>").append(EOL); 167 } 168 169 buff.append("</table>").append(EOL); 170 171 return buff.toString(); 172 } 173 174 /** 175 * Returns an HTML table that contains a row for each band line. 176 * @param tableStyle text that is added to the <tt><table></tt> tag. 177 * @return an HTML table that contains a row for each band line. 178 */ 179 public String toHtmlBandTable(String tableStyle) 180 { 181 final String EOL = System.getProperty("line.separator"); 182 int colCount = BAND_LINE_COLUMN_NAMES.size(); 183 184 StringBuilder buff = new StringBuilder(); 185 186 buff.append("<table"); 187 if (tableStyle == null) 188 buff.append(">"); 189 else 190 buff.append(" ").append(tableStyle).append(">"); 191 buff.append(EOL); 192 193 //Column headings 194 buff.append(" <tr>"); 195 for (int h=0; h < colCount; h++) 196 buff.append("<th>").append(BAND_LINE_COLUMN_NAMES.get(h)).append("</th>"); 197 buff.append("</tr>").append(EOL); 198 199 final int imageCol = 9; 200 201 //Data 202 for (List<String> bandLine : bandLines) 203 { 204 buff.append(" <tr>"); 205 int col = 0; 206 for (String data : bandLine) 207 { 208 buff.append("<td>"); 209 if ((col < imageCol) || data.equals("-")) 210 { 211 buff.append(data); 212 } 213 else 214 { 215 buff.append("<a href=\"").append(data).append("\">"); 216 buff.append(data.substring(data.lastIndexOf('/')+1)); 217 buff.append("</a>"); 218 } 219 buff.append("</td>"); 220 col++; 221 } 222 buff.append("</tr>").append(EOL); 223 } 224 225 buff.append("</table>").append(EOL); 226 227 return buff.toString(); 228 } 229 230 /** 231 * Creates a new historical record by parsing the given text. 232 * The text is expected to be in the same format as that which is 233 * found in the "historical record" field of the new VLA Calibrator 234 * Database. 235 * 236 * @param text to be parsed. 237 * @return a new record. 238 * 239 * @throws IllegalArgumentException if {@code text} is not in the 240 * expected format. 241 */ 242 public static VlaHistoricalCalibratorData parse(String text) 243 { 244 VlaHistoricalCalibratorData data = new VlaHistoricalCalibratorData(); 245 246 if (isOldVlaRecord(text)) 247 { 248 Map<String, String> map = data.makeMap(text); 249 250 data.makeNameLine(map, "J2000"); 251 data.makeNameLine(map, "B1950"); 252 data.makeBandLines(map); 253 } 254 255 return data; 256 } 257 258 /** 259 * Returns <i>true</i> if it looks like {@code text} is in a form 260 * that the {@link #parse(String)} method of this class understands. 261 * Specifically, this method will return <i>true</i> if {@code text} 262 * contains the string "origin=VLA.Calibrator.Catalog". 263 * 264 * @param text a potential VLA Calibrator Manual entry. 265 * 266 * @return <i>true</i> if the given text looks like it could be an 267 * old VLA Calibrator Manual entry. 268 */ 269 public static boolean isOldVlaRecord(String text) 270 { 271 return text.contains("origin=VLA.Calibrator.Catalog"); 272 } 273 274 /** 275 * @param map 276 */ 277 private void makeNameLine(Map<String, String> map, String prefix) 278 { 279 ArrayList<String> line = new ArrayList<String>(); 280 281 final String[] KEYS = {".IAU.NAME", ".POS.CODE", ".RA", ".DEC", 282 ".POS.REF", ".ALT.NAME"}; 283 284 for (String key : KEYS) 285 { 286 String value = map.get(prefix + key); 287 line.add(value == null ? " " : value); 288 } 289 290 line.add(1, prefix); 291 292 nameLines.add(line); 293 } 294 295 private void makeBandLines(Map<String,String> map) 296 { 297 //Find out what bands we have 298 ArrayList<String> bandCodes = new ArrayList<String>(); 299 300 for (String key : map.keySet()) 301 if (key.startsWith("BAND.") && key.endsWith(".WAVELENGTH")) 302 { 303 //Form of key s/b "BAND.?.WAVELENGTH" 304 String[] s = key.split("\\."); 305 bandCodes.add(s[1]); 306 } 307 308 //One line per band code 309 for (String bandCode : bandCodes) 310 makeBandLine(map, "BAND."+bandCode); 311 312 //Sort from largest wavelength to smallest 313 Collections.sort(bandLines, new Comparator<List<String>>() { 314 public int compare(List<String> s1, List<String> s2) 315 { 316 String w1 = s1.get(0).replace("cm", ""); 317 String w2 = s2.get(0).replace("cm", ""); 318 return Double.valueOf(w2).compareTo(Double.valueOf(w1)); 319 } 320 }); 321 } 322 323 private void makeBandLine(Map<String, String> map, String prefix) 324 { 325 ArrayList<String> line = new ArrayList<String>(); 326 327 final String[] KEYS = {".WAVELENGTH", ".QUALITY.A", ".QUALITY.B", 328 ".QUALITY.C", ".QUALITY.D", ".FLUX", 329 ".UV.MIN", ".UV.MAX", ".PLOT.1", ".PLOT.2"}; 330 331 for (String key : KEYS) 332 { 333 String value = map.get(prefix + key); 334 line.add(value == null ? "-" : value); 335 } 336 337 //Prefix is "BAND.?"; we want the value of "?" -- the band code 338 line.add(1, prefix.substring(5, 6)); 339 340 bandLines.add(line); 341 } 342 343 /** 344 * @param text 345 * @return 346 */ 347 private Map<String, String> makeMap(String text) 348 { 349 HashMap<String, String> map = new HashMap<String, String>(); 350 351 String[] entries = text.split(";"); 352 353 if (entries.length < 1) 354 throw new IllegalArgumentException( 355 "Found no name/value pairs in parameter '" + text + "'."); 356 357 for (String entry : entries) 358 { 359 String[] keyValue = entry.split("="); 360 361 if (keyValue.length != 2) 362 { 363 throw new IllegalArgumentException( 364 "Expected format: name=value. Found '" + entry + 365 "' in paramter '" + text + "'."); 366 } 367 368 map.put(keyValue[0], keyValue[1]); 369 } 370 371 return map; 372 } 373 /* 374 public static void main(String[] args) 375 { 376 String text = "origin=VLA.Calibrator.Catalog;J2000.IAU.NAME=2344+824;J2000.POS.CODE=C;J2000.RA=23h44m03.7718s;J2000.DEC=82d26'40.401\";J2000.POS.REF=Jan97;J2000.ALT.NAME=;B1950.IAU.NAME=2342+821;B1950.POS.CODE=C;B1950.RA=23h42m06.4253s;B1950.DEC=82d10'01.320\";B1950.POS.REF=;B1950.ALT.NAME=;BAND.L.WAVELENGTH=20.0cm;BAND.L.QUALITY.A=P;BAND.L.QUALITY.B=P;BAND.L.QUALITY.C=P;BAND.L.QUALITY.D=P;BAND.L.FLUX=3.79Jy;BAND.L.UV.MIN=;BAND.L.UV.MAX=;BAND.L.PLOT.1=http://www.vla.nrao.edu/astro/calib/manual/calplots/20cmC/2344+824.1.ps.Z;BAND.L.PLOT.2=http://www.vla.nrao.edu/astro/calib/manual/calplots/20cmC/2344+824.uv.ps.Z;BAND.C.WAVELENGTH=6.0cm;BAND.C.QUALITY.A=S;BAND.C.QUALITY.B=P;BAND.C.QUALITY.C=P;BAND.C.QUALITY.D=P;BAND.C.FLUX=1.34Jy;BAND.C.UV.MIN=;BAND.C.UV.MAX=;BAND.C.PLOT.1=http://www.vla.nrao.edu/astro/calib/manual/calplots/6cmC/2344+824.1.ps.Z;BAND.C.PLOT.2=http://www.vla.nrao.edu/astro/calib/manual/calplots/6cmC/2344+824.uv.ps.Z;BAND.X.WAVELENGTH=3.7cm;BAND.X.QUALITY.A=S;BAND.X.QUALITY.B=S;BAND.X.QUALITY.C=P;BAND.X.QUALITY.D=P;BAND.X.FLUX=0.75Jy;BAND.X.UV.MIN=;BAND.X.UV.MAX=200kL;BAND.X.PLOT.1=http://www.vla.nrao.edu/astro/calib/manual/calplots/3.7cmC/2344+824.1.ps.Z;BAND.X.PLOT.2=http://www.vla.nrao.edu/astro/calib/manual/calplots/3.7cmC/2344+824.uv.ps.Z;BAND.U.WAVELENGTH=2.0cm;BAND.U.QUALITY.A=W;BAND.U.QUALITY.B=W;BAND.U.QUALITY.C=W;BAND.U.QUALITY.D=W;BAND.U.FLUX=0.4Jy;BAND.U.UV.MIN=;BAND.U.UV.MAX=;BAND.Q.WAVELENGTH=0.7cm;BAND.Q.QUALITY.A=W;BAND.Q.QUALITY.B=W;BAND.Q.QUALITY.C=W;BAND.Q.QUALITY.D=W;BAND.Q.FLUX=0.3Jy;BAND.Q.UV.MIN=;BAND.Q.UV.MAX=; 0"; 377 VlaHistoricalCalibratorData data = VlaHistoricalCalibratorData.parse(text); 378 379 for (List<String> line : data.getNameLines()) 380 System.out.println(line); 381 382 for (List<String> line : data.getBandLines()) 383 System.out.println(line); 384 385 System.out.println(); 386 System.out.println(data.toHtmlNameTable("border=\"1\"")); 387 System.out.println(data.toHtmlBandTable("border=\"1\"")); 388 } 389 */ 390 }