work_tock_lib/
clockin.rs

1use chrono::naive::NaiveDate;
2use chrono::offset::Local;
3use chrono::Datelike;
4//use pest::iterators::Pair;
5//use pest::Parser;
6use crate::gob;
7use gobble::Parser;
8use std::collections::BTreeMap;
9use std::fmt::Display;
10
11use crate::err::TokErr;
12//use crate::pesto::{LineNum, Pestable, Rule, TimeFile};
13use 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>), //replacement tag
26    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); //consider changing
93    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}