package hirondelle.starfield.physics;

import hirondelle.starfield.util.Util;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

/** 
 <b>Perform the desired calculation</b> and generate an image. 

 <P>Scans the star catalog, parses each line into a {@link Star}, applies a boost to get a {@link BoostedStar},
 which is then added to the result. Any files in the star catalog directory whose name ends in '.ignore' are ignored. 
 (This is intended as a convenience when testing.)
*/
public final class Starfield {

  /**  Constructor.  */
  public Starfield(InputParameters aInput){
    fInput = aInput;
    fDirOfMotion = new DirectionOfMotion(aInput.getDirectionOfMotionRA(), aInput.getDirectionOfMotionDec(), aInput.getRotation());
  }

  /** 
   Calculate high-level statistics for the starfield using the given input parameters, and output an image.
   
   <P>The statistics returned are:
   <ul>
    <li>the number of stars in the calculation (visible and invisible)
    <li>the number of visible stars for the current boost, above the given limiting magnitude
    <li>the total brightness index of all the visible stars. 
    Here, each 0-magnitude star contributes a value of 1 to the brightness index, for example. 
   </ul>
   
   <P>If the output file is null, then no image file will be created.   
  */
  public StarfieldStats calculate() {
    StarfieldStats result = new StarfieldStats();
    StarfieldImage image = null;
    if (fInput.getOutputFile() != null){
      image = new StarfieldImage(fInput.getProjector(), fInput.getOutputFile(), fInput.getImageSize(), fInput.getMagnification());
    }
    boolean didFirstLine = false;
    for(File catalogFile : fInput.getCatalogDirectory().listFiles()){
      if (catalogFile.isFile()){
        if (catalogFile.getName().endsWith(".ignore")) continue;
        //open the file, process each line, one at a time
        Util.logVerbose("Scanning catalog file. Name: " + catalogFile.getName());
        try (Scanner scanner =  new Scanner(catalogFile) ){
          while (scanner.hasNextLine()){
            String starRecord = scanner.nextLine();
            Star star = fInput.getCatalog().getRecordParser().parse(starRecord);
            process(star, result, image);
            if(!didFirstLine){
              Util.logVerbose("First Record: " + starRecord);
              Util.logVerbose("Parsed as " + star);
              didFirstLine = true;
            }
          }      
        }
        catch (FileNotFoundException ex) {
          //this won't happen because of explicit checking performed earlier
          ex.printStackTrace();
        }        
      }
    }
    
    if (image != null){
      image.generateFile();
    }
    return result;
  }
  
  public InputParameters getInputParams(){ return fInput; }
  
  // PRIVATE

  private InputParameters fInput;
  private Boost fBoost = new Boost();
  private DirectionOfMotion fDirOfMotion;
  
  private void process(Star aStar, StarfieldStats aStats, StarfieldImage aImage){
    if (aStar != null){
      //Util.log(aStar);
      ++aStats.NumStarsInSimulation;
      if (fDirOfMotion.isNotDefault()){
        //Util.log("Direction of motion is non-default");
        fDirOfMotion.changeCoordsOfThe(aStar);
      }
      BoostedStar boostedStar = fBoost.applyBoostTo(aStar, fInput.getBeta());
      //Util.log(boostedStar);
      if (boostedStar.Magnitude <= fInput.getLimitingMagnitude()){
        ++aStats.NumStarsVisible;
        aStats.BrightnessIndex = aStats.BrightnessIndex + Math.pow(2.512,0-boostedStar.Magnitude); //luminosity relative to a mag-0 star
        aImage.add(boostedStar, aStar.RightAscension);
      }
    }
    else {
      ++aStats.NumRecordsRejected;
    }
  }
}