1use std::env;
2use std::fs::{File, DirBuilder};
3use std::io::{Read, Write};
4use std::collections::hash_map::HashMap;
5use std::path::Path;
6
7use super::util::get_index;
8
9#[derive(Debug)]
10pub struct ConfigFile {
11 pub dictionary_path: String,
12 pub show_phrases: bool,
13 pub profile: String,
14}
15
16#[derive(Debug, Clone)]
17pub struct ProfileFile {
18 pub path: String,
19 pub profiles: HashMap<String, Profile>,
20}
21
22
23impl ProfileFile {
24 pub fn new(path: String) -> Self {
25 ProfileFile {
26 path,
27 profiles: HashMap::new()
28 }
29 }
30 pub fn load(path: String) -> Result<Self, String> {
31 let file = File::open(path.clone());
32 if let Ok(mut file) = file {
33 let mut contents = String::new();
34 if let Err(_) = file.read_to_string(&mut contents) {
35 return Err("Could not read profile file to string".to_string());
36 }
37 let mut lines = contents.lines();
38 println!("{}", path);
39 let mut profile_file = ProfileFile{ path, profiles: HashMap::new()};
40 let mut current_profile: Option<Profile> = None;
41 while let Some(line) = lines.next() {
42 if line.starts_with("[") && line.ends_with("]") {
44 let profile_name = line.replace("[", "");
45 let profile_name = profile_name.replace("]", "");
46 let new_profile = Some(Profile {
47 name: profile_name,
48 words_learnt: HashMap::new(),
49 });
50 if let Some(profile) = current_profile {
53 profile_file.profiles.insert(profile.name.clone(), profile);
54 }
55 current_profile = new_profile;
56 continue;
57 }
58 if let Some(profile) = current_profile.clone() {
63 let mut profile = profile;
64 let mut line_separated = line.split("#");
65 let word = line_separated.next();
66 let count = line_separated.next();
67 if let Some(word) = word {
68 let count = if let Some(count) = count {
71 count.parse::<i64>().unwrap_or(0)
72 } else {
73 0
74 };
75 profile.words_learnt.insert(word.to_string(), count);
76 current_profile = Some(profile);
77 }
78 }
79 }
80 if let Some(profile) = current_profile {
81 profile_file.profiles.insert(profile.name.clone(), profile);
83 } else {
84 profile_file.profiles.insert("default".to_string(), Profile {
86 words_learnt: HashMap::new(),
87 name: "default".to_string(),
88 });
89 }
90 Ok(profile_file)
91 } else {
92 Err(format!("Profile files could not be opened on: {}", path.clone()))
93 }
94 }
95 pub fn save(self: &Self) -> Result<(), String> {
96 if let Some(dir) = Path::new(&self.path).parent() {
97 DirBuilder::new().recursive(true).create(dir).unwrap();
98 }
99 let file = File::create(self.path.clone());
100 match file {
101 Ok(file) => {
102 self.save_to_file(file)
103 },
104 Err(err) => {
105 Err(format!(
106 "Profile files could not be saved to: {} (Err: {:?})",
107 self.path.clone(),
108 err
109 ))
110 },
111 }
112 }
113 pub fn save_to_file(self: &Self, mut file: File) -> Result<(), String> {
114 for profile in self.profiles.values() {
115 file.write_all(format!("[{}]\n", profile.name).as_bytes())
116 .expect("Profile could not be saved on profile file");
117 for (word, count) in &profile.words_learnt {
118 file.write_all(format!("{}#{}\n", word, count).as_bytes())
119 .expect("Could not write word into profile")
120 }
121 }
122 Ok(())
123 }
124}
125
126#[derive(Debug, Clone)]
127pub struct Profile {
128 pub name: String,
129 pub words_learnt: HashMap<String, i64>,
130}
131
132#[derive(Debug, Clone)]
133pub struct Config {
134 pub dictionary_path: String,
135 pub show_phrases: bool,
136 pub profile: Profile,
137 pub profile_file: ProfileFile,
138 pub debugging: bool,
139}
140
141pub fn extract_config(args: &Vec<String>) -> Result<Config, String> {
142 let has_dict = args.contains(&"--dict".to_string()) || args.contains(&"-d".to_string());
144 let dictionary_path;
145 if has_dict {
146 let index_of_dict = (get_index(&args, "--dict") + 1) as usize;
147 dictionary_path = args
148 .get(index_of_dict)
149 .unwrap_or(&"./src".to_string())
150 .to_owned();
151 } else {
152 let current_dir = env::current_dir();
153 match current_dir {
154 Ok(path) => {
155 dictionary_path = format!("{}{}", path.display(), "dict.xdxf");
156 }
157 Err(error) => return Err(error.to_string()),
158 }
159 }
160 let show_phrases = args.contains(&"--phrases".to_string()) || args.contains(&"-p".to_string());
161 let debugging = args.contains(&"--debug".to_string());
162
163 let has_profile = args.contains(&"--profile".to_string());
164 let mut profile = Profile {
165 name: "default".to_string(),
166 words_learnt: HashMap::new(),
167 };
168 let home = env::var("HOME").expect("Cannot load profiles if $HOME is not set");
170 let path = format!("{}/{}", home, ".config/typo-eq/profiles.txt");
171 let profile_file;
172 if has_profile {
173 let index_of_profile = (get_index(&args, "--profile") + 1) as usize;
174 let profile_name = args.get(index_of_profile)
175 .unwrap_or(&"default".to_string())
176 .to_owned();
177 profile.name = profile_name.clone();
178 let file = ProfileFile::load(path.clone());
179 let saved_profile = if let Ok(file) = file {
180 profile_file = file;
181 if let Some(p) = profile_file.profiles.get(&profile_name) {
182 Some(p.clone())
183 } else {None}
184 } else {
185 profile_file = ProfileFile::new(path);
186 None
187 };
188 if let Some(saved_profile) = saved_profile {
189 profile = saved_profile;
190 }
191 } else {
192 profile_file = ProfileFile::new(path);
193 }
194
195 Ok(Config {
196 dictionary_path,
197 debugging,
198 show_phrases,
199 profile,
200 profile_file,
201 })
202}