Christopher Hotchkiss Christopher Hotchkiss
Login

Code

remindwall / RWPureSwift / Sources / AppTypes / ReminderPart.swift

Back to remindwall — Current RemindWall

Download this file

import Foundation
import SwiftData

public enum DaysOfWeek: Int, CaseIterable, Sendable {
    case Sunday = 1,
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday
}

public struct ReminderPart: Equatable, Sendable {
    //Range 1 = Sun to 7 = Sat
    public var weekDay: DaysOfWeek
    public var hour: Int
    public var minute: Int
    
    public init(){
        self.weekDay = .Sunday
        self.hour = 1
        self.minute = 0
    }
    
    public init(weekDay: DaysOfWeek, hour: Int, minute: Int) {
        self.weekDay = weekDay
        self.hour = hour
        self.minute = minute
    }
    
    public init(date: Date, calendar: Calendar){
        self.weekDay = DaysOfWeek(rawValue: calendar.component(.weekday, from: date))!
        self.hour = calendar.component(.hour, from: date)
        self.minute = calendar.component(.minute, from: date)
    }
    
    public func earlyScan() -> ReminderPart {
        var newWeekDay = weekDay.rawValue
        
        //2 hours before
        var newHour = hour - 2
        if newHour < 0 {
            newHour = 24 + newHour
            newWeekDay = newWeekDay - 1
        }
        if newWeekDay < 1 {
            newWeekDay = 7 + newWeekDay
        }
        
        return ReminderPart(weekDay: DaysOfWeek(rawValue:newWeekDay)!, hour: newHour, minute: minute)
    }
    
    public func lateReminder() -> ReminderPart {
        var newWeekDay = weekDay.rawValue
        
        //4 hours after
        var newHour = hour + 4
        if newHour > 23 {
            newHour -= 24
            newWeekDay += 1
        }
        
        if newWeekDay > 7 {
            newWeekDay -= 7
        }
        
        return ReminderPart(weekDay: DaysOfWeek(rawValue:newWeekDay)!, hour: newHour, minute: minute)
    }
    
    /// By default a reminder is late if we are within 4 hours after its window
    public func inLateWindow(asOf: Date, calendar: Calendar) -> Bool {
        let now_rt = ReminderPart(date: asOf, calendar: calendar)
        
        let late_rt = self.lateReminder()
        
        //Have to be on the same days for this to even be close
        if now_rt.weekDay != self.weekDay && now_rt.weekDay != late_rt.weekDay {
            
            return false
        }
        
        //Are we in the right hour range?
        if now_rt.weekDay == self.weekDay && now_rt.hour < self.hour {
            return false
        }
        
        if now_rt.weekDay == late_rt.weekDay && now_rt.hour > late_rt.hour {
            return false
        }
        
        //Are we in the minute range?
        if now_rt.weekDay == self.weekDay && now_rt.hour == self.hour && now_rt.minute < self.minute {
            return false
        }
        
        if now_rt.weekDay == late_rt.weekDay && now_rt.hour == late_rt.hour && now_rt.minute >= late_rt.minute {
            return false
        }
        
        return true
    }
    
    /// By default a reminder scan window is two hours before OR in the late window
    public func inScanWindow(asOf: Date, calendar: Calendar) -> Bool {
        if self.inLateWindow(asOf: asOf, calendar: calendar){
            return true
        }
        
        //Now we just have to check for early
        let now_rt = ReminderPart(date: asOf, calendar: calendar)
        
        let early_rt = self.earlyScan()
        
        //Have to be on the same days for this to even be close
        if now_rt.weekDay != self.weekDay && now_rt.weekDay != early_rt.weekDay {
            return false
        }
        
        //Are we in the right hour range?
        if now_rt.weekDay == early_rt.weekDay && now_rt.hour < early_rt.hour {
            return false
        }
        
        if now_rt.weekDay == self.weekDay && now_rt.hour > self.hour {
            return false
        }
        
        //Are we in the minute range?
        if now_rt.weekDay == early_rt.weekDay && now_rt.hour == early_rt.hour && now_rt.minute < early_rt.minute {
            return false
        }
        
        if now_rt.weekDay == self.weekDay && now_rt.hour == self.hour && now_rt.minute > self.minute {
            return false
        }
        
        return true
    }
}

extension ReminderPart: CustomDebugStringConvertible {
    public var debugDescription: String {
        return "ReminderPart(weekDay: \(weekDay), hour: \(hour), minute: \(minute)"
    }
}