use super::sort::where_some;
use super::{filtered_index_calculator, KeyValueCollection};
use crate::cache::{ChangeSet, SortReason, SortedChangeSet, VirtualChangeSet, VirtualRequest, VirtualResponse};
use crate::list::SortException;
use ferroui_reactive::{Observable, ObservableExt};
use ferroui_system::{IObservable, IObserver};
use std::cell::RefCell;
use std::hash::Hash;
use std::rc::Rc;
pub(crate) fn virtualise<T: Clone + 'static, K: Eq + Hash + Clone + 'static>(
source: Rc<dyn IObservable<SortedChangeSet<T, K>>>,
virtual_requests: Rc<dyn IObservable<VirtualRequest>>,
) -> Rc<dyn IObservable<VirtualChangeSet<T, K>>> {
Observable::create(move |observer: Rc<dyn IObserver<VirtualChangeSet<T, K>>>| {
let virtualiser = Rc::new(RefCell::new(Virtualiser::new(None)));
let request_virtualiser = virtualiser.clone();
let request =
virtual_requests.try_select(move |parameters: VirtualRequest| request_virtualiser.borrow_mut().virtualise_request(parameters).map_err(SortException::into_error));
let data_virtualiser = virtualiser.clone();
let data_change = source.try_select(move |updates: SortedChangeSet<T, K>| data_virtualiser.borrow_mut().update(&updates).map_err(SortException::into_error));
where_some(Observable::merge_all(vec![request, data_change])).subscribe(observer)
})
}
struct Virtualiser<T, K> {
all: KeyValueCollection<T, K>,
current: KeyValueCollection<T, K>,
is_loaded: bool,
parameters: VirtualRequest,
}
impl<T: Clone + 'static, K: Eq + Hash + Clone + 'static> Virtualiser<T, K> {
fn new(request: Option<VirtualRequest>) -> Self {
Self { all: KeyValueCollection::empty(), current: KeyValueCollection::empty(), is_loaded: false, parameters: request.unwrap_or_default() }
}
fn update(&mut self, updates: &SortedChangeSet<T, K>) -> Result<Option<VirtualChangeSet<T, K>>, SortException> {
self.is_loaded = true;
self.all = updates.sorted_items().clone();
self.virtualise(Some(updates))
}
fn virtualise_request(&mut self, parameters: VirtualRequest) -> Result<Option<VirtualChangeSet<T, K>>, SortException> {
if parameters.size() < 1 {
return Ok(None);
}
if parameters.size() == self.parameters.size() && parameters.start_index() == self.parameters.start_index() {
return Ok(None);
}
self.parameters = parameters;
self.virtualise(None)
}
fn virtualise(&mut self, updates: Option<&SortedChangeSet<T, K>>) -> Result<Option<VirtualChangeSet<T, K>>, SortException> {
if !self.is_loaded {
return Ok(None);
}
let previous = self.current.clone();
let virtualised: Vec<(K, T)> = self.all.iter().skip(self.parameters.start_index()).take(self.parameters.size()).cloned().collect();
let sort_reason = updates.map_or(SortReason::DataChanged, |updates| updates.sorted_items().sort_reason());
self.current = KeyValueCollection::new(virtualised, self.all.comparer().clone(), sort_reason, self.all.optimisations());
let notifications = filtered_index_calculator::calculate(&self.current, &previous, updates.map(|updates| updates.changes()))?;
if notifications.is_empty() && previous.count() != self.current.count() {
return Ok(None);
}
let response = VirtualResponse::new(self.parameters.size(), self.parameters.start_index(), self.all.count());
Ok(Some(VirtualChangeSet::new(ChangeSet::from(notifications), self.current.clone(), response)))
}
}