|
| 1 | +-- Handle conditional access tags as described in the OSM wiki: |
| 2 | +-- https://wiki.openstreetmap.org/wiki/Conditional_restrictions |
| 3 | + |
| 4 | +-- Note that we only handle conditional tags for a date range, |
| 5 | +-- meant to be used for temporary restrictions, typically due to |
| 6 | +-- construction. We also require the date range to be at least a |
| 7 | +-- week long |
| 8 | + |
| 9 | + |
| 10 | + |
| 11 | +ConditionalAccess = {} |
| 12 | + |
| 13 | + |
| 14 | +local function parse_conditional_access(way, key) |
| 15 | + local conditional = way:get_value_by_key(key .. ':conditional') |
| 16 | + if not conditional then |
| 17 | + return nil |
| 18 | + end |
| 19 | + |
| 20 | + -- Examples of conditional tags: "no @ (2018 May 22-2018 Oct 7) |
| 21 | + -- or "no @ 2018 Jun 01-2018 Jul 23" |
| 22 | + local condition, time_range = conditional:match("([^@]+)@(.+)") |
| 23 | + if not condition or not time_range then |
| 24 | + return nil |
| 25 | + end |
| 26 | + |
| 27 | + local start_date_str, end_date_str = time_range:match("([^-]+)-(.+)") |
| 28 | + if not start_date_str or not end_date_str then |
| 29 | + return nil |
| 30 | + end |
| 31 | + |
| 32 | + local function parse_date(date_str) |
| 33 | + local year, month, day = date_str:match("(%d+)%s+(%a+)%s+(%d+)") |
| 34 | + |
| 35 | + local month_names = { |
| 36 | + Jan = 1, Feb = 2, Mar = 3, Apr = 4, May = 5, Jun = 6, |
| 37 | + Jul = 7, Aug = 8, Sep = 9, Oct = 10, Nov = 11, Dec = 12 |
| 38 | + } |
| 39 | + month = month_names[month] |
| 40 | + if not year or not month or not day then |
| 41 | + return nil |
| 42 | + end |
| 43 | + |
| 44 | + local numericYear = tonumber(year) |
| 45 | + local numericDay = tonumber(day) |
| 46 | + if numericYear and numericDay then |
| 47 | + return os.time({ year = numericYear, month = month, day = numericDay }) |
| 48 | + else |
| 49 | + return nil |
| 50 | + end |
| 51 | + end |
| 52 | + |
| 53 | + local start_date = parse_date(start_date_str) |
| 54 | + local end_date = parse_date(end_date_str) |
| 55 | + local current_date = os.time() |
| 56 | + |
| 57 | + -- Require start and end date to be more than a week apart |
| 58 | + if not start_date or not end_date or end_date - start_date < 60 * 60 * 24 * 7 then |
| 59 | + return nil |
| 60 | + end |
| 61 | + |
| 62 | + if current_date >= start_date and current_date <= end_date then |
| 63 | + return condition:match("%S+") |
| 64 | + else |
| 65 | + return nil |
| 66 | + end |
| 67 | + end |
| 68 | + |
| 69 | +function ConditionalAccess.parse_by_set(way, keys) |
| 70 | + for i, key in ipairs(keys) do |
| 71 | + local conditional = parse_conditional_access(way, key) |
| 72 | + if conditional then |
| 73 | + return conditional |
| 74 | + end |
| 75 | + end |
| 76 | + return nil |
| 77 | +end |
| 78 | + |
| 79 | +return ConditionalAccess |
0 commit comments