import Foundation import TelegramPresentationData import TelegramStringFormatting private let telegramReleaseDate = Date(timeIntervalSince1970: 1376438400.0) func suggestDates(for string: String, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> [(minDate: Date?, maxDate: Date, string: String?)] { let string = string.folding(options: .diacriticInsensitive, locale: .current).trimmingCharacters(in: .whitespacesAndNewlines).lowercased() if string.count < 3 { return [] } let months: [Int: (String, String)] = [ 1: (strings.Month_GenJanuary, strings.Month_ShortJanuary), 2: (strings.Month_GenFebruary, strings.Month_ShortFebruary), 3: (strings.Month_GenMarch, strings.Month_ShortMarch), 4: (strings.Month_GenApril, strings.Month_ShortApril), 5: (strings.Month_GenMay, strings.Month_ShortMay), 6: (strings.Month_GenJune, strings.Month_ShortJune), 7: (strings.Month_GenJuly, strings.Month_ShortJuly), 8: (strings.Month_GenAugust, strings.Month_ShortAugust), 9: (strings.Month_GenSeptember, strings.Month_ShortSeptember), 10: (strings.Month_GenOctober, strings.Month_ShortOctober), 11: (strings.Month_GenNovember, strings.Month_ShortNovember), 12: (strings.Month_GenDecember, strings.Month_ShortDecember) ] let weekDays: [Int: (String, String)] = [ 1: (strings.Weekday_Monday, strings.Weekday_ShortMonday), 2: (strings.Weekday_Tuesday, strings.Weekday_ShortTuesday), 3: (strings.Weekday_Wednesday, strings.Weekday_ShortWednesday), 4: (strings.Weekday_Thursday, strings.Weekday_ShortThursday), 5: (strings.Weekday_Friday, strings.Weekday_ShortFriday), 6: (strings.Weekday_Saturday, strings.Weekday_ShortSaturday), 7: (strings.Weekday_Sunday, strings.Weekday_ShortSunday.lowercased()), ] let today = strings.Weekday_Today let yesterday = strings.Weekday_Yesterday let dateSeparator = dateTimeFormat.dateSeparator var result: [(Date?, Date, String?)] = [] let calendar = Calendar.current func getLowerDate(for date: Date) -> Date { let components = calendar.dateComponents(in: .current, from: date) let upperComponents = DateComponents(year: components.year, month: components.month, day: components.day, hour: 0, minute: 0, second: 0) return calendar.date(from: upperComponents)! } func getUpperDate(for date: Date) -> Date { let components = calendar.dateComponents(in: .current, from: date) let upperComponents = DateComponents(year: components.year, month: components.month, day: components.day, hour: 23, minute: 59, second: 59) return calendar.date(from: upperComponents)! } let now = Date() let nowComponents = calendar.dateComponents(in: .current, from: now) guard let year = nowComponents.year else { return [] } let midnightDate = calendar.startOfDay(for: now) if today.lowercased().hasPrefix(string) { let todayDate = getUpperDate(for: midnightDate) result.append((midnightDate, todayDate, today)) } if yesterday.lowercased().hasPrefix(string) { let yesterdayMidnight = calendar.date(byAdding: .day, value: -1, to: midnightDate)! let yesterdayDate = getUpperDate(for: yesterdayMidnight) result.append((yesterdayMidnight, yesterdayDate, yesterday)) } func getLowerMonthDate(month: Int, year: Int) -> Date { let upperComponents = DateComponents(year: year, month: month, day: 1, hour: 0, minute: 0, second: 0) return calendar.date(from: upperComponents)! } func getUpperMonthDate(month: Int, year: Int) -> Date { let monthComponents = DateComponents(year: year, month: month) let date = calendar.date(from: monthComponents)! let range = calendar.range(of: .day, in: .month, for: date)! let numDays = range.count let upperComponents = DateComponents(year: year, month: month, day: numDays, hour: 23, minute: 59, second: 59) return calendar.date(from: upperComponents)! } let decimalRange = string.rangeOfCharacter(from: .decimalDigits) if decimalRange != nil { if string.count == 4, let value = Int(string), value <= year { let minDate = getLowerMonthDate(month: 1, year: value) let maxDate = getUpperMonthDate(month: 12, year: value) if maxDate > telegramReleaseDate { result.append((minDate, maxDate, "\(value)")) } } else { do { func process(_ date: Date) { var resultDate = date if resultDate > now && !calendar.isDate(resultDate, equalTo: now, toGranularity: .year) { if let date = calendar.date(byAdding: .year, value: -1, to: resultDate) { resultDate = date } } let stringComponents = string.components(separatedBy: dateSeparator) if stringComponents.count < 3 { for i in 0..<5 { if let date = calendar.date(byAdding: .year, value: -i, to: resultDate), date < now { let lowerDate = getLowerDate(for: resultDate) result.append((lowerDate, date, nil)) } } } else if resultDate < now { let lowerDate = getLowerDate(for: resultDate) result.append((lowerDate, resultDate, nil)) } } let dd = try NSDataDetector(types: NSTextCheckingResult.CheckingType.date.rawValue) if let match = dd.firstMatch(in: string, options: [], range: NSMakeRange(0, string.utf16.count)), let date = match.date, date > telegramReleaseDate { process(date) } else if let match = dd.firstMatch(in: string.replacingOccurrences(of: ".", with: "/"), options: [], range: NSMakeRange(0, string.utf16.count)), let date = match.date, date > telegramReleaseDate { process(date) } } catch { } } } for (day, value) in weekDays { let dayName = value.0.lowercased() let shortDayName = value.1.lowercased() if string == shortDayName || (string.count >= shortDayName.count && dayName.hasPrefix(string)) { var nextDateComponent = calendar.dateComponents([.hour, .minute, .second], from: now) nextDateComponent.weekday = day + calendar.firstWeekday if let date = calendar.nextDate(after: now, matching: nextDateComponent, matchingPolicy: .nextTime, direction: .backward) { let lowerAnchorDate = getLowerDate(for: date) let upperAnchorDate = getUpperDate(for: date) for i in 0..<5 { if let lowerDate = calendar.date(byAdding: .hour, value: -24 * 7 * i, to: lowerAnchorDate), let upperDate = calendar.date(byAdding: .hour, value: -24 * 7 * i, to: upperAnchorDate) { if calendar.isDate(upperDate, equalTo: now, toGranularity: .weekOfYear) { result.append((lowerDate, upperDate, value.0)) } else { result.append((lowerDate, upperDate, nil)) } } } } } } let cleanString = string.trimmingCharacters(in: .decimalDigits).trimmingCharacters(in: .whitespacesAndNewlines) let cleanDigits = string.trimmingCharacters(in: .letters).trimmingCharacters(in: .whitespacesAndNewlines) for (month, value) in months { let monthName = value.0.lowercased() let shortMonthName = value.1.lowercased() if cleanString == shortMonthName || (cleanString.count >= shortMonthName.count && monthName.hasPrefix(cleanString)) { if cleanDigits.count == 4, let year = Int(cleanDigits) { let lowerDate = getLowerMonthDate(month: month, year: year) let upperDate = getUpperMonthDate(month: month, year: year) if upperDate <= now && upperDate > telegramReleaseDate { result.append((lowerDate, upperDate, stringForMonth(strings: strings, month: Int32(month - 1), ofYear: Int32(year - 1900)))) } } else if cleanDigits.isEmpty { for i in (year - 7 ... year).reversed() { let lowerDate = getUpperMonthDate(month: month, year: i) let upperDate = getUpperMonthDate(month: month, year: i) if upperDate <= now && upperDate > telegramReleaseDate { result.append((lowerDate, upperDate, stringForMonth(strings: strings, month: Int32(month - 1), ofYear: Int32(i - 1900)))) } } } } } return result }