use regex::Regex;
use std::{fmt, str::FromStr};
use crate::{Error, Progression, Result};
#[derive(Debug, PartialEq, Clone)]
pub struct Song {
pub title: String,
pub composer: String,
pub style: String,
pub key_signature: String,
pub progression: Progression,
}
impl fmt::Display for Song {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"irealbook://{}={}={}={}=n={}",
self.title, self.composer, self.style, self.key_signature, self.progression
)
}
}
impl FromStr for Song {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
parse_irealbook_url(s)
}
}
pub fn parse_irealbook_url(url: &str) -> Result<Song> {
let re = Regex::new(r"irealbook://(.*?)=(.*?)=(.*?)=(.*?)=(.*?)=(.*)").unwrap();
let Some(captures) = re.captures(url) else {
return Err(Error::InvalidUrl);
};
let title = captures
.get(1)
.ok_or(Error::MissingField("Title"))?
.as_str()
.to_owned();
let composer = captures
.get(2)
.ok_or(Error::MissingField("Composer"))?
.as_str()
.to_owned();
let style = captures
.get(3)
.ok_or(Error::MissingField("Style"))?
.as_str()
.to_owned();
let key_signature = captures
.get(4)
.ok_or(Error::MissingField("Key signature"))?
.as_str()
.to_owned();
let progression = captures
.get(6)
.ok_or(Error::MissingField("Chord progression"))?
.as_str()
.parse()?;
Ok(Song {
title,
composer,
style,
key_signature,
progression,
})
}