<commit_before>// @flow
import moment from 'moment-timezone'
const CENTRAL_TZ = 'America/Winnipeg'
const TIME_FORMAT = 'h:mma'
const RESULT_FORMAT = 'h:mma'

import type {BuildingType, NamedBuildingScheduleType, SingleBuildingScheduleType, DayOfWeekEnumType} from './types'
import type momentT from 'moment'
import flatten from 'lodash/flatten'
import sortBy from 'lodash/sortBy'

type HourPairType = {open: momentT, close: momentT};

export function parseHours({from: fromTime, to: toTime}: SingleBuildingScheduleType, m: momentT): HourPairType {
  let dayOfYear = m.dayOfYear()

  // if the moment is before 3am
  if (m.hour() < 2) {
    dayOfYear -= 1
  }

  let open = moment.tz(fromTime, TIME_FORMAT, true, CENTRAL_TZ)
  open.dayOfYear(dayOfYear)

  let close = moment.tz(toTime, TIME_FORMAT, true, CENTRAL_TZ)
  close.dayOfYear(dayOfYear)

  if (close.isBefore(open)) {
    close.add(1, 'day')
  }

  return {open, close}
}

export function formatBuildingTimes(schedule: SingleBuildingScheduleType, m: momentT): string {
  let {open, close} = parseHours(schedule, m)

  let openString = open.format(RESULT_FORMAT)
  let closeString = close.format(RESULT_FORMAT)
  closeString = closeString === '12:00am' ? 'Midnight' : closeString
  return `${openString} — ${closeString}`
}

export function getStatusOfBuildingAtMoment(schedule: SingleBuildingScheduleType, m: momentT): string {
  let {open, close} = parseHours(schedule, m)

  if (m.isBefore(open) && m.clone().add(30, 'minutes').isSameOrAfter(open)) {
    return `Opens ${m.to(open)}`
  }
  if (m.isBetween(open, close, 'minute', '[)')) {
    if (m.clone().add(30, 'minutes').isSameOrAfter(close)) {
      return `Closes ${m.to(close)}`
    }
    return 'Open'
  }
  return 'Closed'
}

export function isBuildingOpenAtMoment(schedule: SingleBuildingScheduleType, m: momentT): boolean {
  let {open, close} = parseHours(schedule, m)
  return m.isBetween(open, close, 'minute', '[)')
}

export function getDetailedBuildingStatus(info: BuildingType, m: momentT): [boolean, string|null, string][] {
  // Friday: 9:00am – Midnight
  // -- or --
  // Friday Breakfast: 7:00am – 9:45am
  // Friday Lunch: 10:30am – 2:00pm
  // Friday Dinner: 4:30pm – 7:30pm
  // -- alternately --
  // Friday Faculty/Staff Swim: 7:00am – 9:45am
  // Friday Lap Swim: 12:45pm – 2:00pm
  // Friday Open Swim: 7:00am – 2:00pm

  let dayOfWeek = ((m.format('dd'): any): DayOfWeekEnumType)

  let schedules = normalizeBuildingSchedule(info)
  if (!schedules.length) {
    return [[false, null, 'Hours unknown']]
  }

  let results = schedules.map(set => {
    let prefix = set.title
    let filteredSchedules = set.hours.filter(sched => sched.days.includes(dayOfWeek))
    if (!filteredSchedules.length) {
      return [[false, prefix, 'Closed today']]
    }

    return filteredSchedules.map(schedule => {
      let isActive = isBuildingOpenAtMoment(schedule, m)
      let status = formatBuildingTimes(schedule, m)
      if (set.isPhysicallyOpen === false) {
        isActive = false
      }
      return [isActive, prefix, status]
    })
  })

  return flatten(results)
}

export function getShortBuildingStatus(info: BuildingType, m: momentT): string {
  let dayOfWeek = ((m.format('dd'): any): DayOfWeekEnumType)

  let schedules = normalizeBuildingSchedule(info)
  if (!schedules.length) {
    return 'Closed'
  }

  let statuses = schedules.map(set => {
    if (set.isPhysicallyOpen === false) {
      return 'Closed'
    }

    let filteredSchedules = set.hours.filter(sched => sched.days.includes(dayOfWeek))
    if (!filteredSchedules.length) {
      return 'Closed'
    }

    return filteredSchedules.map(schedule => getStatusOfBuildingAtMoment(schedule, m))
  })

  return flatten(statuses).find(status => status !== 'Closed') || 'Closed'
}

