File size: 4,539 Bytes
6ee917b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79


/// 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 }
}