use log::{info,error,warn,trace,debug};
use crate::macros::{
ok_debug,
recv,
send,
};
use crate::collection::{
Collection,
Keychain,
ArtistKey,
AlbumKey,
SongKey,
};
use std::{
sync::Arc,
collections::HashMap,
};
use super::msg::{
SearchToKernel,
KernelToSearch,
};
use crossbeam_channel::{Sender,Receiver};
pub(crate) struct Search {
cache: HashMap<String, Keychain>, collection: Arc<Collection>, to_kernel: Sender<SearchToKernel>, from_kernel: Receiver<KernelToSearch>, }
impl Search {
pub(crate) fn init(
collection: Arc<Collection>,
to_kernel: Sender<SearchToKernel>,
from_kernel: Receiver<KernelToSearch>,
) {
let search = Self {
cache: HashMap::with_capacity(1000),
collection,
to_kernel,
from_kernel,
};
Self::main(search);
}
fn search(&mut self, input: String) -> Keychain {
if let Some(v) = self.cache.get(&input) {
return v.clone()
}
let mut artists: Vec<(f64, ArtistKey)> = self.collection.artists.iter().enumerate().map(|(i, x)| (strsim::jaro(&x.name, &input), ArtistKey::from(i))).collect();
let mut albums: Vec<(f64, AlbumKey)> = self.collection.albums.iter().enumerate().map(|(i, x)| (strsim::jaro(&x.title, &input), AlbumKey::from(i))).collect();
let mut songs: Vec<(f64, SongKey)> = self.collection.songs.iter().enumerate().map(|(i, x)| (strsim::jaro(&x.title, &input), SongKey::from(i))).collect();
artists.sort_by(|a, b| Self::cmp_f64(&a.0, &b.0));
albums.sort_by(|a, b| Self::cmp_f64(&a.0, &b.0));
songs.sort_by(|a, b| Self::cmp_f64(&a.0, &b.0));
let artists: Vec<ArtistKey> = artists.iter().map(|tuple| tuple.1).collect();
let albums: Vec<AlbumKey> = albums.iter().map(|tuple| tuple.1).collect();
let songs: Vec<SongKey> = songs.iter().map(|tuple| tuple.1).collect();
let keychain = Keychain::from_vecs(artists, albums, songs);
if self.cache.len() > 1000 {
self.cache.clear();
} else {
self.cache.insert(input, keychain.clone());
}
keychain
}
pub(crate) fn cmp_f64(a: &f64, b: &f64) -> std::cmp::Ordering {
match (*a <= *b, *a >= *b) {
(false, true) => std::cmp::Ordering::Greater,
(true, false) => std::cmp::Ordering::Less,
(true, true) => std::cmp::Ordering::Equal,
_ => {
error!("cmp_f64() has failed, input: {} - {}", a, b);
std::cmp::Ordering::Less
},
}
}
}
impl Search {
fn main(mut self) {
ok_debug!("Search");
loop {
let msg = recv!(self.from_kernel);
use KernelToSearch::*;
match msg {
Search(input) => self.msg_search(input),
DropCollection => self = self.msg_drop(),
NewCollection(_) => error!("Search: Incorrect message received - NewCollection"),
}
}
}
#[inline(always)]
fn msg_search(&mut self, input: String) {
let result = self.search(input);
send!(self.to_kernel, SearchToKernel::SearchResult(result));
}
#[inline(always)]
fn msg_drop(mut self) -> Self {
drop(self.collection);
debug!("Search: Dropped Collection, waiting...");
loop {
if let KernelToSearch::NewCollection(arc) = recv!(self.from_kernel) {
ok_debug!("Search: New Collection");
self.collection = arc;
return self
}
error!("Search: Incorrect message received");
}
}
}