<commit_before>package edu.gemini.dbTools.ephemeris

import edu.gemini.skycalc.JulianDate
import edu.gemini.spModel.core.{RightAscension, Angle, Coordinates, Declination}

import java.time.Instant
import java.time.ZoneOffset.UTC
import java.time.format.DateTimeFormatter
import java.time.temporal.{TemporalAccessor, TemporalQuery}
import java.util.Locale.US

import scala.util.parsing.combinator.JavaTokenParsers
import scalaz._, Scalaz._

/** Support for formatting and parsing TCS ephemeris files. */
object EphemerisFileFormat {

  /** Marker for the start of ephemeris elements in the file. */
  val SOE = "$$SOE"

  /** Marker for the end of ephemeris elements in the file. */
  val EOE = "$$EOE"

  object Time {
    // Text date format
    val DateFormatString = "yyyy-MMM-dd HH:mm"

    // Regular expression that extracts the time string in the `DateFormatString`
    // format from a line in an ephemeris file.
    val TimeRegex        = """(\d{4}-[a-zA-Z]{3}-\d{1,2}\s+\d{1,2}:\d{1,2})""".r

    val DateFormat       = DateTimeFormatter.ofPattern(DateFormatString, US).withZone(UTC)

    def format(time: Instant): String =
      DateFormat.format(time)

    def parse(s: String): Throwable \/ Instant =
      \/.fromTryCatchNonFatal {
        DateFormat.parse(s, new TemporalQuery[Instant] () {
          override def queryFrom(temporal: TemporalAccessor): Instant =
            Instant.from(temporal)
         }
        )
      }
  }

  def format(ephemeris: EphemerisMap): String = {
    def formatCoords(coords: Coordinates): String = {
      val ra  = Angle.formatHMS(coords.ra.toAngle, " ", 4)
      val dec = Declination.formatDMS(coords.dec, " ", 3)
      s"$ra $dec"
    }

    val lines = ephemeris.toList.map { case (time, (coords, raTrack, decTrack)) =>
      val timeS     = Time.format(time)
      val jdS       = f"${new JulianDate(time.toEpochMilli).toDouble}%.9f"
      val coordsS   = formatCoords(coords)
      val raTrackS  = f"$raTrack%9.5f"
      val decTrackS = f"$decTrack%9.5f"
      s" $timeS $jdS     $coordsS $raTrackS $decTrackS"
    }

    lines.mkString(s"$SOE\n", "\n", (lines.isEmpty ? "" | "\n") + s"$EOE\n")
  }

  object Parser extends JavaTokenParsers {
    override val whiteSpace = """[ \t]+""".r

    private val eol: Parser[Any]     = """(\r?\n)""".r
    private val soeLine: Parser[Any] = SOE~eol<commit_msg>OCSADV-383: remove extra space for TCS<commit_after>package edu.gemini.dbTools.ephemeris

import edu.gemini.skycalc.JulianDate
import edu.gemini.spModel.core.{RightAscension, Angle, Coordinates, Declination}

import java.time.Instant
import java.time.ZoneOffset.UTC
import java.time.format.DateTimeFormatter
import java.time.temporal.{TemporalAccessor, TemporalQuery}
import java.util.Locale.US

import scala.util.parsing.combinator.JavaTokenParsers
import scalaz._, Scalaz._

/** Support for formatting and parsing TCS ephemeris files. */
object EphemerisFileFormat {

  /** Marker for the start of ephemeris elements in the file. */
  val SOE = "$$SOE"

  /** Marker for the end of ephemeris elements in the file. */
  val EOE = "$$EOE"

  object Time {
    // Text date format
    val DateFormatString = "yyyy-MMM-dd HH:mm"

    // Regular expression that extracts the time string in the `DateFormatString`
    // format from a line in an ephemeris file.
    val TimeRegex        = """(\d{4}-[a-zA-Z]{3}-\d{1,2}\s+\d{1,2}:\d{1,2})""".r

    val DateFormat       = DateTimeFormatter.ofPattern(DateFormatString, US).withZone(UTC)

    def format(time: Instant): String =
      DateFormat.format(time)

    def parse(s: String): Throwable \/ Instant =
      \/.fromTryCatchNonFatal {
        DateFormat.parse(s, new TemporalQuery[Instant] () {
          override def queryFrom(temporal: TemporalAccessor): Instant =
            Instant.from(temporal)
         }
        )
      }
  }

  def format(ephemeris: EphemerisMap): String = {
    def formatCoords(coords: Coordinates): String = {
      val ra  = Angle.formatHMS(coords.ra.toAngle, " ", 4)
      val dec = Declination.formatDMS(coords.dec, " ", 3)
      s"$ra $dec"
    }

    val lines = ephemeris.toList.map { case (time, (coords, raTrack, decTrack)) =>
      val timeS     = Time.format(time)
      val jdS       = f"${new JulianDate(time.toEpochMilli).toDouble}%.9f"
      val coordsS   = formatCoords(coords)
      val raTrackS  = f"$raTrack%9.5f"
      val decTrackS = f"$decTrack%9.5f"
      s" $timeS $jdS    $coordsS $raTrackS $decTrackS"
    }

    lines.mkString(s"$SOE\n", "\n", (lines.isEmpty ? "" | "\n") + s"$EOE\n")
  }

  object Parser extends JavaTokenParsers {
    override val whiteSpace = """[ \t]+""".r

    private val eol: Parser[Any]     = """(\r?\n)""".r
    private val soeLine: Parser[Any] = SOE~eol
{'fraction_non_alphanumeric': 0.13527180783817952, 'fraction_numerical': 0.00695322376738306, 'mean_word_length': 3.0297113752122242, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3878952', 'n_tokens_mistral': 1727, 'n_tokens_neox': 1630, 'n_words': 376}