1use getset::{Getters, Setters};
31use serde::{Deserialize, Serialize};
32
33use std::collections::{HashMap, HashSet};
34
35use rpfm_lib::error::{RLibError, Result};
36use rpfm_lib::files::{db::DB, loc::Loc, RFileDecoded, table::DecodedData};
37use rpfm_lib::schema::{Definition, DefinitionPatch};
38
39use crate::dependencies::Dependencies;
40
41#[cfg(test)] mod tests;
42
43#[derive(Clone, Debug, Default, Getters, Setters, Deserialize, Serialize)]
49#[getset(get = "pub", set = "pub")]
50pub struct MergeOptions {
51
52 delta_merge: bool,
54
55 resolutions: Vec<MergeResolution>,
57}
58
59#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
61pub struct MergeConflict {
62
63 pub row_key: Vec<String>,
65
66 pub field_name: String,
68
69 pub candidates: Vec<MergeCandidate>,
71}
72
73#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
75pub struct MergeCandidate {
76
77 pub value: String,
79
80 pub source_paths: Vec<String>,
82}
83
84#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
86pub struct MergeResolution {
87
88 pub row_key: Vec<String>,
90
91 pub field_name: String,
93
94 pub chosen_value: String,
96}
97
98pub fn delta_merge_db(sources: &[(&str, &DB)], baseline: Option<&DB>, resolutions: &[MergeResolution]) -> Result<(DB, Vec<MergeConflict>)> {
110 if sources.len() < 2 {
111 return Err(RLibError::RFileMergeTablesNotEnoughTablesProvided);
112 }
113
114 let table_names = sources.iter().map(|(_, db)| db.table_name()).collect::<HashSet<_>>();
115 if table_names.len() > 1 {
116 return Err(RLibError::RFileMergeTablesDifferentNames);
117 }
118
119 let definition = sources[0].1.definition().clone();
120 let patches = sources[0].1.patches().clone();
121 let table_name = sources[0].1.table_name().to_owned();
122
123 let source_data = sources.iter()
124 .map(|(path, db)| {
125 let mut db = (*db).clone();
126 db.set_definition(&definition);
127 (*path, db.data().to_vec())
128 })
129 .collect::<Vec<_>>();
130 let source_rows = source_data.iter().map(|(path, rows)| (*path, rows.as_slice())).collect::<Vec<_>>();
131
132 let baseline_data = baseline.map(|db| {
133 let mut db = db.clone();
134 db.set_definition(&definition);
135 db.data().to_vec()
136 });
137
138 let (rows, conflicts) = delta_merge_rows(&source_rows, baseline_data.as_deref(), &definition, Some(&patches), resolutions);
139
140 let mut merged = DB::new(&definition, Some(&patches), &table_name);
141 merged.set_data(&rows)?;
142
143 Ok((merged, conflicts))
144}
145
146pub fn delta_merge_loc(sources: &[(&str, &Loc)], baseline: Option<&Loc>, resolutions: &[MergeResolution]) -> Result<(Loc, Vec<MergeConflict>)> {
149 if sources.len() < 2 {
150 return Err(RLibError::RFileMergeTablesNotEnoughTablesProvided);
151 }
152
153 let definition = sources[0].1.definition().clone();
154
155 let source_data = sources.iter()
156 .map(|(path, loc)| {
157 let mut loc = (*loc).clone();
158 loc.set_definition(&definition);
159 (*path, loc.data().to_vec())
160 })
161 .collect::<Vec<_>>();
162 let source_rows = source_data.iter().map(|(path, rows)| (*path, rows.as_slice())).collect::<Vec<_>>();
163
164 let baseline_data = baseline.map(|loc| {
165 let mut loc = loc.clone();
166 loc.set_definition(&definition);
167 loc.data().to_vec()
168 });
169
170 let (rows, conflicts) = delta_merge_rows(&source_rows, baseline_data.as_deref(), &definition, None, resolutions);
171
172 let mut merged = Loc::new();
173 merged.set_definition(&definition);
174 merged.set_data(&rows)?;
175
176 Ok((merged, conflicts))
177}
178
179pub fn db_baseline(dependencies: &Dependencies, table_name: &str) -> Option<DB> {
182 let files = dependencies.db_data(table_name, true, true).ok()?;
183
184 let mut baseline: Option<DB> = None;
185 for file in files {
186 if let Ok(RFileDecoded::DB(table)) = file.decoded() {
187 match baseline {
188 None => baseline = Some(table.clone()),
189 Some(ref mut merged) => merged.data_mut().extend(table.data().iter().cloned()),
190 }
191 }
192 }
193
194 baseline
195}
196
197pub fn loc_baseline(dependencies: &Dependencies) -> Option<Loc> {
200 let files = dependencies.loc_data(true, true).ok()?;
201
202 let mut baseline: Option<Loc> = None;
203 for file in files {
204 if let Ok(RFileDecoded::Loc(table)) = file.decoded() {
205 match baseline {
206 None => baseline = Some(table.clone()),
207 Some(ref mut merged) => merged.data_mut().extend(table.data().iter().cloned()),
208 }
209 }
210 }
211
212 baseline
213}
214
215fn delta_merge_rows(
225 sources: &[(&str, &[Vec<DecodedData>])],
226 baseline: Option<&[Vec<DecodedData>]>,
227 definition: &Definition,
228 patches: Option<&DefinitionPatch>,
229 resolutions: &[MergeResolution],
230) -> (Vec<Vec<DecodedData>>, Vec<MergeConflict>) {
231 let fields = definition.fields_processed();
232 let key_positions = fields.iter().enumerate().filter(|(_, field)| field.is_key(patches)).map(|(position, _)| position).collect::<Vec<_>>();
233
234 if key_positions.is_empty() {
236 let rows = sources.iter().flat_map(|(_, rows)| rows.iter().cloned()).collect();
237 return (rows, vec![]);
238 }
239
240 let row_key = |row: &[DecodedData]| key_positions.iter().map(|&position| row[position].clone()).collect::<Vec<DecodedData>>();
241 let row_key_strings = |row: &[DecodedData]| key_positions.iter().map(|&position| row[position].data_to_string().to_string()).collect::<Vec<String>>();
242
243 let baseline_index = baseline.map(|rows| rows.iter().map(|row| (row_key(row), row)).collect::<HashMap<_, _>>()).unwrap_or_default();
244
245 let mut key_order = Vec::new();
247 let mut rows_by_key: HashMap<Vec<DecodedData>, Vec<(&str, &Vec<DecodedData>)>> = HashMap::new();
248 for (source_path, rows) in sources {
249 for row in rows.iter() {
250 let key = row_key(row);
251 if !rows_by_key.contains_key(&key) {
252 key_order.push(key.clone());
253 }
254 rows_by_key.entry(key).or_default().push((source_path, row));
255 }
256 }
257
258 let mut merged_rows = Vec::with_capacity(key_order.len());
259 let mut conflicts = Vec::new();
260
261 for key in key_order {
262 let candidates = &rows_by_key[&key];
263
264 if let [(_, row)] = candidates[..] {
266 merged_rows.push(row.clone());
267 continue;
268 }
269
270 let baseline_row = baseline_index.get(&key).copied();
271 let key_strings = row_key_strings(candidates[0].1);
272 let mut merged_row = baseline_row.cloned().unwrap_or_else(|| candidates[0].1.clone());
273
274 for (column, field) in fields.iter().enumerate() {
275 let mut distinct_values: Vec<(DecodedData, Vec<String>)> = Vec::new();
276 for (source_path, row) in candidates {
277 let value = &row[column];
278 match distinct_values.iter_mut().find(|(existing, _)| existing == value) {
279 Some((_, source_paths)) => source_paths.push((*source_path).to_owned()),
280 None => distinct_values.push((value.clone(), vec![(*source_path).to_owned()])),
281 }
282 }
283
284 if let [(value, _)] = &distinct_values[..] {
286 merged_row[column] = value.clone();
287 continue;
288 }
289
290 if let Some(baseline_row) = baseline_row {
292 let mut diverging = distinct_values.iter().filter(|(value, _)| value != &baseline_row[column]);
293 if let (Some((value, _)), None) = (diverging.next(), diverging.next()) {
294 merged_row[column] = value.clone();
295 continue;
296 }
297 }
298
299 let resolution = resolutions.iter().find(|resolution| resolution.row_key == key_strings && resolution.field_name == field.name());
300 match resolution.and_then(|resolution| DecodedData::new_from_type_and_string(field.field_type(), &resolution.chosen_value).ok()) {
301 Some(value) => merged_row[column] = value,
302 None => conflicts.push(MergeConflict {
303 row_key: key_strings.clone(),
304 field_name: field.name().to_owned(),
305 candidates: distinct_values.into_iter().map(|(value, source_paths)| MergeCandidate { value: value.data_to_string().to_string(), source_paths }).collect(),
306 }),
307 }
308 }
309
310 merged_rows.push(merged_row);
311 }
312
313 (merged_rows, conflicts)
314}