1use std::collections::HashMap;
5use std::collections::HashSet;
6use std::io;
7use std::path::Path;
8
9use crate::io::read_lines;
13use crate::node::Node;
14use crate::policy::Policy;
15use crate::relation::Relation;
16
17#[derive(Debug, Clone)]
18pub struct PadmetSpec {
19 pub dic_of_relations_in: HashMap<String, Vec<Relation>>,
20 pub dic_of_relations_out: HashMap<String, Vec<Relation>>,
21 pub dic_of_nodes: HashMap<String, Node>,
22 pub policy: Policy,
23 pub info: HashMap<String, HashMap<String, String>>,
24}
25
26#[derive(PartialEq)]
27pub enum PadmetSection {
28 Default,
29 Policy,
30 DatabaseInformation,
31 Nodes,
32 Relations,
33}
34
35impl PadmetSpec {
36 pub fn new(
37 dic_of_relations_in: HashMap<String, Vec<Relation>>,
38 dic_of_relations_out: HashMap<String, Vec<Relation>>,
39 dic_of_nodes: HashMap<String, Node>,
40 policy: Policy,
41 info: HashMap<String, HashMap<String, String>>,
42 ) -> Self {
43 PadmetSpec {
44 dic_of_relations_in,
45 dic_of_relations_out,
46 dic_of_nodes,
47 policy,
48 info,
49 }
50 }
51
52 pub fn from_file<P>(filename: P) -> io::Result<PadmetSpec>
53 where
54 P: AsRef<Path>,
55 {
56 let mut dic_of_relations_in: HashMap<String, Vec<Relation>> = HashMap::new();
57 let mut dic_of_relations_out: HashMap<String, Vec<Relation>> = HashMap::new();
58 let mut dic_of_nodes: HashMap<String, Node> = HashMap::new();
59 let mut policy: Policy = Policy::new();
60 let mut info: HashMap<String, HashMap<String, String>> = HashMap::new();
61
62 let mut padmet_section: PadmetSection = PadmetSection::Default;
63 let lines = read_lines(filename)?;
64 let mut current_data: Option<String> = None;
65 for line in lines.map_while(Result::ok) {
66 if !line.is_empty() {
67 if line == "Data Base informations" {
69 padmet_section = PadmetSection::DatabaseInformation;
70 } else if line == "Policy" {
71 padmet_section = PadmetSection::Policy;
72 } else if line == "Nodes" {
73 padmet_section = PadmetSection::Nodes;
74 } else if line == "Relations" {
75 padmet_section = PadmetSection::Relations;
76 } else if padmet_section == PadmetSection::DatabaseInformation {
78 if !line.contains("\t") {
79 let line = line.replace(":", "");
80 current_data = Some(line.clone());
81 info.insert(line.clone(), HashMap::new());
82 } else {
83 let line = line.replace("\t", "");
84 let mut parts = line.split(":");
85 let key = parts.next().expect("Error parsing PADMet on Data Base informations section. Key not found.").to_owned();
86 let value = parts.next().expect("Error parsing PADMet on Data Base informations section. Value not found.").to_owned();
87 if let Some(ref data_key) = current_data {
88 let hashmap = info
89 .get_mut(data_key)
90 .expect("Expect key to be already present in the info hashmap.");
91 hashmap.insert(key, value);
92 }
93 }
94 } else if padmet_section == PadmetSection::Policy {
95 } else if padmet_section == PadmetSection::Nodes {
97 let mut parts = line.split("\t");
98 let node_type: String = parts.next().expect("Expect node_type").to_owned();
99 let node_id: String = parts.next().expect("Expect node_id").to_owned();
100 let mut node_misc: HashMap<String, Vec<String>> = HashMap::new();
101 let misc_items: Vec<String> = parts.map(|e| e.to_owned()).collect();
102 let mut i = 0;
103 while i + 1 < misc_items.len() {
104 let key = misc_items[i].clone();
105 let value = misc_items[i + 1].clone();
106 if let Some(misc_data) = node_misc.get_mut(&key) {
107 misc_data.push(value);
108 } else {
109 node_misc.insert(key, vec![value]);
110 }
111 i += 2;
112 }
113 let node = Node::new(node_type.clone(), node_id.clone(), node_misc);
115 dic_of_nodes.insert(node_id.clone(), node);
116 } else if padmet_section == PadmetSection::Relations {
117 let mut parts = line.split("\t");
118 let relation_id_in: String =
119 parts.next().expect("Expect relation in node").to_owned();
120 let relation_type: String =
121 parts.next().expect("Expect relation type").to_owned();
122 let relation_id_out: String =
123 parts.next().expect("Expect relation out node").to_owned();
124 let mut relation_misc: HashMap<String, Vec<String>> = HashMap::new();
125 let misc_items: Vec<String> = parts.map(|e| e.to_owned()).collect();
126 let mut i = 0;
127 while i + 1 < misc_items.len() {
128 let key = &misc_items[i];
129 let value = &misc_items[i + 1];
130 if let Some(misc_data) = relation_misc.get_mut(key) {
131 misc_data.push(value.clone());
132 } else {
133 relation_misc.insert(key.clone(), vec![value.clone()]);
134 }
135 i += 2;
136 }
137 let relation = Relation::new(
139 relation_id_in.clone(),
140 relation_id_out.clone(),
141 relation_type,
142 relation_misc,
143 );
144
145 if !dic_of_relations_in.contains_key(&relation_id_in) {
146 dic_of_relations_in.insert(relation_id_in.clone(), Vec::new());
147 }
148 dic_of_relations_in
149 .get_mut(&relation_id_in)
150 .expect("Key should be already be created.")
151 .push(relation.clone());
152 if !dic_of_relations_out.contains_key(&relation_id_out) {
153 dic_of_relations_out.insert(relation_id_out.clone(), Vec::new());
154 }
155 dic_of_relations_out
156 .get_mut(&relation_id_out)
157 .expect("Key should be already be created.")
158 .push(relation.clone());
159 }
160 }
161 }
162
163 let padmet_object = PadmetSpec::new(
164 dic_of_relations_in,
165 dic_of_relations_out,
166 dic_of_nodes,
167 policy,
168 info,
169 );
170 Ok(padmet_object)
171 }
172
173 pub fn get_all_relations(&self) -> Vec<Relation> {
175 let mut all_relations: Vec<Relation> = Vec::new();
176 for relations in self.dic_of_relations_in.values() {
177 for relation in relations {
178 all_relations.push(relation.clone());
179 }
180 }
181 for relations in self.dic_of_relations_out.values() {
182 for relation in relations {
183 all_relations.push(relation.clone());
184 }
185 }
186 all_relations
188 }
189
190 pub fn get_relations_type_id_in(
192 &self,
193 relation_type: &String,
194 relation_id_in: &String,
195 ) -> Vec<Relation> {
196 if let Some(relations) = self.dic_of_relations_in.get(relation_id_in) {
197 let relations_of_type: Vec<Relation> = relations
198 .iter()
199 .filter(|&r| r.relation_type == *relation_type)
200 .cloned()
201 .collect();
202 return relations_of_type;
203 }
204 Vec::new()
205 }
206
207 pub fn get_relations_type_id_out(
209 &self,
210 relation_type: &String,
211 relation_id_out: &String,
212 ) -> Vec<Relation> {
213 if let Some(relations) = self.dic_of_relations_out.get(relation_id_out) {
214 let relations_of_type: Vec<Relation> = relations
215 .iter()
216 .filter(|&r| r.relation_type == *relation_type)
217 .cloned()
218 .collect();
219 return relations_of_type;
220 }
221 Vec::new()
222 }
223
224 pub fn get_relations(
226 self,
227 relation_id_in: &String,
228 relation_type: &String,
229 relation_id_out: &String,
230 ) -> Vec<Relation> {
231 if let Some(relations) = self.dic_of_relations_in.get(relation_id_in) {
232 let relations_filtered = relations
233 .iter()
234 .filter(|&r| r.relation_type == *relation_type && r.id_out == *relation_id_out)
235 .cloned()
236 .collect();
237 return relations_filtered;
238 }
239 Vec::new()
240 }
241
242 pub fn get_nodes_of_type(&self, node_type: &str) -> Vec<Node> {
243 self.dic_of_nodes
244 .values()
245 .filter(|node| node.node_type == node_type)
246 .cloned()
247 .collect()
248 }
249
250 pub fn get_compounds(&self) -> Vec<Node> {
252 self.get_nodes_of_type("compound")
253 }
254
255 pub fn get_reactions(&self) -> Vec<Node> {
257 self.get_nodes_of_type("reaction")
258 }
259
260 pub fn get_genes(&self) -> Vec<Node> {
262 self.get_nodes_of_type("gene")
263 }
264
265 pub fn get_pathways(&self) -> Vec<Node> {
267 self.get_nodes_of_type("pathway")
268 }
269
270 pub fn get_pathways_reactions(&self) -> HashMap<String, HashSet<String>> {
272 let pathways = self.get_pathways();
273 let mut pathway_to_reactions: HashMap<String, HashSet<String>> = HashMap::new();
274 for pathway in pathways {
275 let reactions_relations =
276 self.get_relations_type_id_out(&"is_in_pathway".to_owned(), &(pathway.node_id));
277 let reactions_id: Vec<String> = reactions_relations
278 .into_iter()
279 .map(|relation| relation.id_in)
280 .collect();
281 let reaction_set: HashSet<String> = HashSet::from_iter(reactions_id.iter().cloned());
282 pathway_to_reactions.insert(pathway.node_id, reaction_set);
283 }
284 pathway_to_reactions
285 }
286}
287
288#[cfg(test)]
289mod tests {
290
291 use std::path::PathBuf;
292
293 use super::*;
294
295 #[test]
296 fn test_open_padmet() {
297 let padmet_test_file_1: PathBuf =
298 PathBuf::from("vendor/padmet/tests/test_data/padmet/padmet_1.padmet");
299 let padmet_object: PadmetSpec = PadmetSpec::from_file(padmet_test_file_1).unwrap();
300 let nodes = &padmet_object.dic_of_nodes;
301 dbg!(nodes);
302 let reactions = padmet_object.get_reactions();
303 assert!(reactions.len() > 0);
304
305 let pathways = padmet_object.get_pathways();
306 assert!(pathways.len() > 0);
307 }
308
309 #[test]
310 fn test_get_reactions_of_pathway() {
311 let padmet_test_file_1: PathBuf =
312 PathBuf::from("vendor/padmet/tests/test_data/padmet/padmet_1.padmet");
313 let padmet_object: PadmetSpec = PadmetSpec::from_file(padmet_test_file_1).unwrap();
314 let pathways = padmet_object.get_pathways();
315 let pathway_reactions = padmet_object.get_pathways_reactions();
316 assert_eq!(pathways.len(), pathway_reactions.len());
317 assert!(pathway_reactions.get("FAO-PWY").expect("pathway FAO-PWY should exist in the test padmet file").len() > 0);
318 }
319
320}