use crate::utils::cal_board_numbers;
use crate::videos::base_video::{BaseVideo, NewBaseVideo};
use crate::videos::byte_reader::ByteReader;
use crate::videos::types::{ErrReadVideoReason, Event, MouseEvent, VideoActionStateRecorder};
#[cfg(any(feature = "py", feature = "rs"))]
use crate::videos::NewSomeVideo;
use crate::videos::NewSomeVideo2;
pub struct MvfVideo {
pub file_name: String,
pub data: BaseVideo<Vec<Vec<i32>>>,
}
#[cfg(any(feature = "py", feature = "rs"))]
impl NewSomeVideo<&str> for MvfVideo {
fn new(file_name: &str) -> Self {
MvfVideo {
file_name: file_name.to_string(),
data: BaseVideo::<Vec<Vec<i32>>>::new(file_name),
}
}
}
impl NewSomeVideo2<Vec<u8>, &str> for MvfVideo {
fn new(raw_data: Vec<u8>, file_name: &str) -> Self {
MvfVideo {
file_name: file_name.to_string(),
data: BaseVideo::<Vec<Vec<i32>>>::new(raw_data),
}
}
}
impl MvfVideo {
fn read_board(&mut self, add: i32) -> Result<(), ErrReadVideoReason> {
self.data.width = self.data.get_u8()?.into();
self.data.height = self.data.get_u8()?.into();
self.data.board = vec![vec![0; self.data.width]; self.data.height];
self.data.mine_num = self.data.get_u16()?.into();
for _ in 0..self.data.mine_num {
let w = (self.data.get_u8()? as i32 + add) as usize;
let h = (self.data.get_u8()? as i32 + add) as usize;
self.data.board[h][w] = -1;
}
cal_board_numbers(&mut self.data.board);
Ok(())
}
fn parse_event(
&self,
lb: u16,
rb: u16,
mb: u16,
x: u16,
y: u16,
prev_lb: u16,
prev_rb: u16,
prev_mb: u16,
prev_x: u16,
prev_y: u16,
) -> Vec<String> {
let mut evs: Vec<String> = vec![];
if x != prev_x || y != prev_y {
evs.push("mv".to_string());
}
if lb > 0 && prev_lb == 0 {
evs.push("lc".to_string());
}
if rb > 0 && prev_rb == 0 {
evs.push("rc".to_string());
}
if mb > 0 && prev_mb == 0 {
evs.push("mc".to_string());
}
if lb == 0 && prev_lb > 0 {
evs.push("lr".to_string());
}
if rb == 0 && prev_rb > 0 {
evs.push("rr".to_string());
}
if mb == 0 && prev_mb > 0 {
evs.push("mr".to_string());
}
return evs;
}
fn apply_perm(&self, num: usize, byte: &[usize; 40], bit: &[u8; 40], e: &[u8; 5]) -> u16 {
if (e[byte[num]] & bit[num]) > 0 {
return 1;
} else {
return 0;
}
}
fn read_097(&mut self) -> Result<(), ErrReadVideoReason> {
const MULT: f64 = 100000000.0;
let mut byte = [0; 40];
let mut bit = [0u8; 40];
let mut e = [0u8; 5];
let month = self.data.get_u8()? as u64;
let day = self.data.get_u8()? as u64;
let year = self.data.get_u16()? as u64;
let hour = self.data.get_u8()? as u64;
let minute = self.data.get_u8()? as u64;
let second = self.data.get_u8()? as u64;
let days = self.data.days_since_epoch(year, month, day);
let total_seconds = days * 86400 + hour * 3600 + minute * 60 + second;
self.data.start_time = total_seconds * 1_000_000;
self.data.level = self.data.get_u8()? + 2;
let mode = self.data.get_u8()?;
if mode == 1 {
self.data.mode = 0;
} else if mode == 2 {
self.data.mode = 3;
} else if mode == 3 {
self.data.mode = 1;
} else {
self.data.mode = 2;
}
let _score_sec = self.data.get_u16()? as f64;
let _score_ths = self.data.get_u8()? as f64 / 100.0;
let bbbv = self.data.get_u16()?;
self.data.static_params.bbbv = bbbv.into();
let bbbv_solved = self.data.get_u16()?;
self.data.is_completed = bbbv == bbbv_solved;
self.data.is_official = self.data.is_completed;
self.data.is_fair = self.data.is_completed;
self.data.offset += 6;
self.data.use_question = self.data.get_u8()? != 0;
self.read_board(-1)?;
let byte_len = self.data.get_u8()?;
self.data.player_identifier = self.data.get_unknown_encoding_string(byte_len)?;
let mut s = ['\0'; 40];
let leading = self.data.get_u16()? as f64;
let num1 = leading.sqrt();
let num2 = (leading + 1000.0).sqrt();
let num3 = (num1 + 1000.0).sqrt();
let magic_code = &format!(
"{:08}",
((num3 + 1000.0).cos() * MULT).abs().round() as usize
);
for i in 0..8 {
s[i] = magic_code.chars().nth(i).unwrap();
}
let magic_code = &format!("{:08}", ((num2.sqrt()).sin() * MULT).abs().round() as usize);
for i in 0..8 {
s[i + 8] = magic_code.chars().nth(i).unwrap();
}
let magic_code = &format!("{:08}", (num3.cos() * MULT).abs().round() as usize);
for i in 0..8 {
s[i + 16] = magic_code.chars().nth(i).unwrap();
}
let magic_code = &format!(
"{:08}",
((num1.sqrt() + 1000.0).sin() * MULT).abs().round() as usize
);
for i in 0..8 {
s[i + 24] = magic_code.chars().nth(i).unwrap();
}
let magic_code = &format!(
"{:08}",
(((num2 + 1000.0).sqrt()).cos() * MULT).abs().round() as usize
);
for i in 0..8 {
s[i + 32] = magic_code.chars().nth(i).unwrap();
}
let mut cur = 0;
for i in '0'..='9' {
for j in 0..40 {
if s[j] == i {
byte[cur] = j / 8;
bit[cur] = 1 << (j % 8);
cur += 1;
}
}
}
let event_size = self.data.get_u24()?;
let mut prev_rb;
let mut prev_mb;
let mut prev_lb;
for ii in 0..5 {
e[ii] = self.data.get_u8()?;
}
prev_rb = self.apply_perm(0, &byte, &bit, &e);
prev_mb = self.apply_perm(1, &byte, &bit, &e);
prev_lb = self.apply_perm(2, &byte, &bit, &e);
let mut x = 0u16;
let mut y = 0u16;
let mut prev_x = 0u16;
let mut prev_y = 0u16;
let mut ths = 0;
let mut sec = 0;
let mouse;
for j in 0..9 {
x |= self.apply_perm(12 + j, &byte, &bit, &e) << j;
y |= self.apply_perm(3 + j, &byte, &bit, &e) << j;
}
for j in 0..7 {
ths |= self.apply_perm(21 + j, &byte, &bit, &e) << j;
}
ths *= 10;
for j in 0..10 {
sec |= self.apply_perm(28 + j, &byte, &bit, &e) << j;
}
if prev_mb > 0 {
mouse = "mc".to_string()
} else if prev_rb > 0 {
mouse = "rc".to_string()
} else if prev_lb > 0 {
mouse = "lc".to_string()
} else {
mouse = "mv".to_string()
}
if x >= self.data.width as u16 * 16 || y >= self.data.height as u16 * 16 {
x = self.data.width as u16 * 16;
y = self.data.height as u16 * 16;
}
self.data
.video_action_state_recorder
.push(VideoActionStateRecorder {
time: ths as f64 / 1000.0 + sec as f64,
event: Some(Event::Mouse(MouseEvent { mouse, x, y })),
..VideoActionStateRecorder::default()
});
for _ in 0..event_size - 1 {
for ii in 0..5 {
e[ii] = self.data.get_u8()?;
}
let rb = self.apply_perm(0, &byte, &bit, &e);
let mb = self.apply_perm(1, &byte, &bit, &e);
let lb = self.apply_perm(2, &byte, &bit, &e);
let mut x = 0u16;
let mut y = 0u16;
let mut ths = 0;
let mut sec = 0;
let mouse_s;
for j in 0..9 {
x |= self.apply_perm(12 + j, &byte, &bit, &e) << j;
y |= self.apply_perm(3 + j, &byte, &bit, &e) << j;
}
for j in 0..7 {
ths |= self.apply_perm(21 + j, &byte, &bit, &e) << j;
}
ths *= 10;
for j in 0..10 {
sec |= self.apply_perm(28 + j, &byte, &bit, &e) << j;
}
mouse_s = self.parse_event(lb, rb, mb, x, y, prev_lb, prev_rb, prev_mb, prev_x, prev_y);
prev_x = x;
prev_y = y;
prev_lb = lb;
prev_rb = rb;
prev_mb = mb;
if x >= self.data.width as u16 * 16 || y >= self.data.height as u16 * 16 {
x = self.data.width as u16 * 16;
y = self.data.height as u16 * 16;
}
for mouse in mouse_s {
self.data
.video_action_state_recorder
.push(VideoActionStateRecorder {
time: ths as f64 / 1000.0 + sec as f64,
event: Some(Event::Mouse(MouseEvent { mouse, x, y })),
..VideoActionStateRecorder::default()
});
}
}
let mut start_t = 0.0;
for v in &self.data.video_action_state_recorder {
if let Some(Event::Mouse(mouse_event)) = &v.event {
if mouse_event.mouse == "lr" {
start_t = v.time;
break;
}
}
}
let rtime = self.data.video_action_state_recorder.last().unwrap().time - start_t;
self.data.set_rtime(rtime).unwrap();
self.data.end_time = self.data.start_time + (self.data.get_rtime_ms().unwrap_or(0) as u64) * 1000;
Ok(())
}
pub fn parse(&mut self) -> Result<(), ErrReadVideoReason> {
self.data.can_analyse = true;
let mut c = self.data.get_u8()?;
let d = self.data.get_u8()?;
let _size: usize; if c == 0x11 && d == 0x4D {
self.data.offset += 25;
c = self.data.get_u8()?;
if c as char == '5' {
self.data.offset += 46;
self.data.software = "0.97 beta".to_string();
return self.read_097();
} else {
Ok(())
}
} else {
Ok(())
}
}
}