use crate::subsequence::*;
use regex::Regex;
use std::{
convert::TryFrom,
error::Error,
fs::File,
io::{BufReader, Read},
path::PathBuf,
};
pub struct ChartData {
pub player: u8,
pub genre: String,
pub title: String,
pub artist: String,
pub bpm: f64,
pub play_level: u8,
pub sound_paths: Vec<PathBuf>,
pub subseqs: Vec<SubSequence>,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Object {
Silent,
Note { sound: usize },
}
impl ChartData {
fn from_data(data: String) -> Result<Self, Box<dyn Error>> {
let r = Regex::new(r"#(.{3})(.{2}):(.*)").unwrap();
let mut player = 0;
let mut genre = "".to_string();
let mut title = "".to_string();
let mut artist = "".to_string();
let mut bpm = 0.0;
let mut level = 0;
let mut paths = Vec::new();
let mut subseqs = Vec::new();
for line in data.lines() {
if let Some((command, value)) = line.split_once(" ") {
if !command.starts_with("#") {
continue;
}
match &command[1..] {
"PLAYER" => player = value.parse::<u8>()?,
"GENRE" => genre = value.to_string(),
"TITLE" => title = value.to_string(),
"ARTIST" => artist = value.to_string(),
"BPM" => bpm = value.parse::<f64>()?,
"PLAYLEVEL" => level = value.parse::<u8>()?,
_ => {
if command.starts_with("#WAV") || command.starts_with("#wav") {
paths.push(PathBuf::from(value));
}
}
}
}
}
for m in r.find_iter(data.as_str()) {
if let Ok(seq) = SubSequence::try_from(m.as_str().to_string()) {
subseqs.push(seq);
}
}
Ok(ChartData {
player,
genre,
title,
artist,
bpm,
play_level: level,
sound_paths: paths,
subseqs,
})
}
pub fn from_path(p: PathBuf) -> Result<Self, Box<dyn Error>> {
let f = File::open(&p)?;
let mut r = BufReader::new(f);
let mut data = String::new();
r.read_to_string(&mut data).expect("Failed to read data");
Self::from_data(data)
}
pub fn count_measures(&self) -> usize {
let mut subseqs2 = self.subseqs.clone();
subseqs2.dedup_by_key(|x| x.measure);
subseqs2.len()
}
pub fn get_measure(&self, measure: u32) -> Vec<SubSequence> {
self.subseqs
.iter()
.filter(|&x| x.measure == measure)
.map(|x| x.clone())
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sequence_test() {
let seq =
SubSequence::try_from("#00111:0101010001".to_string()).expect("Failed to parse string");
assert_eq!(seq.measure, 1);
assert_eq!(seq.channel, 11);
assert_eq!(
seq.notes,
vec![
Object::Note { sound: 1 },
Object::Note { sound: 1 },
Object::Note { sound: 1 },
Object::Silent,
Object::Note { sound: 1 }
]
);
}
}