1use super::prelude::*;
4
5pub type IndexedJob<'a> = (usize, &'a Job);
7
8#[derive(Debug, Clone)]
10pub struct JobList<'a> {
11 jobs: Vec<IndexedJob<'a>>,
13 pub configuration: &'a Configuration,
15}
16
17impl<'a> IntoIterator for JobList<'a> {
18 type Item = IndexedJob<'a>;
19 type IntoIter = std::vec::IntoIter<Self::Item>;
20
21 fn into_iter(self) -> Self::IntoIter {
22 self.jobs.into_iter()
23 }
24}
25
26impl<'a> From<&'a JobListOwned> for JobList<'a> {
27 fn from(list: &'a JobListOwned) -> Self {
28 Self {
29 configuration: &list.configuration,
30 jobs: list.iter().map(|(n, j)| (*n, j)).collect(),
31 }
32 }
33}
34
35impl<'a> std::fmt::Display for JobList<'a> {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 writeln!(f)?;
38 let mut count = 0;
39 for (pos, job) in self.iter() {
40 writeln!(f, " Pos: {}", pos + 1)?;
41 job.writeln(f, self.configuration.get(&job.tags))?;
42 writeln!(f)?;
43 count += 1;
44 }
45 let pay = {
46 if let Some(pay) = self.pay_overall() {
47 format!(" = ${}", format::pay_pure(pay))
48 } else {
49 String::new()
50 }
51 };
52 if count > 1 {
53 writeln!(
54 f,
55 "Total: {} job(s), {} hours{}",
56 self.len(),
57 format::hours_pure(self.hours_overall()),
58 pay,
59 )?;
60 }
61 Ok(())
62 }
63}
64
65impl<'a> JobList<'a> {
66 pub fn new(jobs: Vec<(usize, &'a Job)>, configuration: &'a Configuration) -> Self {
68 Self {
69 jobs,
70 configuration,
71 }
72 }
73 pub fn new_from(jobs: &'a Jobs) -> Self {
75 Self {
76 jobs: Vec::new(),
77 configuration: &jobs.configuration,
78 }
79 }
80 pub fn push(&mut self, pos: usize, job: &'a Job) {
82 self.jobs.push((pos, job))
83 }
84 pub fn iter(&self) -> core::slice::Iter<'_, IndexedJob> {
86 self.jobs.iter()
87 }
88 pub fn is_empty(&self) -> bool {
90 self.jobs.is_empty()
91 }
92 pub fn len(&self) -> usize {
94 self.jobs.len()
95 }
96 pub fn drain(&mut self, count: usize) -> Result<(), Error> {
98 if count > self.jobs.len() {
99 return Err(Error::ToFewJobs(count, self.jobs.len()));
100 }
101 self.jobs.drain(0..(self.jobs.len() - count));
102 Ok(())
103 }
104 pub fn tags(&self) -> TagSet {
106 let mut tags = TagSet::new();
107 for (_, job) in &self.jobs {
108 tags.insert_many(job.tags.clone());
109 }
110 tags
111 }
112 pub fn positions(&self) -> Positions {
114 Positions::from_iter(self.jobs.iter().map(|(n, _)| *n))
115 }
116 pub fn get_configuration(&self, tags: &TagSet) -> &Properties {
118 for tag in &tags.0 {
119 if let Some(properties) = self.configuration.tags.get(tag) {
120 return properties;
121 }
122 }
123 &self.configuration.base
124 }
125 pub fn hours_overall(&self) -> f64 {
127 let mut hours = 0.0;
128 for (_, job) in &self.jobs {
129 hours += job.hours(self.get_configuration(&job.tags))
130 }
131 hours
132 }
133 pub fn pay_overall(&self) -> Option<f64> {
135 let mut pay_sum = 0.0;
136 let mut has_payment = false;
137 for (_, job) in &self.jobs {
138 let properties = self.get_configuration(&job.tags);
139 if let Some(rate) = properties.rate {
140 pay_sum += rate * job.hours(properties);
141 has_payment = true;
142 }
143 }
144 if has_payment {
145 Some(pay_sum)
146 } else {
147 None
148 }
149 }
150}