1use chrono::naive::NaiveDate;
2use chrono::offset::Local;
3use chrono::Datelike;
4use crate::gob;
7use gobble::Parser;
8use std::collections::BTreeMap;
9use std::fmt::Display;
10
11use crate::err::TokErr;
12use crate::s_time::STime;
14
15#[derive(Debug)]
16pub struct LineClockAction {
17 pub line: usize,
18 pub col: usize,
19 pub action: ClockAction,
20}
21
22#[derive(Debug)]
23pub enum ClockAction {
24 AddTag(String),
25 ClearTags(Option<String>), In(STime),
27 Out(STime),
28 InOut(STime, STime),
29 SetJob(String),
30 SetDate(usize, usize, Option<isize>),
31 SetNum(String, isize),
32 DefGroup(String, Vec<String>),
33}
34
35use self::ClockAction::*;
36
37pub fn read_date(s: &str) -> Result<NaiveDate, TokErr> {
38 let (d, m, yop) = gob::Date
39 .parse_s(s)
40 .map_err(|_| TokErr::Mess("Could not read date".to_string()))?;
41 Ok(NaiveDate::from_ymd(
42 yop.map(|y| y as i32).unwrap_or(Local::today().year()),
43 m as u32,
44 d as u32,
45 ))
46}
47
48impl ClockAction {
49 pub fn as_date(&self) -> Option<NaiveDate> {
50 match self {
51 ClockAction::SetDate(d, m, Some(y)) => {
52 Some(NaiveDate::from_ymd(*y as i32, *m as u32, *d as u32))
53 }
54 ClockAction::SetDate(d, m, None) => {
55 let date = Local::today();
56 Some(NaiveDate::from_ymd(date.year(), *m as u32, *d as u32))
57 }
58 _ => None,
59 }
60 }
61}
62
63#[derive(Clone, Debug, PartialEq, Eq)]
64pub enum Clockin {
65 In(InData),
66 Out(STime),
67}
68
69pub struct AllData {
70 pub clocks: Vec<Clockin>,
71 pub groups: BTreeMap<String, Vec<String>>,
72}
73
74#[derive(Clone, Debug, PartialEq, Eq)]
75pub struct InData {
76 pub time: STime,
77 pub date: NaiveDate,
78 pub job: String,
79 pub tags: Vec<String>,
80 pub line: usize,
81}
82
83impl Display for InData {
84 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
85 write!(f, "{}({} - {})", self.job, self.date, self.time)
86 }
87}
88
89pub fn read_string(s: &str) -> Result<AllData, TokErr> {
90 let mut job = "General".to_string();
91 let mut tags = Vec::new();
92 let mut date = NaiveDate::from_ymd(1, 1, 1); let mut year: Option<isize> = None;
94
95 let mut c_res = Vec::new();
96 let mut groups = BTreeMap::new();
97
98 let c_ac = gob::line_clock_actions()
99 .parse_s(s)
100 .map_err(|e| e.strung())?;
101 let mut errs = Vec::new();
102
103 for ac in c_ac {
104 match ac.action {
105 SetJob(j) => job = j,
106 SetDate(d, m, Some(y)) => date = NaiveDate::from_ymd(y as i32, m as u32, d as u32),
107 SetDate(d, m, None) => match year {
108 Some(y) => date = NaiveDate::from_ymd(y as i32, m as u32, d as u32),
109 None => errs.push(TokErr::NotSet("date").on_line(ac.line)),
110 },
111 AddTag(s) => tags.push(s.clone()),
112 ClearTags(Some(s)) => tags = vec![s],
113 ClearTags(None) => tags.clear(),
114 SetNum(k, v) => {
115 if &k == "year" {
116 year = Some(v);
117 }
118 }
119 In(time) => c_res.push(Clockin::In(InData {
120 time,
121 job: job.clone(),
122 tags: tags.clone(),
123 date,
124 line: ac.line,
125 })),
126
127 Out(time) => c_res.push(Clockin::Out(time)),
128 InOut(tin, tout) => {
129 c_res.push(Clockin::In(InData {
130 time: tin,
131 job: job.clone(),
132 tags: tags.clone(),
133 date,
134 line: ac.line,
135 }));
136 c_res.push(Clockin::Out(tout));
137 }
138 DefGroup(k, v) => {
139 groups.insert(k, v);
140 }
141 }
142 }
143
144 if errs.len() > 0 {
145 Err(TokErr::Lines(errs))
146 } else {
147 Ok(AllData {
148 clocks: c_res,
149 groups: groups,
150 })
151 }
152}