open-wether / Sources /App /Helper /Reader /GenericReaderProvider.swift
soiz1's picture
Migrated from GitHub
6ee917b verified
/// Can generate a reader with an associated domain -> Could be simplified later once all controller use a comon class to pass variables instead of more protocols
protocol GenericReaderProvider {
associatedtype DomainProvider: GenericDomainProvider
init?(domain: DomainProvider, lat: Float, lon: Float, elevation: Float, mode: GridSelectionMode, options: GenericReaderOptions) throws
init?(domain: DomainProvider, gridpoint: Int, options: GenericReaderOptions) throws
}
extension GenericReaderProvider {
/// Prepare readers for Point, MultiPoint and BoundingBox queries
public static func prepareReaders(domains: [DomainProvider], params: ApiQueryParameter, currentTime: Timestamp, forecastDayDefault: Int, forecastDaysMax: Int, pastDaysMax: Int, allowedRange: Range<Timestamp>) throws -> [(locationId: Int, timezone: TimezoneWithOffset, time: ForecastApiTimeRange, perModel: [(domain: DomainProvider, reader: () throws -> (Self?))])] {
let options = params.readerOptions
let prepared = try params.prepareCoordinates(allowTimezones: true)
switch prepared {
case .coordinates(let coordinates):
return try coordinates.map { prepared in
let coordinates = prepared.coordinate
let timezone = prepared.timezone
let time = try params.getTimerange2(timezone: timezone, current: currentTime, forecastDaysDefault: forecastDayDefault, forecastDaysMax: forecastDaysMax, startEndDate: prepared.startEndDate, allowedRange: allowedRange, pastDaysMax: pastDaysMax)
return (coordinates.locationId, timezone, time, domains.compactMap { domain in
return (domain, {
return try Self.init(domain: domain, lat: coordinates.latitude, lon: coordinates.longitude, elevation: coordinates.elevation, mode: params.cell_selection ?? .land, options: options)
})
})
}
case .boundingBox(let bbox, dates: let dates, timezone: let timezone):
return try domains.flatMap ({ domain in
guard let grid = domain.genericDomain?.grid else {
throw ForecastapiError.generic(message: "Bounding box calls not supported for domain \(domain)")
}
guard let gridpoionts = grid.findBox(boundingBox: bbox) else {
throw ForecastapiError.generic(message: "Bounding box calls not supported for grid of domain \(domain)")
}
if dates.count == 0 {
let time = try params.getTimerange2(timezone: timezone, current: currentTime, forecastDaysDefault: forecastDayDefault, forecastDaysMax: forecastDaysMax, startEndDate: nil, allowedRange: allowedRange, pastDaysMax: pastDaysMax)
var locationId = -1
return gridpoionts.map( { gridpoint in
locationId += 1
return (locationId, timezone, time, [(domain, { () -> Self? in
guard let reader = try Self.init(domain: domain, gridpoint: gridpoint, options: options) else {
return nil
}
return reader
})])
})
}
return try dates.flatMap({ date -> [(Int, TimezoneWithOffset, ForecastApiTimeRange, [(DomainProvider, () throws -> Self?)])] in
let time = try params.getTimerange2(timezone: timezone, current: currentTime, forecastDaysDefault: forecastDayDefault, forecastDaysMax: forecastDaysMax, startEndDate: date, allowedRange: allowedRange, pastDaysMax: pastDaysMax)
var locationId = -1
return gridpoionts.map( { gridpoint in
locationId += 1
return (locationId, timezone, time, [(domain, { () -> Self? in
guard let reader = try Self.init(domain: domain, gridpoint: gridpoint, options: options) else {
return nil
}
return reader
})])
})
})
})
}
}
}
protocol GenericDomainProvider {
var genericDomain: GenericDomain? { get }
}
extension GenericDomain where Self: GenericDomainProvider {
var genericDomain: GenericDomain? { self }
}