ElectronicBabylonianLiterature/ebl-frontend

View on GitHub
src/chronology/domain/DateConverter.ts

Summary

Maintainability
A
0 mins
Test Coverage
B
88%
import data from 'chronology/domain/dateConverterData.json'
import DateConverterBase, {
  CalendarProps,
  GregorianProps,
  JulianProps,
  SeBabylonianProps,
  monthNames,
} from 'chronology/domain/DateConverterBase'
import DateConverterChecks from 'chronology/domain/DateConverterChecks'
import { King, findKingByOrderGlobal } from 'chronology/ui/Kings/Kings'

export default class DateConverter extends DateConverterBase {
  checks: DateConverterChecks = new DateConverterChecks()
  earliestDate: CalendarProps
  latestDate: CalendarProps

  constructor() {
    super()
    this.setToEarliestDate()
    this.earliestDate = { ...this.calendar }
    this.setToLatestDate()
    this.latestDate = { ...this.calendar }
    this.setToJulianDate(-310, 4, 3)
  }

  toDateString(calendarType: 'Julian' | 'Gregorian' = 'Gregorian'): string {
    let {
      gregorianDay: day,
      gregorianMonth: month,
      gregorianYear: year,
      bcGregorianYear: bcYear,
    } = this.calendar
    if (calendarType === 'Julian') {
      day = this.calendar.julianDay
      month = this.calendar.julianMonth
      year = this.calendar.julianYear
      bcYear = this.calendar.bcJulianYear
    }
    const suffix = year < 0 ? ' BCE' : ' CE'
    return `${day} ${monthNames[month - 1]} ${
      year < 0 ? bcYear : year
    }${suffix}${calendarType === 'Julian' ? ' PJC' : ' PGC'}`
  }

  rulerToBrinkmanKings(ruler?: string): King | null {
    ruler = ruler ?? this.calendar?.ruler
    if (ruler) {
      const orderGlobal = data.rulerToBrinkmanKings[ruler]
      return findKingByOrderGlobal(orderGlobal)
    }
    return null
  }

  setToEarliestDate(): void {
    this.setToCjdn(1492871)
  }

  setToLatestDate(): void {
    this.setToCjdn(1748871)
  }

  setToEdgeIfOutsideRange(
    params: GregorianProps | JulianProps | SeBabylonianProps
  ): boolean {
    const rangeCheck = this.checks.isDateWithinValidRange(
      params,
      this.earliestDate,
      this.latestDate
    )
    if (rangeCheck.includes(false)) {
      if (rangeCheck[0] === false) {
        this.setToEarliestDate()
      } else {
        this.setToLatestDate()
      }
      return true
    }
    return false
  }

  setToGregorianDate(
    gregorianYear: number,
    gregorianMonth: number,
    gregorianDay: number
  ): void {
    const params = {
      gregorianYear,
      gregorianMonth,
      gregorianDay,
    }
    if (this.setToEdgeIfOutsideRange(params)) {
      return
    }
    const cjdn = this.computeCjdnFromGregorianDate(params)
    this.setToCjdn(cjdn)
  }

  setToJulianDate(
    julianYear: number,
    julianMonth: number,
    julianDay: number
  ): void {
    const params = { julianYear, julianMonth, julianDay }
    if (this.setToEdgeIfOutsideRange(params)) {
      return
    }
    this.applyDate(
      { year: julianYear, month: julianMonth, day: julianDay },
      'julian'
    )
    this.applyGregorianDateWhenJulian()
    this.updateBabylonianDate()
  }

  setToSeBabylonianDate(
    seBabylonianYear: number,
    mesopotamianMonth: number,
    mesopotamianDay: number
  ): void {
    const params = { seBabylonianYear, mesopotamianMonth, mesopotamianDay }
    if (this.setToEdgeIfOutsideRange(params)) {
      return
    }
    const cjdn = this.computeCjdnFromSeBabylonian(
      seBabylonianYear,
      mesopotamianMonth,
      mesopotamianDay
    )
    this.setToCjdn(cjdn)
  }

  setToMesopotamianDate(
    ruler: string,
    regnalYear: number,
    mesopotamianMonth: number,
    mesopotamianDay: number
  ): void {
    mesopotamianMonth = this.shiftMesopotamianMonthIfNoMatchFound(
      ruler,
      regnalYear,
      mesopotamianMonth
    )
    const rulerIndex = data.rulerName.indexOf(ruler)
    if (rulerIndex === -1) throw new Error('Invalid ruler name.')
    const seBabylonianYear = data.rulerSeYears[rulerIndex] + regnalYear - 1
    this.setToSeBabylonianDate(
      seBabylonianYear,
      mesopotamianMonth,
      mesopotamianDay
    )
  }

  setToCjdn(cjdn: number): void {
    this.applyDate(this.computeJulianDateFromCjnd(cjdn), 'julian')
    this.applyDate(this.computeGregorianDateFromCjdn(cjdn), 'gregorian')
    this.updateBabylonianDate(cjdn)
  }

  private shiftMesopotamianMonthIfNoMatchFound(
    ruler: string,
    regnalYear: number,
    mesopotamianMonth: number
  ): number {
    if ([13, 14].includes(mesopotamianMonth)) {
      this.setToMesopotamianDate(ruler, regnalYear, 1, 1)
      if (
        !this.checks.isIncomingDateHasCorrespondingIntercalary(
          mesopotamianMonth,
          this
        )
      ) {
        mesopotamianMonth =
          { 13: 6, 14: 12 }[mesopotamianMonth] ?? mesopotamianMonth
      }
    }
    return mesopotamianMonth
  }
}

Object.assign(DateConverter.prototype, DateConverterChecks.prototype)