package hirondelle.starfield.physics;

import hirondelle.starfield.util.Consts;
import hirondelle.starfield.util.Util;

import java.awt.Color;
import java.util.LinkedHashMap;
import java.util.Map;

/**
  Struct to carry the data related to a star, plus conversion methods.
  
  <P>A catalog record is parsed into this simple structure, which carries only the data needed for the 
  starfield calculation, and nothing else. All other data from the catalog is ignored.
  
  <P>This class also converts spectral type and color index to a corresponding approximate temperature. 
  The resulting temperature is then converted to a corresponding approximate color.
*/
public final class Star {

  private static Map<String, Double> SPECTRAL_TYPE_TO_TEMPERATURE = new LinkedHashMap<>();
  static {
    SPECTRAL_TYPE_TO_TEMPERATURE.put("M",3050.0);
    SPECTRAL_TYPE_TO_TEMPERATURE.put("K",4450.0);
    SPECTRAL_TYPE_TO_TEMPERATURE.put("G",5600.0);
    SPECTRAL_TYPE_TO_TEMPERATURE.put("F",6750.0);
    SPECTRAL_TYPE_TO_TEMPERATURE.put("A",8750.0);
    SPECTRAL_TYPE_TO_TEMPERATURE.put("B",20000.0);
    SPECTRAL_TYPE_TO_TEMPERATURE.put("O",30000.0);
  }
  
  /**  
   Simple mapping of the first letter of a star's spectral type to a representative approximate temperature in Kelvin.
   <P>The adopted values are:
   <table  border='1' cellpadding='3' cellspacing='0' style='width:50%;'>
    <tr><th>Spectral Type<th>Temperature
    <tr><td>O<td>30,000
    <tr><td>B<td>20,000
    <tr><td>A<td>8,750
    <tr><td>F<td>6,750
    <tr><td>G<td>5,600
    <tr><td>K<td>4,450
    <tr><td>M<td>3,050
   </table>  
  */
  public static double spectralTypeToTemperature(String aSpectralClass){
    Double result = SPECTRAL_TYPE_TO_TEMPERATURE.get(aSpectralClass);
    if (result == null){
      Util.log("Unexpected spectral class: " + Util.quote(aSpectralClass));
    }
    return result;
  }

  /** 
   Simple mapping of color index to a representative approximate temperature in Kelvin.
   <P>The adopted values are:
   <table border='1' cellpadding='3' cellspacing='0'  style='width:50%;'>
    <tr><th>B-V(start)<th>B-V(end)<th>Temperature
    <tr><td>-nn.n<td>-0.32<td>30,000
    <tr><td>-0.31<td>-0.01<td>20,000
    <tr><td>+0.00<td>+0.29<td>8,750
    <tr><td>+0.30<td>+0.56<td>6,750
    <tr><td>+0.57<td>+0.80<td>5,600
    <tr><td>+0.81<td>+1.38<td>4,450
    <tr><td>+1.39<td>+nn.n<td>3,050
   </table>  
  */
  public static double colorIndexToTemperature(double aColorIndex){
    double result = -1; //default, should always be overridden
    if (aColorIndex>=1.39){
      result = 3050.0D;
    }
    else if (aColorIndex>=0.81){
      result = 4450.0D;
    }
    else if (aColorIndex>=0.57){
      result = 5600.0D;
    }
    else if (aColorIndex>=0.30){
      result = 6750.0D;
    }
    else if (aColorIndex>=0.00){
      result = 8750.0D;
    }
    else if (aColorIndex>=-0.31){
      result = 20000.0D;
    }
    else {
      result = 30000.0D;
    }
    
    if (result == -1){
      throw new AssertionError("Unable to assign a temperature to color index: " + aColorIndex);
    }
    return result;
  }
  
  /**
    Map a star's black body surface temperature in Kelvin to a corresponding color.
  */
  public static Color temperatureToColor(double temperature){
    Color result = new Color(255,255,255); //default, should never actually be returned; avoids null
    //note that these temperatures denote the LOWER ENDPOINT endpoint of the corresponding spectral class, 
    //not the mean 
    if (temperature>=30000){ //O
      result = new Color(155,176,255);
    }
    else if (temperature>=10000){ //B
      result = new Color(170,191,255);
    }
    else if (temperature>=7500){ //A
      result = new Color(202,215,255);
    }
    else if (temperature>=6000){ //F
      result = new Color(248,247,255);
    }
    else if (temperature>=5200){ //G
      result = new Color(255,244,234);
    }
    else if (temperature>=3700){ //K
      result = new Color(255,210,161);
    }
    else { //M
      result = new Color(255,204,111);
    }
    return result;
  }
  
  /** Right Ascension of the star in radians. */
  public double RightAscension;
  /** Declination of the star in radians. */
  public double Declination;
  /** The brightness of the star. */
  public double Magnitude;
  /**
   The black-body surface temperature of the star in Kelvin. 
   Catalogs will almost never have this data. It must be deduced from either spectral type,  
   the colour index B-V, or similar.
  */
  public double Temperature;
  
  /** For debugging only. */
  @Override public String toString(){
    StringBuilder result = new StringBuilder();
    result.append("Star RA: " + RightAscension);
    result.append(" Dec: " + Declination);
    result.append(" Mag: " + Magnitude);
    result.append(" Temp: " + Temperature + Consts.NL);
    return result.toString();
  }
  
}