aboutsummaryrefslogtreecommitdiff
path: root/src/soon/agenda.nim
blob: 1c2ce1172bc56c30f85def93ae7604c70a783b47 (plain)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import std/[times, strutils, sequtils, tables, algorithm]
import conditionchecker, typechecker, parsetime, columnize

type Event = object
  name: string
  time: DateTime
  attachments: seq[string]

type Calendar = object
  events: seq[Event]
  readyForAttachments: bool

type ConditionTable = Table[string, seq[string]]

proc allDay(): DateTime =
  return parse("0000", "HHmm", utc())

proc splitWhitespaceExceptParens(str:string): seq[string] =
# Splits a string on whitespace, but maintains whitespace in date groups like (Jan 15)
  var inParens = false
  for token in str.splitWhitespace:
    if inParens:
      result.add(result.pop & ' ' & token)
    else:
      result.add(token)
    for c in token:
      if c == '(': inParens = true
      if c == ')': inParens = false

proc parseDateToTable(date: string): ConditionTable =
  var table = initTable[string,seq[string]]()
  let conditions = splitWhitespaceExceptParens(date)
  for c in conditions:
    let condType = typechecker.checkType(c)
    if not table.hasKey(condType):
      table[condType] = @[]
    table[condType].add(c)
  return table

proc allConditionsMet(conditions: ConditionTable, date: DateTime): bool =
  if conditions.hasKey("unknown"): return false
  for cs in conditions.values:
    if not any(cs, proc(x: string): bool = conditionchecker.checkCond(x, date)):
      return false
  return true

proc newEvents(e: string, conditions: ConditionTable): seq[Event] =
  let event = e.strip
  if conditions.hasKey("time"):
    for t in conditions["time"]:
      result.add(Event(name: event, time: parsetime.toDateTime(t), attachments: @[]))
  else:
    result.add(Event(name: event, time: allDay(), attachments: @[]))

proc processEventLine(line: string, date: DateTime, cal: Calendar): Calendar =
  result = cal
  let split = line.split(",", maxsplit = 1)
  var eventDate = split[0].strip
  var eventName = split[1].strip
  let conditions = parseDateToTable(eventDate)
  if allConditionsMet(conditions, date):
    result.events = result.events.concat(newEvents(eventName, conditions))
    result.readyForAttachments = true
  else:
    result.readyForAttachments = false

proc processLine(line: string, date: DateTime, cal: Calendar): Calendar =
  result = cal
  let stripped = line.strip
  if stripped.startsWith('+'):
    if result.events.len > 0 and result.readyForAttachments:
      result.events[^1].attachments.add(line)
  elif stripped.startsWith('-'):
    result.readyForAttachments = false
  else:
    result = processEventLine(line, date, cal)

proc getCalendarForDate(cal: seq[string], date: DateTime): Calendar =
  result.readyForAttachments = false
  for line in cal:
    result = processLine(line, date, result)

#proc sortTable(t: ConditionTable) =
#  for

# Check nim-lang algorithm basic usage
proc compare(a, b: string): int =
  cmp(a.len, b.len)

proc startWithDate(datePrinted: bool, date: DateTime, format: string): seq[Column] =
  if datePrinted:
    result.add(Column(text: "", color: fgWhite))
  else:
    result.add(Column(text: date.format(format), color: fgYellow))

proc eventTime(event: Event): string =
  if event.time.monthday != 1:
    result = event.time.format("HH:mm")
  else:
    result = ""

# TODO: Sort me
proc getDaysEvents(cal: seq[string], date: DateTime, format: string): seq[Line] =
  var events = getCalendarForDate(cal, date).events
  var datePrinted = false
  for event in events:
    var columns = startWithDate(datePrinted, date, format)
    datePrinted = true
    columns.add(Column(text: eventTime(event), color: fgBlue))
    columns.add(Column(text: event.name, color: fgWhite))
    result.add(Line(columns: columns, attachments: event.attachments))

proc printAgenda*(calendar: seq[string], past: int, future: int) =
  let now = now()
  let today = dateTime(now.year, now.month, now.monthday, 00, 00, 00, 00, local())
  var agenda = newSeq[Line]()
  for day in past..future:
    let curDay = today + day.days
    agenda = agenda.concat(getDaysEvents(calendar, curDay, "ddd  yyyy MMM dd"))
  columnize.echo(agenda)