export function isBuildingOpen(info: BuildingType, m: momentT): boolean {
  let dayOfWeek = ((m.format('dd'): any): DayOfWeekEnumType)

  let schedules = normalizeBuildingSchedule(info)
  if (!schedules.length) {
    return false
  }

  let results = schedules.map(set => {
    if (set.isPhysicallyOpen === false) {
      return false
    }

    let filteredSchedules = set.hours.filter(sched => sched.days.includes(dayOfWeek))
    if (!filteredSchedules.length) {
      return false
    }

    return filteredSchedules.map(schedule => isBuildingOpenAtMoment(schedule, m))
  })<commit_msg>add support for closedForChapelTime<commit_after>// @flow
import moment from 'moment-timezone'
const CENTRAL_TZ = 'America/Winnipeg'
const TIME_FORMAT = 'h:mma'
const RESULT_FORMAT = 'h:mma'

import type {BuildingType, NamedBuildingScheduleType, SingleBuildingScheduleType, DayOfWeekEnumType} from './types'
import type momentT from 'moment'
import flatten from 'lodash/flatten'
import sortBy from 'lodash/sortBy'

type HourPairType = {open: momentT, close: momentT};

export function parseHours({from: fromTime, to: toTime}: SingleBuildingScheduleType, m: momentT): HourPairType {
  let dayOfYear = m.dayOfYear()

  // if the moment is before 3am
  if (m.hour() < 2) {
    dayOfYear -= 1
  }

  let open = moment.tz(fromTime, TIME_FORMAT, true, CENTRAL_TZ)
  open.dayOfYear(dayOfYear)

  let close = moment.tz(toTime, TIME_FORMAT, true, CENTRAL_TZ)
  close.dayOfYear(dayOfYear)

  if (close.isBefore(open)) {
    close.add(1, 'day')
  }

  return {open, close}
}


import {chapelSchedule} from '../../data/new-building-hours'

export function isChapelTime(m: momentT, schedules: SingleBuildingScheduleType[]=chapelSchedule): boolean {
  let dayOfWeek = ((m.format('dd'): any): DayOfWeekEnumType)
  let sched = schedules.find(sched => sched.days.includes(dayOfWeek))
  if (!sched) {
    return false
  }

  return _isBuildingOpenAtMoment(sched, m)
}

export function formatBuildingTimes(schedule: SingleBuildingScheduleType, m: momentT): string {
  let {open, close} = parseHours(schedule, m)

  let openString = open.format(RESULT_FORMAT)
  let closeString = close.format(RESULT_FORMAT)
  closeString = closeString === '12:00am' ? 'Midnight' : closeString
  return `${openString} — ${closeString}`
}

export function getStatusOfBuildingAtMoment(schedule: SingleBuildingScheduleType, m: momentT): string {
  let {open, close} = parseHours(schedule, m)

  if (m.isBefore(open) && m.clone().add(30, 'minutes').isSameOrAfter(open)) {
    return `Opens ${m.to(open)}`
  }
  if (m.isBetween(open, close, 'minute', '[)')) {
    if (m.clone().add(30, 'minutes').isSameOrAfter(close)) {
      return `Closes ${m.to(close)}`
    }
    return 'Open'
  }
  return 'Closed'
}

export function _isBuildingOpenAtMoment(schedule: SingleBuildingScheduleType, m: momentT): boolean {
  let {open, close} = parseHours(schedule, m)
  return m.isBetween(open, close, 'minute', '[)')
}

export function isBuildingOpenAtMoment(schedule: SingleBuildingScheduleType, m: momentT): boolean {
  if (isChapelTime(m)) {
    return false
  }
  return _isBuildingOpenAtMoment(schedule, m)
}

export function getDetailedBuildingStatus(info: BuildingType, m: momentT): [boolean, string|null, string][] {
  // Friday: 9:00am – Midnight
  // -- or --
  // Friday Breakfast: 7:00am – 9:45am
  // Friday Lunch: 10:30am – 2:00pm
  // Friday Dinner: 4:30pm – 7:30pm
  // -- alternately --
  // Friday Faculty/Staff Swim: 7:00am – 9:45am
  // Friday Lap Swim: 12:45pm – 2:00pm
  // Friday Open Swim: 7:00am – 2:00pm

  let dayOfWeek = ((m.format('dd'): any): DayOfWeekEnumType)

  let schedules = normalizeBuildingSchedule(info)
  if (!schedules.length) {
    return [[false, null, 'Hours unknown']]
  }

  let results = schedules.map(set => {
    let prefix = set.title
    if (set.closedForChapelTime && isChapelTime(m)) {
      return [[false, prefix, 'Closed for chapel']]
    }

    let filteredSchedules = set.hours.filter(sched => sched.days.includes(dayOfWeek))
    if (!filteredSchedules.length) {
      return [[false, prefix, 'Closed today']]
    }

    return filteredSchedules.map(schedule => {
      let isActive = isBuildingOpenAtMoment(schedule, m)
      let status = formatBuildingTimes(schedule, m)
      if (set.isPhysicallyOpen === false) {
        isActive = false
      }
      return [isActive, prefix, status]
    })
  })

  return flatten(results)
}

export function getShortBuildingStatus(info: BuildingType, m: momentT): string {
  let dayOfWeek = ((m.format('dd'): any): DayOfWeekEnumType)

  let schedules = normalizeBuildingSchedule(info)
  if (!schedules.length) {
    return 'Closed'
  }

  let statuses = schedules.map(set => {
    if (set.isPhysicallyOpen === false) {
      return 'Closed'
    }
    if (set.closedForChapelTime && isChapelTime(m)) {
      return 'Closed (Chapel)'
    }

    let filteredSchedules = set.hours.filter(sched => sched.days.includes(dayOfWeek))
    if (!filteredSchedules.length) {
      return 'Closed'
    }

    return filteredSchedules.map(schedule => getStatusOfBuildingAtMoment(schedule, m))
  })

  return flatten(statuses).find(status => status !== 'Closed') || 'Closed'
}

export function isBuildingOpen(info: BuildingType, m: momentT): boolean {
  let dayOfWeek = ((m.format('dd'): any): DayOfWeekEnumType)

  let schedules = normalizeBuildingSchedule(info)
  if (!schedules.length) {
    return false
  }

  let results = schedules.map(set => {
    if (set.isPhysicallyOpen === false) {
      return false
    }
    if (set.closedForChapelTime && isChapelTime(m)) {
      return false
    }

    let filteredSchedules = set.hours.filter(sched => sched.days.includes(dayOfWeek))
    if (!filteredSchedules.length) {
      return false
    }

    return filteredSchedules.map(schedule => isBuildingOpenAtMoment(schedule, m))
  })
{'fraction_non_alphanumeric': 0.13430202387130255, 'fraction_numerical': 0.011001556824078879, 'mean_word_length': 4.037114479874543, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 24, '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': '970183', 'n_tokens_mistral': 3386, 'n_tokens_neox': 3120, 'n_words': 758}