use std::path::Path;
use strict_num_extended::{FinF64, NonNegativeF64, PositiveF64};
use crate::bms::{
command::{
ObjId, StringValue,
channel::Channel,
time::{ObjTime, Track},
},
model::{
bmp::{AtBgaDef, BgaDef, Bmp},
judge::ExRankDef,
wav::ExWavDef,
},
parse::{ParseWarning, Result},
};
use crate::bms::model::obj::{
BgaObj, BgmVolumeObj, BpmChangeObj, JudgeObj, KeyVolumeObj, ScrollingFactorObj,
SectionLenChangeObj, SpeedObj, StopObj, TextObj,
};
use crate::bms::{
command::{
graphics::Argb,
minor_command::{StpEvent, SwBgaEvent, WavCmdEvent},
},
model::obj::{BgaArgbObj, BgaKeyboundObj, BgaOpacityObj, OptionObj, SeekObj},
};
pub trait Prompter {
fn handle_def_duplication(&self, duplication: DefDuplication) -> DuplicationWorkaround;
fn handle_track_duplication(&self, duplication: TrackDuplication) -> DuplicationWorkaround;
fn handle_channel_duplication(&self, duplication: ChannelDuplication) -> DuplicationWorkaround;
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum DefDuplication<'a> {
Bmp {
id: ObjId,
older: &'a Bmp,
newer: &'a Bmp,
},
BpmChange {
id: ObjId,
older: &'a StringValue<PositiveF64>,
newer: &'a StringValue<PositiveF64>,
},
ChangeOption {
id: ObjId,
older: &'a str,
newer: &'a str,
},
SpeedFactorChange {
id: ObjId,
older: &'a StringValue<PositiveF64>,
newer: &'a StringValue<PositiveF64>,
},
ScrollingFactorChange {
id: ObjId,
older: &'a StringValue<FinF64>,
newer: &'a StringValue<FinF64>,
},
Text {
id: ObjId,
older: &'a str,
newer: &'a str,
},
Wav {
id: ObjId,
older: &'a Path,
newer: &'a Path,
},
AtBga {
id: ObjId,
older: &'a AtBgaDef,
newer: &'a AtBgaDef,
},
Bga {
id: ObjId,
older: &'a BgaDef,
newer: &'a BgaDef,
},
ExRank {
id: ObjId,
older: &'a ExRankDef,
newer: &'a ExRankDef,
},
ExWav {
id: ObjId,
older: &'a ExWavDef,
newer: &'a ExWavDef,
},
Stop {
id: ObjId,
older: &'a StringValue<NonNegativeF64>,
newer: &'a StringValue<NonNegativeF64>,
},
BgaArgb {
id: ObjId,
older: &'a Argb,
newer: &'a Argb,
},
WavCmdEvent {
wav_index: ObjId,
older: &'a WavCmdEvent,
newer: &'a WavCmdEvent,
},
SwBgaEvent {
id: ObjId,
older: &'a SwBgaEvent,
newer: &'a SwBgaEvent,
},
SeekEvent {
id: ObjId,
older: &'a StringValue<FinF64>,
newer: &'a StringValue<FinF64>,
},
}
pub enum TrackDuplication<'a> {
SectionLenChangeEvent {
track: Track,
older: &'a SectionLenChangeObj,
newer: &'a SectionLenChangeObj,
},
}
pub enum ChannelDuplication<'a> {
BpmChangeEvent {
time: ObjTime,
older: &'a BpmChangeObj,
newer: &'a BpmChangeObj,
},
ScrollingFactorChangeEvent {
time: ObjTime,
older: &'a ScrollingFactorObj,
newer: &'a ScrollingFactorObj,
},
SpeedFactorChangeEvent {
time: ObjTime,
older: &'a SpeedObj,
newer: &'a SpeedObj,
},
BgaChangeEvent {
time: ObjTime,
older: &'a BgaObj,
newer: &'a BgaObj,
},
BgaOpacityChangeEvent {
time: ObjTime,
older: &'a BgaOpacityObj,
newer: &'a BgaOpacityObj,
},
BgaArgbChangeEvent {
time: ObjTime,
older: &'a BgaArgbObj,
newer: &'a BgaArgbObj,
},
StpEvent {
time: ObjTime,
older: &'a StpEvent,
newer: &'a StpEvent,
},
StopEvent {
time: ObjTime,
older: &'a StopObj,
newer: &'a StopObj,
},
BgmVolumeChangeEvent {
time: ObjTime,
older: &'a BgmVolumeObj,
newer: &'a BgmVolumeObj,
},
KeyVolumeChangeEvent {
time: ObjTime,
older: &'a KeyVolumeObj,
newer: &'a KeyVolumeObj,
},
SeekMessageEvent {
time: ObjTime,
older: &'a SeekObj,
newer: &'a SeekObj,
},
TextEvent {
time: ObjTime,
older: &'a TextObj,
newer: &'a TextObj,
},
JudgeEvent {
time: ObjTime,
older: &'a JudgeObj,
newer: &'a JudgeObj,
},
BgaKeyboundEvent {
time: ObjTime,
older: &'a BgaKeyboundObj,
newer: &'a BgaKeyboundObj,
},
OptionEvent {
time: ObjTime,
older: &'a OptionObj,
newer: &'a OptionObj,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum DuplicationWorkaround {
UseOlder,
UseNewer,
WarnAndUseOlder,
WarnAndUseNewer,
}
impl DuplicationWorkaround {
pub(crate) fn apply_def<T>(self, target: &mut T, newer: T, id: ObjId) -> Result<()> {
match self {
Self::UseOlder => Ok(()),
Self::UseNewer => {
*target = newer;
Ok(())
}
Self::WarnAndUseOlder => Err(ParseWarning::DuplicatingDef(id)),
Self::WarnAndUseNewer => {
*target = newer;
Err(ParseWarning::DuplicatingDef(id))
}
}
}
pub(crate) fn apply_track<T>(
self,
target: &mut T,
newer: T,
track: Track,
channel: Channel,
) -> Result<()> {
match self {
Self::UseOlder => Ok(()),
Self::UseNewer => {
*target = newer;
Ok(())
}
Self::WarnAndUseOlder => Err(ParseWarning::DuplicatingTrackObj(track, channel)),
Self::WarnAndUseNewer => {
*target = newer;
Err(ParseWarning::DuplicatingTrackObj(track, channel))
}
}
}
pub(crate) fn apply_channel<T>(
self,
target: &mut T,
newer: T,
time: ObjTime,
channel: Channel,
) -> Result<()> {
match self {
Self::UseOlder => Ok(()),
Self::UseNewer => {
*target = newer;
Ok(())
}
Self::WarnAndUseOlder => Err(ParseWarning::DuplicatingChannelObj(time, channel)),
Self::WarnAndUseNewer => {
*target = newer;
Err(ParseWarning::DuplicatingChannelObj(time, channel))
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AlwaysUseOlder;
impl Prompter for AlwaysUseOlder {
fn handle_def_duplication(&self, _: DefDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::UseOlder
}
fn handle_track_duplication(&self, _: TrackDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::UseOlder
}
fn handle_channel_duplication(&self, _: ChannelDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::UseOlder
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AlwaysUseNewer;
impl Prompter for AlwaysUseNewer {
fn handle_def_duplication(&self, _: DefDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::UseNewer
}
fn handle_track_duplication(&self, _: TrackDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::UseNewer
}
fn handle_channel_duplication(&self, _: ChannelDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::UseNewer
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AlwaysWarnAndUseOlder;
impl Prompter for AlwaysWarnAndUseOlder {
fn handle_def_duplication(&self, _: DefDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::WarnAndUseOlder
}
fn handle_track_duplication(&self, _: TrackDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::WarnAndUseOlder
}
fn handle_channel_duplication(&self, _: ChannelDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::WarnAndUseOlder
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AlwaysWarnAndUseNewer;
impl Prompter for AlwaysWarnAndUseNewer {
fn handle_def_duplication(&self, _: DefDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::WarnAndUseNewer
}
fn handle_track_duplication(&self, _: TrackDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::WarnAndUseNewer
}
fn handle_channel_duplication(&self, _: ChannelDuplication) -> DuplicationWorkaround {
DuplicationWorkaround::WarnAndUseNewer
}
}