use quick_xml::{
Reader, Writer,
events::{BytesEnd, BytesStart, Event},
};
use super::MapPart;
use crate::{Error, Result, symbols::SymbolSet};
#[derive(Debug, Default, Clone)]
pub struct MapParts(pub Vec<MapPart>);
impl MapParts {
pub fn push(&mut self, part: MapPart) {
self.0.push(part);
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn merge_all_parts(&mut self, new_name: Option<String>) {
while let Some(part) = self.0.pop() {
if let Some(first) = self.0.first_mut() {
first.merge(part);
} else {
self.0.push(part);
break;
}
}
if let Some(name) = new_name
&& let Some(first) = self.0.first_mut()
{
first.name = name;
}
}
pub fn merge_two_parts(&mut self, mut part_1_index: usize, part_2_index: usize) -> Result<()> {
if part_1_index >= self.len() || part_2_index >= self.len() || part_1_index == part_2_index
{
Err(Error::MapPartMergeError)
} else {
let part2 = self.0.remove(part_2_index);
if part_1_index > part_2_index {
part_1_index -= 1;
}
self.0[part_1_index].merge(part2);
Ok(())
}
}
pub fn remove_map_part_by_index(&mut self, index: usize) -> Option<MapPart> {
if index < self.len() {
Some(self.0.remove(index))
} else {
None
}
}
pub fn get_map_part_by_name(&self, name: &str) -> Option<&MapPart> {
self.0.iter().find(|p| p.name.as_str() == name)
}
pub fn get_map_part_by_name_mut(&mut self, name: &str) -> Option<&mut MapPart> {
self.0.iter_mut().find(|p| p.name.as_str() == name)
}
pub fn get_map_part_by_index(&self, index: usize) -> Option<&MapPart> {
if index >= self.0.len() {
None
} else {
Some(&self.0[index])
}
}
pub fn get_map_part_by_index_mut(&mut self, index: usize) -> Option<&mut MapPart> {
if index >= self.0.len() {
None
} else {
Some(&mut self.0[index])
}
}
pub fn iter(&self) -> std::slice::Iter<'_, MapPart> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, MapPart> {
self.0.iter_mut()
}
}
impl MapParts {
pub(crate) fn write<W: std::io::Write>(
self,
writer: &mut Writer<W>,
symbols: &SymbolSet,
) -> Result<()> {
writer.write_event(Event::Start(BytesStart::new("parts").with_attributes([
("count", self.0.len().to_string().as_str()),
("current", "0"),
])))?;
writer.get_mut().write_all(b"\n")?;
for part in self.0 {
part.write(writer, symbols)?;
writer.get_mut().write_all(b"\n")?;
}
writer.write_event(Event::End(BytesEnd::new("parts")))?;
Ok(())
}
pub(crate) fn parse<R: std::io::BufRead>(
reader: &mut Reader<R>,
symbols: &SymbolSet,
) -> Result<Self> {
let mut parts = Vec::new();
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf)? {
Event::Start(bytes_start) => {
if matches!(bytes_start.local_name().as_ref(), b"part") {
parts.push(MapPart::parse(reader, &bytes_start, symbols)?);
}
}
Event::End(_) => break,
Event::Eof => {
return Err(Error::ParseOmapFileError(
"Unexpected EOF in parsing MapParts".to_string(),
));
}
_ => (),
}
}
Ok(MapParts(parts))
}
}