package hirondelle.starfield.catalog.parser;

import hirondelle.starfield.physics.Star;
import hirondelle.starfield.util.Util;

/** 
Parse a record from the <a href='http://cdsarc.u-strasbg.fr/viz-bin/Cat?III/135A'>Henry Draper Catalog</a>.
Uses epoch 1900.

<P>Record details:
<pre>
Byte 19..20: RA-H
Byte 21..23: RA-M, example '053' (for 05.3) with no decimal point; has no seconds.
Byte 24:      Sign of declination
Byte 25..26: Dec-deg
Byte 27..28: Dec-min; no seconds
Byte 30..34: Photovisual Mag. Some missing. Example '10.0'; possible leading minus sign. 
                 Uses weird magic values to identify non-stellar objects:
                   20.0 30.0 40.0 50.0
Byte 43..45: Spectral Type. Take byte 43 only.
</pre>

<P>Records discarded by this parser:
<ul>
 <li>those missing magnitude or spectral class
 <li>those of spectral class N,P,R,C,S
</ul>
*/
final class HenryDraperCatalog implements RecordParser {
  
  /** See class comment.  */
  public Star parse(String aLine) {
    Star result = null;
    //Util.logVerbose(aLine);
    if ( aLine.length() < 43 ){
      Util.logVerbose("Skipping record. Truncated.");
    }
    else {
      Chomper chomper = new Chomper(aLine);
      String spectralClass = chomper.forText(43); //first letter only
      if (! Util.textHasContent(spectralClass) ){
        Util.logVerbose("Skipping record. Missing spectral class.");
      }
      else if (spectralClass.startsWith("N") || spectralClass.startsWith("P") || spectralClass.startsWith("R") || spectralClass.startsWith("C") ||  spectralClass.startsWith("S")){
        Util.logVerbose("Skipping record. Not in the set of expected spectral classes: " + spectralClass);
      }
      else if ( chomper.isMissing(30,34) ){
        Util.logVerbose("Skipping record. Missing magnitude.");
      }
      else {
        //no more reasons left for skipping a record
        result = new Star();
        result.Temperature = Star.spectralTypeToTemperature(spectralClass); 
        
        int hour = chomper.forInt(19, 20);
        int min =  chomper.forInt(21, 23);
        double hours = hour + min/600.0D; //be careful to avoid integer division!
        result.RightAscension = Util.radians(hours*15.0D);
        
        int deg = chomper.forInt(25, 26);
        int arcmin = chomper.forInt(27, 28);
        double degrees = deg + arcmin/60.0D; //be careful to avoid integer division!
        if ( "-".equals(chomper.forText(24)) ){
          degrees = -1 * degrees;
        }
        result.Declination = Util.radians(degrees);
        
        result.Magnitude = chomper.forMagnitude(30,34);
      }
    }
    return result;
  }

}